60 return Opts.vplan_print_before_all || Opts.vplan_print_after_all ||
61 !Opts.vplan_print_before.empty() || !Opts.vplan_print_after.empty();
67 bool All = After ? Opts.vplan_print_after_all : Opts.vplan_print_before_all;
69 After ? Opts.vplan_print_after : Opts.vplan_print_before;
74 dbgs() <<
"VPlan for loop in '" << Fn->
getName() <<
"' "
75 << (After ?
"after" :
"before") <<
" " << NumberedPassName <<
'\n';
79 dbgs() << Plan <<
'\n';
97 auto IsConsecutiveAccess = [&](
VPValue *Addr,
Type *AccessTy) {
106 if (!VPBB->getParent())
109 auto EndIter = Term ? Term->getIterator() : VPBB->end();
114 VPValue *VPV = Ingredient.getVPSingleValue();
130 IsConsecutiveAccess(VPI->getOperand(0), VPI->getScalarType());
132 nullptr , IsConsecutive,
133 *VPI, Ingredient.getDebugLoc());
135 bool IsConsecutive = IsConsecutiveAccess(
136 VPI->getOperand(1), VPI->getOperand(0)->getScalarType());
138 *
Store, Ingredient.getOperand(1), Ingredient.getOperand(0),
139 nullptr , IsConsecutive, *VPI, Ingredient.getDebugLoc());
142 Ingredient.operands(), *VPI,
143 Ingredient.getDebugLoc(),
GEP);
155 if (VectorID == Intrinsic::experimental_noalias_scope_decl)
160 if (VectorID == Intrinsic::assume ||
161 VectorID == Intrinsic::lifetime_end ||
162 VectorID == Intrinsic::lifetime_start ||
163 VectorID == Intrinsic::sideeffect ||
164 VectorID == Intrinsic::pseudoprobe) {
169 const bool IsSingleScalar = VectorID != Intrinsic::assume &&
170 VectorID != Intrinsic::pseudoprobe;
174 Ingredient.getDebugLoc());
176 assert(!CI->hasOperandBundles() &&
177 "calls with operand bundles must not be widened");
179 *CI, VectorID,
drop_end(Ingredient.operands()), CI->getType(),
180 VPIRFlags(*CI), *VPI, CI->getDebugLoc());
184 CI->getOpcode(), Ingredient.getOperand(0), CI->getType(), CI,
188 *VPI, Ingredient.getDebugLoc());
192 "inductions must be created earlier");
201 "Only recpies with zero or one defined values expected");
202 Ingredient.eraseFromParent();
213 const Loop *L =
nullptr;
218 if (
A->getOpcode() != Instruction::Store ||
219 B->getOpcode() != Instruction::Store)
232 const APInt *Distance;
238 Type *TyA =
A->getOperand(0)->getScalarType();
239 uint64_t SizeA =
DL.getTypeStoreSize(TyA);
240 Type *TyB =
B->getOperand(0)->getScalarType();
241 uint64_t SizeB =
DL.getTypeStoreSize(TyB);
246 uint64_t MaxStoreSize = std::max(SizeA, SizeB);
248 auto VFs =
B->getParent()->getPlan()->vectorFactors();
259 : ExcludeRecipes(ExcludeRecipes.begin(), ExcludeRecipes.end()),
260 GroupLeader(GroupLeader), PSE(&PSE), L(&L) {}
269 return ExcludeRecipes.contains(
Store) ||
270 (
Store && isNoAliasViaDistance(
Store, &GroupLeader));
283 std::optional<SinkStoreInfo> SinkInfo = {}) {
284 bool CheckReads = SinkInfo.has_value();
288 if (SinkInfo && SinkInfo->shouldSkip(R))
292 if (!
R.mayWriteToMemory() && !(CheckReads &&
R.mayReadFromMemory()))
311 return (IsLoad ? R : R->getOperand(0))->getScalarType();
317template <
unsigned Opcode>
322 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
323 "Only Load and Store opcodes supported");
324 constexpr bool IsLoad = (Opcode == Instruction::Load);
327 RecipesByAddressAndType;
331 if (RepR.getOpcode() != Opcode || !FilterFn(&RepR))
335 VPValue *Addr = RepR.getOperand(IsLoad ? 0 : 1);
339 RecipesByAddressAndType[{AddrSCEV, LoadStoreTy}].push_back(&RepR);
344 for (
auto &Group :
Groups) {
359 auto InsertIfValidSinkCandidate = [ScalarVFOnly, &WorkList](
366 if (Candidate->getParent() == SinkTo ||
367 all_of(Candidate->operands(),
368 [](
VPValue *
Op) { return Op->isDefinedOutsideLoopRegions(); }) ||
380 WorkList.
insert({SinkTo, Candidate});
392 for (
auto &Recipe : *VPBB)
394 InsertIfValidSinkCandidate(VPBB,
Op);
398 for (
unsigned I = 0;
I != WorkList.
size(); ++
I) {
401 std::tie(SinkTo, SinkCandidate) = WorkList[
I];
406 auto UsersOutsideSinkTo =
408 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
410 if (
any_of(UsersOutsideSinkTo, [SinkCandidate](
VPUser *U) {
411 return !U->usesFirstLaneOnly(SinkCandidate);
414 bool NeedsDuplicating = !UsersOutsideSinkTo.empty();
416 if (NeedsDuplicating) {
420 if (
auto *SinkCandidateRepR =
425 SinkCandidateRepR->getOpcode(), SinkCandidate->
operands(),
426 nullptr, *SinkCandidateRepR, *SinkCandidateRepR,
431 Clone = SinkCandidate->
clone();
441 InsertIfValidSinkCandidate(SinkTo,
Op);
450 if (EntryBB->getNumSuccessors() != 2)
455 if (!Succ0 || !Succ1)
458 if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
460 if (Succ0->getSingleSuccessor() == Succ1)
462 if (Succ1->getSingleSuccessor() == Succ0)
479 if (!Region1->isReplicator())
481 auto *MiddleBasicBlock =
483 if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
488 if (!Region2 || !Region2->isReplicator())
491 VPValue *Mask1 = Region1->getEntryBranchOnMask()->getOperand(0);
492 VPValue *Mask2 = Region2->getEntryBranchOnMask()->getOperand(0);
493 if (!Mask1 || Mask1 != Mask2)
496 assert(Mask1 && Mask2 &&
"both region must have conditions");
502 if (TransformedRegions.
contains(Region1))
509 if (!Then1 || !Then2)
517 std::optional<VPExecutionFrequency> Freq1 =
520 if (Freq1 && Freq2) {
521 if (Freq2->Freq < Freq1->Freq) {
524 Freq1.emplace(Freq1->Freq, Freq1->IsEstimated || Freq2->IsEstimated);
548 VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
554 if (Phi1ToMove.getVPSingleValue()->user_empty()) {
555 Phi1ToMove.eraseFromParent();
558 Phi1ToMove.moveBefore(*Merge2, Merge2->begin());
572 TransformedRegions.
insert(Region1);
575 return !TransformedRegions.
empty();
583 std::string RegionName = (
Twine(
"pred.") + Instr->getOpcodeName()).str();
584 assert(Instr->getParent() &&
"Predicated instruction not in any basic block");
585 auto *BlockInMask = PredRecipe->
getMask();
600 BOMRecipe->setExecutionFrequency(RecipeWithoutMask->getExecutionFrequency(),
602 RecipeWithoutMask->clearExecutionFrequency();
611 Region->setParent(ParentRegion);
619 if (RecipeWithoutMask->getScalarType()->isStructTy())
620 Defs =
to_vector(RecipeWithoutMask->users());
623 assert((Def == RecipeWithoutMask ||
624 Def->getOpcode() == Instruction::ExtractValue) &&
625 "only extracts can use a predicated struct");
626 Def->moveBefore(*Pred, Pred->end());
627 if (Def->user_empty())
630 Exiting->appendRecipe(PHIRecipe);
631 Def->replaceAllUsesWith(PHIRecipe);
632 PHIRecipe->setOperand(0, Def);
643 if (RepR.isPredicated())
661 if (ParentRegion && ParentRegion->
getExiting() == CurrentBlock)
673 if (!VPBB->getParent())
685 R.moveBefore(*PredVPBB, PredVPBB->
end());
687 auto *ParentRegion = VPBB->getParent();
688 if (ParentRegion && ParentRegion->getExiting() == VPBB)
689 ParentRegion->setExiting(PredVPBB);
693 return !WorkList.
empty();
700 bool ShouldSimplify =
true;
701 while (ShouldSimplify) {
718 if (
IV.isTruncated())
733 for (
auto *U : FindMyCast->
users()) {
735 if (UserCast && UserCast->getUnderlyingValue() == IRCast) {
736 FoundUserCast = UserCast;
743 FindMyCast = FoundUserCast;
745 if (FindMyCast != &
IV)
770 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
772 PhiR->eraseFromParent();
838 Def->user_empty() || !Def->getUnderlyingValue() ||
839 (RepR && (RepR->isSingleScalar() || RepR->isPredicated())))
852 Def->getUnderlyingInstr()->getOpcode(), Def->operands(),
854 Def->getScalarType(), Def->getUnderlyingInstr());
855 Clone->insertAfter(Def);
856 Def->replaceAllUsesWith(Clone);
857 Def->eraseFromParent();
872 PtrIV->replaceAllUsesWith(PtrAdd);
879 if (HasOnlyVectorVFs &&
none_of(WideIV->users(), [WideIV](
VPUser *U) {
880 return U->usesScalars(WideIV);
891 Plan, ID.getKind(), ID.getInductionOpcode(),
893 WideIV->getScalarType(), WideIV->getStartValue(),
894 WideIV->getStepValue(), WideIV->getDebugLoc(), Builder, WrapFlags);
897 if (!HasOnlyVectorVFs) {
899 "plans containing a scalar VF cannot also include scalable VFs");
900 WideIV->replaceAllUsesWith(Steps);
903 WideIV->replaceUsesWithIf(Steps, [WideIV, HasScalableVF](
VPUser *U) {
905 return U->usesFirstLaneOnly(WideIV);
906 return U->usesScalars(WideIV);
922 return (IntOrFpIV && IntOrFpIV->isTruncated()) ? nullptr : WideIV;
927 if (!Def || Def->getNumOperands() != 2)
935 auto IsWideIVInc = [&]() {
936 auto &ID = WideIV->getInductionDescriptor();
939 VPValue *IVStep = WideIV->getStepValue();
940 switch (ID.getInductionOpcode()) {
941 case Instruction::Add:
943 case Instruction::FAdd:
945 case Instruction::FSub:
948 case Instruction::Sub: {
968 return IsWideIVInc() ? WideIV :
nullptr;
992 VPValue *FirstActiveLane =
B.createFirstActiveLane(Mask,
DL);
994 B.createScalarZExtOrTrunc(FirstActiveLane, CanonicalIVType,
DL);
995 VPValue *EndValue =
B.createAdd(CanonicalIV, FirstActiveLane,
DL);
1000 if (Incoming != WideIV) {
1002 EndValue =
B.createAdd(EndValue, One,
DL);
1007 VPValue *Start = WideIV->getStartValue();
1008 VPValue *Step = WideIV->getStepValue();
1009 EndValue =
B.createDerivedIV(
1011 Start, EndValue, Step);
1025 if (WideIntOrFp && WideIntOrFp->isTruncated())
1035 Start, VectorTC, Step);
1067 assert(EndValue &&
"Must have computed the end value up front");
1072 if (Incoming != WideIV)
1084 auto *Zero = Plan.
getZero(StepTy);
1085 return B.createPtrAdd(EndValue,
B.createSub(Zero, Step),
1090 return B.createNaryOp(
1091 ID.getInductionBinOp()->getOpcode() == Instruction::FAdd
1093 : Instruction::FAdd,
1094 {EndValue, Step}, {ID.getInductionBinOp()->getFastMathFlags()});
1111 const SCEV *Start, *Step;
1129 VPValue *ExitCount = Builder.createOverflowingOp(
1132 return Builder.createDerivedIV(Kind,
nullptr, StartVPV, ExitCount,
1141 VPBuilder VectorPHBuilder(VectorPH, VectorPH->getFirstNonPhi());
1148 &WideIV, VectorPHBuilder, ResumeTC))
1149 EndValues[&WideIV] = EndValue;
1159 R.getVPSingleValue()->replaceAllUsesWith(EndValue);
1160 R.eraseFromParent();
1169 for (
auto [Idx, PredVPBB] :
enumerate(ExitVPBB->getPredecessors())) {
1171 if (PredVPBB == MiddleVPBB) {
1173 Plan, ExitIRI->getOperand(Idx), EndValues, PSE);
1176 Plan, ExitIRI->getOperand(Idx), PSE, ResumeTC, L);
1179 Plan, ExitIRI->getOperand(Idx), PSE);
1182 ExitIRI->setOperand(Idx, Escape);
1206 return Plan.
getZero(Def->getScalarType());
1223 return Def->getOperand(1);
1234 assert(
X->getScalarType()->isIntegerTy(1) &&
"must have boolean operands");
1250 assert(Weights.
size() == 2 &&
"unexpected branch weights");
1252 LLVMContext::MD_prof,
1284 return Plan.
getZero(Def->getScalarType());
1288 Def->getScalarType() ==
A->getScalarType())
1298 if (Def->getScalarType() ==
A->getScalarType())
1308 A->getScalarType() == Def->getScalarType())
1314 return Def->getOperand(0);
1320 return BuildVector->getLastOperand();
1337 return BuildVector->getOperand(BuildVector->getNumOperands() - 2);
1343 return BuildVector->getOperand(Idx);
1347 if (Def->getNumOperands() == 1) {
1348 return Def->getOperand(0);
1352 return Phi->getOperand(0);
1358 if (Def->getNumOperands() == 1 &&
1364 A->getScalarType() == Def->getScalarType())
1376 return Def->getOperand(1);
1388 return VPR->getOperand(0);
1394 return Steps->getOperand(0);
1412struct VPCombineInserter {
1413 SmallVectorImpl<VPSingleDefRecipe *> &Worklist;
1415 void insertHelper(VPRecipeBase *R, VPBasicBlock *VPBB,
1429 VPCombineBuilder &Builder) {
1431 Def->replaceAllUsesWith(V);
1440 RepR && RepR->isPredicated() && RepR->getOpcode() == Instruction::Store &&
1444 RepR->getUnderlyingInstr(), RepR->operandsWithoutMask(),
1445 RepR->isSingleScalar(),
nullptr, *RepR, *RepR,
1446 RepR->getDebugLoc());
1447 Builder.insert(Unmasked);
1459 bool CanCreateNewRecipe =
1465 if (CanCreateNewRecipe &&
1468 return Builder.createLogicalAnd(
X,
Y);
1471 if (CanCreateNewRecipe &&
1476 (!Def->getOperand(0)->hasMoreThanOneUniqueUser() ||
1477 !Def->getOperand(1)->hasMoreThanOneUniqueUser()))
1478 return Builder.createLogicalAnd(
X, Builder.createOr(
Y, Z));
1481 if (CanCreateNewRecipe &&
1485 return Builder.createLogicalOr(Z,
Y);
1489 if (CanCreateNewRecipe &&
1491 return Builder.createNot(
C);
1495 Def->setOperand(0,
C);
1496 Def->setOperand(1,
Y);
1497 Def->setOperand(2,
X);
1503 if (CanCreateNewRecipe &&
1507 Y->getScalarType()->isIntegerTy(1))
1508 return Builder.createOr(
Y, Builder.createLogicalAnd(
X, Z));
1512 if (CanCreateNewRecipe &&
1518 return Builder.createSelect(Builder.createLogicalAnd(Mask0, Mask1),
X,
Y,
1519 Def->getDebugLoc());
1525 Type *TruncTy = Def->getScalarType();
1526 Type *XTy =
X->getScalarType();
1529 unsigned ExtOpcode =
1533 if (
auto *UnderlyingExt =
Y->getUnderlyingValue()) {
1535 Ext->setUnderlyingValue(UnderlyingExt);
1539 auto *Trunc = Builder.createWidenCast(Instruction::Trunc,
X, TruncTy);
1548 return Builder.createSub(Plan.
getZero(
X->getScalarType()),
X,
1549 Def->getDebugLoc(),
"", NW);
1552 if (CanCreateNewRecipe &&
1560 return Builder.createSub(
X,
Y, Def->getDebugLoc(),
"", NW);
1567 Def->getDebugLoc());
1574 MulR->hasNoSignedWrap() &&
1576 return Builder.createNaryOp(
1579 Def->getDebugLoc());
1584 return Builder.createNaryOp(
1590 if (CanCreateNewRecipe &&
1593 return Builder.createAnd(
1595 Def->getDebugLoc());
1605 return match(U, m_Not(m_Specific(Cmp))) ||
1606 (match(U, m_Select(m_Specific(Cmp), m_VPValue(),
1608 U->getOperand(1) != Cmp && U->getOperand(2) != Cmp);
1615 R->setOperand(1,
Y);
1616 R->setOperand(2,
X);
1621 R->replaceAllUsesWith(Cmp);
1626 if (!Cmp->getDebugLoc() && Def->getDebugLoc())
1627 Cmp->setDebugLoc(Def->getDebugLoc());
1640 if (
Op->getNumUsers() > 1 ||
1644 }
else if (!UnpairedCmp) {
1645 UnpairedCmp =
Op->getDefiningRecipe();
1649 UnpairedCmp =
nullptr;
1656 if (NewOps.
size() < Def->getNumOperands())
1663 if (CanCreateNewRecipe &&
1668 X->getScalarType() ==
Y->getScalarType())
1673 X->getScalarType() != Def->getScalarType())
1674 return Builder.createWidenCast(Instruction::Trunc,
X, Def->getScalarType());
1681 Def->getScalarType()->isIntegerTy(1)) {
1682 Def->setOperand(1, Plan.
getTrue());
1683 Def->setOperand(0,
Y);
1693 Def->replaceUsesWithIf(Def->getOperand(0), [Def](
VPUser *U) {
1694 return U->usesFirstLaneOnly(Def);
1704 "broadcast operand must be single-scalar");
1705 Def->setOperand(0, Z);
1710 Def->replaceUsesWithIf(
1711 X, [Def](
const VPUser *U) {
return U->usesScalars(Def); });
1723 return Builder.createNaryOp(Instruction::ExtractElement, {
X, LaneToExtract},
1724 Def->getDebugLoc());
1736 IVInc->getNumUsers() == 2) {
1742 if ((Phi->getNumUsers() == 1 || (Phi->getNumUsers() == 2 && Inc)) &&
1744 Def->replaceAllUsesWith(IVInc);
1746 Inc->replaceAllUsesWith(Phi);
1747 Phi->setOperand(0,
Y);
1756 Def->replaceUsesWithIf(StartV, [](
const VPUser *U) {
1758 return PhiR && PhiR->isInLoop();
1775 [[maybe_unused]]
unsigned InitWorklistSize = Worklist.
size();
1777 VPCombineBuilder Builder({Worklist});
1778 while (!Worklist.
empty()) {
1779 assert(Worklist.
size() < InitWorklistSize * 2 &&
1780 "Worklist is growing large, possible cycle?");
1782 Builder.setInsertPoint(Def);
1788 Def->replaceAllUsesWith(New);
1789 Def->eraseFromParent();
1793 Def->eraseFromParent();
1811 R.getVPSingleValue()->replaceAllUsesWith(
X);
1827 while (!Worklist.
empty()) {
1836 R->replaceAllUsesWith(
1837 Builder.createLogicalAnd(HeaderMask, Builder.createLogicalAnd(
X,
Y)));
1841static std::optional<Instruction::BinaryOps>
1844 case Intrinsic::masked_udiv:
1845 return Instruction::UDiv;
1846 case Intrinsic::masked_sdiv:
1847 return Instruction::SDiv;
1848 case Intrinsic::masked_urem:
1849 return Instruction::URem;
1850 case Intrinsic::masked_srem:
1851 return Instruction::SRem;
1868 if (RepR && (RepR->isSingleScalar() || RepR->isPredicated()))
1872 if (RepR && RepR->getOpcode() == Instruction::Store &&
1875 RepOrWidenR->getUnderlyingInstr(), RepOrWidenR->operands(),
1876 true ,
nullptr , *RepR ,
1877 *RepR , RepR->getDebugLoc());
1878 Clone->insertBefore(RepOrWidenR);
1880 VPValue *ExtractOp = Clone->getOperand(0);
1886 Clone->setOperand(0, ExtractOp);
1887 RepR->eraseFromParent();
1899 VPValue *SafeDivisor = Builder.createSelect(
1900 IntrR->getOperand(2), IntrR->getOperand(1),
1902 VPValue *Clone = Builder.createNaryOp(
1903 *
Opc, {IntrR->getOperand(0), SafeDivisor},
1906 IntrR->eraseFromParent();
1915 auto IntroducesBCastOf = [](
const VPValue *
Op) {
1924 return !U->usesScalars(
Op);
1928 if (
any_of(RepOrWidenR->users(), IntroducesBCastOf(RepOrWidenR)) &&
1931 make_filter_range(Op->users(), not_equal_to(RepOrWidenR)),
1932 IntroducesBCastOf(Op)))
1936 bool LiveInNeedsBroadcast =
1937 isa<VPIRValue>(Op) && !isa<VPConstant>(Op);
1938 auto *OpR = dyn_cast<VPReplicateRecipe>(Op);
1939 return LiveInNeedsBroadcast || (OpR && OpR->isSingleScalar());
1947 RepOrWidenR->getUnderlyingInstr());
1948 Clone->insertBefore(RepOrWidenR);
1949 RepOrWidenR->replaceAllUsesWith(Clone);
1951 RepOrWidenR->eraseFromParent();
1984 if (Blend.isNormalized() || !
match(Blend.getMask(0),
m_False()))
1985 UniqueValues.
insert(Blend.getIncomingValue(0));
1986 for (
unsigned I = 1;
I != Blend.getNumIncomingValues(); ++
I)
1988 UniqueValues.
insert(Blend.getIncomingValue(
I));
1990 if (UniqueValues.
size() == 1) {
1991 Blend.replaceAllUsesWith(*UniqueValues.
begin());
1992 Blend.eraseFromParent();
1996 if (Blend.isNormalized())
2002 unsigned StartIndex = 0;
2003 for (
unsigned I = 0;
I != Blend.getNumIncomingValues(); ++
I) {
2015 OperandsWithMask.
push_back(Blend.getIncomingValue(StartIndex));
2017 for (
unsigned I = 0;
I != Blend.getNumIncomingValues(); ++
I) {
2018 if (
I == StartIndex)
2020 OperandsWithMask.
push_back(Blend.getIncomingValue(
I));
2021 OperandsWithMask.
push_back(Blend.getMask(
I));
2026 OperandsWithMask, Blend, Blend.getDebugLoc());
2027 NewBlend->insertBefore(&Blend);
2029 VPValue *DeadMask = Blend.getMask(StartIndex);
2031 Blend.eraseFromParent();
2036 if (NewBlend->getNumOperands() == 3 &&
2038 VPValue *Inc0 = NewBlend->getOperand(0);
2039 VPValue *Inc1 = NewBlend->getOperand(1);
2040 VPValue *OldMask = NewBlend->getOperand(2);
2041 NewBlend->setOperand(0, Inc1);
2042 NewBlend->setOperand(1, Inc0);
2043 NewBlend->setOperand(2, NewMask);
2070 APInt MaxVal = AlignedTC - 1;
2073 unsigned NewBitWidth =
2079 bool MadeChange =
false;
2107 "canonical IV is not expected to have a truncation");
2112 NewWideIV->insertBefore(WideIV);
2119 Cmp->replaceAllUsesWith(
2120 VPBuilder(Cmp).createICmp(Cmp->getPredicate(), NewWideIV, NewBTC));
2134 return any_of(
Cond->getDefiningRecipe()->operands(), [&Plan, BestVF, BestUF,
2136 return isConditionTrueViaVFAndUF(C, Plan, BestVF, BestUF, PSE);
2150 const SCEV *VectorTripCount =
2155 "Trip count SCEV must be computable");
2170 bool MadeChange =
false;
2178 for (
VPBasicBlock *VPBB : {PreheaderVPBB, ExitingVPBB}) {
2187 Builder.setInsertPoint(Extract);
2190 Start = Builder.createAdd(
2195 Extract->eraseFromParent();
2214 return !
Offset ||
Offset->isDefinedOutsideLoopRegions();
2233 auto *Term = &ExitingVPBB->
back();
2244 const SCEV *VectorTripCount =
2250 "Trip count SCEV must be computable");
2264 Term->setOperand(1, Plan.
getTrue());
2269 {}, Term->getDebugLoc());
2271 Term->eraseFromParent();
2279 assert(Plan.
hasVF(BestVF) &&
"BestVF is not available in Plan");
2280 assert(Plan.
hasUF(BestUF) &&
"BestUF is not available in Plan");
2296 RecurKind RK = PhiR.getRecurrenceKind();
2303 RecWithFlags->dropPoisonGeneratingFlags();
2310 return MemR->getAlign();
2315struct VPCSEDenseMapInfo :
public DenseMapInfo<VPSingleDefRecipe *> {
2318 static Type *getGEPSourceElementType(
const VPSingleDefRecipe *R) {
2321 return TypeSwitch<const VPSingleDefRecipe *, Type *>(R)
2322 .Case([](
const VPReplicateRecipe *
I) ->
Type * {
2324 return GEP->getSourceElementType();
2327 .Case<VPVectorPointerRecipe, VPWidenGEPRecipe>(
2328 [](
auto *
I) {
return I->getSourceElementType(); })
2329 .
Default([](
auto *) {
return nullptr; });
2333 static bool canHandle(
const VPSingleDefRecipe *Def) {
2340 if (!
C || (!
C->first &&
C->second == Instruction::Alloca))
2345 if (
Def->mayWriteToMemory())
2347 return !
Def->mayReadFromMemory() ||
2348 (!
C->first &&
C->second == Instruction::Load);
2352 static unsigned getHashValue(
const VPSingleDefRecipe *Def) {
2355 getGEPSourceElementType(Def),
Def->getScalarType(),
2358 if (RFlags->hasPredicate())
2361 return hash_combine(Result, SIVSteps->getInductionOpcode());
2372 static bool isEqual(
const VPSingleDefRecipe *L,
const VPSingleDefRecipe *R) {
2373 if (
L->getVPRecipeID() !=
R->getVPRecipeID() ||
2376 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2378 !
equal(
L->operands(),
R->operands()))
2382 "must have valid opcode info for both recipes");
2384 if (LFlags->hasPredicate() &&
2385 LFlags->getPredicate() !=
2389 if (LSIV->getInductionOpcode() !=
2407 const VPRegionBlock *RegionL =
L->getRegion();
2408 const VPRegionBlock *RegionR =
R->getRegion();
2411 L->getParent() !=
R->getParent())
2413 return L->getScalarType() ==
R->getScalarType();
2431 if (R.mayWriteToMemory())
2434 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2437 auto [It, Inserted] =
2438 (IsLoad ? LoadCSEMap : CSEMap).try_emplace(Def, Def);
2443 if (!VPDT.
dominates(V->getParent(), VPBB))
2461 Def->replaceAllUsesWith(V);
2475 bool Sinking =
false) {
2504 "Expected vector prehader's successor to be the vector loop region");
2512 return !Op->isDefinedOutsideLoopRegions();
2518 R.moveBefore(*Preheader, Preheader->
end());
2536 assert(!RepR->isPredicated() &&
2537 "Expected prior transformation of predicated replicates to "
2538 "replicate regions");
2543 if (!RepR->isSingleScalar())
2547 if (RepR->getOpcode() == Instruction::Store &&
2548 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2556 if (
any_of(Def->users(), [&SinkBB, &LoopRegion](
VPUser *U) {
2557 auto *UserR = cast<VPRecipeBase>(U);
2558 VPBasicBlock *Parent = UserR->getParent();
2560 if (SinkBB && SinkBB != Parent)
2565 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2566 Parent->getSinglePredecessor() != LoopRegion;
2576 assert((!R.mayWriteToMemory() ||
2577 (RepR && RepR->getOpcode() == Instruction::Store &&
2578 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2579 "The only recipes that may write to memory are expected to be "
2580 "stores with invariant pointer-operand");
2588 "Defining block must dominate sink block");
2613 VPValue *ResultVPV = R.getVPSingleValue();
2615 unsigned NewResSizeInBits = MinBWs.
lookup(UI);
2616 if (!NewResSizeInBits)
2629 (void)OldResSizeInBits;
2637 VPW->dropPoisonGeneratingFlags();
2639 assert((OldResSizeInBits != NewResSizeInBits ||
2641 "Only ICmps should not need extending the result.");
2654 unsigned OpSizeInBits =
Op->getScalarType()->getScalarSizeInBits();
2655 if (OpSizeInBits == NewResSizeInBits)
2657 assert(OpSizeInBits > NewResSizeInBits &&
"nothing to truncate");
2658 auto [ProcessedIter, Inserted] = ProcessedTruncs.
try_emplace(
Op);
2662 Builder.setInsertPoint(PH);
2664 Builder.setInsertPoint(&R);
2665 ProcessedIter->second =
2666 Builder.createWidenCast(Instruction::Trunc,
Op, NewResTy);
2668 Op = ProcessedIter->second;
2672 NWR->insertBefore(&R);
2677 VPValue *Replacement = NWR->getVPSingleValue();
2684 R.eraseFromParent();
2690 std::optional<VPDominatorTree> VPDT;
2698 bool SimplifiedPhi =
false;
2709 "Two successors expected for BranchOnCond");
2710 unsigned RemovedIdx;
2721 "There must be a single edge between VPBB and its successor");
2726 SimplifiedPhi =
true;
2730 if (!PhiR || PhiR->getNumIncoming() != 1)
2732 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
2733 PhiR->eraseFromParent();
2750 if (Reachable.contains(
B))
2761 for (
VPValue *Def : R.definedValues())
2762 Def->replaceAllUsesWith(&Tmp);
2763 R.eraseFromParent();
2767 return SimplifiedPhi;
2795 auto GetSimplifiedLiveInViaSCEV = [&](
VPValue *VPV) ->
VPValue * {
2804 if (
VPValue *SimplifiedLiveIn = GetSimplifiedLiveInViaSCEV(LiveIn))
2805 LiveIn->replaceAllUsesWith(SimplifiedLiveIn);
2816 "expected to run before loop regions are created");
2818 auto CanUseVersionedStride = [&VPDT, Header = Header, &Plan](
VPUser *U) {
2824 return VPDT.
dominates(Header, R->getParent());
2828 Value *StrideV = Stride->getValue();
2829 const APInt *StrideConst;
2836 CanUseVersionedStride);
2850 CanUseVersionedStride);
2852 RewriteMap[StrideV] = StrideExpr;
2858 const SCEV *ScevExpr = ExpSCEV.getSCEV();
2859 const SCEV *NewSCEV =
2864 ExpSCEV.replaceAllUsesWith(NewExp);
2874 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](
VPRecipeBase *Root) {
2879 while (!Worklist.
empty()) {
2882 if (!Visited.
insert(CurRec).second)
2904 RecWithFlags->isDisjoint()) {
2907 Builder.createAdd(
A,
B, RecWithFlags->getDebugLoc());
2908 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
2909 RecWithFlags->replaceAllUsesWith(New);
2910 RecWithFlags->eraseFromParent();
2913 RecWithFlags->dropPoisonGeneratingFlags();
2918 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
2919 "found instruction with poison generating flags not covered by "
2920 "VPRecipeWithIRFlags");
2925 if (
VPRecipeBase *OpDef = Operand->getDefiningRecipe())
2947 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
2948 if (AddrDef && WidenRec->isConsecutive() && WidenRec->getMask() &&
2949 match(WidenRec->getMask(), m_UnlessHdrMask))
2950 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2952 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
2953 if (AddrDef && InterleaveRec->getMask() &&
2954 match(InterleaveRec->getMask(), m_UnlessHdrMask))
2955 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2965 const bool &EpilogueAllowed) {
2966 if (InterleaveGroups.empty())
2977 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
2984 for (
const auto *IG : InterleaveGroups) {
2987 for (
auto *Member : IG->members())
2989 StartMember = Member;
2997 for (
unsigned I = 0;
I < IG->getFactor(); ++
I) {
3003 StoredValues.
push_back(StoreR->getStoredValue());
3010 bool NeedsMaskForGaps =
3011 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
3012 (!StoredValues.
empty() && !IG->isFull());
3015 auto *InsertPos = IRMemberToRecipe.
lookup(IRInsertPos);
3019 "Dead member in non-load group?");
3024 InsertPos->getAsRecipe()))
3025 InsertPos = MemberR;
3026 IRInsertPos = &InsertPos->getIngredient();
3036 VPValue *Addr = Start->getAddr();
3038 if (IG->getIndex(StartMember) != 0 ||
3046 assert(IG->getIndex(IRInsertPos) != 0 &&
3047 "index of insert position shouldn't be zero");
3051 IG->getIndex(IRInsertPos),
3055 Addr =
B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
3061 if (IG->isReverse()) {
3064 -(int64_t)IG->getFactor(), NW, InsertPosR->
getDebugLoc());
3065 ReversePtr->insertBefore(InsertPosR);
3069 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
3071 VPIG->insertBefore(InsertPosR);
3074 for (
unsigned i = 0; i < IG->getFactor(); ++i)
3077 if (!Member->getType()->isVoidTy()) {
3099struct CountableConditionMatch {
3101 PredicatedScalarEvolution &PSE;
3104 CountableConditionMatch(VPValue *&Cmp, PredicatedScalarEvolution &PSE,
3108 template <
typename ITy>
bool match(ITy *V)
const {
3128 return CountableConditionMatch(Cmp, PSE, L);
3147 VPValue *Uncountable =
nullptr;
3164 if (ExitBlocks.
size() != 1)
3171 if (!ExitBlocks.
front()->phis().empty())
3187 LatchVPBB->clearSuccessors();
3197 Term->setOperand(0, Countable);
3261 VPValue *UncountableCondition =
nullptr;
3268 Worklist.
push_back(UncountableCondition);
3269 while (!Worklist.
empty()) {
3273 if (V->isDefinedOutsideLoopRegions())
3306 if (Recipes.
empty() ||
3310 return UncountableCondition;
3365 for (
auto &Exit : Exits) {
3366 if (Exit.EarlyExitingVPBB == LatchVPBB)
3370 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
3371 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
3385 "loop with side effects",
3386 "EarlyExitSideEffectsCond", ORE, TheLoop);
3401 assert(
Load &&
"Couldn't find exactly one load");
3404 "Uncountable exit condition load is conditional.");
3418 DL.getTypeStoreSize(
Load->getScalarType()).getFixedValue());
3424 "load used by the exit condition that may "
3426 "EarlyExitSideEffectsFaultingLoad", ORE,
3439 "load used by the exit condition with an "
3440 "unsupported memory access pattern",
3441 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3449 "load used by the exit condition with an "
3450 "unsupported memory access pattern",
3451 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3461 while (InsertIt != HeaderVPBB->
end() &&
3463 erase(ConditionRecipes, &*InsertIt);
3466 for (
auto *Recipe :
reverse(ConditionRecipes))
3467 Recipe->moveBefore(*HeaderVPBB, InsertIt);
3471 VPBuilder MaskBuilder(HeaderVPBB, InsertIt);
3473 Type *IVScalarTy =
IV->getScalarType();
3479 "uncountable.exit.mask");
3484 if (R.mayReadOrWriteMemory() && &R !=
Load) {
3486 if (!VPDT.
dominates(R.getParent(), LatchVPBB)) {
3488 "Early exit loop with side effects contains unsupported "
3489 "conditional memory operations",
3490 "EarlyExitSideEffectsUnsupportedConditionalMemOps", ORE, TheLoop);
3501 "Expected BranchOnCond terminator for MiddleVPBB");
3512 auto Phis = ScalarPH->
phis();
3517 "Early exit loop with side effects contains "
3518 "unsupported reductions, inductions or recurrences",
3519 "EarlyExitSideEffectsReductions", ORE, TheLoop);
3527 "Continuing from different IV");
3563 "Auto-vectorization of early exit loops with potentially "
3564 "faulting loads is not supported",
3565 "EarlyExitFaultingLoads", ORE, TheLoop);
3569 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
3571 for (
auto [EarlyExitingVPBB, ExitBlock] :
3578 cast<VPIRPhi>(&R)->getIncomingValueForBlock(EarlyExitingVPBB);
3581 if (ExitV != PhiR.getBackedgeValue())
3584 "Found reduction used on an early exit",
3585 "Cannot vectorize early exit loop with reduction used on an "
3587 "ReductionUsedOnEarlyExit", ORE, TheLoop);
3594 VPValue *CondOfEarlyExitingVPBB;
3595 [[maybe_unused]]
bool Matched =
3596 match(EarlyExitingVPBB->getTerminator(),
3598 assert(Matched &&
"Terminator must be BranchOnCond");
3602 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
3603 auto *CondToEarlyExit = EarlyExitingBuilder.
createNaryOp(
3605 TrueSucc == ExitBlock
3606 ? CondOfEarlyExitingVPBB
3607 : EarlyExitingBuilder.
createNot(CondOfEarlyExitingVPBB));
3613 "exit condition must dominate the latch");
3621 assert(!Exits.
empty() &&
"must have at least one early exit");
3628 for (
const auto &[Num, VPB] :
enumerate(RPOT))
3631 return RPOIdx[
A.EarlyExitingVPBB] < RPOIdx[
B.EarlyExitingVPBB];
3637 for (
unsigned I = 0;
I + 1 < Exits.
size(); ++
I)
3638 for (
unsigned J =
I + 1; J < Exits.
size(); ++J)
3640 Exits[
I].EarlyExitingVPBB) &&
3641 "RPO sort must place dominating exits before dominated ones");
3647 VPValue *Combined = Exits[0].CondToExit;
3669 "Unexpected terminator");
3670 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
3671 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
3672 LatchExitingBranch->eraseFromParent();
3675 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
3676 LatchVPBB->clearSuccessors();
3681 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
3682 MiddleVPBB->clearPredecessors();
3683 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
3685 LatchVPBB, MiddleVPBB, ORE,
3686 TheLoop, PSE, DT, AC);
3691 for (
unsigned Idx = 0; Idx != Exits.
size(); ++Idx) {
3695 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
3703 Exits.
size() == 1 ? VectorEarlyExitVPBBs[0]
3706 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
3738 for (
auto [Exit, VectorEarlyExitVPBB] :
3739 zip_equal(Exits, VectorEarlyExitVPBBs)) {
3740 auto &[EarlyExitingVPBB, EarlyExitVPBB,
_] = Exit;
3752 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
3753 VPValue *NewIncoming = IncomingVal;
3755 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
3760 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
3761 ExitIRI->addIncoming(NewIncoming);
3764 EarlyExitingVPBB->getTerminator()->eraseFromParent();
3799 bool IsLastDispatch = (
I + 2 == Exits.
size());
3801 IsLastDispatch ? VectorEarlyExitVPBBs.
back()
3807 VectorEarlyExitVPBBs[
I]->setPredecessors({CurrentBB});
3810 CurrentBB = FalseBB;
3825 VPValue *VecOp = Red->getVecOp();
3828 if (Red->isPartialReduction())
3832 auto IsExtendedRedValidAndClampRange =
3845 "getExtendedReductionCost only supports integer types");
3846 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
3847 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
3848 Red->getFastMathFlagsOrNone(), CostKind);
3849 return ExtRedCost.
isValid() && ExtRedCost < ExtCost + RedCost;
3857 IsExtendedRedValidAndClampRange(
3877 Type *LHSSrcTy =
LHS->getOperand(0)->getScalarType();
3879 Type *RHSSrcTy =
RHS ?
RHS->getOperand(0)->getScalarType() : LHSSrcTy;
3881 if (
Mul->getScalarType()->getScalarSizeInBits() >=
3884 if (ExtKind == ExtendKind::PR_ZeroExtend)
3885 return Mul->hasNoUnsignedWrap();
3886 return ExtKind == ExtendKind::PR_SignExtend &&
Mul->hasNoSignedWrap();
3902 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3903 Opcode != Instruction::FAdd)
3907 if (Red->isPartialReduction())
3913 auto IsMulAccValidAndClampRange =
3925 (Ext0->getOpcode() != Ext1->getOpcode() ||
3926 Ext0->getOpcode() == Instruction::CastOps::FPExt))
3930 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
3932 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
3933 SrcVecTy, CostKind);
3939 ExtCost += Ext0->computeCost(VF, Ctx);
3941 ExtCost += Ext1->computeCost(VF, Ctx);
3943 ExtCost += OuterExt->computeCost(VF, Ctx);
3945 return MulAccCost.
isValid() &&
3946 MulAccCost < ExtCost + MulCost + RedCost;
3951 VPValue *VecOp = Red->getVecOp();
3989 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
3991 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
3992 Mul->setOperand(1, ExtB);
4002 ExtendAndReplaceConstantOp(RecipeA, RecipeB,
B,
Mul);
4007 IsMulAccValidAndClampRange(
Mul, RecipeA, RecipeB,
nullptr)) {
4014 if (!
Sub && IsMulAccValidAndClampRange(
Mul,
nullptr,
nullptr,
nullptr))
4031 ExtendAndReplaceConstantOp(Ext0, Ext1,
B,
Mul);
4040 (Ext->getOpcode() == Ext0->getOpcode() ||
4041 (Ext0 == Ext1 && Ext0->getOpcode() == Instruction::SExt)) &&
4042 Ext0->getOpcode() == Ext1->getOpcode() &&
Mul->hasOneUse() &&
4044 IsMulAccValidAndClampRange(
Mul, Ext0, Ext1, Ext)) {
4046 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(),
nullptr,
4047 *Ext0, *Ext0, Ext0->getDebugLoc());
4048 NewExt0->insertBefore(Ext0);
4053 Ext->getScalarType(),
nullptr, *Ext1,
4054 *Ext1, Ext1->getDebugLoc());
4057 auto *NewMul =
Mul->cloneWithOperands({NewExt0, NewExt1});
4058 NewMul->insertBefore(
Mul);
4059 Ext->replaceAllUsesWith(NewMul);
4060 Ext->eraseFromParent();
4061 Mul->eraseFromParent();
4075 if (Red->isPartialReduction())
4079 auto IP = std::next(Red->getIterator());
4090 Red->replaceAllUsesWith(AbstractR);
4112 return CommonMetadata;
4115template <
unsigned Opcode>
4120 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
4121 "Only Load and Store opcodes supported");
4128 for (
auto Recipes :
Groups) {
4129 if (Recipes.size() < 2)
4133 "Expected all recipes in group to have the same load-store type");
4140 VPValue *MaskI = RecipeI->getMask();
4146 bool HasComplementaryMask =
false;
4151 VPValue *MaskJ = RecipeJ->getMask();
4160 if (HasComplementaryMask) {
4161 assert(Group.
size() >= 2 &&
"must have at least 2 entries");
4171template <
typename InstType>
4189 for (
auto &Group :
Groups) {
4209 return R->isSingleScalar() == IsSingleScalar;
4211 "all members in group must agree on IsSingleScalar");
4216 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
4217 IsSingleScalar,
nullptr, *EarliestLoad, CommonMetadata);
4219 UnpredicatedLoad->insertBefore(EarliestLoad);
4223 Load->replaceAllUsesWith(UnpredicatedLoad);
4224 Load->eraseFromParent();
4233 if (!StoreLoc || !StoreLoc->AATags.Scope)
4240 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
4252 for (
auto &Group :
Groups) {
4265 VPValue *SelectedValue = Group[0]->getOperand(0);
4268 bool IsSingleScalar = Group[0]->isSingleScalar();
4269 for (
unsigned I = 1;
I < Group.size(); ++
I) {
4270 assert(IsSingleScalar == Group[
I]->isSingleScalar() &&
4271 "all members in group must agree on IsSingleScalar");
4272 VPValue *Mask = Group[
I]->getMask();
4274 SelectedValue = Builder.createSelect(
4277 Value->getScalarType()));
4285 StoreWithMinAlign->getUnderlyingInstr(),
4286 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
4287 nullptr, *LastStore, CommonMetadata);
4288 UnpredicatedStore->insertBefore(*InsertBB, LastStore->
getIterator());
4292 Store->eraseFromParent();
4299 assert(UF > 1 &&
"Expected plan to have an UF > 1");
4305 VPValue *StoredValue =
nullptr;
4311 assert(
MemOp->isConsecutive() &&
"Expected consecutive load/store");
4315 assert(!
MemOp->isMasked() &&
"Masked accesses are not supported yet");
4318 : R.getVPSingleValue()->getScalarType();
4320 std::optional<Instruction::CastOps> CastHint;
4322 : R.getVPSingleValue()->getSingleUser();
4324 CastHint = Cast->getOpcode();
4327 if (!
TTI.hasMultiVectorLoadStore(
4329 VectorAccessType, IsStore, CastHint))
4337 VPBuilder Builder(VPBB, R.getIterator());
4339 VPValue *WideStoredValue = Builder.createNaryOp(
4342 {Multiplier, Ptr,
Align, WideStoredValue},
nullptr,
4343 {}, *
MemOp, R.getDebugLoc());
4345 VPValue *OldLoad = R.getVPSingleValue();
4355 R.eraseFromParent();
4371 VPValue *OpV,
unsigned Idx,
bool IsScalable) {
4376 if (Member0Op == OpV)
4386 return !IsScalable && !W->getMask() && W->isConsecutive() &&
4389 return IR->getInterleaveGroup()->isFull() &&
IR->getVPValue(Idx) == OpV;
4409 if (R->getScalarType() != WideMember0->getScalarType())
4411 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
4419 if (V->isDefinedOutsideLoopRegions())
4421 auto [It, Inserted] = FirstMembersOf.try_emplace(V,
Ops);
4422 if (!Inserted && (It->second.front() == V || V == WideMember0) &&
4427 for (
unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
4430 OpsI.
push_back(
Op->getDefiningRecipe()->getOperand(Idx));
4435 if (
any_of(
enumerate(OpsI), [WideMember0, Idx, IsScalable](
const auto &
P) {
4436 const auto &[OpIdx, OpV] =
P;
4437 return !
canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
4448static std::optional<ElementCount>
4452 if (!InterleaveR || InterleaveR->
getMask())
4453 return std::nullopt;
4455 Type *GroupElementTy =
nullptr;
4459 return Op->getScalarType() == GroupElementTy;
4461 return std::nullopt;
4465 return Op->getScalarType() == GroupElementTy;
4467 return std::nullopt;
4471 if (IG->getFactor() != IG->getNumMembers() || IG->isReverse())
4472 return std::nullopt;
4478 assert(
Size.isScalable() == VF.isScalable() &&
4479 "if Size is scalable, VF must be scalable and vice versa");
4480 return Size.getKnownMinValue();
4484 unsigned MinVal = VF.getKnownMinValue();
4486 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
4489 return std::nullopt;
4497 return RepR && RepR->isSingleScalar();
4511 if (V->isDefinedOutsideLoopRegions()) {
4514 return M->isDefinedOutsideLoopRegions() &&
4515 M->getScalarType() == V->getScalarType();
4517 "expected distinct loop-invariant values of matching scalar type");
4532 for (
unsigned Idx = 0,
E = WideMember0->getNumOperands(); Idx !=
E; ++Idx) {
4534 for (
VPValue *Member : Members)
4535 OpsI.
push_back(Member->getDefiningRecipe()->getOperand(Idx));
4536 WideMember0->setOperand(
4545 auto *LI =
cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos());
4547 *LI, LoadGroup->getAddr(), LoadGroup->getMask(),
true,
4548 *LoadGroup, LoadGroup->getDebugLoc());
4554 assert(RepR->isSingleScalar() && RepR->getOpcode() == Instruction::Load &&
4555 "must be a single scalar load");
4556 NarrowedOps.
insert(RepR);
4561 VPValue *PtrOp = WideLoad->getAddr();
4563 PtrOp = VecPtr->getOperand(0);
4568 nullptr, {}, *WideLoad);
4569 N->insertBefore(WideLoad);
4574std::unique_ptr<VPlan>
4594 "unexpected branch-on-count");
4598 std::optional<ElementCount> VFToOptimize;
4612 if (R.mayWriteToMemory() && !InterleaveR)
4618 return any_of(V->users(), [&](VPUser *U) {
4619 auto *UR = cast<VPRecipeBase>(U);
4620 return UR->getParent()->getParent() != VectorLoop;
4637 std::optional<ElementCount> NarrowedVF =
4639 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
4641 VFToOptimize = NarrowedVF;
4644 if (InterleaveR->getStoredValues().empty())
4649 auto *Member0 = InterleaveR->getStoredValues()[0];
4659 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
4662 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
4663 return IR && IR->getInterleaveGroup()->isFull() &&
4664 IR->getVPValue(Op.index()) == Op.value();
4673 VFToOptimize->isScalable(), FirstMembersOf))
4678 if (StoreGroups.empty())
4682 bool RequiresScalarEpilogue =
4693 std::unique_ptr<VPlan> NewPlan;
4695 NewPlan = std::unique_ptr<VPlan>(Plan.
duplicate());
4696 Plan.
setVF(*VFToOptimize);
4697 NewPlan->removeVF(*VFToOptimize);
4704 for (
auto *StoreGroup : StoreGroups) {
4706 NarrowedOps, Preheader);
4712 StoreGroup->getDebugLoc());
4719 Type *CanIVTy = VectorLoop->getCanonicalIVType();
4725 if (VFToOptimize->isScalable()) {
4728 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale,
UF},
4736 materializeVectorTripCount(Plan, VectorPH,
false,
4737 RequiresScalarEpilogue, Step);
4742 removeDeadRecipes(Plan);
4745 "All VPVectorPointerRecipes should have been removed");
4763 "Cannot handle loops with uncountable early exits");
4770 assert(RecurSplice &&
"expected FirstOrderRecurrenceSplice");
4777 if (
any_of(RecurSplice->users(),
4778 [](
VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
4859 {},
"vector.recur.extract.for.phi");
4862 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
4876 VPValue *WidenIVCandidate = BinOp->getOperand(0);
4877 VPValue *InvariantCandidate = BinOp->getOperand(1);
4879 std::swap(WidenIVCandidate, InvariantCandidate);
4893 auto *ClonedOp = BinOp->
clone();
4894 if (ClonedOp->getOperand(0) == WidenIV) {
4895 ClonedOp->setOperand(0, ScalarIV);
4897 assert(ClonedOp->getOperand(1) == WidenIV &&
"one operand must be WideIV");
4898 ClonedOp->setOperand(1, ScalarIV);
4912 return std::nullopt;
4917 return std::nullopt;
4929 auto CheckSentinel = [&SE](
const SCEV *IVSCEV,
4930 bool UseMax) -> std::optional<APSInt> {
4932 for (
bool Signed : {
true,
false}) {
4941 return std::nullopt;
4949 PhiR->getRecurrenceKind()))
4958 VPValue *BackedgeVal = PhiR->getBackedgeValue();
4972 !
match(FindLastSelect,
4981 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
4986 "IVOfExpressionToSink not being an AddRec must imply "
4987 "FindLastExpression not being an AddRec.");
4996 bool UseMax = *StepDirection;
4997 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
4998 bool UseSigned = SentinelVal && SentinelVal->isSigned();
5005 if (IVOfExpressionToSink) {
5006 const SCEV *FindLastExpressionSCEV =
5008 if (std::optional<bool> NewUseMax =
5010 if (
auto NewSentinel =
5011 CheckSentinel(FindLastExpressionSCEV, *NewUseMax)) {
5014 SentinelVal = *NewSentinel;
5015 UseSigned = NewSentinel->isSigned();
5016 UseMax = *NewUseMax;
5017 IVSCEV = FindLastExpressionSCEV;
5018 IVOfExpressionToSink =
nullptr;
5028 if (AR->hasNoSignedWrap())
5030 else if (AR->hasNoUnsignedWrap())
5040 VPValue *NewFindLastSelect = BackedgeVal;
5042 if (!SentinelVal || IVOfExpressionToSink) {
5045 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
5046 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
5047 if (
match(FindLastSelect,
5049 SelectCond = LoopBuilder.
createNot(SelectCond);
5056 if (SelectCond !=
Cond || IVOfExpressionToSink) {
5059 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
5068 VPIRFlags Flags(MinMaxKind,
false,
false,
5074 NewFindLastSelect, Flags, ExitDL);
5077 VPValue *VectorRegionExitingVal = ReducedIV;
5078 bool SunkExpression =
false;
5079 if (IVOfExpressionToSink) {
5080 VectorRegionExitingVal =
5082 ReducedIV, IVOfExpressionToSink);
5083 SunkExpression =
true;
5087 VPValue *StartVPV = PhiR->getStartValue();
5094 NewRdxResult = MiddleBuilder.
createSelect(Cmp, VectorRegionExitingVal,
5104 AnyOfPhi->insertAfter(PhiR);
5111 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
5124 PhiR->hasUsesOutsideReductionChain());
5126 NewPhiR->setExpressionSunk();
5127 NewPhiR->insertBefore(PhiR);
5128 PhiR->replaceAllUsesWith(NewPhiR);
5129 PhiR->eraseFromParent();
5135struct ReductionExtend {
5136 Type *SrcType =
nullptr;
5143struct ExtendedReductionOperand {
5147 ReductionExtend ExtendA, ExtendB;
5155struct PartialReductionDescriptor {
5158 VPWidenRecipe *ReductionBinOp =
nullptr;
5160 ExtendedReductionOperand ExtendedOp;
5167 unsigned AccumulatorOpIdx;
5168 unsigned ScaleFactor;
5171 VPBlendRecipe *Blend =
nullptr;
5176static std::optional<unsigned>
5180 "Expected a non-normalized blend with two incoming values");
5186 return std::nullopt;
5187 return FirstIncomingHasOneUse ? 0 : 1;
5199 if (!
Op->hasOneUse() ||
5205 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
5206 Op->getOperand(1), NarrowTy);
5208 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
5217 auto *
Sub =
Op->getOperand(0)->getDefiningRecipe();
5219 assert(Ext->getOpcode() ==
5221 "Expected both the LHS and RHS extends to be the same");
5222 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
5225 auto *FreezeX = Builder.insert(
new VPWidenRecipe(Instruction::Freeze, {
X}));
5226 auto *FreezeY = Builder.insert(
new VPWidenRecipe(Instruction::Freeze, {
Y}));
5227 auto *
Max = Builder.insert(
5229 {FreezeX, FreezeY}, SrcTy));
5230 auto *Min = Builder.insert(
5232 {FreezeX, FreezeY}, SrcTy));
5233 auto *AbsDiff = Builder.insert(
5236 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
5237 Op->getScalarType());
5249 assert(
Mul->hasOneUse() && Ext->getOpcode() == MulLHS->getOpcode() &&
5250 MulLHS->getOpcode() == MulRHS->getOpcode() &&
5252 "Expected the outer extend to be foldable");
5254 auto *NewLHS = Builder.createWidenCast(
5255 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
5256 auto *NewRHS = MulLHS == MulRHS
5258 : Builder.createWidenCast(MulRHS->getOpcode(),
5259 MulRHS->getOperand(0),
5260 Ext->getScalarType());
5261 auto *NewMul =
Mul->cloneWithOperands({NewLHS, NewRHS});
5262 Builder.insert(NewMul);
5263 Op->replaceAllUsesWith(NewMul);
5264 Op->eraseFromParent();
5265 Mul->eraseFromParent();
5274 VPValue *VecOp = Red->getVecOp();
5327static void transformToPartialReduction(
const PartialReductionDescriptor &Link,
5335 WidenRecipe->
getOperand(1 - Link.AccumulatorOpIdx));
5338 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
5354 if ((WidenRecipe->
getOpcode() == Instruction::Sub &&
5356 (WidenRecipe->
getOpcode() == Instruction::FSub &&
5361 if (WidenRecipe->
getOpcode() == Instruction::FSub) {
5373 Builder.insert(NegRecipe);
5374 ExtendedOp = NegRecipe;
5389 std::optional<unsigned> BlendReductionIdx =
5390 getBlendReductionUpdateValueIdx(Link.Blend);
5391 assert(BlendReductionIdx &&
5393 "Expected blend to contain the reduction update");
5407 [[maybe_unused]]
bool IsLastInChain =
5411 assert((!ExitValue || IsLastInChain) &&
5412 "if we found ExitValue, it must match RdxPhi's backedge value");
5423 PartialRed->insertBefore(WidenRecipe);
5433 E->insertBefore(WidenRecipe);
5434 PartialRed->replaceAllUsesWith(
E);
5440 const PartialReductionDescriptor &Link,
5443 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5444 std::optional<unsigned> BinOpc = std::nullopt;
5446 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5447 BinOpc = ExtendedOp.ExtendsUser->
getOpcode();
5449 std::optional<llvm::FastMathFlags>
Flags;
5453 auto GetLinkOpcode = [&Link]() ->
unsigned {
5456 return Instruction::Add;
5458 return Instruction::FAdd;
5460 return Link.ReductionBinOp->
getOpcode();
5465 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
5466 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
5483static std::optional<ExtendedReductionOperand>
5486 "Op should be operand of UpdateR");
5494 if (
Op->hasOneUse() &&
5503 Type *RHSInputType =
Y->getScalarType();
5504 if (LHSInputType != RHSInputType ||
5505 LHSExt->getOpcode() != RHSExt->getOpcode())
5506 return std::nullopt;
5509 return ExtendedReductionOperand{
5515 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
5518 VPValue *CastSource = CastRecipe->getOperand(0);
5529 return ExtendedReductionOperand{
5536 if (!
Op->hasOneUse())
5537 return std::nullopt;
5542 return std::nullopt;
5552 return std::nullopt;
5559 const APInt *RHSConst =
nullptr;
5565 return std::nullopt;
5569 if (Cast && OuterExtKind &&
5571 return std::nullopt;
5573 Type *RHSInputType = LHSInputType;
5582 if (OuterExtKind && MulOp->
getOpcode() == Instruction::Mul &&
5584 return std::nullopt;
5586 return ExtendedReductionOperand{
5587 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
5594static std::optional<SmallVector<PartialReductionDescriptor>>
5601 return std::nullopt;
5602 VPValue *ExitValue = RdxResult->getOperand(0);
5611 VPValue *CurrentValue = ExitValue;
5612 while (CurrentValue != RedPhiR) {
5614 std::optional<unsigned> BlendReductionIdx;
5618 return std::nullopt;
5620 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
5621 if (!BlendReductionIdx)
5622 return std::nullopt;
5629 return std::nullopt;
5636 std::optional<ExtendedReductionOperand> ExtendedOp =
5637 matchExtendedReductionOperand(UpdateR,
Op);
5639 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
5641 return std::nullopt;
5649 return std::nullopt;
5651 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
5654 return std::nullopt;
5656 PartialReductionDescriptor Link(
5657 {UpdateR, *ExtendedOp, RK,
5662 CurrentValue = PrevValue;
5667 std::reverse(Chain.
begin(), Chain.
end());
5677 assert(Phi->getVFScaleFactor() == 1 &&
"scale factor must not be set");
5678 Phi->setVFScaleFactor(Factor);
5683 StartInst->setOperand(2, NewScaleFactor);
5690 VPValue *OldStartValue = StartInst->getOperand(0);
5691 StartInst->setOperand(0, StartInst->getOperand(1));
5695 assert(RdxResult &&
"Could not find reduction result");
5698 unsigned SubOpc = RK ==
RecurKind::FSub ? Instruction::BinaryOps::FSub
5699 : Instruction::BinaryOps::Sub;
5702 Phi->getDebugLoc());
5718 if (
auto Chain = getScaledReductionChain(&RedPhiR))
5719 PhiToChain.
try_emplace(&RedPhiR, std::move(*Chain));
5720 else if (CostCtx.
Opts.use_partial_reductions_by_default &&
5724 UnorderedReductions.
push_back(&RedPhiR);
5730 for (
auto *Rdx : UnorderedReductions) {
5746 ? std::make_optional(Rdx->getFastMathFlagsOrNone())
5750 Backedge->getOpcode(), ScalarTy,
nullptr,
5752 std::nullopt, CostCtx.
CostKind, FMF);
5753 return PRCost <= CurrentCost;
5759 Rdx->getRecurrenceKind(), Rdx->getFastMathFlagsOrNone(),
5760 Backedge->getUnderlyingInstr(), Rdx, OtherOp,
nullptr,
5763 Partial->insertBefore(Backedge);
5764 Backedge->replaceAllUsesWith(Partial);
5765 Backedge->eraseFromParent();
5768 if (PhiToChain.
empty())
5776 for (
auto &[
_, Chain] : PhiToChain)
5777 for (
const PartialReductionDescriptor &Link : Chain) {
5778 PartialReductionOps.
insert(Link.ExtendedOp.ExtendsUser);
5780 PartialReductionBlends.
insert(Link.Blend);
5781 ScaledReductionMap[Link.ReductionBinOp] = Link.ScaleFactor;
5787 auto ExtendUsersValid = [&](
VPValue *Ext) {
5789 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
5793 auto IsProfitablePartialReductionChainForVF =
5800 for (
const PartialReductionDescriptor &Link : Chain) {
5801 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5802 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
5806 PartialCost += LinkCost;
5807 RegularCost += Link.ReductionBinOp->
computeCost(VF, CostCtx);
5809 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5810 RegularCost += ExtendedOp.ExtendsUser->
computeCost(VF, CostCtx);
5813 RegularCost += Extend->computeCost(VF, CostCtx);
5815 return PartialCost.
isValid() && PartialCost < RegularCost;
5823 for (
auto &[RedPhiR, Chain] : PhiToChain) {
5824 for (
const PartialReductionDescriptor &Link : Chain) {
5825 if (!
all_of(Link.ExtendedOp.ExtendsUser->
operands(), ExtendUsersValid)) {
5829 auto UseIsValid = [&, RedPhiR = RedPhiR](
VPUser *U) {
5831 return PhiR == RedPhiR;
5835 return Blend == Link.Blend || PartialReductionBlends.
contains(Blend);
5837 return Link.ScaleFactor == ScaledReductionMap.
lookup_or(R, 0) ||
5843 if (!
all_of(Link.ReductionBinOp->
users(), UseIsValid)) {
5852 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
5853 return RepR && RepR->getOpcode() == Instruction::Store;
5864 return IsProfitablePartialReductionChainForVF(Chain, VF);
5870 for (
auto &[Phi, Chain] : PhiToChain) {
5874 for (
const PartialReductionDescriptor &Link : Chain)
5875 transformToPartialReduction(Link, Plan, Phi);
5880 const PartialReductionDescriptor &Link = Chain[0];
5896 if (VPI.getUnderlyingValue() &&
5907 auto ProcessSubset = [&](
VPlan &,
auto ProcessVPInst) {
5910 if (!ProcessVPInst(VPI))
5919 assert(New->getParent() &&
"New recipe must have been inserted");
5920 if (VPI->
getOpcode() == Instruction::Load)
5929 return ReplaceWith(VPI,
VPBuilder(VPI).insert(
5936 "lowerMemoryIdioms", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
5938 VPI, FinalRedStoresBuilder))
5947 return ReplaceWith(VPI,
VPBuilder(VPI).insert(Histogram));
5960 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
5964 return Scalarize(VPI);
5971 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
5973 bool IsLoad = VPI->
getOpcode() == Instruction::Load;
5983 const SCEV *PtrSCEV =
5985 bool IsSingleScalarLoad =
5991 I, Ptr, IsSingleScalarLoad,
6000 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](
VPInstruction *VPI) {
6002 bool IsLoad = VPI->
getOpcode() == Instruction::Load;
6006 std::optional<int64_t> Stride =
6008 if (Stride != 1 && Stride != -1)
6039 return ReplaceWith(VPI,
Load);
6048 auto *StoreR = Builder.createWidenStore(
6051 return ReplaceWith(VPI, StoreR);
6058 return ReplaceWith(VPI, Recipe);
6060 return Scalarize(VPI);
6080 if (VPI.mayHaveSideEffects())
6085 if (VPI.getOpcode() == Instruction::ExtractValue)
6089 if (VPI.isMasked() && !VPI.isSafeToSpeculativelyExecute())
6097 VPI.getOpcode(), VPI.operandsWithoutMask(),
nullptr, VPI,
6098 VPI, VPI.getDebugLoc(), VPI.getScalarType(),
I);
6099 Recipe->insertBefore(&VPI);
6100 VPI.replaceAllUsesWith(Recipe);
6101 VPI.eraseFromParent();
6111 switch (Param.ParamKind) {
6112 case VFParamKind::Vector:
6113 case VFParamKind::GlobalPredicate:
6115 case VFParamKind::OMP_Uniform:
6116 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
6117 SE->isLoopInvariant(
6118 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6120 case VFParamKind::OMP_Linear:
6121 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6122 m_scev_AffineAddRec(
6123 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
6124 m_SpecificLoop(L)));
6141 const auto *It =
find_if(Mappings, [&](
const VFInfo &Info) {
6142 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
6145 if (It == Mappings.end())
6152struct CallWideningDecision {
6153 enum class KindTy { Scalarize,
Intrinsic, VectorVariant };
6154 CallWideningDecision(KindTy Kind,
Function *Variant =
nullptr)
6177 return CallWideningDecision::KindTy::Scalarize;
6187 return CallWideningDecision::KindTy::Scalarize;
6191 false, VF, CostCtx);
6206 return CallWideningDecision::KindTy::Intrinsic;
6210 if (VecFunc && ScalarCost >= VecCallCost)
6211 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
6213 return CallWideningDecision::KindTy::Scalarize;
6219 bool Widened =
false;
6224 if (!VPI.getUnderlyingValue() || VPI.getOpcode() != Instruction::Call)
6229 VPI.op_begin() + CI->arg_size());
6231 CallWideningDecision Decision =
6239 assert((Decision.Kind == CallWideningDecision::KindTy::Scalarize ||
6240 !CI->hasOperandBundles()) &&
6241 "calls with operand bundles must not be widened");
6243 switch (Decision.Kind) {
6244 case CallWideningDecision::KindTy::Intrinsic: {
6248 VPI, VPI.getDebugLoc());
6252 case CallWideningDecision::KindTy::VectorVariant: {
6257 Ops.push_back(Mask);
6259 Ops.push_back(VPI.getOperand(VPI.getNumOperandsWithoutMask() - 1));
6262 Attrs, VPI.getDebugLoc());
6266 case CallWideningDecision::KindTy::Scalarize:
6272 VPI.replaceAllUsesWith(Replacement);
6273 VPI.eraseFromParent();
6290 if (VPI.getOpcode() != Instruction::Trunc)
6314 !
TTI.isTruncateFree(
6315 toVectorTy(VPI.getOperand(0)->getScalarType(), VF),
6319 IsNarrowingProfitable,
Range))
6325 WideIV->getPHINode(), WideIV->getStartValue(), WideIV->getStepValue(),
6326 WideIV->getVFValue(), WideIV->getInductionDescriptor(),
6329 NarrowIV->insertBefore(*HeaderVPBB, HeaderVPBB->
getFirstNonPhi());
6330 VPI.replaceAllUsesWith(NarrowIV);
6331 VPI.eraseFromParent();
6353 if (!MemR || MemR->isConsecutive())
6356 VPValue *Ptr = MemR->getAddr();
6368 VPValue *StoredValue =
nullptr;
6372 StoredValue = StoreR->getStoredValue();
6374 IntrinID = Intrinsic::experimental_vp_strided_store;
6378 IntrinID = Intrinsic::experimental_vp_strided_load;
6381 Align Alignment = MemR->getAlign();
6384 if (!Ctx.TTI.isLegalStridedLoadStore(VectorTy, Alignment))
6389 IntrinID, VectorTy, MemR->isMasked(), Alignment, Ctx);
6390 return StridedLoadStoreCost < CurrentCost;
6401 Ctx.invalidateWideningDecision(&MemR->getIngredient(), VF);
6406 I32VF = Builder.createScalarZExtOrTrunc(
6420 "Stride type from SCEV must match the index type");
6421 VPValue *CanIV = Builder.createScalarZExtOrTrunc(
6424 auto *
Offset = Builder.createOverflowingOp(
6425 Instruction::Mul, {CanIV, StrideInBytes},
6426 {AddRecPtr->hasNoUnsignedWrap(),
false});
6430 VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV,
Offset, NWFlags);
6433 VPValue *NewPtr = Builder.createVectorPointer(
6437 VPValue *Mask = MemR->getMask();
6442 Ops.push_back(StoredValue);
6443 Ops.append({NewPtr, StrideInBytes, Mask, I32VF});
6445 auto *StridedR = Builder.createWidenMemIntrinsic(
6448 *MemR, R.getDebugLoc());
6451 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")
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.
SmallVector< MachineOperand, 4 > 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.
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 bool isGuaranteedNotToCauseUB(const SCEV *Op)
Returns true if Op is guaranteed not to cause immediate UB.
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...
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, const VPIRAttributes &Attrs={})
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 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.
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.
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 by all users.
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.
const VectorizeOptions & getVectorizeOptions(const LLVMContext &C)
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...