LLVM 24.0.0git
VPlanTransforms.cpp
Go to the documentation of this file.
1//===-- VPlanTransforms.cpp - Utility VPlan to VPlan transforms -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file implements a set of utility VPlan to VPlan transformations.
11///
12//===----------------------------------------------------------------------===//
13
14#include "VPlanTransforms.h"
15#include "VPRecipeBuilder.h"
16#include "VPlan.h"
17#include "VPlanAnalysis.h"
18#include "VPlanCFG.h"
19#include "VPlanDominatorTree.h"
20#include "VPlanHelpers.h"
21#include "VPlanPatternMatch.h"
22#include "VPlanUtils.h"
23#include "VectorizeOptions.h"
24#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/SetVector.h"
29#include "llvm/ADT/TypeSwitch.h"
31#include "llvm/Analysis/Loads.h"
37#include "llvm/IR/Intrinsics.h"
38#include "llvm/IR/MDBuilder.h"
39#include "llvm/IR/Metadata.h"
42#include "llvm/Support/Regex.h"
45
46using namespace llvm;
47using namespace LoopVectorizationUtils;
48using namespace VPlanPatternMatch;
49using namespace SCEVPatternMatch;
50
52 const VectorizeOptions &Opts = getVectorizeOptions(Plan.getContext());
53 if (Opts.vplan_verify_each && !verifyVPlanIsValid(Plan))
54 report_fatal_error("Broken VPlan found, compilation aborted!");
55}
56
57#ifndef NDEBUG
59 const VectorizeOptions &Opts = getVectorizeOptions(Plan.getContext());
60 return Opts.vplan_print_before_all || Opts.vplan_print_after_all ||
61 !Opts.vplan_print_before.empty() || !Opts.vplan_print_after.empty();
62}
63
65 StringRef NumberedPassName, bool After) {
66 const VectorizeOptions &Opts = getVectorizeOptions(Plan.getContext());
67 bool All = After ? Opts.vplan_print_after_all : Opts.vplan_print_before_all;
69 After ? Opts.vplan_print_after : Opts.vplan_print_before;
70 if (!All && none_of(Passes, [&](StringRef Entry) {
71 return Regex(Entry).match(NumberedPassName);
72 }))
73 return;
74 dbgs() << "VPlan for loop in '" << Fn->getName() << "' "
75 << (After ? "after" : "before") << " " << NumberedPassName << '\n';
76 if (Opts.vplan_print_vector_region_scope && Plan.getVectorLoopRegion())
78 else
79 dbgs() << Plan << '\n';
80}
81#endif
82
83/// Returns the metadata attached to \p R, or an empty set for a recipe that
84/// does not carry any.
86 if (auto *MD = dyn_cast<VPIRMetadata>(R))
87 return *MD;
88 return {};
89}
90
93 Loop *OuterLoop) {
94
95 // Returns true if the access of \p AccessTy at \p Addr can be widened to a
96 // consecutive vector access.
97 auto IsConsecutiveAccess = [&](VPValue *Addr, Type *AccessTy) {
98 return !hasIrregularType(AccessTy, Plan.getDataLayout()) &&
99 vputils::getConstantStride(Addr, AccessTy, PSE, OuterLoop) == 1;
100 };
101
103 Plan.getVectorLoopRegion());
105 // Skip blocks outside region
106 if (!VPBB->getParent())
107 break;
108 VPRecipeBase *Term = VPBB->getTerminator();
109 auto EndIter = Term ? Term->getIterator() : VPBB->end();
110 // Introduce each ingredient into VPlan.
111 for (VPRecipeBase &Ingredient :
112 make_early_inc_range(make_range(VPBB->begin(), EndIter))) {
113
114 VPValue *VPV = Ingredient.getVPSingleValue();
115 if (!VPV->getUnderlyingValue())
116 continue;
117
119
120 VPRecipeBase *NewRecipe = nullptr;
121 if (auto *PhiR = dyn_cast<VPPhi>(&Ingredient)) {
122 auto *Phi = cast<PHINode>(PhiR->getUnderlyingValue());
123 NewRecipe = new VPWidenPHIRecipe(PhiR->operands(), PhiR->getDebugLoc(),
124 Phi->getName());
125 } else if (auto *VPI = dyn_cast<VPInstruction>(&Ingredient)) {
126 assert(!isa<PHINode>(Inst) && "phis should be handled above");
127 // Create VPWidenMemoryRecipe for loads and stores.
128 if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
129 bool IsConsecutive =
130 IsConsecutiveAccess(VPI->getOperand(0), VPI->getScalarType());
131 NewRecipe = new VPWidenLoadRecipe(
132 *Load, Ingredient.getOperand(0), nullptr /*Mask*/, IsConsecutive,
133 Load->getAlign(), *VPI, Ingredient.getDebugLoc());
134 } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
135 bool IsConsecutive = IsConsecutiveAccess(
136 VPI->getOperand(1), VPI->getOperand(0)->getScalarType());
137 NewRecipe = new VPWidenStoreRecipe(
138 *Store, Ingredient.getOperand(1), Ingredient.getOperand(0),
139 nullptr /*Mask*/, IsConsecutive, Store->getAlign(), *VPI,
140 Ingredient.getDebugLoc());
142 NewRecipe = new VPWidenGEPRecipe(GEP->getSourceElementType(),
143 Ingredient.operands(), *VPI,
144 Ingredient.getDebugLoc(), GEP);
145 } else if (CallInst *CI = dyn_cast<CallInst>(Inst)) {
146 Intrinsic::ID VectorID = getVectorIntrinsicIDForCall(CI, &TLI);
147 if (VectorID == Intrinsic::not_intrinsic)
148 return false;
149
150 // The noalias.scope.decl intrinsic declares a noalias scope that
151 // is valid for a single iteration. Emitting it as a single-scalar
152 // replicate would incorrectly extend the scope across multiple
153 // original iterations packed into one vector iteration.
154 // FIXME: If we want to vectorize this loop, then we have to drop
155 // all the associated !alias.scope and !noalias.
156 if (VectorID == Intrinsic::experimental_noalias_scope_decl)
157 return false;
158
159 // These intrinsics are recognized by getVectorIntrinsicIDForCall
160 // but are not widenable. Emit them as replicate instead of widening.
161 if (VectorID == Intrinsic::assume ||
162 VectorID == Intrinsic::lifetime_end ||
163 VectorID == Intrinsic::lifetime_start ||
164 VectorID == Intrinsic::sideeffect ||
165 VectorID == Intrinsic::pseudoprobe) {
166 // If the operand of llvm.assume holds before vectorization, it will
167 // also hold per lane.
168 // llvm.pseudoprobe requires to be duplicated per lane for accurate
169 // sample count.
170 const bool IsSingleScalar = VectorID != Intrinsic::assume &&
171 VectorID != Intrinsic::pseudoprobe;
172 NewRecipe = new VPReplicateRecipe(CI, Ingredient.operands(),
173 /*IsSingleScalar=*/IsSingleScalar,
174 /*Mask=*/nullptr, *VPI, *VPI,
175 Ingredient.getDebugLoc());
176 } else {
177 assert(!CI->hasOperandBundles() &&
178 "calls with operand bundles must not be widened");
179 NewRecipe = new VPWidenIntrinsicRecipe(
180 *CI, VectorID, drop_end(Ingredient.operands()), CI->getType(),
181 VPIRFlags(*CI), *VPI, CI->getDebugLoc());
182 }
183 } else if (auto *CI = dyn_cast<CastInst>(Inst)) {
184 NewRecipe = new VPWidenCastRecipe(
185 CI->getOpcode(), Ingredient.getOperand(0), CI->getType(), CI,
186 VPIRFlags(*CI), VPIRMetadata(*CI));
187 } else {
188 NewRecipe = new VPWidenRecipe(*Inst, Ingredient.operands(), *VPI,
189 *VPI, Ingredient.getDebugLoc());
190 }
191 } else {
192 assert(isa<VPWidenInductionRecipe>(&Ingredient) &&
193 "inductions must be created earlier");
194 continue;
195 }
196
197 NewRecipe->insertBefore(&Ingredient);
198 if (NewRecipe->getNumDefinedValues() == 1)
199 VPV->replaceAllUsesWith(NewRecipe->getVPSingleValue());
200 else
201 assert(NewRecipe->getNumDefinedValues() == 0 &&
202 "Only recpies with zero or one defined values expected");
203 Ingredient.eraseFromParent();
204 }
205 }
206 return true;
207}
208
209/// Helper for extra no-alias checks via known-safe recipe and SCEV.
212 VPReplicateRecipe &GroupLeader;
213 PredicatedScalarEvolution *PSE = nullptr;
214 const Loop *L = nullptr;
215
216 // Return true if \p A and \p B are known to not alias for all VFs in the
217 // plan, checked via the distance between the accesses
218 bool isNoAliasViaDistance(VPReplicateRecipe *A, VPReplicateRecipe *B) const {
219 if (A->getOpcode() != Instruction::Store ||
220 B->getOpcode() != Instruction::Store)
221 return false;
222
223 if (!PSE || !L)
224 return A == B;
225
226 VPValue *AddrA = A->getOperand(1);
227 const SCEV *SCEVA = vputils::getSCEVExprForVPValue(AddrA, *PSE, L);
228 VPValue *AddrB = B->getOperand(1);
229 const SCEV *SCEVB = vputils::getSCEVExprForVPValue(AddrB, *PSE, L);
231 return false;
232
233 const APInt *Distance;
234 ScalarEvolution &SE = *PSE->getSE();
235 if (!match(SE.getMinusSCEV(SCEVA, SCEVB), m_scev_APInt(Distance)))
236 return false;
237
238 const DataLayout &DL = SE.getDataLayout();
239 Type *TyA = A->getOperand(0)->getScalarType();
240 uint64_t SizeA = DL.getTypeStoreSize(TyA);
241 Type *TyB = B->getOperand(0)->getScalarType();
242 uint64_t SizeB = DL.getTypeStoreSize(TyB);
243
244 // Use the maximum store size to ensure no overlap from either direction.
245 // Currently only handles fixed sizes, as it is only used for
246 // replicating VPReplicateRecipes.
247 uint64_t MaxStoreSize = std::max(SizeA, SizeB);
248
249 auto VFs = B->getParent()->getPlan()->vectorFactors();
251 if (MaxVF.isScalable())
252 return false;
253 return Distance->abs().uge(MaxVF.getFixedValue() * MaxStoreSize);
254 }
255
256public:
259 const Loop &L)
260 : ExcludeRecipes(ExcludeRecipes.begin(), ExcludeRecipes.end()),
261 GroupLeader(GroupLeader), PSE(&PSE), L(&L) {}
262
263 SinkStoreInfo(VPReplicateRecipe &GroupLeader) : GroupLeader(GroupLeader) {}
264
265 /// Return true if \p R should be skipped during alias checking, either
266 /// because it's in the exclude set or because no-alias can be proven via
267 /// SCEV.
268 bool shouldSkip(VPRecipeBase &R) const {
270 return ExcludeRecipes.contains(Store) ||
271 (Store && isNoAliasViaDistance(Store, &GroupLeader));
272 }
273};
274
275/// Check if a memory operation doesn't alias with memory operations using
276/// scoped noalias metadata, in blocks in the single-successor chain between \p
277/// FirstBB and \p LastBB. If \p SinkInfo is std::nullopt, only recipes that may
278/// write to memory are checked (for load hoisting). Otherwise recipes that both
279/// read and write memory are checked, and SCEV is used to prove no-alias
280/// between the group leader and other replicate recipes (for store sinking).
281static bool
283 VPBasicBlock *FirstBB, VPBasicBlock *LastBB,
284 std::optional<SinkStoreInfo> SinkInfo = {}) {
285 bool CheckReads = SinkInfo.has_value();
286 for (VPBasicBlock *VPBB :
288 for (VPRecipeBase &R : *VPBB) {
289 if (SinkInfo && SinkInfo->shouldSkip(R))
290 continue;
291
292 // Skip recipes that don't need checking.
293 if (!R.mayWriteToMemory() && !(CheckReads && R.mayReadFromMemory()))
294 continue;
295
297 if (!Loc)
298 // Conservatively assume aliasing for memory operations without
299 // location.
300 return false;
301
303 return false;
304 }
305 }
306 return true;
307}
308
309/// Get the value type of a VPInstruction or VPReplicateRecipe load or store.
311 bool IsLoad = vputils::getOpcode(R) == Instruction::Load;
312 return (IsLoad ? R : R->getOperand(0))->getScalarType();
313}
314
315/// Collect either replicated Loads or Stores grouped by their address SCEV and
316/// their load-store type, in a deep-traversal of the vector loop region in \p
317/// Plan.
318template <unsigned Opcode>
321 VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L,
322 function_ref<bool(VPReplicateRecipe *)> FilterFn) {
323 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
324 "Only Load and Store opcodes supported");
325 constexpr bool IsLoad = (Opcode == Instruction::Load);
328 RecipesByAddressAndType;
332 if (RepR.getOpcode() != Opcode || !FilterFn(&RepR))
333 continue;
334
335 // For loads, operand 0 is address; for stores, operand 1 is address.
336 VPValue *Addr = RepR.getOperand(IsLoad ? 0 : 1);
337 const Type *LoadStoreTy = getLoadStoreValueType(&RepR);
338 const SCEV *AddrSCEV = vputils::getSCEVExprForVPValue(Addr, PSE, L);
339 if (!isa<SCEVCouldNotCompute>(AddrSCEV))
340 RecipesByAddressAndType[{AddrSCEV, LoadStoreTy}].push_back(&RepR);
341 }
342 }
343 auto Groups = to_vector(RecipesByAddressAndType.values());
344 VPDominatorTree VPDT(Plan);
345 for (auto &Group : Groups) {
346 // Sort mem ops by dominance order, with earliest (most dominating) first.
348 return VPDT.properlyDominates(A, B);
349 });
350 }
351 return Groups;
352}
353
354static bool sinkScalarOperands(VPlan &Plan) {
355 auto Iter = vp_depth_first_deep(Plan.getEntry());
356 bool ScalarVFOnly = Plan.hasScalarVFOnly();
357 bool Changed = false;
358
360 auto InsertIfValidSinkCandidate = [ScalarVFOnly, &WorkList](
361 VPBasicBlock *SinkTo, VPValue *Op) {
362 auto *Candidate = dyn_cast<VPSingleDefRecipe>(Op);
364 VPInstruction>(Candidate))
365 return;
366
367 if (Candidate->getParent() == SinkTo ||
368 all_of(Candidate->operands(),
369 [](VPValue *Op) { return Op->isDefinedOutsideLoopRegions(); }) ||
370 vputils::cannotHoistOrSinkRecipe(*Candidate, /*Sinking=*/true))
371 return;
372
373 if (!ScalarVFOnly && !vputils::doesGeneratePerAllLanes(Candidate))
374 return;
375
376 // Only single-scalar VPInstructions can be sunk.
377 if (auto *VPI = dyn_cast<VPInstruction>(Candidate))
378 if (!vputils::isSingleScalar(VPI))
379 return;
380
381 WorkList.insert({SinkTo, Candidate});
382 };
383
384 // First, collect the operands of all recipes in replicate blocks as seeds for
385 // sinking.
387 VPBasicBlock *EntryVPBB = VPR->getEntryBasicBlock();
388 if (!VPR->isReplicator() || EntryVPBB->getSuccessors().size() != 2)
389 continue;
390 VPBasicBlock *VPBB = cast<VPBasicBlock>(EntryVPBB->getSuccessors().front());
391 if (VPBB->getSingleSuccessor() != VPR->getExitingBasicBlock())
392 continue;
393 for (auto &Recipe : *VPBB)
394 for (VPValue *Op : Recipe.operands())
395 InsertIfValidSinkCandidate(VPBB, Op);
396 }
397
398 // Try to sink each replicate or scalar IV steps recipe in the worklist.
399 for (unsigned I = 0; I != WorkList.size(); ++I) {
400 VPBasicBlock *SinkTo;
401 VPSingleDefRecipe *SinkCandidate;
402 std::tie(SinkTo, SinkCandidate) = WorkList[I];
403
404 // All recipe users of SinkCandidate must be in the same block SinkTo or all
405 // users outside of SinkTo must only use the first lane of SinkCandidate. In
406 // the latter case, we need to duplicate SinkCandidate.
407 auto UsersOutsideSinkTo =
408 make_filter_range(SinkCandidate->users(), [SinkTo](VPUser *U) {
409 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
410 });
411 if (any_of(UsersOutsideSinkTo, [SinkCandidate](VPUser *U) {
412 return !U->usesFirstLaneOnly(SinkCandidate);
413 }))
414 continue;
415 bool NeedsDuplicating = !UsersOutsideSinkTo.empty();
416
417 if (NeedsDuplicating) {
418 if (ScalarVFOnly)
419 continue;
420 VPSingleDefRecipe *Clone;
421 if (auto *SinkCandidateRepR =
422 dyn_cast<VPReplicateRecipe>(SinkCandidate)) {
423 // TODO: Handle converting to uniform recipes as separate transform,
424 // then cloning should be sufficient here.
426 SinkCandidateRepR->getOpcode(), SinkCandidate->operands(),
427 /*Mask=*/nullptr, *SinkCandidateRepR, *SinkCandidateRepR,
428 SinkCandidate->getDebugLoc(), SinkCandidate->getScalarType(),
429 SinkCandidate->getUnderlyingInstr());
430 // TODO: add ".cloned" suffix to name of Clone's VPValue.
431 } else {
432 Clone = SinkCandidate->clone();
433 }
434
435 Clone->insertBefore(SinkCandidate);
436 SinkCandidate->replaceUsesWithIf(Clone, [SinkTo](VPUser *U) {
437 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
438 });
439 }
440 SinkCandidate->moveBefore(SinkTo->getFirstNonPhi());
441 for (VPValue *Op : SinkCandidate->operands())
442 InsertIfValidSinkCandidate(SinkTo, Op);
443 Changed = true;
444 }
445 return Changed;
446}
447
448/// If \p R is a triangle region, return the 'then' block of the triangle.
450 auto *EntryBB = cast<VPBasicBlock>(R->getEntry());
451 if (EntryBB->getNumSuccessors() != 2)
452 return nullptr;
453
454 auto *Succ0 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[0]);
455 auto *Succ1 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[1]);
456 if (!Succ0 || !Succ1)
457 return nullptr;
458
459 if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
460 return nullptr;
461 if (Succ0->getSingleSuccessor() == Succ1)
462 return Succ0;
463 if (Succ1->getSingleSuccessor() == Succ0)
464 return Succ1;
465 return nullptr;
466}
467
468// Merge replicate regions in their successor region, if a replicate region
469// is connected to a successor replicate region with the same predicate by a
470// single, empty VPBasicBlock.
472 SmallPtrSet<VPRegionBlock *, 4> TransformedRegions;
473
474 // Collect replicate regions followed by an empty block, followed by another
475 // replicate region with matching masks to process front. This is to avoid
476 // iterator invalidation issues while merging regions.
479 vp_depth_first_deep(Plan.getEntry()))) {
480 if (!Region1->isReplicator())
481 continue;
482 auto *MiddleBasicBlock =
483 dyn_cast_or_null<VPBasicBlock>(Region1->getSingleSuccessor());
484 if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
485 continue;
486
487 auto *Region2 =
488 dyn_cast_or_null<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
489 if (!Region2 || !Region2->isReplicator())
490 continue;
491
492 VPValue *Mask1 = Region1->getEntryBranchOnMask()->getOperand(0);
493 VPValue *Mask2 = Region2->getEntryBranchOnMask()->getOperand(0);
494 if (!Mask1 || Mask1 != Mask2)
495 continue;
496
497 assert(Mask1 && Mask2 && "both region must have conditions");
498 WorkList.push_back(Region1);
499 }
500
501 // Move recipes from Region1 to its successor region, if both are triangles.
502 for (VPRegionBlock *Region1 : WorkList) {
503 if (TransformedRegions.contains(Region1))
504 continue;
505 auto *MiddleBasicBlock = cast<VPBasicBlock>(Region1->getSingleSuccessor());
506 auto *Region2 = cast<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
507
508 VPBasicBlock *Then1 = getPredicatedThenBlock(Region1);
509 VPBasicBlock *Then2 = getPredicatedThenBlock(Region2);
510 if (!Then1 || !Then2)
511 continue;
512
513 // The merged region is entered whenever either of the original regions was,
514 // so use the higher, i.e. more conservative, of their entry frequencies.
515 // If only one of the two is known, the higher one is unknown, so the
516 // result must be unknown too.
517 VPBranchOnMaskRecipe *Guard2 = Region2->getEntryBranchOnMask();
518 std::optional<VPExecutionFrequency> Freq1 =
519 Region1->getEntryBranchOnMask()->getExecutionFrequency();
520 std::optional<VPExecutionFrequency> Freq2 = Guard2->getExecutionFrequency();
521 if (Freq1 && Freq2) {
522 if (Freq2->Freq < Freq1->Freq) {
523 // Freq1's frequency is taken, but it is only as trustworthy as the
524 // less trustworthy of the two.
525 Freq1.emplace(Freq1->Freq, Freq1->IsEstimated || Freq2->IsEstimated);
526 Guard2->setExecutionFrequency(Freq1, Plan.getContext());
527 }
528 } else if (Freq2) {
529 Guard2->clearExecutionFrequency();
530 }
531
532 // Note: No fusion-preventing memory dependencies are expected in either
533 // region. Such dependencies should be rejected during earlier dependence
534 // checks, which guarantee accesses can be re-ordered for vectorization.
535 //
536 // Move recipes to the successor region.
537 for (VPRecipeBase &ToMove : make_early_inc_range(reverse(*Then1)))
538 ToMove.moveBefore(Then2->getFirstNonPhi());
539
540 auto *Merge1 = cast<VPBasicBlock>(Then1->getSingleSuccessor());
541 auto *Merge2 = cast<VPBasicBlock>(Then2->getSingleSuccessor());
542
543 // Move VPPredInstPHIRecipes from the merge block to the successor region's
544 // merge block. Update all users inside the successor region to use the
545 // original values.
546 for (VPRecipeBase &Phi1ToMove : make_early_inc_range(reverse(*Merge1))) {
547 VPValue *PredInst1 =
548 cast<VPPredInstPHIRecipe>(&Phi1ToMove)->getOperand(0);
549 VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
550 Phi1ToMoveV->replaceUsesWithIf(PredInst1, [Then2](VPUser *U) {
551 return cast<VPRecipeBase>(U)->getParent() == Then2;
552 });
553
554 // Remove phi recipes that are unused after merging the regions.
555 if (Phi1ToMove.getVPSingleValue()->user_empty()) {
556 Phi1ToMove.eraseFromParent();
557 continue;
558 }
559 Phi1ToMove.moveBefore(Merge2->begin());
560 }
561
562 // Remove the dead recipes in Region1's entry block.
563 for (VPRecipeBase &R :
564 make_early_inc_range(reverse(*Region1->getEntryBasicBlock())))
565 R.eraseFromParent();
566
567 // Finally, remove the first region.
568 for (VPBlockBase *Pred : make_early_inc_range(Region1->getPredecessors())) {
569 VPBlockUtils::disconnectBlocks(Pred, Region1);
570 VPBlockUtils::connectBlocks(Pred, MiddleBasicBlock);
571 }
572 VPBlockUtils::disconnectBlocks(Region1, MiddleBasicBlock);
573 TransformedRegions.insert(Region1);
574 }
575
576 return !TransformedRegions.empty();
577}
578
580 VPRegionBlock *ParentRegion,
581 VPlan &Plan) {
582 Instruction *Instr = PredRecipe->getUnderlyingInstr();
583 // Build the triangular if-then region.
584 std::string RegionName = (Twine("pred.") + Instr->getOpcodeName()).str();
585 assert(Instr->getParent() && "Predicated instruction not in any basic block");
586 auto *BlockInMask = PredRecipe->getMask();
587 auto *MaskDef = BlockInMask->getDefiningRecipe();
588 auto *BOMRecipe = new VPBranchOnMaskRecipe(
589 BlockInMask, MaskDef ? MaskDef->getDebugLoc() : DebugLoc::getUnknown());
590 auto *Entry =
591 Plan.createVPBasicBlock(Twine(RegionName) + ".entry", BOMRecipe);
592
593 // Replace predicated replicate recipe with a replicate recipe without a
594 // mask but in the replicate region.
595 auto *RecipeWithoutMask = new VPReplicateRecipe(
596 PredRecipe->getUnderlyingInstr(), PredRecipe->operandsWithoutMask(),
597 PredRecipe->isSingleScalar(), nullptr /*Mask*/, *PredRecipe, *PredRecipe,
598 PredRecipe->getDebugLoc());
599 // The predicated recipe executes exactly when the guarding branch-on-mask is
600 // taken, so move its execution frequency there.
601 BOMRecipe->setExecutionFrequency(RecipeWithoutMask->getExecutionFrequency(),
602 Plan.getContext());
603 RecipeWithoutMask->clearExecutionFrequency();
604 auto *Pred =
605 Plan.createVPBasicBlock(Twine(RegionName) + ".if", RecipeWithoutMask);
606 auto *Exiting = Plan.createVPBasicBlock(Twine(RegionName) + ".continue");
608 Plan.createReplicateRegion(Entry, Exiting, RegionName);
609
610 // Note: first set Entry as region entry and then connect successors starting
611 // from it in order, to propagate the "parent" of each VPBasicBlock.
612 Region->setParent(ParentRegion);
613 VPBlockUtils::insertTwoBlocksAfter(Pred, Exiting, Entry);
614 VPBlockUtils::connectBlocks(Pred, Exiting);
615
616 PredRecipe->replaceAllUsesWith(RecipeWithoutMask);
617 // Move the extracts of a struct result into the region, so only scalars
618 // leave it.
619 SmallVector<VPUser *> Defs = {RecipeWithoutMask};
620 if (RecipeWithoutMask->getScalarType()->isStructTy())
621 Defs = to_vector(RecipeWithoutMask->users());
622 for (VPUser *U : Defs) {
623 auto *Def = cast<VPReplicateRecipe>(U);
624 assert((Def == RecipeWithoutMask ||
625 Def->getOpcode() == Instruction::ExtractValue) &&
626 "only extracts can use a predicated struct");
627 Def->moveBefore(Pred->end());
628 if (Def->user_empty())
629 continue;
630 auto *PHIRecipe = new VPPredInstPHIRecipe(Def, Def->getDebugLoc());
631 Exiting->appendRecipe(PHIRecipe);
632 Def->replaceAllUsesWith(PHIRecipe);
633 PHIRecipe->setOperand(0, Def);
634 }
635 PredRecipe->eraseFromParent();
636 return Region;
637}
638
639static void addReplicateRegions(VPlan &Plan) {
642 vp_depth_first_deep(Plan.getEntry()))) {
644 if (RepR.isPredicated())
645 WorkList.push_back(&RepR);
646 }
647
648 unsigned BBNum = 0;
649 for (VPReplicateRecipe *RepR : WorkList) {
650 VPBasicBlock *CurrentBlock = RepR->getParent();
651 VPBasicBlock *SplitBlock = CurrentBlock->splitAt(RepR->getIterator());
652
653 BasicBlock *OrigBB = RepR->getUnderlyingInstr()->getParent();
654 SplitBlock->setName(
655 OrigBB->hasName() ? OrigBB->getName() + "." + Twine(BBNum++) : "");
656 // Record predicated instructions for above packing optimizations.
658 createReplicateRegion(RepR, CurrentBlock->getParent(), Plan);
660
661 VPRegionBlock *ParentRegion = Region->getParent();
662 if (ParentRegion && ParentRegion->getExiting() == CurrentBlock)
663 ParentRegion->setExiting(SplitBlock);
664 }
665}
666
669
670 // Collect single-successor chains in the loop region.
671 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
673 vp_depth_first_deep(LoopRegion->getEntry()))) {
674 if (!VPBB->getParent())
675 continue;
676 VPBlockBase *PredBlock = VPBB->getSinglePredecessor();
677 if (!isa_and_nonnull<VPBasicBlock>(PredBlock) ||
678 !PredBlock->getSingleSuccessor())
679 continue;
680 WorkList.push_back(VPBB);
681 }
682
683 for (VPBasicBlock *VPBB : WorkList) {
684 VPBasicBlock *PredVPBB = cast<VPBasicBlock>(VPBB->getSinglePredecessor());
685 for (VPRecipeBase &R : make_early_inc_range(*VPBB))
686 R.moveBefore(PredVPBB->end());
687 VPBlockUtils::disconnectBlocks(PredVPBB, VPBB);
688 auto *ParentRegion = VPBB->getParent();
689 if (ParentRegion && ParentRegion->getExiting() == VPBB)
690 ParentRegion->setExiting(PredVPBB);
691 VPBlockUtils::transferSuccessors(VPBB, PredVPBB);
692 // VPBB is now dead and will be cleaned up when the plan gets destroyed.
693 }
694 return !WorkList.empty();
695}
696
698 // Convert masked VPReplicateRecipes to if-then region blocks.
700
701 bool ShouldSimplify = true;
702 while (ShouldSimplify) {
703 ShouldSimplify = sinkScalarOperands(Plan);
704 ShouldSimplify |= mergeReplicateRegionsIntoSuccessors(Plan);
705 ShouldSimplify |= mergeBlocksIntoPredecessors(Plan);
706 }
707}
708
709/// Remove redundant casts of inductions.
710///
711/// Such redundant casts are casts of induction variables that can be ignored,
712/// because we already proved that the casted phi is equal to the uncasted phi
713/// in the vectorized loop. There is no need to vectorize the cast - the same
714/// value can be used for both the phi and casts in the vector loop.
719 if (IV.isTruncated())
720 continue;
721
722 // A sequence of IR Casts has potentially been recorded for IV, which
723 // *must be bypassed* when the IV is vectorized, because the vectorized IV
724 // will produce the desired casted value. This sequence forms a def-use
725 // chain and is provided in reverse order, ending with the cast that uses
726 // the IV phi. Search for the recipe of the last cast in the chain and
727 // replace it with the original IV. Note that only the final cast is
728 // expected to have users outside the cast-chain and the dead casts left
729 // over will be cleaned up later.
730 ArrayRef<Instruction *> Casts = IV.getInductionDescriptor().getCastInsts();
731 VPValue *FindMyCast = &IV;
732 for (Instruction *IRCast : reverse(Casts)) {
733 VPSingleDefRecipe *FoundUserCast = nullptr;
734 for (auto *U : FindMyCast->users()) {
735 auto *UserCast = dyn_cast<VPSingleDefRecipe>(U);
736 if (UserCast && UserCast->getUnderlyingValue() == IRCast) {
737 FoundUserCast = UserCast;
738 break;
739 }
740 }
741 // A cast recipe in the chain may have been removed by earlier DCE.
742 if (!FoundUserCast)
743 break;
744 FindMyCast = FoundUserCast;
745 }
746 if (FindMyCast != &IV)
747 FindMyCast->replaceAllUsesWith(&IV);
748 }
749}
750
751/// If R is a phi-like recipe starting a dead cycle of recipes, erase all
752/// reachable recipes of the dead cycle and return true. Otherwise leave the
753/// plan unchanged and return false.
755 auto *PhiR = dyn_cast<VPSingleDefRecipe>(R);
756 if (!PhiR || !isa<VPPhi, VPReductionPHIRecipe>(R))
757 return false;
758
759 // The transitive users of PhiR are closed under users, so the cycle is dead
760 // if every one of them can be erased.
762 auto *R = cast<VPRecipeBase>(U);
763 // Bail out if a user must be retained, or if it is a phi-like recipe other
764 // than PhiR;
765 if (R->mayHaveSideEffects() || (R != PhiR && isa<VPPhiAccessors>(R)))
766 return false;
767 }
768
769 // Break the cycle by replacing PhiR with its first incoming value, which is
770 // defined outside the cycle. That leaves the rest of the cycle dead.
771 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
772 SmallVector<VPValue *> Incoming(PhiR->operands());
773 PhiR->eraseFromParent();
774 for (VPValue *Op : Incoming)
776 return true;
777}
778
781 Plan.getEntry());
783 // The recipes in the block are processed in reverse order, to catch chains
784 // of dead recipes.
785 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB)))
787 R.eraseFromParent();
788
789 // Erase dead cycles starting at one of VPBB's phi-like recipes. Erasing a
790 // cycle may also erase other phi-like recipes of VPBB, so restart the scan
791 // of the phi section after each removal. This terminates, as each removal
792 // erases the cycle's phi.
793 bool Changed = true;
794 while (Changed) {
795 Changed = false;
796 for (VPRecipeBase &R : VPBB->phis()) {
797 if (tryToRemoveDeadCycle(&R)) {
798 Changed = true;
799 break;
800 }
801 }
802 }
803 }
804}
805
806/// Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd
807/// (IndStart, ScalarIVSteps (0, Step)) if only its scalar values are used, as
808/// VPWidenPointerInductionRecipe will generate vectors only. If some users
809/// require vectors while other require scalars, the scalar uses need to extract
810/// the scalars from the generated vectors (Note that this is different to how
811/// int/fp inductions are handled). Legalize extract-from-ends using uniform
812/// VPReplicateRecipe of wide inductions to use regular VPReplicateRecipe, so
813/// the correct end value is available. Also optimize
814/// VPWidenIntOrFpInductionRecipe, if any of its users needs scalar values, by
815/// providing them scalar steps built on the canonical scalar IV and update the
816/// original IV's users. This is an optional optimization to reduce the needs of
817/// vector extracts.
820 bool HasOnlyVectorVFs = !Plan.hasScalarVFOnly();
821
823 for (VPWidenInductionRecipe &PhiR :
825 WideIVs.push_back(&PhiR);
826
827 // Try to narrow wide and replicating recipes to uniform recipes, based on
828 // VPlan analysis.
829 // TODO: Apply to all recipes in the future, to replace legacy uniformity
830 // analysis.
831 for (VPWidenInductionRecipe *PhiR : WideIVs) {
833 for (VPUser *U : reverse(Users)) {
834 auto *Def = dyn_cast<VPRecipeWithIRFlags>(U);
835 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
836 // Skip recipes that shouldn't be narrowed.
837 if (!Def ||
839 Def->user_empty() || !Def->getUnderlyingValue() ||
840 (RepR && (RepR->isSingleScalar() || RepR->isPredicated())))
841 continue;
842
843 // Skip recipes that may have other lanes than their first used.
845 continue;
846
847 // TODO: Support scalarizing ExtractValue.
848 if (match(Def,
850 continue;
851
853 Def->getUnderlyingInstr()->getOpcode(), Def->operands(),
854 /*Mask=*/nullptr, *Def, getMetadataOf(Def), DebugLoc::getUnknown(),
855 Def->getScalarType(), Def->getUnderlyingInstr());
856 Clone->insertAfter(Def);
857 Def->replaceAllUsesWith(Clone);
858 Def->eraseFromParent();
859 }
860 }
861
862 VPBuilder Builder(HeaderVPBB->getFirstNonPhi());
863 for (VPWidenInductionRecipe *PhiR : WideIVs) {
864 // Replace wide pointer inductions which have only their scalars used by
865 // PtrAdd(IndStart, ScalarIVSteps (0, Step)).
866 if (auto *PtrIV = dyn_cast<VPWidenPointerInductionRecipe>(PhiR)) {
867 if (!Plan.hasScalarVFOnly() &&
868 !PtrIV->onlyScalarsGenerated(Plan.hasScalableVF()))
869 continue;
870
871 VPValue *PtrAdd =
872 vputils::scalarizeVPWidenPointerInduction(PtrIV, Plan, Builder);
873 PtrIV->replaceAllUsesWith(PtrAdd);
874 continue;
875 }
876
877 // Replace widened induction with scalar steps for users that only use
878 // scalars.
879 auto *WideIV = cast<VPWidenIntOrFpInductionRecipe>(PhiR);
880 if (HasOnlyVectorVFs && none_of(WideIV->users(), [WideIV](VPUser *U) {
881 return U->usesScalars(WideIV);
882 }))
883 continue;
884
885 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
886 VPIRFlags::WrapFlagsTy WrapFlags;
887 // We can preserve nuw when the step is non-negative.
888 const APInt *Step;
889 if (match(WideIV->getStepValue(), m_APInt(Step)) && Step->isNonNegative())
890 WrapFlags = WideIV->getNoWrapFlagsOrNone().withoutNoSignedWrap();
892 Plan, ID.getKind(), ID.getInductionOpcode(),
893 dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
894 WideIV->getScalarType(), WideIV->getStartValue(),
895 WideIV->getStepValue(), WideIV->getDebugLoc(), Builder, WrapFlags);
896
897 // Update scalar users of IV to use Step instead.
898 if (!HasOnlyVectorVFs) {
899 assert(!Plan.hasScalableVF() &&
900 "plans containing a scalar VF cannot also include scalable VFs");
901 WideIV->replaceAllUsesWith(Steps);
902 } else {
903 bool HasScalableVF = Plan.hasScalableVF();
904 WideIV->replaceUsesWithIf(Steps, [WideIV, HasScalableVF](VPUser *U) {
905 if (HasScalableVF)
906 return U->usesFirstLaneOnly(WideIV);
907 return U->usesScalars(WideIV);
908 });
909 }
910 }
911}
912
913/// Check if \p VPV is an untruncated wide induction, either before or after the
914/// increment. If so return the header IV (before the increment), otherwise
915/// return null.
918 auto *WideIV = dyn_cast<VPWidenInductionRecipe>(VPV);
919 if (WideIV) {
920 // VPV itself is a wide induction, separately compute the end value for exit
921 // users if it is not a truncated IV.
922 auto *IntOrFpIV = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
923 return (IntOrFpIV && IntOrFpIV->isTruncated()) ? nullptr : WideIV;
924 }
925
926 // Check if VPV is an optimizable induction increment.
927 VPRecipeBase *Def = VPV->getDefiningRecipe();
928 if (!Def || Def->getNumOperands() != 2)
929 return nullptr;
930 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(0));
931 if (!WideIV)
932 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(1));
933 if (!WideIV)
934 return nullptr;
935
936 auto IsWideIVInc = [&]() {
937 auto &ID = WideIV->getInductionDescriptor();
938
939 // Check if VPV increments the induction by the induction step.
940 VPValue *IVStep = WideIV->getStepValue();
941 switch (ID.getInductionOpcode()) {
942 case Instruction::Add:
943 return match(VPV, m_c_Add(m_Specific(WideIV), m_Specific(IVStep)));
944 case Instruction::FAdd:
945 return match(VPV, m_c_FAdd(m_Specific(WideIV), m_Specific(IVStep)));
946 case Instruction::FSub:
947 return match(VPV, m_Binary<Instruction::FSub>(m_Specific(WideIV),
948 m_Specific(IVStep)));
949 case Instruction::Sub: {
950 // IVStep will be the negated step of the subtraction. Check if Step == -1
951 // * IVStep.
952 VPValue *Step;
953 if (!match(VPV, m_Sub(m_VPValue(), m_VPValue(Step))))
954 return false;
955 const SCEV *IVStepSCEV = vputils::getSCEVExprForVPValue(IVStep, PSE);
956 const SCEV *StepSCEV = vputils::getSCEVExprForVPValue(Step, PSE);
957 ScalarEvolution &SE = *PSE.getSE();
958 return !isa<SCEVCouldNotCompute>(IVStepSCEV) &&
959 !isa<SCEVCouldNotCompute>(StepSCEV) &&
960 IVStepSCEV == SE.getNegativeSCEV(StepSCEV);
961 }
962 default:
963 return ID.getKind() == InductionDescriptor::IK_PtrInduction &&
964 match(VPV, m_GetElementPtr(m_Specific(WideIV),
965 m_Specific(WideIV->getStepValue())));
966 }
967 llvm_unreachable("should have been covered by switch above");
968 };
969 return IsWideIVInc() ? WideIV : nullptr;
970}
971
972/// Attempts to optimize the induction variable exit values for users in the
973/// early exit block.
976 VPValue *Incoming, *Mask;
978 m_VPValue(Incoming))))
979 return nullptr;
980
981 auto *WideIV = getOptimizableIVOf(Incoming, PSE);
982 if (!WideIV)
983 return nullptr;
984
985 // Calculate the final index.
986 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
987 auto *CanonicalIV = LoopRegion->getCanonicalIV();
988 Type *CanonicalIVType = LoopRegion->getCanonicalIVType();
989 auto *ExtractR = cast<VPInstruction>(Op);
990 VPBuilder B(ExtractR);
991
992 DebugLoc DL = ExtractR->getDebugLoc();
993 VPValue *FirstActiveLane = B.createFirstActiveLane(Mask, DL);
994 FirstActiveLane =
995 B.createScalarZExtOrTrunc(FirstActiveLane, CanonicalIVType, DL);
996 VPValue *EndValue = B.createAdd(CanonicalIV, FirstActiveLane, DL);
997
998 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
999 // changed it means the exit is using the incremented value, so we need to
1000 // add the step.
1001 if (Incoming != WideIV) {
1002 VPValue *One = Plan.getConstantInt(CanonicalIVType, 1);
1003 EndValue = B.createAdd(EndValue, One, DL);
1004 }
1005
1006 if (!match(WideIV, m_CanonicalWidenIV())) {
1007 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
1008 VPValue *Start = WideIV->getStartValue();
1009 VPValue *Step = WideIV->getStepValue();
1010 EndValue = B.createDerivedIV(
1011 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1012 Start, EndValue, Step);
1013 }
1014
1015 return EndValue;
1016}
1017
1018/// Compute the end value for \p WideIV, unless it is truncated. Creates a
1019/// VPDerivedIVRecipe for non-canonical inductions.
1021 VPBuilder &VectorPHBuilder,
1022 VPValue *VectorTC) {
1023 auto *WideIntOrFp = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
1024 // Truncated wide inductions resume from the last lane of their vector value
1025 // in the last vector iteration which is handled elsewhere.
1026 if (WideIntOrFp && WideIntOrFp->isTruncated())
1027 return nullptr;
1028
1029 VPValue *Start = WideIV->getStartValue();
1030 VPValue *Step = WideIV->getStepValue();
1031 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
1032 VPValue *EndValue = VectorTC;
1033 if (!match(WideIV, m_CanonicalWidenIV())) {
1034 EndValue = VectorPHBuilder.createDerivedIV(
1035 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1036 Start, VectorTC, Step);
1037 }
1038
1039 // EndValue is derived from the vector trip count (which has the same type as
1040 // the widest induction) and thus may be wider than the induction here.
1041 Type *ScalarTypeOfWideIV = WideIV->getScalarType();
1042 if (ScalarTypeOfWideIV != EndValue->getScalarType()) {
1043 EndValue = VectorPHBuilder.createScalarCast(Instruction::Trunc, EndValue,
1044 ScalarTypeOfWideIV,
1045 WideIV->getDebugLoc());
1046 }
1047
1048 return EndValue;
1049}
1050
1051/// Attempts to optimize the induction variable exit values for users in the
1052/// exit block coming from the latch in the original scalar loop.
1053static VPValue *
1057 VPValue *Incoming;
1060 m_VPValue(Incoming)))))
1061 return nullptr;
1062
1063 VPWidenInductionRecipe *WideIV = getOptimizableIVOf(Incoming, PSE);
1064 if (!WideIV)
1065 return nullptr;
1066
1067 VPValue *EndValue = EndValues.lookup(WideIV);
1068 assert(EndValue && "Must have computed the end value up front");
1069
1070 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
1071 // changed it means the exit is using the incremented value, so we don't
1072 // need to subtract the step.
1073 if (Incoming != WideIV)
1074 return EndValue;
1075
1076 // Otherwise, subtract the step from the EndValue.
1077 auto *ExtractR = cast<VPInstruction>(Op);
1078 VPBuilder B(ExtractR);
1079 VPValue *Step = WideIV->getStepValue();
1080 Type *ScalarTy = WideIV->getScalarType();
1081 if (ScalarTy->isIntegerTy())
1082 return B.createSub(EndValue, Step, DebugLoc::getUnknown(), "ind.escape");
1083 if (ScalarTy->isPointerTy()) {
1084 Type *StepTy = Step->getScalarType();
1085 auto *Zero = Plan.getZero(StepTy);
1086 return B.createPtrAdd(EndValue, B.createSub(Zero, Step),
1087 DebugLoc::getUnknown(), "ind.escape");
1088 }
1089 if (ScalarTy->isFloatingPointTy()) {
1090 const auto &ID = WideIV->getInductionDescriptor();
1091 return B.createNaryOp(
1092 ID.getInductionBinOp()->getOpcode() == Instruction::FAdd
1093 ? Instruction::FSub
1094 : Instruction::FAdd,
1095 {EndValue, Step}, {ID.getInductionBinOp()->getFastMathFlags()});
1096 }
1097 llvm_unreachable("all possible induction types must be handled");
1098 return nullptr;
1099}
1100
1103 VPValue *ResumeTC,
1104 const Loop *L) {
1105 VPValue *Incoming;
1108 m_VPValue(Incoming)))))
1109 return nullptr;
1110
1111 const SCEV *IncomingSCEV = vputils::getSCEVExprForVPValue(Incoming, PSE, L);
1112 const SCEV *Start, *Step;
1113 if (!match(IncomingSCEV, m_scev_AffineAddRec(m_SCEV(Start), m_SCEV(Step),
1114 m_SpecificLoop(L))))
1115 return nullptr;
1116
1117 auto *ExtractR = cast<VPInstruction>(Op);
1118 DebugLoc DL = ExtractR->getDebugLoc();
1119 VPBuilder Builder(ExtractR);
1120 VPSCEVExpander Expander(Builder, *PSE.getSE(), DL);
1121 VPValue *StartVPV = Expander.expand(Start);
1122 VPValue *StepVPV = Expander.expand(Step);
1123
1124 Type *StartTy = StartVPV->getScalarType();
1125 assert(StartTy->isIntOrPtrTy() && "The type must be SCEVable");
1129 Type *TCTy = ResumeTC->getScalarType();
1130 VPValue *ExitCount = Builder.createOverflowingOp(
1131 Instruction::Sub, {ResumeTC, Plan.getConstantInt(TCTy, 1)},
1132 {/*HasNUW=*/true, /*HasNSW=*/false}, DebugLoc::getUnknown());
1133 return Builder.createDerivedIV(Kind, /*FPBinOp=*/nullptr, StartVPV, ExitCount,
1134 StepVPV);
1135}
1136
1138 VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L) {
1139 // Compute end values for all inductions.
1140 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
1141 auto *VectorPH = cast<VPBasicBlock>(VectorRegion->getSinglePredecessor());
1142 VPBuilder VectorPHBuilder(VectorPH->getFirstNonPhi());
1144 VPValue *ResumeTC =
1145 Plan.hasTailFolded() ? Plan.getTripCount() : &Plan.getVectorTripCount();
1147 VectorRegion->getEntryBasicBlock()->phis())) {
1149 &WideIV, VectorPHBuilder, ResumeTC))
1150 EndValues[&WideIV] = EndValue;
1151 }
1152
1153 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
1154 for (VPRecipeBase &R : make_early_inc_range(*MiddleVPBB)) {
1155 VPValue *Op;
1156 if (!match(&R, m_ExitingIVValue(m_VPValue(Op))))
1157 continue;
1158 auto *WideIV = cast<VPWidenInductionRecipe>(Op);
1159 if (VPValue *EndValue = EndValues.lookup(WideIV)) {
1160 R.getVPSingleValue()->replaceAllUsesWith(EndValue);
1161 R.eraseFromParent();
1162 }
1163 }
1164
1165 // Then, optimize exit block users.
1166 for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
1167 for (VPRecipeBase &R : ExitVPBB->phis()) {
1168 auto *ExitIRI = cast<VPIRPhi>(&R);
1169
1170 for (auto [Idx, PredVPBB] : enumerate(ExitVPBB->getPredecessors())) {
1171 VPValue *Escape = nullptr;
1172 if (PredVPBB == MiddleVPBB) {
1174 Plan, ExitIRI->getOperand(Idx), EndValues, PSE);
1175 if (!Escape)
1177 Plan, ExitIRI->getOperand(Idx), PSE, ResumeTC, L);
1178 } else {
1180 Plan, ExitIRI->getOperand(Idx), PSE);
1181 }
1182 if (Escape)
1183 ExitIRI->setOperand(Idx, Escape);
1184 }
1185 }
1186 }
1187}
1188
1189/// Try to simplify logical and bitwise recipes in \p Def.
1191 VPValue *X;
1192
1193 // X | AllOnes -> AllOnes
1194 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_AllOnes())))
1195 return Plan.getAllOnesValue(Def->getScalarType());
1196
1197 // X | 0 -> X
1198 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_ZeroInt())))
1199 return X;
1200
1201 // X | !X -> AllOnes
1203 return Plan.getAllOnesValue(Def->getScalarType());
1204
1205 // X & 0 -> 0
1206 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_ZeroInt())))
1207 return Plan.getZero(Def->getScalarType());
1208
1209 // X & AllOnes -> X
1210 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_AllOnes())))
1211 return X;
1212
1213 // X && false -> false
1214 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False())))
1215 return Plan.getFalse();
1216
1217 // X && true -> X
1218 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True())))
1219 return X;
1220
1221 // X && (X && Y) -> X && Y
1222 if (match(Def, m_LogicalAnd(m_VPValue(X),
1224 return Def->getOperand(1);
1225
1226 // X && !X -> 0
1228 return Plan.getFalse();
1229
1230 if (match(Def, m_Select(m_VPValue(), m_VPValue(X), m_Deferred(X))))
1231 return X;
1232
1233 // X != false -> X
1235 assert(X->getScalarType()->isIntegerTy(1) && "must have boolean operands");
1236 return X;
1237 }
1238
1239 return nullptr;
1240}
1241
1242/// Swap the branch weights recorded for \p R, a select whose two selected
1243/// operands are being swapped,
1245 auto *MD = dyn_cast<VPIRMetadata>(&R);
1246 if (!MD)
1247 return;
1249 if (!extractBranchWeights(MD->getMetadata(LLVMContext::MD_prof), Weights))
1250 return;
1251 assert(Weights.size() == 2 && "unexpected branch weights");
1252 MD->setMetadata(
1253 LLVMContext::MD_prof,
1254 MDBuilder(Plan.getContext()).createBranchWeights(Weights[1], Weights[0]));
1255}
1256
1257/// Return an existing value or a live in for VPSingleDefRecipe \p Def if
1258/// possible. This shouldn't create or modify recipes.
1260 // Simplification of live-in IR values for SingleDef recipes using
1261 // InstSimplifyFolder.
1262 const DataLayout &DL = Plan.getDataLayout();
1263 if (VPValue *V = vputils::tryToFoldLiveIns(*Def, Def->operands(), DL))
1264 return V;
1265
1266 // Fold PredPHI LiveIn -> LiveIn.
1267 if (auto *PredPHI = dyn_cast<VPPredInstPHIRecipe>(Def)) {
1268 VPValue *Op = PredPHI->getOperand(0);
1269 if (isa<VPIRValue>(Op))
1270 return Op;
1271 }
1272
1273 if (VPValue *V = simplifyLogicalRecipe(Plan, Def))
1274 return V;
1275
1276 VPValue *A, *B;
1277
1278 // icmp Pred X, X -> true if Pred is true when equal, false otherwise.
1279 CmpPredicate Pred;
1280 if (match(Def, m_ICmp(Pred, m_VPValue(A), m_Deferred(A))))
1281 return ICmpInst::isTrueWhenEqual(Pred) ? Plan.getTrue() : Plan.getFalse();
1282
1283 if (match(Def, m_c_Add(m_VPValue(A), m_ZeroInt())))
1284 return A;
1285
1286 if (match(Def, m_c_Mul(m_VPValue(A), m_One())))
1287 return A;
1288
1289 if (match(Def, m_c_Mul(m_VPValue(), m_ZeroInt())))
1290 return Plan.getZero(Def->getScalarType());
1291
1292 // A bitcast to the same type is a no-op.
1293 if (match(Def, m_BitCast(m_VPValue(A))) &&
1294 Def->getScalarType() == A->getScalarType())
1295 return A;
1296
1297 // Shifting by zero is a no-op.
1300 m_AShr(m_VPValue(A), m_ZeroInt())))))
1301 return A;
1302
1303 if (match(Def, m_Trunc(m_ZExtOrSExt(m_VPValue(A)))))
1304 if (Def->getScalarType() == A->getScalarType())
1305 return A;
1306
1307 if (match(Def, m_Not(m_Not(m_VPValue(A)))))
1308 return A;
1309
1310 // Remove redundant DerviedIVs, that is 0 + A * 1 -> A and 0 + 0 * x -> 0.
1311 if ((match(Def, m_DerivedIV(m_ZeroInt(), m_VPValue(A), m_One())) ||
1313 m_VPValue()))) &&
1314 A->getScalarType() == Def->getScalarType())
1315 return A;
1316
1317 // Simplify MaskedCond with no block mask to its single operand.
1319 !cast<VPInstruction>(Def)->isMasked())
1320 return Def->getOperand(0);
1321
1322 // Look through ExtractLastLane.
1323 if (match(Def, m_ExtractLastLane(m_VPValue(A)))) {
1324 if (match(A, m_BuildVector())) {
1325 auto *BuildVector = cast<VPInstruction>(A);
1326 return BuildVector->getLastOperand();
1327 }
1328
1329 if (match(A, m_Broadcast(m_VPValue(B))))
1330 return B;
1331
1334 return A;
1335
1336 if (Plan.hasScalarVFOnly())
1337 return A;
1338 }
1339
1340 // Look through ExtractPenultimateElement (BuildVector ....).
1342 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1343 return BuildVector->getOperand(BuildVector->getNumOperands() - 2);
1344 }
1345
1346 uint64_t Idx;
1348 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1349 return BuildVector->getOperand(Idx);
1350 }
1351
1353 if (Def->getNumOperands() == 1) {
1354 return Def->getOperand(0);
1355 }
1356 if (auto *Phi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(Def)) {
1357 if (all_equal(Phi->incoming_values()))
1358 return Phi->getOperand(0);
1359 }
1360 return nullptr;
1361 }
1362
1363 VPIRValue *IRV;
1364 if (Def->getNumOperands() == 1 &&
1366 return IRV;
1367
1369 m_One())) &&
1370 A->getScalarType() == Def->getScalarType())
1371 return A;
1372
1373 // Some simplifications can only be applied after unrolling. Perform them
1374 // below.
1375 if (!Plan.isUnrolled())
1376 return nullptr;
1377
1378 // Simplify extracts of the same single-scalar.
1380 all_equal(drop_begin(Def->operands())) &&
1381 vputils::isSingleScalar(Def->getOperand(1)))
1382 return Def->getOperand(1);
1383
1384 // Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
1385 // scalar canonical IV.
1387 if (match(Def, m_ExtractLane(m_ZeroInt(), m_CanonicalWidenIV(WidenIV))))
1388 return WidenIV->getRegion()->getCanonicalIV();
1389
1390 // Simplify unrolled VectorPointer without offset, or with zero offset, to
1391 // just the pointer operand.
1392 if (auto *VPR = dyn_cast<VPVectorPointerRecipe>(Def))
1393 if (!VPR->getVFxPart() || match(VPR->getVFxPart(), m_ZeroInt()))
1394 return VPR->getOperand(0);
1395
1396 // VPScalarIVSteps after unrolling can be replaced by their start value, if
1397 // the start index is zero and only the first lane 0 is demanded.
1398 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Def))
1399 if (!Steps->getStartIndex() && vputils::onlyFirstLaneUsed(Steps))
1400 return Steps->getOperand(0);
1401
1402 if (Plan.getConcreteUF() == 1 && match(Def, m_ExtractLastPart(m_VPValue(A))))
1403 return A;
1404
1405 return nullptr;
1406}
1407
1408/// Returns true if \p V is available at the end of \p VPBB, i.e. it either is a
1409/// live-in from the original IR or defined in \p VPBB.
1410static bool isAvailableAtEndOf(VPValue *V, const VPBasicBlock *VPBB) {
1411 VPRecipeBase *DefR = V->getDefiningRecipe();
1412 return DefR ? DefR->getParent() == VPBB : isa<VPIRValue>(V);
1413}
1414
1415namespace {
1416/// Inserter for VPBuilderBase which appends all created VPSingleDefRecipes to a
1417/// worklist, so they get combined as well.
1418struct VPCombineInserter {
1419 SmallVectorImpl<VPSingleDefRecipe *> &Worklist;
1420
1421 void insertHelper(VPRecipeBase *R, VPBasicBlock::iterator It) {
1422 R->insertBefore(It);
1423 if (auto *Def = dyn_cast<VPSingleDefRecipe>(R))
1424 Worklist.push_back(Def);
1425 }
1426};
1427
1428using VPCombineBuilder = VPBuilderBase<VPCombineInserter>;
1429} // namespace
1430
1431/// Combine \p Def into a simpler recipe. May modify or create new recipes via
1432/// \p Builder.
1434 VPCombineBuilder &Builder) {
1435 if (auto *V = simplifyRecipe(Plan, Def)) {
1436 Def->replaceAllUsesWith(V);
1437 return Def;
1438 }
1439
1440 // Drop the mask of a predicated store masked by the header mask (which is
1441 // guaranteed to be true at least for the first lane) and both the stored
1442 // value and the address are uniform across VF and UF. The header mask is
1443 // still the abstract region value here.
1444 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Def);
1445 RepR && RepR->isPredicated() && RepR->getOpcode() == Instruction::Store &&
1446 all_of(RepR->operandsWithoutMask(), vputils::isUniformAcrossVFsAndUFs) &&
1447 match(RepR->getMask(), m_HeaderMask())) {
1448 auto *Unmasked = new VPReplicateRecipe(
1449 RepR->getUnderlyingInstr(), RepR->operandsWithoutMask(),
1450 RepR->isSingleScalar(), /*Mask=*/nullptr, *RepR, *RepR,
1451 RepR->getDebugLoc());
1452 Builder.insert(Unmasked);
1453 return Unmasked;
1454 }
1455
1456 // Avoid replacing VPInstructions with underlying values with new
1457 // VPInstructions, as we would fail to create widen/replicate recpes from the
1458 // new VPInstructions without an underlying value, and miss out on some
1459 // transformations that only apply to widened/replicated recipes later, by
1460 // doing so.
1461 // TODO: We should also not replace non-VPInstructions like VPWidenRecipe with
1462 // VPInstructions without underlying values, as those will get skipped during
1463 // cost computation.
1464 bool CanCreateNewRecipe =
1465 !isa<VPInstruction>(Def) || !Def->getUnderlyingValue();
1466
1467 VPValue *X, *Y, *Z;
1468
1469 // X && (Y && X) -> X && Y
1470 if (CanCreateNewRecipe &&
1473 return Builder.createLogicalAnd(X, Y);
1474
1475 // (X && Y) | (X && Z) -> X && (Y | Z)
1476 if (CanCreateNewRecipe &&
1479 // Simplify only if one of the operands has one use to avoid creating an
1480 // extra recipe.
1481 (!Def->getOperand(0)->hasMoreThanOneUniqueUser() ||
1482 !Def->getOperand(1)->hasMoreThanOneUniqueUser()))
1483 return Builder.createLogicalAnd(X, Builder.createOr(Y, Z));
1484
1485 // (X && Y) | !X -> !X || Y
1486 if (CanCreateNewRecipe &&
1487 match(Def,
1489 m_VPValue(Z, m_Not(m_Deferred(X))))))
1490 return Builder.createLogicalOr(Z, Y);
1491
1492 // select C, false, true -> not C
1493 VPValue *C;
1494 if (CanCreateNewRecipe &&
1495 match(Def, m_Select(m_VPValue(C), m_False(), m_True())))
1496 return Builder.createNot(C);
1497
1498 // select !C, X, Y -> select C, Y, X
1499 if (match(Def, m_Select(m_Not(m_VPValue(C)), m_VPValue(X), m_VPValue(Y)))) {
1500 Def->setOperand(0, C);
1501 Def->setOperand(1, Y);
1502 Def->setOperand(2, X);
1503 swapSelectBranchWeights(*Def, Plan);
1504 return Def;
1505 }
1506
1507 // select X, (i1 Y | Z), Y -> Y | (X && Z)
1508 if (CanCreateNewRecipe &&
1509 match(Def, m_Select(m_VPValue(X),
1511 m_Deferred(Y))) &&
1512 Y->getScalarType()->isIntegerTy(1))
1513 return Builder.createOr(Y, Builder.createLogicalAnd(X, Z));
1514
1515 // select M0, (select M1, X, Y), Y -> select (M0 && M1), X, Y
1516 VPValue *Mask0, *Mask1;
1517 if (CanCreateNewRecipe &&
1518 match(Def,
1519 m_SelectLike(m_VPValue(Mask0),
1521 m_VPValue(Y))),
1522 m_Deferred(Y))))
1523 return Builder.createSelect(Builder.createLogicalAnd(Mask0, Mask1), X, Y,
1524 Def->getDebugLoc());
1525
1526 if (match(Def, m_Trunc(m_VPValue(Y, m_ZExtOrSExt(m_VPValue(X)))))) {
1527 // Don't replace a non-widened cast recipe with a widened cast.
1528 if (!isa<VPWidenCastRecipe>(Def))
1529 return nullptr;
1530 Type *TruncTy = Def->getScalarType();
1531 Type *XTy = X->getScalarType();
1532 if (XTy->getScalarSizeInBits() < TruncTy->getScalarSizeInBits()) {
1533
1534 unsigned ExtOpcode =
1535 match(Y, m_SExt(m_VPValue())) ? Instruction::SExt : Instruction::ZExt;
1536 auto *Ext =
1537 Builder.createWidenCast(Instruction::CastOps(ExtOpcode), X, TruncTy);
1538 if (auto *UnderlyingExt = Y->getUnderlyingValue()) {
1539 // UnderlyingExt has distinct return type, used to retain legacy cost.
1540 Ext->setUnderlyingValue(UnderlyingExt);
1541 }
1542 return Ext;
1543 } else if (XTy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits()) {
1544 auto *Trunc = Builder.createWidenCast(Instruction::Trunc, X, TruncTy);
1545 return Trunc;
1546 }
1547 }
1548
1549 if (CanCreateNewRecipe && match(Def, m_c_Mul(m_VPValue(X), m_AllOnes()))) {
1550 // Preserve nsw from the Mul on the new Sub.
1552 false, cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap()};
1553 return Builder.createSub(Plan.getZero(X->getScalarType()), X,
1554 Def->getDebugLoc(), "", NW);
1555 }
1556
1557 if (CanCreateNewRecipe &&
1558 match(Def, m_c_Add(m_VPValue(X),
1559 m_VPValue(Z, m_Sub(m_ZeroInt(), m_VPValue(Y)))))) {
1560 // Preserve nsw from the Add and the Sub, if it's present on both, on the
1561 // new Sub.
1563 false, cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap() &&
1564 cast<VPRecipeWithIRFlags>(Z)->hasNoSignedWrap()};
1565 return Builder.createSub(X, Y, Def->getDebugLoc(), "", NW);
1566 }
1567
1568 const APInt *APC;
1569 if (CanCreateNewRecipe && match(Def, m_URem(m_VPValue(X), m_APInt(APC))) &&
1570 APC->isPowerOf2())
1571 return Builder.createAnd(X, Plan.getConstantInt(*APC - 1),
1572 Def->getDebugLoc());
1573
1574 if (CanCreateNewRecipe && match(Def, m_c_Mul(m_VPValue(X), m_APInt(APC))) &&
1575 APC->isPowerOf2()) {
1576 auto *MulR = cast<VPRecipeWithIRFlags>(Def);
1577 unsigned ShiftAmt = APC->exactLogBase2();
1578 VPIRFlags::WrapFlagsTy NW(MulR->hasNoUnsignedWrap(),
1579 MulR->hasNoSignedWrap() &&
1580 ShiftAmt != APC->getBitWidth() - 1);
1581 return Builder.createNaryOp(
1582 Instruction::Shl,
1583 {X, Plan.getConstantInt(APC->getBitWidth(), ShiftAmt)}, NW,
1584 Def->getDebugLoc());
1585 }
1586
1587 if (CanCreateNewRecipe && match(Def, m_UDiv(m_VPValue(X), m_APInt(APC))) &&
1588 APC->isPowerOf2())
1589 return Builder.createNaryOp(
1590 Instruction::LShr,
1591 {X, Plan.getConstantInt(APC->getBitWidth(), APC->exactLogBase2())},
1592 *cast<VPRecipeWithIRFlags>(Def), Def->getDebugLoc());
1593
1594 // (X >> C) << C -> X & (-1 << C).
1595 if (CanCreateNewRecipe &&
1596 match(Def, m_Shl(m_LShr(m_VPValue(X), m_VPValue(Y, m_APInt(APC))),
1597 m_Deferred(Y))))
1598 return Builder.createAnd(
1599 X, Plan.getConstantInt(APInt::getAllOnes(APC->getBitWidth()) << *APC),
1600 Def->getDebugLoc());
1601
1602 if (match(Def, m_Not(m_VPValue(X)))) {
1603 // Try to fold Not into compares by adjusting the predicate in-place.
1604 CmpPredicate Pred;
1605 if (match(X, m_Cmp(Pred, m_VPValue(), m_VPValue()))) {
1606 auto *Cmp = cast<VPRecipeWithIRFlags>(X);
1607 // Only fold if every user is a Not of the cmp, or a select using the cmp
1608 // solely as its condition.
1609 if (all_of(Cmp->users(), [Cmp](VPUser *U) {
1610 return match(U, m_Not(m_Specific(Cmp))) ||
1611 (match(U, m_Select(m_Specific(Cmp), m_VPValue(),
1612 m_VPValue())) &&
1613 U->getOperand(1) != Cmp && U->getOperand(2) != Cmp);
1614 })) {
1615 Cmp->setPredicate(CmpInst::getInversePredicate(Pred));
1616 for (VPUser *U : to_vector(Cmp->users())) {
1617 auto *R = cast<VPSingleDefRecipe>(U);
1618 if (match(R, m_Select(m_Specific(Cmp), m_VPValue(X), m_VPValue(Y)))) {
1619 // select (cmp pred), X, Y -> select (cmp inv_pred), Y, X
1620 R->setOperand(1, Y);
1621 R->setOperand(2, X);
1622 swapSelectBranchWeights(*R, Plan);
1623 } else {
1624 // not (cmp pred) -> cmp inv_pred
1625 assert(match(R, m_Not(m_Specific(Cmp))) && "Unexpected user");
1626 R->replaceAllUsesWith(Cmp);
1627 }
1628 }
1629 // If Cmp doesn't have a debug location, use the one from the negation,
1630 // to preserve the location.
1631 if (!Cmp->getDebugLoc() && Def->getDebugLoc())
1632 Cmp->setDebugLoc(Def->getDebugLoc());
1633 return Def;
1634 }
1635 }
1636 }
1637
1638 // Fold any-of (fcmp uno A, A), (fcmp uno B, B), ... ->
1639 // any-of (fcmp uno A, B), ...
1640 if (match(Def, m_AnyOf())) {
1642 VPRecipeBase *UnpairedCmp = nullptr;
1643 for (VPValue *Op : Def->operands()) {
1644 VPValue *X;
1645 if (Op->getNumUsers() > 1 ||
1647 m_Deferred(X)))) {
1648 NewOps.push_back(Op);
1649 } else if (!UnpairedCmp) {
1650 UnpairedCmp = Op->getDefiningRecipe();
1651 } else {
1652 NewOps.push_back(Builder.createFCmp(CmpInst::FCMP_UNO,
1653 UnpairedCmp->getOperand(0), X));
1654 UnpairedCmp = nullptr;
1655 }
1656 }
1657
1658 if (UnpairedCmp)
1659 NewOps.push_back(UnpairedCmp->getVPSingleValue());
1660
1661 if (NewOps.size() < Def->getNumOperands())
1662 return Builder.createNaryOp(VPInstruction::AnyOf, NewOps);
1663 }
1664
1665 // Fold (fcmp uno X, X) | (fcmp uno Y, Y) -> fcmp uno X, Y
1666 // This is useful for fmax/fmin without fast-math flags, where we need to
1667 // check if any operand is NaN.
1668 if (CanCreateNewRecipe &&
1670 m_Deferred(X)),
1672 m_Deferred(Y)))) &&
1673 X->getScalarType() == Y->getScalarType())
1674 return Builder.createFCmp(CmpInst::FCMP_UNO, X, Y);
1675
1677 m_One())) &&
1678 X->getScalarType() != Def->getScalarType())
1679 return Builder.createWidenCast(Instruction::Trunc, X, Def->getScalarType());
1680
1681 // For i1 vp.merges produced by AnyOf reductions:
1682 // vp.merge true, (or X, Y), X, evl -> vp.merge Y, true, X, evl
1684 m_VPValue(X), m_VPValue())) &&
1686 Def->getScalarType()->isIntegerTy(1)) {
1687 Def->setOperand(1, Plan.getTrue());
1688 Def->setOperand(0, Y);
1689 return Def;
1690 }
1691
1692 if (match(Def, m_BuildVector()) && all_equal(Def->operands()))
1693 return Builder.createNaryOp(VPInstruction::Broadcast, Def->getOperand(0));
1694
1695 // Replace uses of a BuildVector by users that only use its first lane with
1696 // its first operand directly.
1697 if (match(Def, m_BuildVector())) {
1698 Def->replaceUsesWithIf(Def->getOperand(0), [Def](VPUser *U) {
1699 return U->usesFirstLaneOnly(Def);
1700 });
1701 return Def;
1702 }
1703
1704 // Look through broadcast of single-scalar when used as select conditions; in
1705 // that case the scalar condition can be used directly.
1706 if (match(Def,
1709 "broadcast operand must be single-scalar");
1710 Def->setOperand(0, Z);
1711 return Def;
1712 }
1713
1714 if (match(Def, m_Broadcast(m_VPValue(X)))) {
1715 Def->replaceUsesWithIf(
1716 X, [Def](const VPUser *U) { return U->usesScalars(Def); });
1717 return Def;
1718 }
1719
1720 // Some simplifications can only be applied after unrolling. Perform them
1721 // below.
1722 if (!Plan.isUnrolled())
1723 return nullptr;
1724
1725 // Simplify extract-lane with single source to extract-element.
1726 VPValue *LaneToExtract;
1727 if (match(Def, m_ExtractLane(m_VPValue(LaneToExtract), m_VPValue(X))))
1728 return Builder.createNaryOp(Instruction::ExtractElement, {X, LaneToExtract},
1729 Def->getDebugLoc());
1730
1731 // Look for cycles where Def is of the form:
1732 // X = phi(0, IVInc) ; used only by IVInc, or by IVInc and Inc = X + Y
1733 // IVInc = X + Step ; used by X and Def
1734 // Def = IVInc + Y
1735 // Fold the increment Y into the phi's start value, replace Def with IVInc,
1736 // and if Inc exists, replace it with X.
1737 VPValue *IVInc;
1738 if (match(Def, m_Add(m_VPValue(IVInc, m_Add(m_VPValue(X), m_VPValue())),
1739 m_VPValue(Y))) &&
1740 match(X, m_VPPhi(m_ZeroInt(), m_Specific(IVInc))) &&
1741 IVInc->getNumUsers() == 2) {
1742 auto *Phi = cast<VPPhi>(X);
1743 // If Phi has a second user (besides IVInc's defining recipe), it must be
1744 // Inc = Phi + Y for the fold to apply.
1746 Phi, m_Add(m_Specific(Phi), m_Specific(Y)));
1747 if ((Phi->getNumUsers() == 1 || (Phi->getNumUsers() == 2 && Inc)) &&
1748 isAvailableAtEndOf(Y, Phi->getIncomingBlock(0))) {
1749 Def->replaceAllUsesWith(IVInc);
1750 if (Inc)
1751 Inc->replaceAllUsesWith(Phi);
1752 Phi->setOperand(0, Y);
1753 return Def;
1754 }
1755 }
1756
1757 // Simplify redundant ReductionStartVector recipes after unrolling.
1758 VPValue *StartV;
1760 m_VPValue(StartV), m_VPValue(), m_VPValue()))) {
1761 Def->replaceUsesWithIf(StartV, [](const VPUser *U) {
1762 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(U);
1763 return PhiR && PhiR->isInLoop();
1764 });
1765 return Def;
1766 }
1767
1768 return nullptr;
1769}
1770
1774 Plan.getEntry());
1776 for (VPSingleDefRecipe &Def :
1778 Worklist.push_back(&Def);
1779
1780 [[maybe_unused]] unsigned InitWorklistSize = Worklist.size();
1781
1782 VPCombineBuilder Builder({Worklist});
1783 while (!Worklist.empty()) {
1784 assert(Worklist.size() < InitWorklistSize * 2 &&
1785 "Worklist is growing large, possible cycle?");
1786 VPSingleDefRecipe *Def = Worklist.pop_back_val();
1787 Builder.setInsertPoint(Def);
1788 VPSingleDefRecipe *New = combineRecipe(Plan, Def, Builder);
1789 if (!New)
1790 continue;
1791 if (New != Def) {
1792 // Replace the recipe with a new one.
1793 Def->replaceAllUsesWith(New);
1794 Def->eraseFromParent();
1795 // TODO: Append users to the worklist (might need a setvector)
1796 } else if (vputils::isDeadRecipe(*Def)) {
1797 // Recipe was modified - it may be dead now.
1798 Def->eraseFromParent();
1799 }
1800 }
1801}
1802
1804 // Pull out reverses from any elementwise op.
1805 // binop(reverse(x), reverse(y)) -> reverse(binop(x,y))
1807 Plan, [](VPValue *&X) { return m_Reverse(m_VPValue(X)); },
1808 [](auto *X) { return new VPInstruction(VPInstruction::Reverse, X); });
1809
1810 // reverse(reverse(x)) -> x
1811 VPValue *X;
1814 for (VPRecipeBase &R : make_early_inc_range(*VPBB))
1815 if (match(&R, m_Reverse(m_Reverse(m_VPValue(X)))))
1816 R.getVPSingleValue()->replaceAllUsesWith(X);
1817}
1818
1819/// Reassociate (headermask && x) && y -> headermask && (x && y) to allow the
1820/// header mask to be simplified further when tail folding, e.g. in
1821/// optimizeEVLMasks.
1822static void reassociateHeaderMask(VPlan &Plan) {
1823 VPValue *HeaderMask = Plan.getVectorLoopRegion()->getHeaderMask();
1824 if (!HeaderMask)
1825 return;
1826
1827 SmallVector<VPUser *> Worklist;
1828 for (VPUser *U : HeaderMask->users())
1829 if (match(U, m_LogicalAnd(m_Specific(HeaderMask), m_VPValue())))
1831
1832 while (!Worklist.empty()) {
1833 auto *R = dyn_cast<VPSingleDefRecipe>(Worklist.pop_back_val());
1834 VPValue *X, *Y;
1835 if (!R || !match(R, m_LogicalAnd(
1836 m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(X)),
1837 m_VPValue(Y))))
1838 continue;
1839 append_range(Worklist, R->users());
1840 VPBuilder Builder(R);
1841 R->replaceAllUsesWith(
1842 Builder.createLogicalAnd(HeaderMask, Builder.createLogicalAnd(X, Y)));
1843 }
1844}
1845
1846static std::optional<Instruction::BinaryOps>
1848 switch (ID) {
1849 case Intrinsic::masked_udiv:
1850 return Instruction::UDiv;
1851 case Intrinsic::masked_sdiv:
1852 return Instruction::SDiv;
1853 case Intrinsic::masked_urem:
1854 return Instruction::URem;
1855 case Intrinsic::masked_srem:
1856 return Instruction::SRem;
1857 default:
1858 return {};
1859 }
1860}
1861
1863 if (Plan.hasScalarVFOnly())
1864 return;
1865
1867 vp_depth_first_deep(Plan.getEntry()))) {
1868 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
1871 continue;
1872 auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
1873 if (RepR && (RepR->isSingleScalar() || RepR->isPredicated()))
1874 continue;
1875
1876 auto *RepOrWidenR = cast<VPRecipeWithIRFlags>(&R);
1877 if (RepR && RepR->getOpcode() == Instruction::Store &&
1878 vputils::isSingleScalar(RepR->getOperand(1))) {
1879 auto *Clone = new VPReplicateRecipe(
1880 RepOrWidenR->getUnderlyingInstr(), RepOrWidenR->operands(),
1881 true /*IsSingleScalar*/, nullptr /*Mask*/, *RepR /*Flags*/,
1882 *RepR /*Metadata*/, RepR->getDebugLoc());
1883 Clone->insertBefore(RepOrWidenR);
1884 VPBuilder Builder(Clone);
1885 VPValue *ExtractOp = Clone->getOperand(0);
1886 if (vputils::isUniformAcrossVFsAndUFs(RepR->getOperand(1)))
1887 ExtractOp =
1888 Builder.createNaryOp(VPInstruction::ExtractLastPart, ExtractOp);
1889 ExtractOp =
1890 Builder.createNaryOp(VPInstruction::ExtractLastLane, ExtractOp);
1891 Clone->setOperand(0, ExtractOp);
1892 RepR->eraseFromParent();
1893 continue;
1894 }
1895
1896 // Narrow llvm.masked.{u,s}{div,rem} intrinsics with a safe divisor.
1897 if (auto *IntrR = dyn_cast<VPWidenIntrinsicRecipe>(RepOrWidenR)) {
1898 if (!vputils::onlyFirstLaneUsed(IntrR))
1899 continue;
1900 auto Opc = getUnmaskedDivRemOpcode(IntrR->getVectorIntrinsicID());
1901 if (!Opc)
1902 continue;
1903 VPBuilder Builder(IntrR);
1904 VPValue *SafeDivisor = Builder.createSelect(
1905 IntrR->getOperand(2), IntrR->getOperand(1),
1906 Plan.getConstantInt(IntrR->getScalarType(), 1));
1907 VPValue *Clone = Builder.createNaryOp(
1908 *Opc, {IntrR->getOperand(0), SafeDivisor},
1909 VPIRFlags::getDefaultFlags(*Opc), IntrR->getDebugLoc());
1910 IntrR->replaceAllUsesWith(Clone);
1911 IntrR->eraseFromParent();
1912 continue;
1913 }
1914
1915 // Skip recipes that aren't single scalars.
1916 if (!vputils::isSingleScalar(RepOrWidenR))
1917 continue;
1918
1919 // Predicate to check if a user of Op introduces extra broadcasts.
1920 auto IntroducesBCastOf = [](const VPValue *Op) {
1921 return [Op](const VPUser *U) {
1922 if (auto *VPI = dyn_cast<VPInstruction>(U)) {
1926 VPI->getOpcode()))
1927 return false;
1928 }
1929 return !U->usesScalars(Op);
1930 };
1931 };
1932
1933 if (any_of(RepOrWidenR->users(), IntroducesBCastOf(RepOrWidenR)) &&
1934 none_of(RepOrWidenR->operands(), [&](VPValue *Op) {
1935 if (any_of(
1936 make_filter_range(Op->users(), not_equal_to(RepOrWidenR)),
1937 IntroducesBCastOf(Op)))
1938 return false;
1939 // Non-constant live-ins require broadcasts, while constants do not
1940 // need explicit broadcasts.
1941 bool LiveInNeedsBroadcast =
1942 isa<VPIRValue>(Op) && !isa<VPConstant>(Op);
1943 auto *OpR = dyn_cast<VPReplicateRecipe>(Op);
1944 return LiveInNeedsBroadcast || (OpR && OpR->isSingleScalar());
1945 }))
1946 continue;
1947
1948 auto *Clone = VPBuilder::createSingleScalarOp(
1949 vputils::getOpcode(RepOrWidenR), RepOrWidenR->operands(),
1950 /*Mask=*/nullptr, *RepOrWidenR, getMetadataOf(RepOrWidenR),
1951 DebugLoc::getUnknown(), RepOrWidenR->getScalarType(),
1952 RepOrWidenR->getUnderlyingInstr());
1953 Clone->insertBefore(RepOrWidenR);
1954 RepOrWidenR->replaceAllUsesWith(Clone);
1955 if (vputils::isDeadRecipe(*RepOrWidenR))
1956 RepOrWidenR->eraseFromParent();
1957 }
1958 }
1959}
1960
1961/// Try to see if all of \p Blend's masks share a common value logically and'ed
1962/// and remove it from the masks.
1964 if (Blend->isNormalized())
1965 return;
1966 VPValue *CommonEdgeMask;
1967 if (!match(Blend->getMask(0),
1968 m_LogicalAnd(m_VPValue(CommonEdgeMask), m_VPValue())))
1969 return;
1970 for (unsigned I = 0; I < Blend->getNumIncomingValues(); I++)
1971 if (!match(Blend->getMask(I),
1972 m_LogicalAnd(m_Specific(CommonEdgeMask), m_VPValue())))
1973 return;
1974 for (unsigned I = 0; I < Blend->getNumIncomingValues(); I++)
1975 Blend->setMask(I, Blend->getMask(I)->getDefiningRecipe()->getOperand(1));
1976}
1977
1978/// Normalize and simplify VPBlendRecipes. Should be run after combineRecipes
1979/// to make sure the masks are simplified.
1980static void simplifyBlends(VPlan &Plan) {
1983 for (VPBlendRecipe &Blend :
1985 removeCommonBlendMask(&Blend);
1986
1987 // Try to remove redundant blend recipes.
1988 SmallPtrSet<VPValue *, 4> UniqueValues;
1989 if (Blend.isNormalized() || !match(Blend.getMask(0), m_False()))
1990 UniqueValues.insert(Blend.getIncomingValue(0));
1991 for (unsigned I = 1; I != Blend.getNumIncomingValues(); ++I)
1992 if (!match(Blend.getMask(I), m_False()))
1993 UniqueValues.insert(Blend.getIncomingValue(I));
1994
1995 if (UniqueValues.size() == 1) {
1996 Blend.replaceAllUsesWith(*UniqueValues.begin());
1997 Blend.eraseFromParent();
1998 continue;
1999 }
2000
2001 if (Blend.isNormalized())
2002 continue;
2003
2004 // Normalize the blend so its first incoming value is used as the initial
2005 // value with the others blended into it.
2006
2007 unsigned StartIndex = 0;
2008 for (unsigned I = 0; I != Blend.getNumIncomingValues(); ++I) {
2009 // If a value's mask is used only by the blend then is can be deadcoded.
2010 // TODO: Find the most expensive mask that can be deadcoded, or a mask
2011 // that's used by multiple blends where it can be removed from them all.
2012 VPValue *Mask = Blend.getMask(I);
2013 if (Mask->hasOneUse() && !match(Mask, m_False())) {
2014 StartIndex = I;
2015 break;
2016 }
2017 }
2018
2019 SmallVector<VPValue *, 4> OperandsWithMask;
2020 OperandsWithMask.push_back(Blend.getIncomingValue(StartIndex));
2021
2022 for (unsigned I = 0; I != Blend.getNumIncomingValues(); ++I) {
2023 if (I == StartIndex)
2024 continue;
2025 OperandsWithMask.push_back(Blend.getIncomingValue(I));
2026 OperandsWithMask.push_back(Blend.getMask(I));
2027 }
2028
2029 auto *NewBlend =
2030 new VPBlendRecipe(cast_or_null<PHINode>(Blend.getUnderlyingValue()),
2031 OperandsWithMask, Blend, Blend.getDebugLoc());
2032 NewBlend->insertBefore(&Blend);
2033
2034 VPValue *DeadMask = Blend.getMask(StartIndex);
2035 Blend.replaceAllUsesWith(NewBlend);
2036 Blend.eraseFromParent();
2038
2039 /// Simplify BLEND %a, %b, Not(%mask) -> BLEND %b, %a, %mask.
2040 VPValue *NewMask;
2041 if (NewBlend->getNumOperands() == 3 &&
2042 match(NewBlend->getMask(1), m_Not(m_VPValue(NewMask)))) {
2043 VPValue *Inc0 = NewBlend->getOperand(0);
2044 VPValue *Inc1 = NewBlend->getOperand(1);
2045 VPValue *OldMask = NewBlend->getOperand(2);
2046 NewBlend->setOperand(0, Inc1);
2047 NewBlend->setOperand(1, Inc0);
2048 NewBlend->setOperand(2, NewMask);
2049 if (OldMask->user_empty())
2050 cast<VPInstruction>(OldMask)->eraseFromParent();
2051 }
2052 }
2053 }
2054}
2055
2056/// Optimize the width of vector induction variables in \p Plan based on a known
2057/// constant Trip Count, \p BestVF and \p BestUF.
2059 ElementCount BestVF,
2060 unsigned BestUF) {
2061 // Only proceed if we have not completely removed the vector region.
2062 if (!Plan.getVectorLoopRegion())
2063 return false;
2064
2065 const APInt *TC;
2066 if (!BestVF.isFixed() || !match(Plan.getTripCount(), m_APInt(TC)))
2067 return false;
2068
2069 // Calculate the minimum power-of-2 bit width that can fit the known TC, VF
2070 // and UF. Returns at least 8.
2071 auto ComputeBitWidth = [](APInt TC, uint64_t Align) {
2072 APInt AlignedTC =
2075 APInt MaxVal = AlignedTC - 1;
2076 return std::max<unsigned>(PowerOf2Ceil(MaxVal.getActiveBits()), 8);
2077 };
2078 unsigned NewBitWidth =
2079 ComputeBitWidth(*TC, BestVF.getKnownMinValue() * BestUF);
2080
2081 LLVMContext &Ctx = Plan.getContext();
2082 auto *NewIVTy = IntegerType::get(Ctx, NewBitWidth);
2083
2084 bool MadeChange = false;
2085
2086 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
2087 for (VPRecipeBase &Phi : HeaderVPBB->phis()) {
2088 // Currently only handle canonical IVs as it is trivial to replace the start
2089 // and stop values, and we currently only perform the optimization when the
2090 // IV has a single use.
2092 if (!match(&Phi, m_CanonicalWidenIV(WideIV)))
2093 continue;
2094 if (WideIV->hasMoreThanOneUniqueUser() ||
2095 NewIVTy == WideIV->getScalarType())
2096 continue;
2097
2098 // Currently only handle cases where the single user is a header-mask
2099 // comparison with the backedge-taken-count, TC - 1.
2100 VPUser *SingleUser = WideIV->getSingleUser();
2101 VPValue *BTC;
2102 if (!SingleUser ||
2103 !match(
2104 SingleUser,
2105 m_ICmp(m_Specific(WideIV),
2107 BTC, m_Sub(m_Specific(Plan.getTripCount()), m_One()))))))
2108 continue;
2109
2110 // Update IV operands and comparison bound to use new narrower type.
2111 assert(!WideIV->isTruncated() &&
2112 "canonical IV is not expected to have a truncation");
2113 auto *NewWideIV = new VPWidenIntOrFpInductionRecipe(
2114 WideIV->getPHINode(), Plan.getZero(NewIVTy),
2115 Plan.getConstantInt(NewIVTy, 1), WideIV->getVFValue(),
2116 WideIV->getInductionDescriptor(), *WideIV, WideIV->getDebugLoc());
2117 NewWideIV->insertBefore(WideIV);
2118
2119 auto *NewBTC =
2120 new VPWidenCastRecipe(Instruction::Trunc, BTC, NewIVTy, nullptr,
2121 VPIRFlags::getDefaultFlags(Instruction::Trunc));
2122 Plan.getVectorPreheader()->appendRecipe(NewBTC);
2123 auto *Cmp = cast<VPInstruction>(WideIV->getSingleUser());
2124 Cmp->replaceAllUsesWith(
2125 VPBuilder(Cmp).createICmp(Cmp->getPredicate(), NewWideIV, NewBTC));
2126
2127 MadeChange = true;
2128 }
2129
2130 return MadeChange;
2131}
2132
2133/// Return true if \p Cond is known to be true for given \p BestVF and \p
2134/// BestUF.
2136 ElementCount BestVF, unsigned BestUF,
2139 return any_of(Cond->getDefiningRecipe()->operands(), [&Plan, BestVF, BestUF,
2140 &PSE](VPValue *C) {
2141 return isConditionTrueViaVFAndUF(C, Plan, BestVF, BestUF, PSE);
2142 });
2143
2144 auto *CanIV = Plan.getVectorLoopRegion()->getCanonicalIV();
2147 m_c_Add(m_Specific(CanIV), m_Specific(&Plan.getVFxUF())),
2148 m_Specific(&Plan.getVectorTripCount()))))
2149 return false;
2150
2151 // The compare checks CanIV + VFxUF == vector trip count. The vector trip
2152 // count is not conveniently available as SCEV so far, so we compare directly
2153 // against the original trip count. This is stricter than necessary, as we
2154 // will only return true if the trip count == vector trip count.
2155 const SCEV *VectorTripCount =
2157 if (isa<SCEVCouldNotCompute>(VectorTripCount))
2158 VectorTripCount = vputils::getSCEVExprForVPValue(Plan.getTripCount(), PSE);
2159 assert(!isa<SCEVCouldNotCompute>(VectorTripCount) &&
2160 "Trip count SCEV must be computable");
2161 ScalarEvolution &SE = *PSE.getSE();
2162 ElementCount NumElements = BestVF * BestUF;
2163 const SCEV *C = SE.getElementCount(VectorTripCount->getType(), NumElements);
2164 return SE.isKnownPredicate(CmpInst::ICMP_EQ, VectorTripCount, C);
2165}
2166
2167// Replaces ExtractVectorForPart instructions with ICMP when the VF is scalar
2168// and the source is a WideActiveLaneMask. The unused mask is removed later
2169// when removing dead recipes.
2171 ElementCount BestVF) {
2172 if (!BestVF.isScalar())
2173 return false;
2174
2175 bool MadeChange = false;
2176 VPBuilder Builder;
2177 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2178 VPBasicBlock *PreheaderVPBB = Plan.getVectorPreheader();
2179 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2180
2181 VPValue *Start, *TC;
2182 uint64_t Idx;
2183 for (VPBasicBlock *VPBB : {PreheaderVPBB, ExitingVPBB}) {
2184 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2187 m_VPValue()),
2188 m_ConstantInt(Idx))))
2189 continue;
2190
2191 auto *Extract = cast<VPInstruction>(&R);
2192 Builder.setInsertPoint(Extract);
2193
2194 if (Idx > 0)
2195 Start = Builder.createAdd(
2196 Start, Plan.getConstantInt(Start->getScalarType(), Idx));
2197
2198 VPValue *ICmp = Builder.createICmp(CmpInst::ICMP_ULT, Start, TC);
2199 Extract->replaceAllUsesWith(ICmp);
2200 Extract->eraseFromParent();
2201 MadeChange = true;
2202 }
2203 }
2204
2205 return MadeChange;
2206}
2207
2208/// Return true if the branch \p Term with condition \p Cond (null if \p Term
2209/// has no condition operand) is the vector loop's latch check.
2210static bool isVectorLatchCheck(VPRecipeBase *Term, VPValue *Cond, VPlan &Plan) {
2211 // BranchOnCount compares the canonical IV increment against the vector trip
2212 // count, plus an offset for epilogue loops.
2213 VPValue *Offset = nullptr;
2214 auto m_CanIVInc = m_Add(m_VPValue(), m_Specific(&Plan.getVFxUF()));
2215 if (match(Term,
2217 m_CombineOr(m_CanIVInc, m_c_Add(m_CanIVInc, m_VPValue(Offset))),
2218 m_VPValue())))
2219 return !Offset || Offset->isDefinedOutsideLoopRegions();
2220
2221 if (!Cond)
2222 return false;
2223
2224 // The active-lane-mask form used when the tail is folded by masking.
2225 return match(Cond,
2228 m_ZeroInt())));
2229}
2230
2231/// Try to simplify the branch condition of \p Plan. This may restrict the
2232/// resulting plan to \p BestVF and \p BestUF.
2234 unsigned BestUF,
2236 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2237 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2238 auto *Term = &ExitingVPBB->back();
2239
2240 // Find the branch condition, if there is one.
2241 VPValue *Cond = nullptr;
2242 if (!match(Term, m_BranchOnCond(m_VPValue(Cond))))
2244
2245 if (isVectorLatchCheck(Term, Cond, Plan)) {
2246 // Try to simplify the branch condition if VectorTC <= VF * UF when the
2247 // latch terminator is BranchOnCount or
2248 // BranchOnCond(Not(ExtractVectorForPart(WideActiveLaneMask), 0))
2249 const SCEV *VectorTripCount =
2251 if (isa<SCEVCouldNotCompute>(VectorTripCount))
2252 VectorTripCount =
2254 assert(!isa<SCEVCouldNotCompute>(VectorTripCount) &&
2255 "Trip count SCEV must be computable");
2256 ScalarEvolution &SE = *PSE.getSE();
2257 ElementCount NumElements = BestVF * BestUF;
2258 const SCEV *C = SE.getElementCount(VectorTripCount->getType(), NumElements);
2259 if (!SE.isKnownPredicate(CmpInst::ICMP_ULE, VectorTripCount, C))
2260 return false;
2261 } else if (!Cond ||
2262 !isConditionTrueViaVFAndUF(Cond, Plan, BestVF, BestUF, PSE)) {
2263 return false;
2264 }
2265
2266 // The vector loop region only executes once. Convert terminator of the
2267 // exiting block to exit in the first iteration.
2268 if (match(Term, m_BranchOnTwoConds())) {
2269 Term->setOperand(1, Plan.getTrue());
2270 return true;
2271 }
2272
2273 auto *BOC = new VPInstruction(VPInstruction::BranchOnCond, Plan.getTrue(), {},
2274 {}, Term->getDebugLoc());
2275 ExitingVPBB->appendRecipe(BOC);
2276 Term->eraseFromParent();
2277
2278 return true;
2279}
2280
2282 unsigned BestUF,
2284 assert(Plan.hasVF(BestVF) && "BestVF is not available in Plan");
2285 assert(Plan.hasUF(BestUF) && "BestUF is not available in Plan");
2286
2287 bool MadeChange =
2288 simplifyBranchConditionForVFAndUF(Plan, BestVF, BestUF, PSE);
2289 MadeChange |= replaceMaskWithCompareForScalarPlan(Plan, BestVF);
2290 MadeChange |= optimizeVectorInductionWidthForTCAndVFUF(Plan, BestVF, BestUF);
2291
2292 if (MadeChange) {
2293 Plan.setVF(BestVF);
2294 assert(Plan.getConcreteUF() == BestUF && "BestUF must match the Plan's UF");
2295 }
2296}
2297
2301 RecurKind RK = PhiR.getRecurrenceKind();
2302 if (RK != RecurKind::Add && RK != RecurKind::Mul && RK != RecurKind::Sub &&
2304 continue;
2305
2307 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(U)) {
2308 RecWithFlags->dropPoisonGeneratingFlags();
2309 }
2310 }
2311}
2312
2314 if (auto *MemR = dyn_cast<VPWidenMemoryRecipe>(R))
2315 return MemR->getAlign();
2316 return cast<LoadInst>(R->getUnderlyingInstr())->getAlign();
2317}
2318
2319namespace {
2320struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
2321 /// If recipe \p R will lower to a GEP with a non-i8 source element type,
2322 /// return that source element type.
2323 static Type *getGEPSourceElementType(const VPSingleDefRecipe *R) {
2324 // All VPInstructions that lower to GEPs must have the i8 source element
2325 // type (as they are PtrAdds), so we omit it.
2326 return TypeSwitch<const VPSingleDefRecipe *, Type *>(R)
2327 .Case([](const VPReplicateRecipe *I) -> Type * {
2328 if (auto *GEP = dyn_cast<GetElementPtrInst>(I->getUnderlyingValue()))
2329 return GEP->getSourceElementType();
2330 return nullptr;
2331 })
2332 .Case<VPVectorPointerRecipe, VPWidenGEPRecipe>(
2333 [](auto *I) { return I->getSourceElementType(); })
2334 .Default([](auto *) { return nullptr; });
2335 }
2336
2337 /// Returns true if recipe \p Def can be safely handed for CSE.
2338 static bool canHandle(const VPSingleDefRecipe *Def) {
2339 // We can extend the list of handled recipes in the future,
2340 // provided we account for the data embedded in them while checking for
2341 // equality or hashing.
2343
2344 // Allocas must not be merged, as each creates a distinct allocation.
2345 if (!C || (!C->first && C->second == Instruction::Alloca))
2346 return false;
2347
2348 // Loads are handled as cse() only reuses them within a block with no
2349 // intervening memory write. Any other memory access is rejected.
2350 if (Def->mayWriteToMemory())
2351 return false;
2352 return !Def->mayReadFromMemory() ||
2353 (!C->first && C->second == Instruction::Load);
2354 }
2355
2356 /// Hash the underlying data of \p Def.
2357 static unsigned getHashValue(const VPSingleDefRecipe *Def) {
2358 hash_code Result = hash_combine(
2359 Def->getVPRecipeID(), vputils::getOpcodeOrIntrinsicID(Def),
2360 getGEPSourceElementType(Def), Def->getScalarType(),
2362 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
2363 if (RFlags->hasPredicate())
2364 return hash_combine(Result, RFlags->getPredicate());
2365 if (auto *SIVSteps = dyn_cast<VPScalarIVStepsRecipe>(Def))
2366 return hash_combine(Result, SIVSteps->getInductionOpcode());
2367 if (auto *DIV = dyn_cast<VPDerivedIVRecipe>(Def))
2368 return hash_combine(Result, DIV->getInductionKind(), DIV->getFPBinOp());
2369 // Fold in the separately stored consecutive flag. Alignment is left out and
2370 // handled by cse.
2371 if (auto *Load = dyn_cast<VPWidenMemoryRecipe>(Def))
2372 return hash_combine(Result, Load->isConsecutive());
2373 if (auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(Def))
2374 return hash_combine(Result, ExpSCEV->getSCEV());
2375 return Result;
2376 }
2377
2378 /// Check equality of underlying data of \p L and \p R.
2379 static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
2380 if (L->getVPRecipeID() != R->getVPRecipeID() ||
2383 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2385 !equal(L->operands(), R->operands()))
2386 return false;
2389 "must have valid opcode info for both recipes");
2390 if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
2391 if (LFlags->hasPredicate() &&
2392 LFlags->getPredicate() !=
2393 cast<VPRecipeWithIRFlags>(R)->getPredicate())
2394 return false;
2395 if (auto *LSIV = dyn_cast<VPScalarIVStepsRecipe>(L))
2396 if (LSIV->getInductionOpcode() !=
2397 cast<VPScalarIVStepsRecipe>(R)->getInductionOpcode())
2398 return false;
2399 if (auto *LDIV = dyn_cast<VPDerivedIVRecipe>(L)) {
2400 auto *RDIV = cast<VPDerivedIVRecipe>(R);
2401 if (LDIV->getInductionKind() != RDIV->getInductionKind() ||
2402 LDIV->getFPBinOp() != RDIV->getFPBinOp())
2403 return false;
2404 }
2405 // Compare the separately stored consecutive flag. Alignment is left out and
2406 // handled by cse.
2407 if (auto *LL = dyn_cast<VPWidenMemoryRecipe>(L))
2408 if (LL->isConsecutive() != cast<VPWidenMemoryRecipe>(R)->isConsecutive())
2409 return false;
2410 // Whether to expand in IR is left out and handled by cse.
2411 if (auto *LExp = dyn_cast<VPExpandSCEVRecipe>(L))
2412 if (LExp->getSCEV() != cast<VPExpandSCEVRecipe>(R)->getSCEV())
2413 return false;
2414 // Phi recipes can only be equal if they are in the same VPBB, as they
2415 // implicitly depend on their predecessors.
2416 if (isa<VPWidenPHIRecipe>(L) && L->getParent() != R->getParent())
2417 return false;
2418 // Recipes in replicate regions implicitly depend on predicate. If either
2419 // recipe is in a replicate region, only consider them equal if both have
2420 // the same parent.
2421 const VPRegionBlock *RegionL = L->getRegion();
2422 const VPRegionBlock *RegionR = R->getRegion();
2423 if (((RegionL && RegionL->isReplicator()) ||
2424 (RegionR && RegionR->isReplicator())) &&
2425 L->getParent() != R->getParent())
2426 return false;
2427 return L->getScalarType() == R->getScalarType();
2428 }
2429};
2430} // end anonymous namespace
2431
2432/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
2433/// Plan.
2436 // CSE map for loads. Must be cleared on recipes that may write to memory, and
2437 // at the end of each VPBB.
2439 LoadCSEMap;
2440
2442 Plan.getEntry());
2444 for (VPRecipeBase &R : *VPBB) {
2445 if (R.mayWriteToMemory())
2446 LoadCSEMap.clear();
2447 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2448 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2449 continue;
2450 bool IsLoad = vputils::getOpcode(Def) == Instruction::Load;
2451 auto [It, Inserted] =
2452 (IsLoad ? LoadCSEMap : CSEMap).try_emplace(Def, Def);
2453 if (Inserted)
2454 continue;
2455 VPSingleDefRecipe *V = It->second;
2456 // V must dominate Def for a valid replacement.
2457 if (!VPDT.dominates(V->getParent(), VPBB))
2458 continue;
2459 if (IsLoad) {
2460 if (getLoadAlign(V) < getLoadAlign(Def)) {
2461 // Record Def as the candidate for subsequent loads, as it may be
2462 // reusable where V is not.
2463 It->second = Def;
2464 continue;
2465 }
2466 // Keep only metadata common to both loads on the survivor.
2467 cast<VPIRMetadata>(V)->intersect(*cast<VPIRMetadata>(Def));
2468 }
2469 // Only expansions in IR can replace expansions in IR.
2470 auto *DefExp = dyn_cast<VPExpandSCEVRecipe>(Def);
2471 if (DefExp && DefExp->expandInIR() &&
2472 !cast<VPExpandSCEVRecipe>(V)->expandInIR()) {
2473 It->second = Def;
2474 continue;
2475 }
2476 // Only keep flags present on both V and Def.
2477 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(V))
2478 RFlags->intersectFlags(*cast<VPRecipeWithIRFlags>(Def));
2479 // Only keep call attributes valid for both V and Def.
2480 if (auto *Call = dyn_cast<VPWidenCallRecipe>(V))
2481 Call->intersectAttrs(*cast<VPWidenCallRecipe>(Def), Plan.getContext());
2482 Def->replaceAllUsesWith(V);
2483 // Reset Plan's TC when TC expressions are CSE'd.
2484 if (Def == Plan.getTripCount())
2485 Plan.resetTripCount(V);
2486 }
2487 LoadCSEMap.clear();
2488 }
2489}
2490
2491/// Return true if we do not know how to (mechanically) hoist or sink a
2492/// non-memory or memory recipe \p R out of a loop region. When sinking, passing
2493/// \p Sinking = true ensures that assumes aren't sunk.
2495 VPBasicBlock *LastBB,
2496 bool Sinking = false) {
2497 if (!isa<VPReplicateRecipe>(R) || !R.mayReadOrWriteMemory() ||
2499 return vputils::cannotHoistOrSinkRecipe(R, Sinking);
2500
2501 // Check that the memory operation doesn't alias between FirstBB and LastBB.
2502 auto MemLoc = vputils::getMemoryLocation(R);
2503
2504 // TODO: Could make use of SinkStoreInfo::isNoAliasViaDistance by collecting
2505 // stores upfront, and constructing a full SinkStoreInfo.
2506 auto SinkInfo =
2507 Sinking ? std::make_optional(SinkStoreInfo(cast<VPReplicateRecipe>(R)))
2508 : std::nullopt;
2509
2510 return !MemLoc ||
2511 !canHoistOrSinkWithNoAliasCheck(*MemLoc, FirstBB, LastBB, SinkInfo);
2512}
2513
2514/// Move loop-invariant recipes out of the vector loop region in \p Plan.
2515static void licm(VPlan &Plan, const VPDominatorTree &VPDT) {
2516 VPBasicBlock *Preheader = Plan.getVectorPreheader();
2517
2518 // Hoist any loop invariant recipes from the vector loop region to the
2519 // preheader. Perform a shallow traversal of the vector loop region, to
2520 // exclude recipes in replicate regions. Only hoist from blocks dominating the
2521 // exiting block, which are guaranteed to execute if the vector pre-header is,
2522 // so we don't need to check speculation safety.
2523 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
2524 assert(Preheader->getSingleSuccessor() == LoopRegion &&
2525 "Expected vector prehader's successor to be the vector loop region");
2526 VPBasicBlock *ExitingVPBB = LoopRegion->getExitingBasicBlock();
2528 vp_depth_first_shallow(LoopRegion->getEntry()))) {
2529 if (!VPDT.dominates(VPBB, ExitingVPBB))
2530 continue;
2531 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2532 if (any_of(R.operands(), [](VPValue *Op) {
2533 return !Op->isDefinedOutsideLoopRegions();
2534 }))
2535 continue;
2536 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2537 LoopRegion->getExitingBasicBlock()))
2538 continue;
2539 R.moveBefore(Preheader->end());
2540 }
2541 }
2542
2543 // Sink recipes with no users inside the vector loop region if all users are
2544 // in the same exit block of the region.
2545 // TODO: Extend to sink recipes from inner loops.
2547 LoopRegion->getEntry());
2549 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
2550 // TODO: Use R.definedValues() instead of casting to VPSingleDefRecipe to
2551 // support recipes with multiple defined values (e.g., interleaved loads).
2552 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2553 if (!Def)
2554 continue;
2555
2556 if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
2557 assert(!RepR->isPredicated() &&
2558 "Expected prior transformation of predicated replicates to "
2559 "replicate regions");
2560 // narrowToSingleScalarRecipes should have already maximally narrowed
2561 // replicates to single-scalar replicates.
2562 // TODO: When unrolling, replicateByVF doesn't handle sunk
2563 // non-single-scalar replicates correctly.
2564 if (!RepR->isSingleScalar())
2565 continue;
2566
2567 // The pointer operand of stores must be loop-invariant.
2568 if (RepR->getOpcode() == Instruction::Store &&
2569 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2570 continue;
2571 }
2572
2573 // Cannot sink the recipe if the user is defined in a loop region or a
2574 // non-successor of the vector loop region. Cannot sink if user is a phi
2575 // either.
2576 VPBasicBlock *SinkBB = nullptr;
2577 if (any_of(Def->users(), [&SinkBB, &LoopRegion](VPUser *U) {
2578 auto *UserR = cast<VPRecipeBase>(U);
2579 VPBasicBlock *Parent = UserR->getParent();
2580 // TODO: Support sinking when users are in multiple blocks.
2581 if (SinkBB && SinkBB != Parent)
2582 return true;
2583 SinkBB = Parent;
2584 // TODO: If the user is a PHI node, we should check the block of
2585 // incoming value. Support PHI node users if needed.
2586 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2587 Parent->getSinglePredecessor() != LoopRegion;
2588 }))
2589 continue;
2590
2591 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2592 LoopRegion->getExitingBasicBlock(),
2593 /*Sinking=*/true))
2594 continue;
2595
2596 [[maybe_unused]] auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
2597 assert((!R.mayWriteToMemory() ||
2598 (RepR && RepR->getOpcode() == Instruction::Store &&
2599 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2600 "The only recipes that may write to memory are expected to be "
2601 "stores with invariant pointer-operand");
2602
2603 if (!SinkBB)
2604 SinkBB = cast<VPBasicBlock>(LoopRegion->getSingleSuccessor());
2605
2606 // TODO: This will need to be a check instead of a assert after
2607 // conditional branches in vectorized loops are supported.
2608 assert(VPDT.properlyDominates(VPBB, SinkBB) &&
2609 "Defining block must dominate sink block");
2610 // TODO: Clone the recipe if users are on multiple exit paths, instead of
2611 // just moving.
2612 Def->moveBefore(SinkBB->getFirstNonPhi());
2613 }
2614 }
2615}
2616
2618 VPlan &Plan, const MapVector<Instruction *, uint64_t> &MinBWs) {
2619 if (Plan.hasScalarVFOnly())
2620 return;
2621 // Keep track of created truncates, so they can be re-used. Note that we
2622 // cannot use RAUW after creating a new truncate, as this would could make
2623 // other uses have different types for their operands, making them invalidly
2624 // typed.
2626 VPBasicBlock *PH = Plan.getVectorPreheader();
2629 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2632 continue;
2633
2634 VPValue *ResultVPV = R.getVPSingleValue();
2635 auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
2636 unsigned NewResSizeInBits = MinBWs.lookup(UI);
2637 if (!NewResSizeInBits)
2638 continue;
2639
2640 // If the value wasn't vectorized, we must maintain the original scalar
2641 // type. Skip those here, after incrementing NumProcessedRecipes. Also
2642 // skip casts which do not need to be handled explicitly here, as
2643 // redundant casts will be removed during recipe simplification.
2645 continue;
2646
2647 Type *OldResTy = ResultVPV->getScalarType();
2648 unsigned OldResSizeInBits = OldResTy->getScalarSizeInBits();
2649 assert(OldResTy->isIntegerTy() && "only integer types supported");
2650 (void)OldResSizeInBits;
2651
2652 auto *NewResTy = IntegerType::get(Plan.getContext(), NewResSizeInBits);
2653
2654 // Any wrapping introduced by shrinking this operation shouldn't be
2655 // considered undefined behavior. So, we can't unconditionally copy
2656 // arithmetic wrapping flags to VPW.
2657 if (auto *VPW = dyn_cast<VPRecipeWithIRFlags>(&R))
2658 VPW->dropPoisonGeneratingFlags();
2659
2660 assert((OldResSizeInBits != NewResSizeInBits ||
2661 match(&R, m_ICmp(m_VPValue(), m_VPValue()))) &&
2662 "Only ICmps should not need extending the result.");
2663 assert(!isa<VPWidenStoreRecipe>(&R) && "stores cannot be narrowed");
2664
2665 // Loads/intrinsics are not recreated; they keep producing their original
2666 // wide result and narrowed users will truncate it as needed below.
2668 continue;
2669
2670 // Shrink operands by introducing truncates as needed.
2671 unsigned StartIdx =
2672 match(&R, m_Select(m_VPValue(), m_VPValue(), m_VPValue())) ? 1 : 0;
2673 SmallVector<VPValue *> NewOperands(R.operands());
2674 for (VPValue *&Op : drop_begin(NewOperands, StartIdx)) {
2675 unsigned OpSizeInBits = Op->getScalarType()->getScalarSizeInBits();
2676 if (OpSizeInBits == NewResSizeInBits)
2677 continue;
2678 assert(OpSizeInBits > NewResSizeInBits && "nothing to truncate");
2679 auto [ProcessedIter, Inserted] = ProcessedTruncs.try_emplace(Op);
2680 if (Inserted) {
2681 VPBuilder Builder;
2682 if (isa<VPIRValue>(Op))
2683 Builder.setInsertPoint(PH);
2684 else
2685 Builder.setInsertPoint(&R);
2686 ProcessedIter->second =
2687 Builder.createWidenCast(Instruction::Trunc, Op, NewResTy);
2688 }
2689 Op = ProcessedIter->second;
2690 }
2691
2692 auto *NWR = cast<VPWidenRecipe>(&R)->cloneWithOperands(NewOperands);
2693 NWR->insertBefore(&R);
2694
2695 // Wrap NWR in a ZExt to preserve the original wide type for downstream
2696 // users. Not needed for ICmps, whose result type is i1 irrespective of
2697 // the narrowing of their operands.
2698 VPValue *Replacement = NWR->getVPSingleValue();
2699 if (Replacement->getScalarType() != OldResTy)
2700 Replacement =
2702 .createWidenCast(Instruction::ZExt, Replacement, OldResTy)
2703 ->getVPSingleValue();
2704 ResultVPV->replaceAllUsesWith(Replacement);
2705 R.eraseFromParent();
2706 }
2707 }
2708}
2709
2710bool VPlanTransforms::removeBranchOnConst(VPlan &Plan, bool OnlyLatches) {
2711 std::optional<VPDominatorTree> VPDT;
2712 if (OnlyLatches)
2713 VPDT.emplace(Plan);
2714
2715 // Collect all blocks before modifying the CFG so we can identify unreachable
2716 // ones after constant branch removal.
2718
2719 bool SimplifiedPhi = false;
2720 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(AllBlocks)) {
2721 VPValue *Cond;
2722 // Skip blocks that are not terminated by BranchOnCond.
2723 if (VPBB->empty() || !match(&VPBB->back(), m_BranchOnCond(m_VPValue(Cond))))
2724 continue;
2725
2726 if (OnlyLatches && !VPBlockUtils::isLatch(VPBB, *VPDT))
2727 continue;
2728
2729 assert(VPBB->getNumSuccessors() == 2 &&
2730 "Two successors expected for BranchOnCond");
2731 unsigned RemovedIdx;
2732 if (match(Cond, m_True()))
2733 RemovedIdx = 1;
2734 else if (match(Cond, m_False()))
2735 RemovedIdx = 0;
2736 else
2737 continue;
2738
2739 VPBasicBlock *RemovedSucc =
2740 cast<VPBasicBlock>(VPBB->getSuccessors()[RemovedIdx]);
2741 assert(count(RemovedSucc->getPredecessors(), VPBB) == 1 &&
2742 "There must be a single edge between VPBB and its successor");
2743 // Values coming from VPBB into phi recipes of RemovedSucc are removed from
2744 // these recipes and single-entry header phis are removed.
2745 for (VPRecipeBase &R : make_early_inc_range(RemovedSucc->phis())) {
2746 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(VPBB);
2747 SimplifiedPhi = true;
2748 // Remove now invalid header phis that are left single-entry after
2749 // removing their backedges.
2750 auto *PhiR = dyn_cast<VPHeaderPHIRecipe>(&R);
2751 if (!PhiR || PhiR->getNumIncoming() != 1)
2752 continue;
2753 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
2754 PhiR->eraseFromParent();
2755 }
2756
2757 // Disconnect blocks and remove the terminator.
2758 VPBlockUtils::disconnectBlocks(VPBB, RemovedSucc);
2759 VPBB->back().eraseFromParent();
2760 }
2761
2762 // Compute which blocks are still reachable from the entry after constant
2763 // branch removal.
2766
2767 // Detach all unreachable blocks from their successors, removing their recipes
2768 // and incoming values from phi recipes.
2769 VPSymbolicValue Tmp(nullptr);
2770 for (VPBlockBase *B : AllBlocks) {
2771 if (Reachable.contains(B))
2772 continue;
2773 for (VPBlockBase *Succ : to_vector(B->successors())) {
2774 if (auto *SuccBB = dyn_cast<VPBasicBlock>(Succ))
2775 for (VPRecipeBase &R : SuccBB->phis())
2776 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(B);
2778 }
2779 for (VPBasicBlock *DeadBB :
2781 for (VPRecipeBase &R : make_early_inc_range(*DeadBB)) {
2782 for (VPValue *Def : R.definedValues())
2783 Def->replaceAllUsesWith(&Tmp);
2784 R.eraseFromParent();
2785 }
2786 }
2787 }
2788 return SimplifiedPhi;
2789}
2790
2813
2816 auto GetSimplifiedLiveInViaSCEV = [&](VPValue *VPV) -> VPValue * {
2817 const SCEV *Expr = vputils::getSCEVExprForVPValue(VPV, PSE);
2818 const APInt *C;
2819 if (match(Expr, m_scev_APInt(C)))
2820 return Plan.getConstantInt(*C);
2821 return nullptr;
2822 };
2823
2824 for (VPValue *LiveIn : to_vector(Plan.getLiveIns())) {
2825 if (VPValue *SimplifiedLiveIn = GetSimplifiedLiveInViaSCEV(LiveIn))
2826 LiveIn->replaceAllUsesWith(SimplifiedLiveIn);
2827 }
2828}
2829
2831 VPlan &Plan, PredicatedScalarEvolution &PSE,
2832 const SymbolicStrideMap &StridesMap, const VPDominatorTree &VPDT) {
2833 // Replace VPValues for known constant strides guaranteed by predicated scalar
2834 // evolution that are guaranteed to be guarded by the runtime checks; that is,
2835 // blocks dominated by the vector header.
2836 assert(!Plan.getVectorLoopRegion() &&
2837 "expected to run before loop regions are created");
2838 const auto &[Header, _] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
2839 auto CanUseVersionedStride = [&VPDT, Header = Header, &Plan](VPUser *U) {
2840 auto *R = cast<VPRecipeBase>(U);
2841 // Skip phis if the loop if loop is not yet guarded.
2842 if (isa<VPPhiAccessors>(R) &&
2843 Header == Plan.getEntry()->getSingleSuccessor())
2844 return false;
2845 return VPDT.dominates(Header, R->getParent());
2846 };
2847 ValueToSCEVMapTy RewriteMap;
2848 for (const SCEVUnknown *Stride : StridesMap.values()) {
2849 Value *StrideV = Stride->getValue();
2850 const APInt *StrideConst;
2851 const SCEV *StrideExpr = PSE.getSCEV(StrideV);
2852 if (!match(StrideExpr, m_scev_APInt(StrideConst)))
2853 // Only handle constant strides for now.
2854 continue;
2855 if (VPValue *StrideVPV = Plan.getLiveIn(StrideV))
2856 StrideVPV->replaceUsesWithIf(Plan.getConstantInt(*StrideConst),
2857 CanUseVersionedStride);
2858
2859 // The versioned value may not be used in the loop directly but through an
2860 // integral cast (sext/zext/trunc). Add new live-ins in those cases.
2861 for (Value *U : StrideV->users()) {
2863 continue;
2864 VPValue *StrideVPV = Plan.getLiveIn(U);
2865 if (!StrideVPV)
2866 continue;
2867 unsigned BW = U->getType()->getScalarSizeInBits();
2868 APInt C = isa<SExtInst>(U) ? StrideConst->sext(BW)
2869 : StrideConst->zextOrTrunc(BW);
2870 StrideVPV->replaceUsesWithIf(Plan.getConstantInt(C),
2871 CanUseVersionedStride);
2872 }
2873 RewriteMap[StrideV] = StrideExpr;
2874 }
2875
2876 ScalarEvolution &SE = *PSE.getSE();
2877 for (VPExpandSCEVRecipe &ExpSCEV :
2879 const SCEV *ScevExpr = ExpSCEV.getSCEV();
2880 const SCEV *NewSCEV =
2881 SCEVParameterRewriter::rewrite(ScevExpr, SE, RewriteMap);
2882 if (NewSCEV == ScevExpr || !SE.isGuaranteedNotToCauseUB(NewSCEV))
2883 continue;
2884 VPValue *NewExp = vputils::getOrCreateVPValueForSCEVExpr(Plan, NewSCEV);
2885 ExpSCEV.replaceAllUsesWith(NewExp);
2886 if (Plan.getTripCount() == &ExpSCEV)
2887 Plan.resetTripCount(NewExp);
2888 }
2889}
2890
2892 // Collect recipes in the backward slice of `Root` that may generate a poison
2893 // value that is used after vectorization.
2895 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](VPRecipeBase *Root) {
2897 Worklist.push_back(Root);
2898
2899 // Traverse the backward slice of Root through its use-def chain.
2900 while (!Worklist.empty()) {
2901 VPRecipeBase *CurRec = Worklist.pop_back_val();
2902
2903 if (!Visited.insert(CurRec).second)
2904 continue;
2905
2906 // Prune search if we find another recipe generating a widen memory
2907 // instruction. Widen memory instructions involved in address computation
2908 // will lead to gather/scatter instructions, which don't need to be
2909 // handled.
2911 VPHeaderPHIRecipe>(CurRec))
2912 continue;
2913
2914 // This recipe contributes to the address computation of a widen
2915 // load/store. If the underlying instruction has poison-generating flags,
2916 // drop them directly.
2917 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(CurRec)) {
2918 VPValue *A, *B;
2919 // Dropping disjoint from an OR may yield incorrect results, as some
2920 // analysis may have converted it to an Add implicitly (e.g. SCEV used
2921 // for dependence analysis). Instead, replace it with an equivalent Add.
2922 // This is possible as all users of the disjoint OR only access lanes
2923 // where the operands are disjoint or poison otherwise.
2924 if (match(RecWithFlags, m_BinaryOr(m_VPValue(A), m_VPValue(B))) &&
2925 RecWithFlags->isDisjoint()) {
2926 VPBuilder Builder(RecWithFlags);
2927 VPInstruction *New =
2928 Builder.createAdd(A, B, RecWithFlags->getDebugLoc());
2929 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
2930 RecWithFlags->replaceAllUsesWith(New);
2931 RecWithFlags->eraseFromParent();
2932 CurRec = New;
2933 } else
2934 RecWithFlags->dropPoisonGeneratingFlags();
2935 } else {
2938 (void)Instr;
2939 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
2940 "found instruction with poison generating flags not covered by "
2941 "VPRecipeWithIRFlags");
2942 }
2943
2944 // Add new definitions to the worklist.
2945 for (VPValue *Operand : CurRec->operands())
2946 if (VPRecipeBase *OpDef = Operand->getDefiningRecipe())
2947 Worklist.push_back(OpDef);
2948 }
2949 });
2950
2951 // We want to exclude the tail folding case, as we don't need to drop flags
2952 // for operations computing the first lane in this case: the first lane of the
2953 // header mask must always be true. For reverse memory accesses, the mask is
2954 // wrapped in a Reverse, which is just a permutation of the header mask, so
2955 // peel it off before checking. The header mask is still the abstract region
2956 // value at this point (materialization happens later).
2957 auto m_UnlessHdrMask = m_Unless( // NOLINT
2959
2960 // Traverse all the recipes in the VPlan and collect the poison-generating
2961 // recipes in the backward slice starting at the address of a VPWidenRecipe or
2962 // VPInterleaveRecipe.
2963 auto Iter =
2966 for (VPRecipeBase &Recipe : *VPBB) {
2967 if (auto *WidenRec = dyn_cast<VPWidenMemoryRecipe>(&Recipe)) {
2968 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
2969 if (AddrDef && WidenRec->isConsecutive() && WidenRec->getMask() &&
2970 match(WidenRec->getMask(), m_UnlessHdrMask))
2971 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2972 } else if (auto *InterleaveRec = dyn_cast<VPInterleaveRecipe>(&Recipe)) {
2973 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
2974 if (AddrDef && InterleaveRec->getMask() &&
2975 match(InterleaveRec->getMask(), m_UnlessHdrMask))
2976 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2977 }
2978 }
2979 }
2980}
2981
2983 VPlan &Plan,
2985 &InterleaveGroups,
2986 const bool &EpilogueAllowed) {
2987 if (InterleaveGroups.empty())
2988 return;
2989
2991 for (VPBasicBlock *VPBB :
2994 for (VPRecipeBase &R : make_filter_range(*VPBB, [](VPRecipeBase &R) {
2995 return isa<VPWidenMemoryRecipe>(&R);
2996 })) {
2997 auto *MemR = cast<VPWidenMemoryRecipe>(&R);
2998 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
2999 }
3000
3001 // Interleave memory: for each Interleave Group we marked earlier as relevant
3002 // for this VPlan, replace the Recipes widening its memory instructions with a
3003 // single VPInterleaveRecipe at its insertion point.
3004 VPDominatorTree VPDT(Plan);
3005 for (const auto *IG : InterleaveGroups) {
3006 VPWidenMemoryRecipe *Start = nullptr;
3007 Instruction *StartMember = nullptr;
3008 for (auto *Member : IG->members())
3009 if (VPWidenMemoryRecipe *R = IRMemberToRecipe.lookup(Member)) {
3010 StartMember = Member;
3011 Start = R;
3012 break;
3013 }
3014 if (!StartMember) // All member recipes are dead, so the group is dead.
3015 continue;
3016 VPIRMetadata InterleaveMD(*Start);
3017 SmallVector<VPValue *, 4> StoredValues;
3018 for (unsigned I = 0; I < IG->getFactor(); ++I) {
3019 Instruction *MemberI = IG->getMember(I);
3020 if (!MemberI)
3021 continue;
3022 if (VPWidenMemoryRecipe *MemoryR = IRMemberToRecipe.lookup(MemberI)) {
3023 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(MemoryR->getAsRecipe()))
3024 StoredValues.push_back(StoreR->getStoredValue());
3025 InterleaveMD.intersect(*MemoryR);
3026 } else {
3027 InterleaveMD.intersect(VPIRMetadata(*MemberI));
3028 }
3029 }
3030
3031 bool NeedsMaskForGaps =
3032 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
3033 (!StoredValues.empty() && !IG->isFull());
3034
3035 Instruction *IRInsertPos = IG->getInsertPos();
3036 auto *InsertPos = IRMemberToRecipe.lookup(IRInsertPos);
3037 if (!InsertPos) {
3038 // InsertPos member is dead: find a new member that is alive.
3039 assert(isa<VPWidenLoadRecipe>(Start->getAsRecipe()) &&
3040 "Dead member in non-load group?");
3041 InsertPos = Start;
3042 for (Instruction *Member : IG->members())
3043 if (VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member))
3044 if (VPDT.properlyDominates(MemberR->getAsRecipe(),
3045 InsertPos->getAsRecipe()))
3046 InsertPos = MemberR;
3047 IRInsertPos = &InsertPos->getIngredient();
3048 }
3049 VPRecipeBase *InsertPosR = InsertPos->getAsRecipe();
3050
3052 if (auto *Gep = dyn_cast<GetElementPtrInst>(
3053 getLoadStorePointerOperand(IRInsertPos)->stripPointerCasts()))
3054 NW = Gep->getNoWrapFlags().withoutNoUnsignedWrap();
3055
3056 // Get or create the start address for the interleave group.
3057 VPValue *Addr = Start->getAddr();
3058 VPRecipeBase *AddrDef = Addr->getDefiningRecipe();
3059 if (IG->getIndex(StartMember) != 0 ||
3060 (AddrDef && !VPDT.properlyDominates(AddrDef, InsertPosR))) {
3061 // Either member zero's recipe is dead, or we cannot re-use the address of
3062 // member zero because it does not dominate the insert position. Instead,
3063 // use the address of the insert position and create a PtrAdd adjusting it
3064 // to the address of member zero.
3065 // TODO: Hoist Addr's defining recipe (and any operands as needed) to
3066 // InsertPos or sink loads above zero members to join it.
3067 assert(IG->getIndex(IRInsertPos) != 0 &&
3068 "index of insert position shouldn't be zero");
3069 auto &DL = IRInsertPos->getDataLayout();
3070 APInt Offset(32,
3071 DL.getTypeAllocSize(getLoadStoreType(IRInsertPos)) *
3072 IG->getIndex(IRInsertPos),
3073 /*IsSigned=*/true);
3074 VPValue *OffsetVPV = Plan.getConstantInt(-Offset);
3075 VPBuilder B(InsertPosR);
3076 Addr = B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
3077 }
3078 // If the group is reverse, adjust the index to refer to the last vector
3079 // lane instead of the first. We adjust the index from the first vector
3080 // lane, rather than directly getting the pointer for lane VF - 1, because
3081 // the pointer operand of the interleaved access is supposed to be uniform.
3082 if (IG->isReverse()) {
3083 auto *ReversePtr = new VPVectorEndPointerRecipe(
3084 Addr, &Plan.getVF(), getLoadStoreType(IRInsertPos),
3085 -(int64_t)IG->getFactor(), NW, InsertPosR->getDebugLoc());
3086 ReversePtr->insertBefore(InsertPosR);
3087 Addr = ReversePtr;
3088 }
3089 auto *VPIG = new VPInterleaveRecipe(
3090 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
3091 InterleaveMD, InsertPosR->getDebugLoc());
3092 VPIG->insertBefore(InsertPosR);
3093
3094 unsigned J = 0;
3095 for (unsigned i = 0; i < IG->getFactor(); ++i)
3096 if (Instruction *Member = IG->getMember(i)) {
3097 VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member);
3098 if (!Member->getType()->isVoidTy()) {
3099 if (MemberR) {
3100 VPValue *OriginalV = MemberR->getAsRecipe()->getVPSingleValue();
3101 OriginalV->replaceAllUsesWith(VPIG->getVPValue(J));
3102 }
3103 J++;
3104 }
3105 if (MemberR)
3106 MemberR->getAsRecipe()->eraseFromParent();
3107 }
3108 }
3109}
3110
3111/// Matches an exit condition formed by comparing a value loaded from memory
3112/// with a loop-invariant term. Binds the comparison for the condition.
3118
3119namespace {
3120struct CountableConditionMatch {
3121 VPValue *&Cmp;
3122 PredicatedScalarEvolution &PSE;
3123 Loop *L;
3124
3125 CountableConditionMatch(VPValue *&Cmp, PredicatedScalarEvolution &PSE,
3126 Loop *L)
3127 : Cmp(Cmp), PSE(PSE), L(L) {}
3128
3129 template <typename ITy> bool match(ITy *V) const {
3130 VPValue *Update;
3132 V, m_VPValue(Cmp, m_c_ICmp(m_VPValue(Update, m_Add(m_VPValue(),
3133 m_VPValue())),
3134 m_LiveIn()))))
3135 return false;
3136
3137 const SCEV *S = vputils::getSCEVExprForVPValue(Update, PSE, L);
3140 }
3141};
3142} // end anonymous namespace
3143
3144/// Matches an exit condition formed by comparing the current value of a
3145/// affine add recurrence in the given loop with a stride of 1 against a
3146/// loop-invariant term. Binds the comparison for the condition.
3148 Loop *L) {
3149 return CountableConditionMatch(Cmp, PSE, L);
3150}
3151
3154 Loop *L) {
3155 // Check for a single combined exit in the latch block.
3156 // TODO: Generalize to other blocks besides the latch.
3157 // If we don't find a combined condition in the latch, just return true
3158 // to proceed with vectorization.
3159 auto [_, LatchVPBB] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
3160
3161 // We're looking for a conditional branch...
3162 auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
3163 if (!Term || Term->getOpcode() != VPInstruction::BranchOnCond)
3164 return true;
3165
3166 // ...where the condition is a combination of both a countable and an
3167 // uncountable comparison.
3168 VPValue *Uncountable = nullptr;
3169 VPValue *Countable = nullptr;
3170 VPValue *Cond = Term->getOperand(0);
3172 m_Countable(Countable, PSE, L)),
3173 m_c_BinaryOr(m_Uncountable(Uncountable),
3174 m_Countable(Countable, PSE, L)))))
3175 return true;
3176
3177 // If the conditions are combined with a logical or (select), then we'll
3178 // need to freeze the individual terms when splitting.
3179 bool NeedsFreeze = match(Cond, m_LogicalOr(m_VPValue(), m_VPValue()));
3180
3181 // If we do have a combined exit condition, bail out if there's more than
3182 // one exit block.
3183 // TODO: Support additional exits.
3184 ArrayRef<VPIRBasicBlock *> ExitBlocks = Plan.getExitBlocks();
3185 if (ExitBlocks.size() != 1)
3186 return false;
3187
3188 // If there are any live-outs, bail out. The exit block is an existing IR
3189 // block, and if we split the exiting block then the incoming blocks and
3190 // values won't be correct.
3191 // TODO: Support live-outs with combined exits.
3192 if (!ExitBlocks.front()->phis().empty())
3193 return false;
3194
3195 // Split the latch block just before the terminator.
3196 VPBasicBlock *NewLatch = LatchVPBB->splitAt(Term->getIterator());
3197
3198 // Create new terminator for uncountable condition.
3199 VPBuilder EEBuilder(LatchVPBB);
3200 if (NeedsFreeze)
3201 Uncountable = EEBuilder.createFreeze(Uncountable);
3202 EEBuilder.createNaryOp(VPInstruction::BranchOnCond, {Uncountable});
3203
3204 // We need to connect the uncountable exit to the sole exit block. The
3205 // latch is expected to connect to the middle block instead.
3206 // In canonical form, the backedge is the last successor for the latch. So
3207 // the first successor (true path) should be the exit for both conditions.
3208 LatchVPBB->clearSuccessors();
3209 NewLatch->clearPredecessors();
3210 VPBlockUtils::connectBlocks(LatchVPBB, ExitBlocks.front());
3211 VPBlockUtils::connectBlocks(LatchVPBB, NewLatch);
3212
3213 // Set condition for latch block to countable condition.
3214 if (NeedsFreeze) {
3215 VPBuilder NewLatchBuilder(Term);
3216 Countable = NewLatchBuilder.createFreeze(Countable);
3217 }
3218 Term->setOperand(0, Countable);
3219
3220 return true;
3221}
3222
3223/// Returns the VPValue representing the uncountable exit comparison used by
3224/// AnyOf if the recipes it depends on can be traced back to live-ins and
3225/// the addresses (in GEP/PtrAdd form) of any (non-masked) load used in
3226/// generating the values for the comparison. The recipes are stored in
3227/// \p Recipes.
3228static VPValue *
3230 VPBasicBlock *LatchVPBB) {
3231 // Given a plain CFG VPlan loop with countable latch exiting block
3232 // \p LatchVPBB, we're looking to match the recipes contributing to the
3233 // uncountable exit condition comparison (here, vp<%4>) back to either
3234 // live-ins or the address nodes for the load used as part of the uncountable
3235 // exit comparison so that we can either move them within the loop, or copy
3236 // them to the preheader depending on the chosen method for dealing with
3237 // stores in uncountable exit loops.
3238 //
3239 // Currently, the address of the load is restricted to a GEP with 2 operands
3240 // and a live-in base address. This constraint may be relaxed later.
3241 //
3242 // VPlan ' for UF>=1' {
3243 // Live-in vp<%0> = VF * UF
3244 // Live-in vp<%1> = vector-trip-count
3245 // Live-in ir<20> = original trip-count
3246 //
3247 // ir-bb<entry>:
3248 // Successor(s): scalar.ph, vector.ph
3249 //
3250 // vector.ph:
3251 // Successor(s): for.body
3252 //
3253 // for.body:
3254 // EMIT vp<%2> = phi ir<0>, vp<%index.next>
3255 // EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, for.inc ]
3256 // EMIT ir<%uncountable.addr> = getelementptr inbounds nuw ir<%pred>,ir<%iv>
3257 // EMIT ir<%uncountable.val> = load ir<%uncountable.addr>
3258 // EMIT ir<%uncountable.cond> = icmp sgt ir<%uncountable.val>, ir<500>
3259 // EMIT vp<%3> = masked-cond ir<%uncountable.cond>
3260 // Successor(s): for.inc
3261 //
3262 // for.inc:
3263 // EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1>
3264 // EMIT ir<%countable.cond> = icmp eq ir<%iv.next>, ir<20>
3265 // EMIT vp<%index.next> = add nuw vp<%2>, vp<%0>
3266 // EMIT vp<%freeze> = freeze ir<%3>
3267 // EMIT vp<%4> = any-of ir<%freeze>
3268 // EMIT vp<%5> = icmp eq vp<%index.next>, vp<%1>
3269 // EMIT branch-on-two-conds vp<%4>, vp<%5>
3270 // Successor(s): middle.block, middle.block, for.body
3271 //
3272 // middle.block:
3273 // Successor(s): ir-bb<exit>, scalar.ph
3274 //
3275 // ir-bb<exit>:
3276 // No successors
3277 //
3278 // scalar.ph:
3279 // }
3280
3281 // Find the uncountable loop exit condition.
3282 VPValue *UncountableCondition = nullptr;
3283 if (!match(LatchVPBB->getTerminator(),
3284 m_BranchOnTwoConds(m_AnyOf(m_VPValue(UncountableCondition)),
3285 m_VPValue())))
3286 return nullptr;
3287
3289 Worklist.push_back(UncountableCondition);
3290 while (!Worklist.empty()) {
3291 VPValue *V = Worklist.pop_back_val();
3292
3293 // Any value defined outside the loop does not need to be copied.
3294 if (V->isDefinedOutsideLoopRegions())
3295 continue;
3296
3297 VPValue *Op1, *Op2;
3298 // Walk back through recipes until we find at least one load from memory.
3299 if (match(V, m_Cmp(m_VPValue(Op1), m_VPValue(Op2)))) {
3300 Worklist.push_back(Op1);
3301 Worklist.push_back(Op2);
3302 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3303 } else if (match(V, m_VPInstruction<Instruction::Load>(m_VPValue(Op1)))) {
3304 VPRecipeBase *GepR = Op1->getDefiningRecipe();
3305 // Only matching base + single offset term for now.
3306 if (GepR->getNumOperands() != 2)
3307 return nullptr;
3308 // Matching a GEP with a loop-invariant base ptr.
3310 m_LiveIn(), m_VPValue())))
3311 return nullptr;
3312 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3313 Recipes.push_back(cast<VPInstruction>(GepR));
3314 } else if (match(V, m_Freeze(m_VPValue(Op1)))) {
3315 Worklist.push_back(Op1);
3316 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3318 m_VPValue(Op1)))) {
3319 Worklist.push_back(Op1);
3320 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3321 } else
3322 return nullptr;
3323 }
3324
3325 // If we couldn't match anything, don't return the condition. It may be
3326 // defined outside the loop.
3327 if (Recipes.empty() ||
3329 return nullptr;
3330
3331 return UncountableCondition;
3332}
3333
3339
3340/// Update \p Plan to mask memory operations in the loop based on whether the
3341/// early exit is taken or not.
3342///
3343/// We're currently expecting to find a loop with properties similar to the
3344/// following:
3345///
3346/// for.body:
3347/// ir<%indvars.iv> = WIDEN-INDUCTION nuw nsw ir<0>, ir<1>, vp<%0>
3348/// EMIT ir<%arrayidx> = getelementptr inbounds nuw ir<@c>, ir<%indvars.iv>
3349/// EMIT-SCALAR ir<%0> = load ir<%arrayidx>
3350/// EMIT ir<%cmp1> = icmp sgt ir<%0>, ir<5>
3351/// EMIT vp<%1> = masked-cond ir<%cmp1>
3352/// Successor(s): if.end
3353///
3354/// if.end:
3355/// EMIT ir<%arrayidx3> = getelementptr inbounds nuw ir<@src>, ir<%indvars.iv>
3356/// EMIT-SCALAR ir<%2> = load ir<%arrayidx3>
3357/// EMIT ir<%add> = add nsw ir<%2>, ir<42>
3358/// EMIT ir<%arrayidx5> = getelementptr inbounds nuw ir<@dst>, ir<%indvars.iv>
3359/// EMIT store ir<%add>, ir<%arrayidx5>
3360/// EMIT ir<%indvars.iv.next> = add nuw nsw ir<%indvars.iv>, ir<1>
3361/// EMIT vp<%freeze> = freeze ir<%1>
3362/// EMIT vp<%3> = any-of ir<%freeze>
3363/// EMIT ir<%exitcond.not> = icmp eq ir<%indvars.iv.next>, ir<10000>
3364/// EMIT branch-on-two-conds vp<%3>, ir<%exitcond.not>
3365/// Successor(s): middle.block, middle.block, for.body
3366///
3367/// We currently expect LoopVectorizationLegality to ensure that:
3368/// * There must also be a counted exit. We will need to support speculative
3369/// or first-faulting loads before we can remove this restriction.
3370/// * Any stores within the loop must not alias with the load used for the
3371/// uncountable exit. We can relax this a bit with runtime aliasing checks.
3372/// * Other memory operations in the loop can take place before or after the
3373/// uncountable exit, but must also be unconditional. We need to support
3374/// combining the conditions in VPlanPredicator.
3375/// * The loop must have a single unconditional load contributing to the
3376/// uncountable exit comparison, and the other term must be loop-invariant.
3377/// Improving upon this requires work in getRecipesForUncountableExit to
3378/// handle more complex recipe graphs.
3381 VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB,
3382 OptimizationRemarkEmitter *ORE, Loop *TheLoop,
3384
3385 // Disconnect early exiting blocks from successors, remove branches.
3386 for (auto &Exit : Exits) {
3387 if (Exit.EarlyExitingVPBB == LatchVPBB)
3388 continue;
3389
3390 for (VPRecipeBase &R : Exit.EarlyExitVPBB->phis())
3391 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
3392 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
3393 VPBlockUtils::disconnectBlocks(Exit.EarlyExitingVPBB, Exit.EarlyExitVPBB);
3394 }
3395
3396 VPDominatorTree VPDT(Plan);
3397
3398 // We can abandon a VPlan entirely if we return false here, so we shouldn't
3399 // crash if some earlier assumptions on scalar IR don't hold for the vplan
3400 // version of the loop.
3401 SmallVector<VPInstruction *, 8> ConditionRecipes;
3402
3403 VPValue *Cond = getRecipesForUncountableExit(ConditionRecipes, LatchVPBB);
3404 if (!Cond) {
3405 reportVectorizationFailure("Unable to determine early exit condition for "
3406 "loop with side effects",
3407 "EarlyExitSideEffectsCond", ORE, TheLoop);
3408 return false;
3409 }
3410
3411 // Find load contributing to condition.
3412 // At the moment LoopVectorizationLegality only supports a single
3413 // early-exit expression with a compare and a single load that must
3414 // be unconditional.
3415 // TODO: Support more than one load.
3416 auto *Load =
3417 find_singleton<VPInstruction>(ConditionRecipes, [](auto *I, bool _) {
3419 ? I
3420 : nullptr;
3421 });
3422 assert(Load && "Couldn't find exactly one load");
3423 // TODO: Support conditional loads for uncountable exits.
3424 assert(VPDT.dominates(Load->getParent(), LatchVPBB) &&
3425 "Uncountable exit condition load is conditional.");
3426 VPInstruction *Ptr = cast<VPInstruction>(Load->getOperand(0));
3427
3428 // Ensure that we are guaranteed to be able to dereference the memory used
3429 // for determining the uncountable exit for the maximum possible number of
3430 // scalar iterations of the loop.
3431 //
3432 // TODO: Support first-faulting loads in cases where we don't know whether
3433 // all possible addresses are dereferenceable.
3434 {
3436 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, TheLoop);
3437 const DataLayout &DL = Plan.getDataLayout();
3438 APInt EltSize(DL.getIndexTypeSizeInBits(Ptr->getScalarType()),
3439 DL.getTypeStoreSize(Load->getScalarType()).getFixedValue());
3441 PtrSCEV, cast<LoadInst>(Load->getUnderlyingInstr())->getAlign(),
3442 PSE.getSE()->getConstant(EltSize), TheLoop, *PSE.getSE(), DT, AC,
3443 &Predicates)) {
3444 reportVectorizationFailure("Early exit loop with side effects contains "
3445 "load used by the exit condition that may "
3446 "fault",
3447 "EarlyExitSideEffectsFaultingLoad", ORE,
3448 TheLoop);
3449 return false;
3450 }
3451 }
3452
3453 // Check for a single GEP for the condition load to see if we can link it to
3454 // a widen IV recipe with a step of 1; we're only interested in contiguous
3455 // accesses for the condition load right now.
3456 auto *IV = cast<VPWidenInductionRecipe>(&HeaderVPBB->front());
3457 if (!match(IV->getStartValue(), m_SpecificInt(0)) ||
3458 !match(IV->getStepValue(), m_SpecificInt(1))) {
3459 reportVectorizationFailure("Early exit loop with side effects contains "
3460 "load used by the exit condition with an "
3461 "unsupported memory access pattern",
3462 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3463 TheLoop);
3464 return false;
3465 }
3466
3468 m_LiveIn(), m_Specific(IV)))) {
3469 reportVectorizationFailure("Early exit loop with side effects contains "
3470 "load used by the exit condition with an "
3471 "unsupported memory access pattern",
3472 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3473 TheLoop);
3474 return false;
3475 }
3476
3477 // We want to guarantee that the uncountable exit condition (and the mask
3478 // we will generate from it) are available for all operations in the loop
3479 // that need to be masked. If the condition recipes are not already the first
3480 // recipes in the header after the last phi, move them there.
3481 auto InsertIt = HeaderVPBB->getFirstNonPhi();
3482 while (InsertIt != HeaderVPBB->end() &&
3483 is_contained(ConditionRecipes, &*InsertIt)) {
3484 erase(ConditionRecipes, &*InsertIt);
3485 InsertIt++;
3486 }
3487 for (auto *Recipe : reverse(ConditionRecipes))
3488 Recipe->moveBefore(InsertIt);
3489
3490 // Create a mask to represent all lanes that fully execute in the vector loop,
3491 // stopping short of any early exit.
3492 VPBuilder MaskBuilder(InsertIt);
3493 VPValue *FirstActive = MaskBuilder.createFirstActiveLane(Cond);
3494 Type *IVScalarTy = IV->getScalarType();
3495 VPValue *Zero = Plan.getZero(IVScalarTy);
3496 FirstActive =
3497 MaskBuilder.createScalarZExtOrTrunc(FirstActive, IVScalarTy, DebugLoc());
3499 {Zero, FirstActive}, DebugLoc(),
3500 "uncountable.exit.mask");
3501
3502 // Convert all other memory operations to use the mask.
3503 for (VPBasicBlock *VPBB : vp_rpo_plain_cfg_loop_body(HeaderVPBB))
3504 for (VPRecipeBase &R : *VPBB)
3505 if (R.mayReadOrWriteMemory() && &R != Load) {
3506 // TODO: Handle conditional memory operations in the loop.
3507 if (!VPDT.dominates(R.getParent(), LatchVPBB)) {
3509 "Early exit loop with side effects contains unsupported "
3510 "conditional memory operations",
3511 "EarlyExitSideEffectsUnsupportedConditionalMemOps", ORE, TheLoop);
3512 return false;
3513 }
3514 cast<VPInstruction>(&R)->addMask(Mask);
3515 }
3516
3517 // Update middle block branch to compare (IV + however many lanes were active)
3518 // against the full trip count, since we may be exiting the vector loop early.
3519 // If we didn't take an early exit, we should get the equivalent of VF from
3520 // the FirstActiveLane.
3521 assert(match(MiddleVPBB->getTerminator(), m_BranchOnCond()) &&
3522 "Expected BranchOnCond terminator for MiddleVPBB");
3523 VPBuilder MiddleBuilder(MiddleVPBB->getTerminator());
3524 VPValue *ScalarIV = MiddleBuilder.createNaryOp(VPInstruction::ExtractLane,
3525 {Zero, IV}, DebugLoc());
3526 VPValue *ExitIV = MiddleBuilder.createAdd(ScalarIV, FirstActive);
3527 VPValue *FullTC =
3528 MiddleBuilder.createICmp(CmpInst::ICMP_EQ, ExitIV, Plan.getTripCount());
3529 MiddleVPBB->getTerminator()->setOperand(0, FullTC);
3530
3531 // Update resume phi in scalar.ph.
3532 VPBasicBlock *ScalarPH = Plan.getScalarPreheader();
3533 auto Phis = ScalarPH->phis();
3534 // TODO: Handle more than one Phi; re-derive from IV.
3535 // TODO: Handle reductions.
3536 if (range_size(Phis) != 1) {
3538 "Early exit loop with side effects contains "
3539 "unsupported reductions, inductions or recurrences",
3540 "EarlyExitSideEffectsReductions", ORE, TheLoop);
3541 return false;
3542 }
3543 VPPhi *ContinueIV = cast<VPPhi>(Phis.begin());
3544 // Make sure we're referring to the same IV.
3545 assert(
3546 match(ContinueIV->getOperand(0),
3548 "Continuing from different IV");
3549 ContinueIV->setOperand(0, ExitIV);
3550 return true;
3551}
3552
3553// Returns true if the loop contains stores, the only writes legality accepts in
3554// early-exit loops.
3555static bool loopHasStores(VPBasicBlock *HeaderVPBB) {
3556 return any_of(vp_rpo_plain_cfg_loop_body(HeaderVPBB), [](VPBasicBlock *VPBB) {
3557 return any_of(*VPBB, [VPBB](VPRecipeBase &R) {
3558 (void)VPBB;
3560 return false;
3561 if (!R.mayWriteToMemory()) {
3562 assert((!R.mayHaveSideEffects() || &R == VPBB->getTerminator() ||
3563 R.isSafeToSpeculativelyExecute()) &&
3564 "legality only accepts recipes with side effects that are "
3565 "safe to speculate");
3566 return false;
3567 }
3569 "legality only accepts stores as writes in early-exit loops");
3570 return true;
3571 });
3572 });
3573}
3574
3576 VPlan &Plan, OptimizationRemarkEmitter *ORE, Loop *TheLoop,
3578 UncountableExitStyle Style) {
3579#ifndef NDEBUG
3580 VPDominatorTree VPDT(Plan);
3581#endif
3582
3583 auto *MiddleVPBB = VPBlockUtils::getPlainCFGMiddleBlock(Plan);
3584 auto [HeaderVPBB, LatchVPBB] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
3585
3586 if (loopHasStores(HeaderVPBB))
3588
3589 // Dereferenceability is checked separately for uncountable exit loops with
3590 // stores, as only the loads contributing to the exit condition need to
3591 // be checked.
3592 if (Style == UncountableExitStyle::ReadOnly &&
3593 !areAllLoadsDereferenceable(HeaderVPBB, TheLoop, PSE, DT, AC)) {
3595 "Auto-vectorization of early exit loops with potentially "
3596 "faulting loads is not supported",
3597 "EarlyExitFaultingLoads", ORE, TheLoop);
3598 return false;
3599 }
3600
3601 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
3603 for (auto [EarlyExitingVPBB, ExitBlock] :
3604 vputils::getEarlyExits(Plan, MiddleVPBB)) {
3605 // The final value of a reduction is computed in the middle block, which is
3606 // only reached when leaving the vector loop via the latch.
3607 // TODO: Support reductions used on early exits.
3608 for (VPRecipeBase &R : ExitBlock->phis()) {
3609 VPValue *ExitV =
3610 cast<VPIRPhi>(&R)->getIncomingValueForBlock(EarlyExitingVPBB);
3611 for (VPReductionPHIRecipe &PhiR :
3612 make_isa_range<VPReductionPHIRecipe>(HeaderVPBB->phis())) {
3613 if (ExitV != PhiR.getBackedgeValue())
3614 continue;
3616 "Found reduction used on an early exit",
3617 "Cannot vectorize early exit loop with reduction used on an "
3618 "early exit",
3619 "ReductionUsedOnEarlyExit", ORE, TheLoop);
3620 return false;
3621 }
3622 }
3623
3624 // Collect condition for this early exit.
3625 VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors()[0];
3626 VPValue *CondOfEarlyExitingVPBB;
3627 [[maybe_unused]] bool Matched =
3628 match(EarlyExitingVPBB->getTerminator(),
3629 m_BranchOnCond(m_VPValue(CondOfEarlyExitingVPBB)));
3630 assert(Matched && "Terminator must be BranchOnCond");
3631
3632 // Insert the MaskedCond in the EarlyExitingVPBB so the predicator adds
3633 // the correct block mask.
3634 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
3635 auto *CondToEarlyExit = EarlyExitingBuilder.createNaryOp(
3637 TrueSucc == ExitBlock
3638 ? CondOfEarlyExitingVPBB
3639 : EarlyExitingBuilder.createNot(CondOfEarlyExitingVPBB));
3640 assert((isa<VPIRValue>(CondOfEarlyExitingVPBB) ||
3641 !VPDT.properlyDominates(EarlyExitingVPBB, LatchVPBB) ||
3642 VPDT.properlyDominates(
3643 CondOfEarlyExitingVPBB->getDefiningRecipe()->getParent(),
3644 LatchVPBB)) &&
3645 "exit condition must dominate the latch");
3646 Exits.push_back({
3647 EarlyExitingVPBB,
3648 ExitBlock,
3649 CondToEarlyExit,
3650 });
3651 }
3652
3653 assert(!Exits.empty() && "must have at least one early exit");
3654 // Sort exits by RPO order to get correct program order. RPO gives a
3655 // topological ordering of the CFG, ensuring upstream exits are checked
3656 // before downstream exits in the dispatch chain.
3658 HeaderVPBB);
3660 for (const auto &[Num, VPB] : enumerate(RPOT))
3661 RPOIdx[VPB] = Num;
3662 llvm::sort(Exits, [&RPOIdx](const EarlyExitInfo &A, const EarlyExitInfo &B) {
3663 return RPOIdx[A.EarlyExitingVPBB] < RPOIdx[B.EarlyExitingVPBB];
3664 });
3665#ifndef NDEBUG
3666 // After RPO sorting, verify that for any pair where one exit dominates
3667 // another, the dominating exit comes first. This is guaranteed by RPO
3668 // (topological order) and is required for the dispatch chain correctness.
3669 for (unsigned I = 0; I + 1 < Exits.size(); ++I)
3670 for (unsigned J = I + 1; J < Exits.size(); ++J)
3671 assert(!VPDT.properlyDominates(Exits[J].EarlyExitingVPBB,
3672 Exits[I].EarlyExitingVPBB) &&
3673 "RPO sort must place dominating exits before dominated ones");
3674#endif
3675
3676 // Build the AnyOf condition for the latch terminator using logical OR
3677 // to avoid poison propagation from later exit conditions when an earlier
3678 // exit is taken.
3679 VPValue *Combined = Exits[0].CondToExit;
3680 for (const EarlyExitInfo &Info : drop_begin(Exits))
3681 Combined = LatchBuilder.createLogicalOr(Combined, Info.CondToExit);
3682 Combined = LatchBuilder.createFreeze(Combined);
3683
3684 // Even though the logical or prevents posion propagation, we need to freeze
3685 // Combined to prevent poisoning the entire AnyOf result:
3686 //
3687 // Exits[0].CondToExit = [0,1,0,0]
3688 // Exits[1].CondToExit = [0,0,p,p]
3689 // Combined = [0,1,p,p]
3690 // freeze(Combined) = [0,1,?,?]
3691 // AnyOf = 1
3692 VPValue *IsAnyExitTaken =
3693 LatchBuilder.createNaryOp(VPInstruction::AnyOf, Combined);
3694
3695 // Create a comparison for the latch exit condition and replace the
3696 // BranchOnCond with a BranchOnTwoConds. The original BranchOnCond's condition
3697 // is used as the latch-exit condition; canonical IV recipes have not been
3698 // introduced yet, so there is no BranchOnCount to derive the condition from.
3699 auto *LatchExitingBranch = cast<VPInstruction>(LatchVPBB->getTerminator());
3700 assert(LatchExitingBranch->getOpcode() == VPInstruction::BranchOnCond &&
3701 "Unexpected terminator");
3702 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
3703 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
3704 LatchExitingBranch->eraseFromParent();
3705 LatchBuilder.setInsertPoint(LatchVPBB);
3707 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
3708 LatchVPBB->clearSuccessors();
3709
3711 // If handling the exiting lane in the scalar loop, combine the exit
3712 // conditions into a single BranchOnCond.
3713 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
3714 MiddleVPBB->clearPredecessors();
3715 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
3716 return handleUncountableExitsWithSideEffects(Plan, Exits, HeaderVPBB,
3717 LatchVPBB, MiddleVPBB, ORE,
3718 TheLoop, PSE, DT, AC);
3719 }
3720
3721 // Create the vector.early.exit blocks.
3722 SmallVector<VPBasicBlock *> VectorEarlyExitVPBBs(Exits.size());
3723 for (unsigned Idx = 0; Idx != Exits.size(); ++Idx) {
3724 Twine BlockSuffix = Exits.size() == 1 ? "" : Twine(".") + Twine(Idx);
3725 VPBasicBlock *VectorEarlyExitVPBB =
3726 Plan.createVPBasicBlock("vector.early.exit" + BlockSuffix);
3727 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
3728 }
3729
3730 // Create the dispatch block (or reuse the single exit block if only one
3731 // exit). The dispatch block computes the first active lane of the combined
3732 // condition and, for multiple exits, chains through conditions to determine
3733 // which exit to take.
3734 VPBasicBlock *DispatchVPBB =
3735 Exits.size() == 1 ? VectorEarlyExitVPBBs[0]
3736 : Plan.createVPBasicBlock("vector.early.exit.check");
3737 DispatchVPBB->setPredecessors({LatchVPBB});
3738 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
3739 VPBuilder DispatchBuilder(DispatchVPBB->begin());
3740 VPValue *FirstActiveLane = DispatchBuilder.createFirstActiveLane(
3741 {Combined}, DebugLoc::getUnknown(), "first.active.lane");
3742
3743 // For each early exit, disconnect the original exiting block
3744 // (early.exiting.I) from the exit block (ir-bb<exit.I>) and route through a
3745 // new vector.early.exit block. Update ir-bb<exit.I>'s phis to extract their
3746 // values at the first active lane:
3747 //
3748 // Input:
3749 // early.exiting.I:
3750 // ...
3751 // EMIT branch-on-cond vp<%cond.I>
3752 // Successor(s): in.loop.succ, ir-bb<exit.I>
3753 //
3754 // ir-bb<exit.I>:
3755 // IR %phi = phi [ vp<%incoming.I>, early.exiting.I ], ...
3756 //
3757 // Output:
3758 // early.exiting.I:
3759 // ...
3760 // Successor(s): in.loop.succ
3761 //
3762 // vector.early.exit.I:
3763 // EMIT vp<%exit.val> = extract-lane vp<%first.lane>, vp<%incoming.I>
3764 // Successor(s): ir-bb<exit.I>
3765 //
3766 // ir-bb<exit.I>:
3767 // IR %phi = phi ... (extra operand: vp<%exit.val> from
3768 // vector.early.exit.I)
3769 //
3770 for (auto [Exit, VectorEarlyExitVPBB] :
3771 zip_equal(Exits, VectorEarlyExitVPBBs)) {
3772 auto &[EarlyExitingVPBB, EarlyExitVPBB, _] = Exit;
3773 // Adjust the phi nodes in EarlyExitVPBB.
3774 // 1. remove incoming values from EarlyExitingVPBB,
3775 // 2. extract the incoming value at FirstActiveLane
3776 // 3. add back the extracts as last operands for the phis
3777 // Then adjust the CFG, removing the edge between EarlyExitingVPBB and
3778 // EarlyExitVPBB and adding a new edge between VectorEarlyExitVPBB and
3779 // EarlyExitVPBB. The extracts at FirstActiveLane are now the incoming
3780 // values from VectorEarlyExitVPBB.
3781 for (VPRecipeBase &R : EarlyExitVPBB->phis()) {
3782 auto *ExitIRI = cast<VPIRPhi>(&R);
3783 VPValue *IncomingVal =
3784 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
3785 VPValue *NewIncoming = IncomingVal;
3786 if (!isa<VPIRValue>(IncomingVal)) {
3787 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
3788 NewIncoming = EarlyExitBuilder.createNaryOp(
3789 VPInstruction::ExtractLane, {FirstActiveLane, IncomingVal},
3790 DebugLoc::getUnknown(), "early.exit.value");
3791 }
3792 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
3793 ExitIRI->addIncoming(NewIncoming);
3794 }
3795
3796 EarlyExitingVPBB->getTerminator()->eraseFromParent();
3797 VPBlockUtils::disconnectBlocks(EarlyExitingVPBB, EarlyExitVPBB);
3798 VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, EarlyExitVPBB);
3799 }
3800
3801 // Chain through exits: for each exit, check if its condition is true at
3802 // the first active lane. If so, take that exit; otherwise, try the next.
3803 // The last exit needs no check since it must be taken if all others fail.
3804 //
3805 // For 3 exits (cond.0, cond.1, cond.2), this creates:
3806 //
3807 // latch:
3808 // ...
3809 // EMIT vp<%combined> = logical-or vp<%cond.0>, vp<%cond.1>, vp<%cond.2>
3810 // EMIT vp<%combined.freeze> = freeze vp<%combined>
3811 // ...
3812 //
3813 // vector.early.exit.check:
3814 // EMIT vp<%first.lane> = first-active-lane vp<%combined.freeze>
3815 // EMIT vp<%at.cond.0> = extract-lane vp<%first.lane>, vp<%cond.0>
3816 // EMIT branch-on-cond vp<%at.cond.0>
3817 // Successor(s): vector.early.exit.0, vector.early.exit.check.0
3818 //
3819 // vector.early.exit.check.0:
3820 // EMIT vp<%at.cond.1> = extract-lane vp<%first.lane>, vp<%cond.1>
3821 // EMIT branch-on-cond vp<%at.cond.1>
3822 // Successor(s): vector.early.exit.1, vector.early.exit.2
3823 VPBasicBlock *CurrentBB = DispatchVPBB;
3824 for (auto [I, Exit] : enumerate(ArrayRef(Exits).drop_back())) {
3825 VPValue *LaneVal = DispatchBuilder.createNaryOp(
3826 VPInstruction::ExtractLane, {FirstActiveLane, Exit.CondToExit},
3827 DebugLoc::getUnknown(), "exit.cond.at.lane");
3828
3829 // For the last dispatch, branch directly to the last exit on false;
3830 // otherwise, create a new check block.
3831 bool IsLastDispatch = (I + 2 == Exits.size());
3832 VPBasicBlock *FalseBB =
3833 IsLastDispatch ? VectorEarlyExitVPBBs.back()
3834 : Plan.createVPBasicBlock(
3835 Twine("vector.early.exit.check.") + Twine(I));
3836
3837 DispatchBuilder.createNaryOp(VPInstruction::BranchOnCond, {LaneVal});
3838 CurrentBB->setSuccessors({VectorEarlyExitVPBBs[I], FalseBB});
3839 VectorEarlyExitVPBBs[I]->setPredecessors({CurrentBB});
3840 FalseBB->setPredecessors({CurrentBB});
3841
3842 CurrentBB = FalseBB;
3843 DispatchBuilder.setInsertPoint(CurrentBB);
3844 }
3845
3846 return true;
3847}
3848
3849/// This function tries convert extended in-loop reductions to
3850/// VPExpressionRecipe and clamp the \p Range if it is beneficial and
3851/// valid. The created recipe must be decomposed to its constituent
3852/// recipes before execution.
3853static VPExpressionRecipe *
3855 VFRange &Range) {
3856 Type *RedTy = Red->getScalarType();
3857 VPValue *VecOp = Red->getVecOp();
3858
3859 // We don't handle partial reductions here.
3860 if (Red->isPartialReduction())
3861 return nullptr;
3862
3863 // Clamp the range if using extended-reduction is profitable.
3864 auto IsExtendedRedValidAndClampRange =
3865 [&](unsigned Opcode, Instruction::CastOps ExtOpc, Type *SrcTy) -> bool {
3867 [&](ElementCount VF) {
3868 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3870
3872 InstructionCost ExtCost =
3873 cast<VPWidenCastRecipe>(VecOp)->computeCost(VF, Ctx);
3874 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3875
3876 assert(!RedTy->isFloatingPointTy() &&
3877 "getExtendedReductionCost only supports integer types");
3878 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
3879 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
3880 Red->getFastMathFlagsOrNone(), CostKind);
3881 return ExtRedCost.isValid() && ExtRedCost < ExtCost + RedCost;
3882 },
3883 Range);
3884 };
3885
3886 VPValue *A;
3887 // Match reduce(ext)).
3889 IsExtendedRedValidAndClampRange(
3890 RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()),
3891 cast<VPWidenCastRecipe>(VecOp)->getOpcode(), A->getScalarType()))
3892 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
3893
3894 return nullptr;
3895}
3896
3898
3902
3903/// Returns true if the narrow \p Mul in ext(mul(ext(A), ext(B))) or
3904/// ext(mul(ext(A), C)) cannot wrap. The kind of the inner extends selects
3905/// whether nuw (zext) or nsw (sext) is required on \p Mul.
3907 auto *LHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
3908 auto *RHS = dyn_cast<VPWidenCastRecipe>(Mul->getOperand(1));
3909 Type *LHSSrcTy = LHS->getOperand(0)->getScalarType();
3910 // A constant RHS must fit in the source type of the LHS.
3911 Type *RHSSrcTy = RHS ? RHS->getOperand(0)->getScalarType() : LHSSrcTy;
3913 if (Mul->getScalarType()->getScalarSizeInBits() >=
3914 LHSSrcTy->getScalarSizeInBits() + RHSSrcTy->getScalarSizeInBits())
3915 return true;
3916 if (ExtKind == ExtendKind::PR_ZeroExtend)
3917 return Mul->hasNoUnsignedWrap();
3918 return ExtKind == ExtendKind::PR_SignExtend && Mul->hasNoSignedWrap();
3919}
3920
3921/// This function tries convert extended in-loop reductions to
3922/// VPExpressionRecipe and clamp the \p Range if it is beneficial
3923/// and valid. The created VPExpressionRecipe must be decomposed to its
3924/// constituent recipes before execution. Patterns of the
3925/// VPExpressionRecipe:
3926/// reduce.add(mul(...)),
3927/// reduce.add(mul(ext(A), ext(B))),
3928/// reduce.add(ext(mul(ext(A), ext(B)))).
3929/// reduce.fadd(fmul(ext(A), ext(B)))
3930static VPExpressionRecipe *
3932 VPCostContext &Ctx, VFRange &Range) {
3933 unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());
3934 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3935 Opcode != Instruction::FAdd)
3936 return nullptr;
3937
3938 // We don't handle partial reductions here.
3939 if (Red->isPartialReduction())
3940 return nullptr;
3941
3942 Type *RedTy = Red->getScalarType();
3943
3944 // Clamp the range if using multiply-accumulate-reduction is profitable.
3945 auto IsMulAccValidAndClampRange =
3947 VPWidenCastRecipe *OuterExt) -> bool {
3949 [&](ElementCount VF) {
3951 Type *SrcTy = Ext0 ? Ext0->getOperand(0)->getScalarType() : RedTy;
3952 InstructionCost MulAccCost;
3953
3954 // getMulAccReductionCost for in-loop reductions does not support
3955 // mixed or floating-point extends.
3956 if (Ext0 && Ext1 &&
3957 (Ext0->getOpcode() != Ext1->getOpcode() ||
3958 Ext0->getOpcode() == Instruction::CastOps::FPExt))
3959 return false;
3960
3961 bool IsZExt =
3962 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
3963 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3964 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
3965 SrcVecTy, CostKind);
3966
3967 InstructionCost MulCost = Mul->computeCost(VF, Ctx);
3968 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3969 InstructionCost ExtCost = 0;
3970 if (Ext0)
3971 ExtCost += Ext0->computeCost(VF, Ctx);
3972 if (Ext1)
3973 ExtCost += Ext1->computeCost(VF, Ctx);
3974 if (OuterExt)
3975 ExtCost += OuterExt->computeCost(VF, Ctx);
3976
3977 return MulAccCost.isValid() &&
3978 MulAccCost < ExtCost + MulCost + RedCost;
3979 },
3980 Range);
3981 };
3982
3983 VPValue *VecOp = Red->getVecOp();
3984 VPRecipeBase *Sub = nullptr;
3985 VPValue *A, *B;
3986 VPValue *Tmp = nullptr;
3987
3988 if (RedTy->isFloatingPointTy())
3989 return nullptr;
3990
3991 // Sub reductions could have a sub between the add reduction and vec op.
3992 if (match(VecOp, m_Sub(m_ZeroInt(), m_VPValue(Tmp)))) {
3993 Sub = VecOp->getDefiningRecipe();
3994 VecOp = Tmp;
3995 }
3996
3997 // If ValB is a constant and can be safely extended, truncate it to the same
3998 // type as ExtA's operand, then extend it to the same type as ExtA. This
3999 // creates two uniform extends that can more easily be matched by the rest of
4000 // the bundling code. The ExtB reference, ValB and operand 1 of Mul are all
4001 // replaced with the new extend of the constant.
4002 auto ExtendAndReplaceConstantOp = [](VPWidenCastRecipe *ExtA,
4003 VPWidenCastRecipe *&ExtB, VPValue *&ValB,
4004 VPWidenRecipe *Mul) {
4005 if (!ExtA || ExtB || !isa<VPIRValue>(ValB))
4006 return;
4007 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
4008 Instruction::CastOps ExtOpc = ExtA->getOpcode();
4009 const APInt *Const;
4010 if (!match(ValB, m_APInt(Const)) ||
4012 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
4013 return;
4014 // The truncate ensures that the type of each extended operand is the
4015 // same, and it's been proven that the constant can be extended from
4016 // NarrowTy safely. Necessary since ExtA's extended operand would be
4017 // e.g. an i8, while the const will likely be an i32. This will be
4018 // elided by later optimisations.
4019 VPBuilder Builder(Mul);
4020 auto *Trunc =
4021 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
4022 Type *WideTy = ExtA->getScalarType();
4023 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
4024 Mul->setOperand(1, ExtB);
4025 };
4026
4027 // Try to match reduce.add(mul(...)).
4028 if (match(VecOp, m_Mul(m_VPValue(A), m_VPValue(B)))) {
4029 auto *RecipeA = dyn_cast<VPWidenCastRecipe>(A);
4030 auto *RecipeB = dyn_cast<VPWidenCastRecipe>(B);
4031 auto *Mul = cast<VPWidenRecipe>(VecOp);
4032
4033 // Convert reduce.add(mul(ext, const)) to reduce.add(mul(ext, ext(const)))
4034 ExtendAndReplaceConstantOp(RecipeA, RecipeB, B, Mul);
4035
4036 // Match reduce.add/sub(mul(ext, ext)).
4037 if (RecipeA && RecipeB && match(RecipeA, m_ZExtOrSExt(m_VPValue())) &&
4038 match(RecipeB, m_ZExtOrSExt(m_VPValue())) &&
4039 IsMulAccValidAndClampRange(Mul, RecipeA, RecipeB, nullptr)) {
4040 if (Sub)
4041 return new VPExpressionRecipe(RecipeA, RecipeB, Mul,
4042 cast<VPWidenRecipe>(Sub), Red);
4043 return new VPExpressionRecipe(RecipeA, RecipeB, Mul, Red);
4044 }
4045 // TODO: Add an expression type for this variant with a negated mul
4046 if (!Sub && IsMulAccValidAndClampRange(Mul, nullptr, nullptr, nullptr))
4047 return new VPExpressionRecipe(Mul, Red);
4048 }
4049 // TODO: Add an expression type for negated versions of other expression
4050 // variants.
4051 if (Sub)
4052 return nullptr;
4053
4054 // Match reduce.add(ext(mul(A, B))).
4055 if (match(VecOp, m_ZExtOrSExt(m_Mul(m_VPValue(A), m_VPValue(B))))) {
4056 auto *Ext = cast<VPWidenCastRecipe>(VecOp);
4057 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
4058 auto *Ext0 = dyn_cast<VPWidenCastRecipe>(A);
4059 auto *Ext1 = dyn_cast<VPWidenCastRecipe>(B);
4060
4061 // reduce.add(ext(mul(ext, const)))
4062 // -> reduce.add(ext(mul(ext, ext(const))))
4063 ExtendAndReplaceConstantOp(Ext0, Ext1, B, Mul);
4064
4065 // reduce.add(ext(mul(ext(A), ext(B))))
4066 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
4067 // The inner extends must either have the same opcode as the outer extend or
4068 // be the same sext, in which case the multiply cannot result in a negative
4069 // value without wrapping. If the narrow mul cannot wrap, the outer extend
4070 // can be folded away by doing wider extends for the operands of the mul.
4071 if (Ext0 && Ext1 &&
4072 (Ext->getOpcode() == Ext0->getOpcode() ||
4073 (Ext0 == Ext1 && Ext0->getOpcode() == Instruction::SExt)) &&
4074 Ext0->getOpcode() == Ext1->getOpcode() && Mul->hasOneUse() &&
4076 IsMulAccValidAndClampRange(Mul, Ext0, Ext1, Ext)) {
4077 auto *NewExt0 = new VPWidenCastRecipe(
4078 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(), nullptr,
4079 *Ext0, *Ext0, Ext0->getDebugLoc());
4080 NewExt0->insertBefore(Ext0);
4081
4082 VPWidenCastRecipe *NewExt1 = NewExt0;
4083 if (Ext0 != Ext1) {
4084 NewExt1 = new VPWidenCastRecipe(Ext1->getOpcode(), Ext1->getOperand(0),
4085 Ext->getScalarType(), nullptr, *Ext1,
4086 *Ext1, Ext1->getDebugLoc());
4087 NewExt1->insertBefore(Ext1);
4088 }
4089 auto *NewMul = Mul->cloneWithOperands({NewExt0, NewExt1});
4090 NewMul->insertBefore(Mul);
4091 Ext->replaceAllUsesWith(NewMul);
4092 Ext->eraseFromParent();
4093 Mul->eraseFromParent();
4094 return new VPExpressionRecipe(NewExt0, NewExt1, NewMul, Red);
4095 }
4096 }
4097 return nullptr;
4098}
4099
4100/// This function tries to create abstract recipes from the reduction recipe for
4101/// following optimizations and cost estimation.
4103 VPCostContext &Ctx,
4104 VFRange &Range) {
4105 // Creation of VPExpressions for partial reductions is entirely handled in
4106 // transformToPartialReduction.
4107 if (Red->isPartialReduction())
4108 return;
4109
4110 VPExpressionRecipe *AbstractR = nullptr;
4111 auto IP = std::next(Red->getIterator());
4112 if (auto *MulAcc = tryToMatchAndCreateMulAccumulateReduction(Red, Ctx, Range))
4113 AbstractR = MulAcc;
4114 else if (auto *ExtRed = tryToMatchAndCreateExtendedReduction(Red, Ctx, Range))
4115 AbstractR = ExtRed;
4116 // Cannot create abstract inloop reduction recipes.
4117 if (!AbstractR)
4118 return;
4119
4120 AbstractR->insertBefore(IP);
4121 Red->replaceAllUsesWith(AbstractR);
4122}
4123
4133
4134// Collect common metadata from a group of replicate recipes by intersecting
4135// metadata from all recipes in the group.
4137 VPIRMetadata CommonMetadata = *Recipes.front();
4138 for (VPReplicateRecipe *Recipe : drop_begin(Recipes))
4139 CommonMetadata.intersect(*Recipe);
4140 // The recipe using the common metadata is not predicated, so it does not
4141 // share the group's execution frequency.
4142 CommonMetadata.clearExecutionFrequency();
4143 return CommonMetadata;
4144}
4145
4146template <unsigned Opcode>
4150 const Loop *L) {
4151 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
4152 "Only Load and Store opcodes supported");
4153
4154 // For each address, collect operations with the same or complementary masks.
4157 Plan, PSE, L,
4158 [](VPReplicateRecipe *RepR) { return RepR->isPredicated(); });
4159 for (auto Recipes : Groups) {
4160 if (Recipes.size() < 2)
4161 continue;
4162
4164 "Expected all recipes in group to have the same load-store type");
4165
4166 // Collect groups with the same or complementary masks.
4167 for (VPReplicateRecipe *&RecipeI : Recipes) {
4168 if (!RecipeI)
4169 continue;
4170
4171 VPValue *MaskI = RecipeI->getMask();
4173 Group.push_back(RecipeI);
4174 RecipeI = nullptr;
4175
4176 // Find all operations with the same or complementary masks.
4177 bool HasComplementaryMask = false;
4178 for (VPReplicateRecipe *&RecipeJ : Recipes) {
4179 if (!RecipeJ)
4180 continue;
4181
4182 VPValue *MaskJ = RecipeJ->getMask();
4183 // Check if any operation in the group has a complementary mask with
4184 // another, that is M1 == NOT(M2) or M2 == NOT(M1).
4185 HasComplementaryMask |= match(MaskI, m_Not(m_Specific(MaskJ))) ||
4186 match(MaskJ, m_Not(m_Specific(MaskI)));
4187 Group.push_back(RecipeJ);
4188 RecipeJ = nullptr;
4189 }
4190
4191 if (HasComplementaryMask) {
4192 assert(Group.size() >= 2 && "must have at least 2 entries");
4193 AllGroups.push_back(std::move(Group));
4194 }
4195 }
4196 }
4197
4198 return AllGroups;
4199}
4200
4201// Find the recipe with minimum alignment in the group.
4202template <typename InstType>
4203static VPReplicateRecipe *
4205 return *min_element(Group, [](VPReplicateRecipe *A, VPReplicateRecipe *B) {
4206 return cast<InstType>(A->getUnderlyingInstr())->getAlign() <
4207 cast<InstType>(B->getUnderlyingInstr())->getAlign();
4208 });
4209}
4210
4213 const Loop *L) {
4214 auto Groups =
4216 if (Groups.empty())
4217 return;
4218
4219 // Process each group of loads.
4220 for (auto &Group : Groups) {
4221 // Try to use the earliest (most dominating) load to replace all others.
4222 VPReplicateRecipe *EarliestLoad = Group[0];
4223 VPBasicBlock *FirstBB = EarliestLoad->getParent();
4224 VPBasicBlock *LastBB = Group.back()->getParent();
4225
4226 // Check that the load doesn't alias with stores between first and last.
4227 auto LoadLoc = vputils::getMemoryLocation(*EarliestLoad);
4228 if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck(*LoadLoc, FirstBB, LastBB))
4229 continue;
4230
4231 // Collect common metadata from all loads in the group.
4232 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
4233
4234 // Find the load with minimum alignment to use.
4235 auto *LoadWithMinAlign = findRecipeWithMinAlign<LoadInst>(Group);
4236
4237 bool IsSingleScalar = EarliestLoad->isSingleScalar();
4238 assert(all_of(Group,
4239 [IsSingleScalar](VPReplicateRecipe *R) {
4240 return R->isSingleScalar() == IsSingleScalar;
4241 }) &&
4242 "all members in group must agree on IsSingleScalar");
4243
4244 // Create an unpredicated version of the earliest load with common
4245 // metadata.
4246 auto *UnpredicatedLoad = new VPReplicateRecipe(
4247 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
4248 IsSingleScalar, /*Mask=*/nullptr, *EarliestLoad, CommonMetadata);
4249
4250 UnpredicatedLoad->insertBefore(EarliestLoad);
4251
4252 // Replace all loads in the group with the unpredicated load.
4253 for (VPReplicateRecipe *Load : Group) {
4254 Load->replaceAllUsesWith(UnpredicatedLoad);
4255 Load->eraseFromParent();
4256 }
4257 }
4258}
4259
4260static bool
4262 PredicatedScalarEvolution &PSE, const Loop &L) {
4263 auto StoreLoc = vputils::getMemoryLocation(*StoresToSink.front());
4264 if (!StoreLoc || !StoreLoc->AATags.Scope)
4265 return false;
4266
4267 // When sinking a group of stores, all members of the group alias each other.
4268 // Skip them during the alias checks.
4269 VPBasicBlock *FirstBB = StoresToSink.front()->getParent();
4270 VPBasicBlock *LastBB = StoresToSink.back()->getParent();
4271 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
4272 return canHoistOrSinkWithNoAliasCheck(*StoreLoc, FirstBB, LastBB, SinkInfo);
4273}
4274
4277 const Loop *L) {
4278 auto Groups =
4280 if (Groups.empty())
4281 return;
4282
4283 for (auto &Group : Groups) {
4284 if (!canSinkStoreWithNoAliasCheck(Group, PSE, *L))
4285 continue;
4286
4287 // Use the last (most dominated) store's location for the unconditional
4288 // store.
4289 VPReplicateRecipe *LastStore = Group.back();
4290
4291 // Collect common alias metadata from all stores in the group.
4292 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
4293
4294 // Build select chain for stored values.
4295 VPValue *SelectedValue = Group[0]->getOperand(0);
4296 VPBuilder Builder(LastStore);
4297
4298 bool IsSingleScalar = Group[0]->isSingleScalar();
4299 for (unsigned I = 1; I < Group.size(); ++I) {
4300 assert(IsSingleScalar == Group[I]->isSingleScalar() &&
4301 "all members in group must agree on IsSingleScalar");
4302 VPValue *Mask = Group[I]->getMask();
4303 VPValue *Value = Group[I]->getOperand(0);
4304 SelectedValue = Builder.createSelect(
4305 Mask, Value, SelectedValue, Group[I]->getDebugLoc(), "",
4306 VPIRFlags::getDefaultFlags(Instruction::Select,
4307 Value->getScalarType()));
4308 }
4309
4310 // Find the store with minimum alignment to use.
4311 auto *StoreWithMinAlign = findRecipeWithMinAlign<StoreInst>(Group);
4312
4313 // Create unconditional store with selected value and common metadata.
4314 auto *UnpredicatedStore = new VPReplicateRecipe(
4315 StoreWithMinAlign->getUnderlyingInstr(),
4316 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
4317 /*Mask=*/nullptr, *LastStore, CommonMetadata);
4318 UnpredicatedStore->insertBefore(LastStore);
4319
4320 // Remove all predicated stores from the group.
4321 for (VPReplicateRecipe *Store : Group)
4322 Store->eraseFromParent();
4323 }
4324}
4325
4327 unsigned UF,
4328 const TargetTransformInfo &TTI) {
4329 assert(UF > 1 && "Expected plan to have an UF > 1");
4330
4331 auto m_ContiguousVecPtr = m_VecPtr(m_VPValue(), m_One());
4334 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
4335 VPValue *StoredValue = nullptr;
4336 if (!match(&R, m_WidenLoad(m_ContiguousVecPtr)) &&
4337 !match(&R, m_WidenStore(m_ContiguousVecPtr, m_VPValue(StoredValue))))
4338 continue;
4339
4340 auto *MemOp = cast<VPWidenMemoryRecipe>(&R);
4341 assert(MemOp->isConsecutive() && "Expected consecutive load/store");
4342
4343 // TODO: Support masked loads/stores. This requires widening the header
4344 // mask to the same factor as the memory operation.
4345 assert(!MemOp->isMasked() && "Masked accesses are not supported yet");
4346
4347 Type *AccessType = StoredValue ? StoredValue->getScalarType()
4348 : R.getVPSingleValue()->getScalarType();
4349 bool IsStore = isa<VPWidenStoreRecipe>(MemOp->getAsRecipe());
4350 std::optional<Instruction::CastOps> CastHint;
4351 VPUser *MaybeCast = IsStore ? StoredValue->getDefiningRecipe()
4352 : R.getVPSingleValue()->getSingleUser();
4353 if (auto *Cast = dyn_cast_if_present<VPWidenCastRecipe>(MaybeCast))
4354 CastHint = Cast->getOpcode();
4355
4356 VectorType *VectorAccessType = VectorType::get(AccessType, VF);
4357 if (!TTI.hasMultiVectorLoadStore(
4358 /*NumVectors=*/UF, TargetTransformInfo::MaskSource::None,
4359 VectorAccessType, IsStore, CastHint))
4360 continue;
4361
4362 DebugLoc DL = R.getDebugLoc();
4363 VPValue *Ptr = MemOp->getAddr();
4364 VPValue *Align = Plan.getConstantInt(64, MemOp->getAlign().value());
4365 VPValue *Multiplier = Plan.getConstantInt(64, 1);
4366
4367 VPBuilder Builder(&R);
4368 if (IsStore) {
4369 VPValue *WideStoredValue = Builder.createNaryOp(
4370 VPInstruction::ConcatVectors, {StoredValue}, DL);
4371 Builder.createNaryOp(VPInstruction::WideVectorStore,
4372 {Multiplier, Ptr, Align, WideStoredValue}, nullptr,
4373 {}, *MemOp, R.getDebugLoc());
4374 } else {
4375 VPValue *OldLoad = R.getVPSingleValue();
4376 VPValue *Load = Builder.createNaryOp(
4377 VPInstruction::WideVectorLoad, {Multiplier, Ptr, Align}, nullptr,
4378 {}, *MemOp, R.getDebugLoc(), "", OldLoad->getScalarType());
4379 VPValue *Extract =
4380 Builder.createNaryOp(VPInstruction::ExtractVectorForPart,
4381 {Load, Plan.getConstantInt(64, 0)}, DL);
4382 OldLoad->replaceAllUsesWith(Extract);
4383 }
4384
4385 R.eraseFromParent();
4386 }
4387 }
4388}
4389
4390/// Returns true if \p V is VPWidenLoadRecipe or VPInterleaveRecipe that can be
4391/// converted to a narrower recipe. \p V is used by a wide recipe that feeds a
4392/// store interleave group at index \p Idx, \p WideMember0 is the recipe feeding
4393/// the same interleave group at index 0. A VPWidenLoadRecipe can be narrowed to
4394/// an index-independent load if it feeds all wide ops at all indices (\p OpV
4395/// must be the operand at index \p OpIdx for both the recipe at lane 0, \p
4396/// WideMember0). A VPInterleaveRecipe can be narrowed to a wide load, if \p V
4397/// is defined at \p Idx of a load interleave group.
4398/// A live-in or recipe defined outside the loop region can be converted, if it
4399/// is the same across all lanes, or we can create a BuildVector for it.
4400static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx,
4401 VPValue *OpV, unsigned Idx, bool IsScalable) {
4402 VPValue *Member0Op = WideMember0->getOperand(OpIdx);
4403 if (Member0Op->isDefinedOutsideLoopRegions()) {
4404 // Operand matches Member0, broadcast across all fields for both live-ins
4405 // and recipes.
4406 if (Member0Op == OpV)
4407 return true;
4408 // Otherwise distinct per-field VPValues are assembled into a BuildVector.
4409 return !IsScalable && OpV->isDefinedOutsideLoopRegions() &&
4410 OpV->getScalarType() == Member0Op->getScalarType();
4411 }
4412 VPRecipeBase *Member0OpR = Member0Op->getDefiningRecipe();
4413 if (auto *W = dyn_cast<VPWidenLoadRecipe>(Member0OpR))
4414 // For scalable VFs, the narrowed plan processes vscale iterations at once,
4415 // so a shared wide load cannot be narrowed to a uniform scalar; bail out.
4416 return !IsScalable && !W->getMask() && W->isConsecutive() &&
4417 Member0Op == OpV;
4418 if (auto *IR = dyn_cast<VPInterleaveRecipe>(Member0OpR))
4419 return IR->getInterleaveGroup()->isFull() && IR->getVPValue(Idx) == OpV;
4420 return false;
4421}
4422
4423/// Returns true if the wide recipes in \p Ops and their operand trees can be
4424/// narrowed. \p FirstMembersOf maps each in-loop value to the first member
4425/// list it was seen in, across all store groups.
4426static bool
4428 DenseMap<VPValue *, SmallVector<VPValue *>> &FirstMembersOf) {
4429 auto *WideMember0 = dyn_cast<VPRecipeWithIRFlags>(Ops[0]);
4430 if (!WideMember0)
4431 return false;
4432 for (VPValue *V : Ops) {
4434 return false;
4435 auto *R = cast<VPRecipeWithIRFlags>(V);
4436 if (vputils::getOpcode(R) != vputils::getOpcode(WideMember0))
4437 return false;
4438 if (R->getScalarType() != WideMember0->getScalarType())
4439 return false;
4440 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
4441 return false;
4442 }
4443
4444 // The first member is narrowed in place using the other members' operands.
4445 // Bail out if a value is the first member of one list and also part of a
4446 // different list.
4447 for (VPValue *V : Ops) {
4448 if (V->isDefinedOutsideLoopRegions())
4449 continue;
4450 auto [It, Inserted] = FirstMembersOf.try_emplace(V, Ops);
4451 if (!Inserted && (It->second.front() == V || V == WideMember0) &&
4452 !equal(It->second, Ops))
4453 return false;
4454 }
4455
4456 for (unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
4458 for (VPValue *Op : Ops)
4459 OpsI.push_back(Op->getDefiningRecipe()->getOperand(Idx));
4460
4461 if (canNarrowOps(OpsI, IsScalable, FirstMembersOf))
4462 continue;
4463
4464 if (any_of(enumerate(OpsI), [WideMember0, Idx, IsScalable](const auto &P) {
4465 const auto &[OpIdx, OpV] = P;
4466 return !canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
4467 }))
4468 return false;
4469 }
4470
4471 return true;
4472}
4473
4474/// Returns VF from \p VFs if \p IR is a full interleave group with factor and
4475/// number of members both equal to VF. The interleave group must also access
4476/// the full vector width.
4477static std::optional<ElementCount>
4480 const TargetTransformInfo &TTI) {
4481 if (!InterleaveR || InterleaveR->getMask())
4482 return std::nullopt;
4483
4484 Type *GroupElementTy = nullptr;
4485 if (InterleaveR->getStoredValues().empty()) {
4486 GroupElementTy = InterleaveR->getVPValue(0)->getScalarType();
4487 if (!all_of(InterleaveR->definedValues(), [GroupElementTy](VPValue *Op) {
4488 return Op->getScalarType() == GroupElementTy;
4489 }))
4490 return std::nullopt;
4491 } else {
4492 GroupElementTy = InterleaveR->getStoredValues()[0]->getScalarType();
4493 if (!all_of(InterleaveR->getStoredValues(), [GroupElementTy](VPValue *Op) {
4494 return Op->getScalarType() == GroupElementTy;
4495 }))
4496 return std::nullopt;
4497 }
4498
4499 auto IG = InterleaveR->getInterleaveGroup();
4500 if (IG->getFactor() != IG->getNumMembers() || IG->isReverse())
4501 return std::nullopt;
4502
4503 auto GetVectorBitWidthForVF = [&TTI](ElementCount VF) {
4504 TypeSize Size = TTI.getRegisterBitWidth(
4507 assert(Size.isScalable() == VF.isScalable() &&
4508 "if Size is scalable, VF must be scalable and vice versa");
4509 return Size.getKnownMinValue();
4510 };
4511
4512 for (ElementCount VF : VFs) {
4513 unsigned MinVal = VF.getKnownMinValue();
4514 unsigned GroupSize = GroupElementTy->getScalarSizeInBits() * MinVal;
4515 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
4516 return {VF};
4517 }
4518 return std::nullopt;
4519}
4520
4521/// Returns true if \p VPValue is a narrow VPValue.
4522static bool isAlreadyNarrow(VPValue *VPV) {
4523 if (isa<VPIRValue>(VPV))
4524 return true;
4525 auto *RepR = dyn_cast<VPReplicateRecipe>(VPV);
4526 return RepR && RepR->isSingleScalar();
4527}
4528
4529// Convert the wide recipes defining the VPValues in \p Members feeding an
4530// interleave group to a single narrow variant. The first member is reused as
4531// the narrowed recipe. BuildVectors for live-in operands are inserted into \p
4532// Preheader.
4534 SmallPtrSetImpl<VPValue *> &NarrowedOps,
4535 VPBasicBlock *Preheader) {
4536 VPValue *V = Members.front();
4537 if (NarrowedOps.contains(V))
4538 return V;
4539
4540 if (V->isDefinedOutsideLoopRegions()) {
4541 assert(all_of(Members,
4542 [V](VPValue *M) {
4543 return M->isDefinedOutsideLoopRegions() &&
4544 M->getScalarType() == V->getScalarType();
4545 }) &&
4546 "expected distinct loop-invariant values of matching scalar type");
4547 auto *BV = new VPInstruction(VPInstruction::BuildVector, Members);
4548 Preheader->appendRecipe(BV);
4549 NarrowedOps.insert(BV);
4550 return BV;
4551 }
4552
4553 if (isAlreadyNarrow(V))
4554 return V;
4555
4556 VPRecipeBase *R = V->getDefiningRecipe();
4558 auto *WideMember0 = cast<VPRecipeWithIRFlags>(R);
4559 for (VPValue *Member : Members.drop_front())
4560 WideMember0->intersectFlags(*cast<VPRecipeWithIRFlags>(Member));
4561 for (unsigned Idx = 0, E = WideMember0->getNumOperands(); Idx != E; ++Idx) {
4563 for (VPValue *Member : Members)
4564 OpsI.push_back(Member->getDefiningRecipe()->getOperand(Idx));
4565 WideMember0->setOperand(
4566 Idx, narrowInterleaveGroupOp(OpsI, NarrowedOps, Preheader));
4567 }
4568 return V;
4569 }
4570
4571 if (auto *LoadGroup = dyn_cast<VPInterleaveRecipe>(R)) {
4572 // Narrow interleave group to wide load, as transformed VPlan will only
4573 // process one original iteration.
4574 const InterleaveGroup<Instruction> *IG = LoadGroup->getInterleaveGroup();
4575 auto *LI = cast<LoadInst>(IG->getInsertPos());
4576 auto *L = VPBuilder(LoadGroup).createWidenLoad(
4577 *LI, LoadGroup->getAddr(), LoadGroup->getMask(), /*Consecutive=*/true,
4578 IG->getAlign(), *LoadGroup, LoadGroup->getDebugLoc());
4579 NarrowedOps.insert(L);
4580 return L;
4581 }
4582
4583 auto *WideLoad = cast<VPWidenLoadRecipe>(R);
4584 VPValue *PtrOp = WideLoad->getAddr();
4585 if (auto *VecPtr = dyn_cast<VPVectorPointerRecipe>(PtrOp))
4586 PtrOp = VecPtr->getOperand(0);
4587 // Narrow wide load to uniform scalar load, as transformed VPlan will only
4588 // process one original iteration.
4589 auto *N = new VPReplicateRecipe(&WideLoad->getIngredient(), {PtrOp},
4590 /*IsUniform*/ true,
4591 /*Mask*/ nullptr, {}, *WideLoad);
4592 N->insertBefore(WideLoad);
4593 NarrowedOps.insert(N);
4594 return N;
4595}
4596
4597std::unique_ptr<VPlan>
4599 const TargetTransformInfo &TTI) {
4600 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
4601
4602 if (!VectorLoop)
4603 return nullptr;
4604
4605 // Only handle single-block loops for now.
4606 if (VectorLoop->getEntryBasicBlock() != VectorLoop->getExitingBasicBlock())
4607 return nullptr;
4608
4609 // Skip plans when we may not be able to properly narrow.
4610 VPBasicBlock *Exiting = VectorLoop->getExitingBasicBlock();
4611 if (!match(&Exiting->back(), m_BranchOnCount()))
4612 return nullptr;
4613
4614 assert(match(&Exiting->back(),
4616 m_Specific(&Plan.getVectorTripCount()))) &&
4617 "unexpected branch-on-count");
4618
4621 std::optional<ElementCount> VFToOptimize;
4622 for (auto &R : *VectorLoop->getEntryBasicBlock()) {
4625 continue;
4626
4627 // Bail out on recipes not supported at the moment:
4628 // * phi recipes other than the canonical induction
4629 // * recipes writing to memory except interleave groups
4630 // Only support plans with a canonical induction phi.
4631 if (R.isPhi())
4632 return nullptr;
4633
4634 auto *InterleaveR = dyn_cast<VPInterleaveRecipe>(&R);
4635 if (R.mayWriteToMemory() && !InterleaveR)
4636 return nullptr;
4637
4638 // Bail out if any recipe defines a vector value used outside the
4639 // vector loop region.
4640 if (any_of(R.definedValues(), [&](VPValue *V) {
4641 return any_of(V->users(), [&](VPUser *U) {
4642 auto *UR = cast<VPRecipeBase>(U);
4643 return UR->getParent()->getParent() != VectorLoop;
4644 });
4645 }))
4646 return nullptr;
4647
4648 // All other ops are allowed, but we reject uses that cannot be converted
4649 // when checking all allowed consumers (store interleave groups) below.
4650 if (!InterleaveR)
4651 continue;
4652
4653 // Try to find a single VF, where all interleave groups are consecutive and
4654 // saturate the full vector width. If we already have a candidate VF, check
4655 // if it is applicable for the current InterleaveR, otherwise look for a
4656 // suitable VF across the Plan's VFs.
4658 VFToOptimize ? SmallVector<ElementCount>({*VFToOptimize})
4659 : to_vector(Plan.vectorFactors());
4660 std::optional<ElementCount> NarrowedVF =
4661 isConsecutiveInterleaveGroup(InterleaveR, VFs, TTI);
4662 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
4663 return nullptr;
4664 VFToOptimize = NarrowedVF;
4665
4666 // Skip read interleave groups.
4667 if (InterleaveR->getStoredValues().empty())
4668 continue;
4669
4670 // Narrow interleave groups, if all operands are already matching narrow
4671 // ops.
4672 auto *Member0 = InterleaveR->getStoredValues()[0];
4673 if (isAlreadyNarrow(Member0) &&
4674 all_of(InterleaveR->getStoredValues(), equal_to(Member0))) {
4675 StoreGroups.push_back(InterleaveR);
4676 continue;
4677 }
4678
4679 // For now, we only support full interleave groups storing load interleave
4680 // groups.
4681 if (all_of(enumerate(InterleaveR->getStoredValues()), [](auto Op) {
4682 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
4683 if (!DefR)
4684 return false;
4685 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
4686 return IR && IR->getInterleaveGroup()->isFull() &&
4687 IR->getVPValue(Op.index()) == Op.value();
4688 })) {
4689 StoreGroups.push_back(InterleaveR);
4690 continue;
4691 }
4692
4693 // Check if all values feeding InterleaveR are matching wide recipes whose
4694 // operands can be narrowed, without conflicting uses across groups.
4695 if (!canNarrowOps(InterleaveR->getStoredValues(),
4696 VFToOptimize->isScalable(), FirstMembersOf))
4697 return nullptr;
4698 StoreGroups.push_back(InterleaveR);
4699 }
4700
4701 if (StoreGroups.empty())
4702 return nullptr;
4703
4704 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
4705 bool RequiresScalarEpilogue =
4706 MiddleVPBB->getNumSuccessors() == 1 &&
4707 MiddleVPBB->getSingleSuccessor() == Plan.getScalarPreheader();
4708 // Bail out for tail-folding (middle block with a single successor to exit).
4709 if (MiddleVPBB->getNumSuccessors() != 2 && !RequiresScalarEpilogue)
4710 return nullptr;
4711
4712 // All interleave groups in Plan can be narrowed for VFToOptimize. Split the
4713 // original Plan into 2: a) a new clone which contains all VFs of Plan, except
4714 // VFToOptimize, and b) the original Plan with VFToOptimize as single VF.
4715 // TODO: Handle cases where only some interleave groups can be narrowed.
4716 std::unique_ptr<VPlan> NewPlan;
4717 if (size(Plan.vectorFactors()) != 1) {
4718 NewPlan = std::unique_ptr<VPlan>(Plan.duplicate());
4719 Plan.setVF(*VFToOptimize);
4720 NewPlan->removeVF(*VFToOptimize);
4721 }
4722
4723 // Convert InterleaveGroup \p R to a single VPWidenLoadRecipe.
4724 SmallPtrSet<VPValue *, 4> NarrowedOps;
4725 VPBasicBlock *Preheader = Plan.getVectorPreheader();
4726 // Narrow operation tree rooted at store groups.
4727 for (auto *StoreGroup : StoreGroups) {
4728 VPValue *Res = narrowInterleaveGroupOp(StoreGroup->getStoredValues(),
4729 NarrowedOps, Preheader);
4730 const InterleaveGroup<Instruction> *IG = StoreGroup->getInterleaveGroup();
4731 auto *SI = cast<StoreInst>(IG->getInsertPos());
4732 VPBuilder(StoreGroup)
4733 .createWidenStore(*SI, StoreGroup->getAddr(), Res, nullptr,
4734 /*Consecutive=*/true, IG->getAlign(), *StoreGroup,
4735 StoreGroup->getDebugLoc());
4736 StoreGroup->eraseFromParent();
4737 }
4738
4739 // Adjust induction to reflect that the transformed plan only processes one
4740 // original iteration.
4742 Type *CanIVTy = VectorLoop->getCanonicalIVType();
4743 VPBasicBlock *VectorPH = Plan.getVectorPreheader();
4744 VPBuilder PHBuilder(VectorPH->getFirstNonPhi());
4745
4746 VPValue *UF = &Plan.getUF();
4747 VPValue *Step;
4748 if (VFToOptimize->isScalable()) {
4749 VPValue *VScale =
4750 PHBuilder.createElementCount(CanIVTy, ElementCount::getScalable(1));
4751 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale, UF},
4752 {true, false});
4753 Plan.getVF().replaceAllUsesWith(VScale);
4754 } else {
4755 Step = UF;
4756 Plan.getVF().replaceAllUsesWith(Plan.getConstantInt(CanIVTy, 1));
4757 }
4758 // Materialize vector trip count with the narrowed step.
4759 materializeVectorTripCount(Plan, VectorPH, /*TailByMasking=*/false,
4760 RequiresScalarEpilogue, Step);
4761
4762 CanIVInc->setOperand(1, Step);
4763 Plan.getVFxUF().replaceAllUsesWith(Step);
4764
4765 removeDeadRecipes(Plan);
4766 assert(none_of(*VectorLoop->getEntryBasicBlock(),
4768 "All VPVectorPointerRecipes should have been removed");
4769 return NewPlan;
4770}
4771
4773 VFRange &Range) {
4774 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
4775 auto *MiddleVPBB = Plan.getMiddleBlock();
4776 VPBuilder MiddleBuilder(MiddleVPBB->getFirstNonPhi());
4777
4778 auto IsScalableOne = [](ElementCount VF) -> bool {
4779 return VF == ElementCount::getScalable(1);
4780 };
4781
4784 VectorRegion->getEntryBasicBlock()->phis())) {
4785 assert(VectorRegion->getSingleSuccessor() == Plan.getMiddleBlock() &&
4786 "Cannot handle loops with uncountable early exits");
4787
4788 // Find the existing splice for this FOR, created in
4789 // createHeaderPhiRecipes. All uses of FOR have already been replaced with
4790 // RecurSplice there; only RecurSplice itself still references FOR.
4791 auto *RecurSplice =
4793 assert(RecurSplice && "expected FirstOrderRecurrenceSplice");
4794
4795 // For VF vscale x 1, if vscale = 1, we are unable to extract the
4796 // penultimate value of the recurrence. Instead we rely on the existing
4797 // extract of the last element from the result of
4798 // VPInstruction::FirstOrderRecurrenceSplice.
4799 // TODO: Consider vscale_range info and UF.
4800 if (any_of(RecurSplice->users(),
4801 [](VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
4803 Range))
4804 return;
4805
4806 // This is the second phase of vectorizing first-order recurrences, creating
4807 // extracts for users outside the loop. An overview of the transformation is
4808 // described below. Suppose we have the following loop with some use after
4809 // the loop of the last a[i-1],
4810 //
4811 // for (int i = 0; i < n; ++i) {
4812 // t = a[i - 1];
4813 // b[i] = a[i] - t;
4814 // }
4815 // use t;
4816 //
4817 // There is a first-order recurrence on "a". For this loop, the shorthand
4818 // scalar IR looks like:
4819 //
4820 // scalar.ph:
4821 // s.init = a[-1]
4822 // br scalar.body
4823 //
4824 // scalar.body:
4825 // i = phi [0, scalar.ph], [i+1, scalar.body]
4826 // s1 = phi [s.init, scalar.ph], [s2, scalar.body]
4827 // s2 = a[i]
4828 // b[i] = s2 - s1
4829 // br cond, scalar.body, exit.block
4830 //
4831 // exit.block:
4832 // use = lcssa.phi [s1, scalar.body]
4833 //
4834 // In this example, s1 is a recurrence because it's value depends on the
4835 // previous iteration. In the first phase of vectorization, we created a
4836 // VPFirstOrderRecurrencePHIRecipe v1 for s1. Now we create the extracts
4837 // for users in the scalar preheader and exit block.
4838 //
4839 // vector.ph:
4840 // v_init = vector(..., ..., ..., a[-1])
4841 // br vector.body
4842 //
4843 // vector.body
4844 // i = phi [0, vector.ph], [i+4, vector.body]
4845 // v1 = phi [v_init, vector.ph], [v2, vector.body]
4846 // v2 = a[i, i+1, i+2, i+3]
4847 // v1' = splice(v1(3), v2(0, 1, 2))
4848 // b[i, i+1, i+2, i+3] = v2 - v1'
4849 // br cond, vector.body, middle.block
4850 //
4851 // middle.block:
4852 // vector.recur.extract.for.phi = v2(2)
4853 // vector.recur.extract = v2(3)
4854 // br cond, scalar.ph, exit.block
4855 //
4856 // scalar.ph:
4857 // scalar.recur.init = phi [vector.recur.extract, middle.block],
4858 // [s.init, otherwise]
4859 // br scalar.body
4860 //
4861 // scalar.body:
4862 // i = phi [0, scalar.ph], [i+1, scalar.body]
4863 // s1 = phi [scalar.recur.init, scalar.ph], [s2, scalar.body]
4864 // s2 = a[i]
4865 // b[i] = s2 - s1
4866 // br cond, scalar.body, exit.block
4867 //
4868 // exit.block:
4869 // lo = lcssa.phi [s1, scalar.body],
4870 // [vector.recur.extract.for.phi, middle.block]
4871 //
4872 // Update extracts of the splice in the middle block: they extract the
4873 // penultimate element of the recurrence.
4875 make_range(MiddleVPBB->getFirstNonPhi(), MiddleVPBB->end()))) {
4876 if (!match(&R, m_ExtractLastLaneOfLastPart(m_Specific(RecurSplice))))
4877 continue;
4878
4879 auto *ExtractR = cast<VPInstruction>(&R);
4880 VPValue *PenultimateElement = MiddleBuilder.createNaryOp(
4881 VPInstruction::ExtractPenultimateElement, RecurSplice->getOperand(1),
4882 {}, "vector.recur.extract.for.phi");
4883 for (VPUser *ExitU : to_vector(ExtractR->users())) {
4884 if (auto *ExitPhi = dyn_cast<VPIRPhi>(ExitU))
4885 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
4886 }
4887 }
4888 }
4889}
4890
4891/// Check if \p V is a binary expression of a widened IV and a loop-invariant
4892/// value. Returns the widened IV if found, nullptr otherwise.
4894 auto *BinOp = dyn_cast<VPWidenRecipe>(V);
4895 if (!BinOp || !Instruction::isBinaryOp(BinOp->getOpcode()) ||
4896 Instruction::isIntDivRem(BinOp->getOpcode()))
4897 return nullptr;
4898
4899 VPValue *WidenIVCandidate = BinOp->getOperand(0);
4900 VPValue *InvariantCandidate = BinOp->getOperand(1);
4901 if (!isa<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate))
4902 std::swap(WidenIVCandidate, InvariantCandidate);
4903
4904 if (!InvariantCandidate->isDefinedOutsideLoopRegions())
4905 return nullptr;
4906
4907 return dyn_cast<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate);
4908}
4909
4910/// Create a scalar version of \p BinOp, with its \p WidenIV operand replaced
4911/// by \p ScalarIV, and place it after \p ScalarIV's defining recipe.
4915 BinOp->getNumOperands() == 2 && "BinOp must have 2 operands");
4916 auto *ClonedOp = BinOp->clone();
4917 if (ClonedOp->getOperand(0) == WidenIV) {
4918 ClonedOp->setOperand(0, ScalarIV);
4919 } else {
4920 assert(ClonedOp->getOperand(1) == WidenIV && "one operand must be WideIV");
4921 ClonedOp->setOperand(1, ScalarIV);
4922 }
4923 ClonedOp->insertAfter(ScalarIV->getDefiningRecipe());
4924 return ClonedOp;
4925}
4926
4927/// If \p S is an affine AddRec, returns true if its step is known to be
4928/// positive and false if it is known to be negative. Returns std::nullopt if
4929/// \p S is not an affine AddRec, or if the sign of its step cannot be
4930/// determined.
4931static std::optional<bool> getStepDirection(const SCEV *S,
4932 ScalarEvolution &SE) {
4933 const SCEV *Step;
4934 if (!match(S, m_scev_AffineAddRec(m_SCEV(), m_SCEV(Step))))
4935 return std::nullopt;
4936 if (SE.isKnownPositive(Step))
4937 return true;
4938 if (SE.isKnownNegative(Step))
4939 return false;
4940 return std::nullopt;
4941}
4942
4945 Loop &L) {
4946 ScalarEvolution &SE = *PSE.getSE();
4947 VPRegionBlock *VectorLoopRegion = Plan.getVectorLoopRegion();
4948
4949 // Helper lambda to check if the IV range excludes the sentinel value. Try
4950 // signed first, then unsigned. Return an excluded sentinel if found,
4951 // otherwise return std::nullopt.
4952 auto CheckSentinel = [&SE](const SCEV *IVSCEV,
4953 bool UseMax) -> std::optional<APSInt> {
4954 unsigned BW = IVSCEV->getType()->getScalarSizeInBits();
4955 for (bool Signed : {true, false}) {
4956 APSInt Sentinel = UseMax ? APSInt::getMinValue(BW, /*Unsigned=*/!Signed)
4957 : APSInt::getMaxValue(BW, /*Unsigned=*/!Signed);
4958
4959 ConstantRange IVRange =
4960 Signed ? SE.getSignedRange(IVSCEV) : SE.getUnsignedRange(IVSCEV);
4961 if (!IVRange.contains(Sentinel))
4962 return Sentinel;
4963 }
4964 return std::nullopt;
4965 };
4966
4967 VPValue *HeaderMask = VectorLoopRegion->getHeaderMask();
4968 for (VPRecipeBase &Phi :
4969 make_early_inc_range(VectorLoopRegion->getEntryBasicBlock()->phis())) {
4970 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&Phi);
4972 PhiR->getRecurrenceKind()))
4973 continue;
4974
4975 Type *PhiTy = PhiR->getScalarType();
4976 if (PhiTy->isPointerTy() || PhiTy->isFloatingPointTy())
4977 continue;
4978
4979 // If there's a header mask, the backedge select will not be the find-last
4980 // select.
4981 VPValue *BackedgeVal = PhiR->getBackedgeValue();
4982 auto *FindLastSelect = cast<VPSingleDefRecipe>(BackedgeVal);
4983 if (HeaderMask &&
4984 !match(BackedgeVal,
4985 m_Select(m_Specific(HeaderMask),
4986 m_VPSingleDefRecipe(FindLastSelect), m_Specific(PhiR))))
4987 continue;
4988
4989 // Get the find-last expression from the find-last select of the reduction
4990 // phi. The find-last select should be a select between the phi and the
4991 // find-last expression.
4992 VPValue *Cond, *FindLastExpression;
4993 if (!match(FindLastSelect, m_SelectLike(m_VPValue(Cond), m_Specific(PhiR),
4994 m_VPValue(FindLastExpression))) &&
4995 !match(FindLastSelect,
4996 m_SelectLike(m_VPValue(Cond), m_VPValue(FindLastExpression),
4997 m_Specific(PhiR))))
4998 continue;
4999
5000 // Check if FindLastExpression is a simple expression of a widened IV. If
5001 // so, we can track the underlying IV instead and sink the expression.
5002 auto *IVOfExpressionToSink = getExpressionIV(FindLastExpression);
5003 const SCEV *IVSCEV = vputils::getSCEVExprForVPValue(
5004 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
5005 &L);
5006 if (!match(IVSCEV, m_scev_AffineAddRec(m_SCEV(), m_SCEV()))) {
5007 assert(!match(vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L),
5009 "IVOfExpressionToSink not being an AddRec must imply "
5010 "FindLastExpression not being an AddRec.");
5011 continue;
5012 }
5013
5014 // Determine direction from the step of IVSCEV, if possible.
5015 std::optional<bool> StepDirection = getStepDirection(IVSCEV, SE);
5016 if (!StepDirection)
5017 continue;
5018
5019 bool UseMax = *StepDirection;
5020 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
5021 bool UseSigned = SentinelVal && SentinelVal->isSigned();
5022
5023 // Sinking an expression will disable epilogue vectorization. Only use it,
5024 // if FindLastExpression cannot be vectorized via a sentinel. Sinking may
5025 // also prevent vectorizing using a sentinel (e.g., if the expression is a
5026 // multiply or divide by large constant, respectively), which also makes
5027 // sinking undesirable.
5028 if (IVOfExpressionToSink) {
5029 const SCEV *FindLastExpressionSCEV =
5030 vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L);
5031 if (std::optional<bool> NewUseMax =
5032 getStepDirection(FindLastExpressionSCEV, SE)) {
5033 if (auto NewSentinel =
5034 CheckSentinel(FindLastExpressionSCEV, *NewUseMax)) {
5035 // The original expression already has a sentinel, so prefer not
5036 // sinking to keep epilogue vectorization possible.
5037 SentinelVal = *NewSentinel;
5038 UseSigned = NewSentinel->isSigned();
5039 UseMax = *NewUseMax;
5040 IVSCEV = FindLastExpressionSCEV;
5041 IVOfExpressionToSink = nullptr;
5042 }
5043 }
5044 }
5045
5046 // If no sentinel was found, fall back to a boolean AnyOf reduction to track
5047 // if the condition was ever true. Requires the IV to not wrap, otherwise we
5048 // cannot use min/max.
5049 if (!SentinelVal) {
5050 auto *AR = cast<SCEVAddRecExpr>(IVSCEV);
5051 if (AR->hasNoSignedWrap())
5052 UseSigned = true;
5053 else if (AR->hasNoUnsignedWrap())
5054 UseSigned = false;
5055 else
5056 continue;
5057 }
5058
5060 BackedgeVal,
5062
5063 VPValue *NewFindLastSelect = BackedgeVal;
5064 VPValue *SelectCond = Cond;
5065 if (!SentinelVal || IVOfExpressionToSink) {
5066 // When we need to create a new select, normalize the condition so that
5067 // PhiR is the last operand and include the header mask if needed.
5068 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
5069 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
5070 if (match(FindLastSelect,
5072 SelectCond = LoopBuilder.createNot(SelectCond);
5073
5074 // When tail folding, mask the condition with the header mask to prevent
5075 // propagating poison from inactive lanes in the last vector iteration.
5076 if (HeaderMask)
5077 SelectCond = LoopBuilder.createLogicalAnd(HeaderMask, SelectCond);
5078
5079 if (SelectCond != Cond || IVOfExpressionToSink) {
5080 NewFindLastSelect = LoopBuilder.createSelect(
5081 SelectCond,
5082 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
5083 PhiR, DL);
5084 }
5085 }
5086
5087 // Create the reduction result in the middle block using sentinel directly.
5088 RecurKind MinMaxKind =
5089 UseMax ? (UseSigned ? RecurKind::SMax : RecurKind::UMax)
5090 : (UseSigned ? RecurKind::SMin : RecurKind::UMin);
5091 VPIRFlags Flags(MinMaxKind, /*IsOrdered=*/false, /*IsInLoop=*/false,
5092 FastMathFlags());
5093 DebugLoc ExitDL = RdxResult->getDebugLoc();
5094 VPBuilder MiddleBuilder(RdxResult);
5095 VPValue *ReducedIV =
5097 NewFindLastSelect, Flags, ExitDL);
5098
5099 // If IVOfExpressionToSink is an expression to sink, sink it now.
5100 VPValue *VectorRegionExitingVal = ReducedIV;
5101 bool SunkExpression = false;
5102 if (IVOfExpressionToSink) {
5103 VectorRegionExitingVal =
5104 cloneBinOpForScalarIV(cast<VPWidenRecipe>(FindLastExpression),
5105 ReducedIV, IVOfExpressionToSink);
5106 SunkExpression = true;
5107 }
5108
5109 VPValue *NewRdxResult;
5110 VPValue *StartVPV = PhiR->getStartValue();
5111 if (SentinelVal) {
5112 // Sentinel-based approach: reduce IVs with min/max, compare against
5113 // sentinel to detect if condition was ever true, select accordingly.
5114 VPValue *Sentinel = Plan.getConstantInt(*SentinelVal);
5115 auto *Cmp = MiddleBuilder.createICmp(CmpInst::ICMP_NE, ReducedIV,
5116 Sentinel, ExitDL);
5117 NewRdxResult = MiddleBuilder.createSelect(Cmp, VectorRegionExitingVal,
5118 StartVPV, ExitDL);
5119 StartVPV = Sentinel;
5120 } else {
5121 // Introduce a boolean AnyOf reduction to track if the condition was ever
5122 // true in the loop. Use it to select the initial start value, if it was
5123 // never true.
5124 auto *AnyOfPhi = new VPReductionPHIRecipe(
5125 /*Phi=*/nullptr, RecurKind::Or, *Plan.getFalse(), *Plan.getFalse(),
5126 RdxUnordered{1}, {}, /*HasUsesOutsideReductionChain=*/false);
5127 AnyOfPhi->insertAfter(PhiR);
5128
5129 VPBuilder LoopBuilder(BackedgeVal->getDefiningRecipe());
5130 VPValue *OrVal = LoopBuilder.createOr(AnyOfPhi, SelectCond);
5131 AnyOfPhi->setOperand(1, OrVal);
5132
5133 NewRdxResult = MiddleBuilder.createAnyOfReduction(
5134 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
5135
5136 // Initialize the IV reduction phi with the neutral element, not the
5137 // original start value, to ensure correct min/max reduction results.
5138 StartVPV = Plan.getOrAddLiveIn(
5139 getRecurrenceIdentity(MinMaxKind, IVSCEV->getType(), {}));
5140 }
5141 RdxResult->replaceAllUsesWith(NewRdxResult);
5142 RdxResult->eraseFromParent();
5143
5144 auto *NewPhiR = new VPReductionPHIRecipe(
5145 cast<PHINode>(PhiR->getUnderlyingInstr()), RecurKind::FindIV, *StartVPV,
5146 *NewFindLastSelect, RdxUnordered{1}, {},
5147 PhiR->hasUsesOutsideReductionChain());
5148 if (SunkExpression)
5149 NewPhiR->setExpressionSunk();
5150 NewPhiR->insertBefore(PhiR);
5151 PhiR->replaceAllUsesWith(NewPhiR);
5152 PhiR->eraseFromParent();
5153 }
5154}
5155
5156namespace {
5157
5158struct ReductionExtend {
5159 Type *SrcType = nullptr;
5160 ExtendKind Kind = ExtendKind::PR_None;
5161};
5162
5163/// Describes the extends used to compute the extended reduction operand.
5164/// ExtendB is optional. If ExtendB is present, ExtendsUser is a binary
5165/// operation.
5166struct ExtendedReductionOperand {
5167 /// The recipe that consumes the extends.
5168 VPWidenRecipe *ExtendsUser = nullptr;
5169 /// Extend descriptions (inputs to getPartialReductionCost).
5170 ReductionExtend ExtendA, ExtendB;
5171};
5172
5173/// A collection of recipes that describe a partial reduction. Matches either
5174/// reduction_bin_op (extended op, accumulator), or
5175/// reduction_bin_op (accumulator, extended op).
5176/// The possible forms of the "extended op" are listed in
5177/// matchExtendedReductionOperand.
5178struct PartialReductionDescriptor {
5179 /// The top-level binary operation that forms the reduction to a scalar
5180 /// after the loop body.
5181 VPWidenRecipe *ReductionBinOp = nullptr;
5182 /// The user of the extends that is then reduced.
5183 ExtendedReductionOperand ExtendedOp;
5184 /// The recurrence kind for the entire partial reduction chain.
5185 /// This allows distinguishing between Sub and AddWithSub recurrences,
5186 /// when the ReductionBinOp is a Instruction::Sub.
5187 RecurKind RK;
5188 /// The index of the accumulator operand of ReductionBinOp. The extended op
5189 /// is `1 - AccumulatorOpIdx`.
5190 unsigned AccumulatorOpIdx;
5191 unsigned ScaleFactor;
5192 /// Optional blend to represent predication for the block that updates the
5193 /// reduction.
5194 VPBlendRecipe *Blend = nullptr;
5195};
5196
5197// Return the incoming index of the single-use value in the blend, which is
5198// expected to be the predicated reduction update.
5199static std::optional<unsigned>
5200getBlendReductionUpdateValueIdx(VPBlendRecipe *Blend) {
5201 assert(Blend && !Blend->isNormalized() &&
5202 Blend->getNumIncomingValues() == 2 &&
5203 "Expected a non-normalized blend with two incoming values");
5204 bool FirstIncomingHasOneUse = Blend->getIncomingValue(0)->hasOneUse();
5205
5206 // Only the update value should have one use (the blend). The previous
5207 // value should always have at least two uses, the blend and the reduction.
5208 if (FirstIncomingHasOneUse == Blend->getIncomingValue(1)->hasOneUse())
5209 return std::nullopt;
5210 return FirstIncomingHasOneUse ? 0 : 1;
5211}
5212
5213static VPSingleDefRecipe *
5214optimizeExtendsForPartialReduction(VPSingleDefRecipe *Op) {
5215 // reduce.add(mul(ext(A), C))
5216 // -> reduce.add(mul(ext(A), ext(trunc(C))))
5217 const APInt *Const;
5218 if (match(Op, m_Mul(m_ZExtOrSExt(m_VPValue()), m_APInt(Const)))) {
5219 auto *ExtA = cast<VPWidenCastRecipe>(Op->getOperand(0));
5220 Instruction::CastOps ExtOpc = ExtA->getOpcode();
5221 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
5222 if (!Op->hasOneUse() ||
5224 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
5225 return Op;
5226
5227 VPBuilder Builder(Op);
5228 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
5229 Op->getOperand(1), NarrowTy);
5230 Type *WideTy = ExtA->getScalarType();
5231 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
5232 return Op;
5233 }
5234
5235 // reduce.add(abs(sub(ext(A), ext(B))))
5236 // -> reduce.add(ext(absolute-difference(A, B)))
5237 VPValue *X, *Y;
5240 auto *Sub = Op->getOperand(0)->getDefiningRecipe();
5241 auto *Ext = cast<VPWidenCastRecipe>(Sub->getOperand(0));
5242 assert(Ext->getOpcode() ==
5243 cast<VPWidenCastRecipe>(Sub->getOperand(1))->getOpcode() &&
5244 "Expected both the LHS and RHS extends to be the same");
5245 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
5246 VPBuilder Builder(Op);
5247 Type *SrcTy = X->getScalarType();
5248 auto *FreezeX = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {X}));
5249 auto *FreezeY = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {Y}));
5250 auto *Max = Builder.insert(
5251 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smax : Intrinsic::umax,
5252 {FreezeX, FreezeY}, SrcTy));
5253 auto *Min = Builder.insert(
5254 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smin : Intrinsic::umin,
5255 {FreezeX, FreezeY}, SrcTy));
5256 auto *AbsDiff = Builder.insert(
5257 new VPWidenRecipe(Instruction::Sub, {Max, Min},
5258 VPIRFlags::getDefaultFlags(Instruction::Sub)));
5259 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
5260 Op->getScalarType());
5261 }
5262
5263 // reduce.add(ext(mul(ext(A), ext(B))))
5264 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
5265 // TODO: Support this optimization for float types.
5267 m_ZExtOrSExt(m_VPValue()))))) {
5268 auto *Ext = cast<VPWidenCastRecipe>(Op);
5269 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
5270 auto *MulLHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5271 auto *MulRHS = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5272 assert(Mul->hasOneUse() && Ext->getOpcode() == MulLHS->getOpcode() &&
5273 MulLHS->getOpcode() == MulRHS->getOpcode() &&
5275 "Expected the outer extend to be foldable");
5276 VPBuilder Builder(Mul);
5277 auto *NewLHS = Builder.createWidenCast(
5278 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
5279 auto *NewRHS = MulLHS == MulRHS
5280 ? NewLHS
5281 : Builder.createWidenCast(MulRHS->getOpcode(),
5282 MulRHS->getOperand(0),
5283 Ext->getScalarType());
5284 auto *NewMul = Mul->cloneWithOperands({NewLHS, NewRHS});
5285 Builder.insert(NewMul);
5286 Op->replaceAllUsesWith(NewMul);
5287 Op->eraseFromParent();
5288 Mul->eraseFromParent();
5289 return NewMul;
5290 }
5291
5292 return Op;
5293}
5294
5295static VPExpressionRecipe *
5296createPartialReductionExpression(VPReductionRecipe *Red) {
5297 VPValue *VecOp = Red->getVecOp();
5298
5299 // reduce.[f]add(ext(op))
5300 // -> VPExpressionRecipe(op, red)
5301 if (match(VecOp, m_WidenAnyExtend(m_VPValue())))
5302 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
5303
5304 // reduce.[f]add(neg(ext(op)))
5305 // -> VPExpressionRecipe(op, sub/neg, red)
5306 if (match(VecOp, m_AnyNeg(m_WidenAnyExtend(m_VPValue())))) {
5307 auto *Neg = cast<VPWidenRecipe>(VecOp);
5308 auto *Ext = cast<VPWidenCastRecipe>(Neg->getLastOperand());
5309 return new VPExpressionRecipe(Ext, Neg, Red);
5310 }
5311
5312 // reduce.[f]add([f]mul(ext(a), ext(b)))
5313 // -> VPExpressionRecipe(a, b, mul, red)
5314 if (match(VecOp, m_FMul(m_FPExt(m_VPValue()), m_FPExt(m_VPValue()))) ||
5315 match(VecOp,
5317 auto *Mul = cast<VPWidenRecipe>(VecOp);
5318 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5319 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5320 return new VPExpressionRecipe(ExtA, ExtB, Mul, Red);
5321 }
5322
5323 // reduce.fadd(fneg(fmul(fpext(a), fpext(b))))
5324 // -> VPExpressionRecipe(a, b, fmul, fsub, red)
5325 if (match(VecOp,
5327 auto *FNeg = cast<VPWidenRecipe>(VecOp);
5328 auto *FMul = cast<VPWidenRecipe>(FNeg->getOperand(0));
5329 auto *ExtA = cast<VPWidenCastRecipe>(FMul->getOperand(0));
5330 auto *ExtB = cast<VPWidenCastRecipe>(FMul->getOperand(1));
5331 return new VPExpressionRecipe(ExtA, ExtB, FMul, FNeg, Red);
5332 }
5333
5334 // reduce.add(neg(mul(ext(a), ext(b))))
5335 // -> VPExpressionRecipe(a, b, mul, sub, red)
5337 m_ZExtOrSExt(m_VPValue()))))) {
5338 auto *Sub = cast<VPWidenRecipe>(VecOp);
5339 auto *Mul = cast<VPWidenRecipe>(Sub->getOperand(1));
5340 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5341 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5342 return new VPExpressionRecipe(ExtA, ExtB, Mul, Sub, Red);
5343 }
5344
5345 llvm_unreachable("Unsupported expression");
5346}
5347
5348// Helper to transform a PartialReductionDescriptor into a partial reduction
5349// recipe. Assumes profitability has been checked.
5350static void transformToPartialReduction(const PartialReductionDescriptor &Link,
5351 VPlan &Plan,
5352 VPReductionPHIRecipe *RdxPhi) {
5353 VPWidenRecipe *WidenRecipe = Link.ReductionBinOp;
5354 assert(WidenRecipe->getNumOperands() == 2 && "Expected binary operation");
5355
5356 VPValue *Accumulator = WidenRecipe->getOperand(Link.AccumulatorOpIdx);
5357 auto *ExtendedOp = cast<VPSingleDefRecipe>(
5358 WidenRecipe->getOperand(1 - Link.AccumulatorOpIdx));
5359
5360 // FIXME: Do these transforms before invoking the cost-model.
5361 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
5362
5363 // Sub-reductions can be implemented in two ways:
5364 // (1) negate the operand in the vector loop (the default way).
5365 // (2) subtract the reduced value from the init value in the middle block.
5366 // Both ways keep the reduction itself as an 'add' reduction.
5367 //
5368 // The ISD nodes for partial reductions don't support folding the
5369 // sub/negation into its operands because the following is not a valid
5370 // transformation:
5371 // sub(0, mul(ext(a), ext(b)))
5372 // -> mul(ext(a), ext(sub(0, b)))
5373 //
5374 // It's therefore better to choose option (2) such that the partial
5375 // reduction is always positive (starting at '0') and to do a final
5376 // subtract in the middle block.
5377 if ((WidenRecipe->getOpcode() == Instruction::Sub &&
5378 Link.RK != RecurKind::Sub) ||
5379 (WidenRecipe->getOpcode() == Instruction::FSub &&
5380 Link.RK != RecurKind::FSub)) {
5381 VPBuilder Builder(WidenRecipe);
5382 Type *ElemTy = ExtendedOp->getScalarType();
5383 VPWidenRecipe *NegRecipe;
5384 if (WidenRecipe->getOpcode() == Instruction::FSub) {
5385 NegRecipe =
5386 new VPWidenRecipe(Instruction::FNeg, {ExtendedOp},
5387 VPIRFlags::getDefaultFlags(Instruction::FNeg),
5389 } else {
5390 auto *Zero = Plan.getZero(ElemTy);
5391 NegRecipe =
5392 new VPWidenRecipe(Instruction::Sub, {Zero, ExtendedOp},
5393 VPIRFlags::getDefaultFlags(Instruction::Sub),
5395 }
5396 Builder.insert(NegRecipe);
5397 ExtendedOp = NegRecipe;
5398 }
5399
5400 // Check if WidenRecipe is the final result of the reduction. If so, look
5401 // through the Select recipe introduced by tail-folding, otherwise look
5402 // through any Blend recipe introduced by predication for the block.
5403 VPValue *ExitSearch =
5404 Link.Blend ? cast<VPValue>(Link.Blend) : cast<VPValue>(WidenRecipe);
5405
5406 VPValue *Cond = nullptr;
5408 ExitSearch,
5409 m_Select(m_VPValue(Cond), m_Specific(ExitSearch), m_Specific(RdxPhi)));
5410
5411 if (Link.Blend) {
5412 std::optional<unsigned> BlendReductionIdx =
5413 getBlendReductionUpdateValueIdx(Link.Blend);
5414 assert(BlendReductionIdx &&
5415 Link.Blend->getIncomingValue(*BlendReductionIdx) == WidenRecipe &&
5416 "Expected blend to contain the reduction update");
5417 VPValue *BlendCond = Link.Blend->getMask(*BlendReductionIdx);
5418 Cond = ExitValue ? VPBuilder(WidenRecipe)
5419 .createLogicalAnd(Cond, BlendCond,
5420 WidenRecipe->getDebugLoc())
5421 : BlendCond;
5422 }
5423
5424 // When folding the tail, the inactive lanes of the reduction update are
5425 // computed from values that do not correspond to any scalar iteration
5426 // and must not be accumulated.
5427 if (!Cond)
5429
5430 [[maybe_unused]] bool IsLastInChain =
5431 RdxPhi->getBackedgeValue() == WidenRecipe ||
5432 RdxPhi->getBackedgeValue() == ExitValue ||
5433 RdxPhi->getBackedgeValue() == Link.Blend;
5434 assert((!ExitValue || IsLastInChain) &&
5435 "if we found ExitValue, it must match RdxPhi's backedge value");
5436
5437 Type *PhiType = RdxPhi->getScalarType();
5438 RecurKind RdxKind =
5440 auto *PartialRed = new VPReductionRecipe(
5441 RdxKind,
5442 RdxKind == RecurKind::FAdd ? WidenRecipe->getFastMathFlagsOrNone()
5443 : FastMathFlags(),
5444 WidenRecipe->getUnderlyingInstr(), Accumulator, ExtendedOp, Cond,
5445 RdxUnordered{/*VFScaleFactor=*/Link.ScaleFactor});
5446 PartialRed->insertBefore(WidenRecipe);
5447
5448 if (ExitValue)
5449 ExitValue->replaceAllUsesWith(PartialRed);
5450 if (Link.Blend)
5451 Link.Blend->replaceAllUsesWith(PartialRed);
5452 WidenRecipe->replaceAllUsesWith(PartialRed);
5453
5454 // For cost-model purposes, fold this into a VPExpression.
5455 VPExpressionRecipe *E = createPartialReductionExpression(PartialRed);
5456 E->insertBefore(WidenRecipe);
5457 PartialRed->replaceAllUsesWith(E);
5458}
5459
5460/// Returns the cost of a link in a partial-reduction chain for a given VF.
5461static InstructionCost
5462getPartialReductionLinkCost(VPCostContext &CostCtx,
5463 const PartialReductionDescriptor &Link,
5464 ElementCount VF) {
5465 Type *RdxType = Link.ReductionBinOp->getScalarType();
5466 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5467 std::optional<unsigned> BinOpc = std::nullopt;
5468 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
5469 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5470 BinOpc = ExtendedOp.ExtendsUser->getOpcode();
5471
5472 std::optional<llvm::FastMathFlags> Flags;
5473 if (RdxType->isFloatingPointTy())
5474 Flags = Link.ReductionBinOp->getFastMathFlagsOrNone();
5475
5476 auto GetLinkOpcode = [&Link]() -> unsigned {
5477 switch (Link.RK) {
5478 case RecurKind::Sub:
5479 return Instruction::Add;
5480 case RecurKind::FSub:
5481 return Instruction::FAdd;
5482 default:
5483 return Link.ReductionBinOp->getOpcode();
5484 }
5485 };
5486
5487 return CostCtx.TTI.getPartialReductionCost(
5488 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
5489 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
5490 CostCtx.CostKind, Flags);
5491}
5492
5493/// Checks if \p Op (which is an operand of \p UpdateR) is an extended reduction
5494/// operand. This is an operand where the source of the value (e.g. a load) has
5495/// been extended (sext, zext, or fpext) before it is used in the reduction.
5496///
5497/// Possible forms matched by this function:
5498/// - UpdateR(PrevValue, ext(...))
5499/// - UpdateR(PrevValue, mul(ext(...), ext(...)))
5500/// - UpdateR(PrevValue, mul(ext(...), Constant))
5501/// - UpdateR(PrevValue, ext(mul(ext(...), ext(...))))
5502/// - UpdateR(PrevValue, ext(mul(ext(...), Constant)))
5503/// - UpdateR(PrevValue, abs(sub(ext(...), ext(...)))
5504///
5505/// Note: The second operand of UpdateR corresponds to \p Op in the examples.
5506static std::optional<ExtendedReductionOperand>
5507matchExtendedReductionOperand(VPWidenRecipe *UpdateR, VPValue *Op) {
5508 assert(is_contained(UpdateR->operands(), Op) &&
5509 "Op should be operand of UpdateR");
5510
5511 // Try matching an absolute difference operand of the form
5512 // `abs(sub(ext(A), ext(B)))`. This will be later transformed into
5513 // `ext(absolute-difference(A, B))`. This allows us to perform the absolute
5514 // difference on a wider type and get the extend for "free" from the partial
5515 // reduction.
5516 VPValue *X, *Y;
5517 if (Op->hasOneUse() &&
5521 auto *Abs = cast<VPWidenIntrinsicRecipe>(Op);
5522 auto *Sub = cast<VPWidenRecipe>(Abs->getOperand(0));
5523 auto *LHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(0));
5524 auto *RHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(1));
5525 Type *LHSInputType = X->getScalarType();
5526 Type *RHSInputType = Y->getScalarType();
5527 if (LHSInputType != RHSInputType ||
5528 LHSExt->getOpcode() != RHSExt->getOpcode())
5529 return std::nullopt;
5530 // Note: This is essentially the same as matching ext(...) as we will
5531 // rewrite this operand to ext(absolute-difference(A, B)).
5532 return ExtendedReductionOperand{
5533 Sub,
5534 /*ExtendA=*/{LHSInputType, getPartialReductionExtendKind(LHSExt)},
5535 /*ExtendB=*/{}};
5536 }
5537
5538 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
5540 auto *CastRecipe = cast<VPWidenCastRecipe>(Op);
5541 VPValue *CastSource = CastRecipe->getOperand(0);
5542 OuterExtKind = getPartialReductionExtendKind(CastRecipe);
5543 if (match(CastSource, m_Mul(m_VPValue(), m_VPValue())) ||
5544 match(CastSource, m_FMul(m_VPValue(), m_VPValue()))) {
5545 // Match: ext(mul(...))
5546 // Record the outer extend kind and set `Op` to the mul. We can then match
5547 // this as a binary operation. Note: We can optimize out the outer extend
5548 // by widening the inner extends to match it. See
5549 // optimizeExtendsForPartialReduction.
5550 Op = CastSource;
5551 } else {
5552 return ExtendedReductionOperand{
5553 UpdateR,
5554 /*ExtendA=*/{CastSource->getScalarType(), *OuterExtKind},
5555 /*ExtendB=*/{}};
5556 }
5557 }
5558
5559 if (!Op->hasOneUse())
5560 return std::nullopt;
5561
5563 if (!MulOp ||
5564 !is_contained({Instruction::Mul, Instruction::FMul}, MulOp->getOpcode()))
5565 return std::nullopt;
5566
5567 // The rest of the matching assumes `Op` is a (possibly extended) mul
5568 // operation.
5569
5570 VPValue *LHS = MulOp->getOperand(0);
5571 VPValue *RHS = MulOp->getOperand(1);
5572
5573 // The LHS of the operation must always be an extend.
5575 return std::nullopt;
5576
5577 auto *LHSCast = cast<VPWidenCastRecipe>(LHS);
5578 Type *LHSInputType = LHSCast->getOperand(0)->getScalarType();
5579 ExtendKind LHSExtendKind = getPartialReductionExtendKind(LHSCast);
5580
5581 // The RHS of the operation can be an extend or a constant integer.
5582 const APInt *RHSConst = nullptr;
5583 VPWidenCastRecipe *RHSCast = nullptr;
5585 RHSCast = cast<VPWidenCastRecipe>(RHS);
5586 else if (!match(RHS, m_APInt(RHSConst)) ||
5587 !canConstantBeExtended(RHSConst, LHSInputType, LHSExtendKind))
5588 return std::nullopt;
5589
5590 // The outer extend kind must match the inner extends for folding.
5591 for (VPWidenCastRecipe *Cast : {LHSCast, RHSCast})
5592 if (Cast && OuterExtKind &&
5593 getPartialReductionExtendKind(Cast) != OuterExtKind)
5594 return std::nullopt;
5595
5596 Type *RHSInputType = LHSInputType;
5597 ExtendKind RHSExtendKind = LHSExtendKind;
5598 if (RHSCast) {
5599 RHSInputType = RHSCast->getOperand(0)->getScalarType();
5600 RHSExtendKind = getPartialReductionExtendKind(RHSCast);
5601 }
5602
5603 // The outer extend can only be treated as extending the operands of the mul
5604 // if the narrow mul cannot wrap.
5605 if (OuterExtKind && MulOp->getOpcode() == Instruction::Mul &&
5607 return std::nullopt;
5608
5609 return ExtendedReductionOperand{
5610 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
5611}
5612
5613/// Examines each operation in the reduction chain corresponding to \p RedPhiR,
5614/// and determines if the target can use a cheaper operation with a wider
5615/// per-iteration input VF and narrower PHI VF. If successful, returns the chain
5616/// of partial reduction descriptors (that are links in the reduction chain).
5617static std::optional<SmallVector<PartialReductionDescriptor>>
5618getScaledReductionChain(VPReductionPHIRecipe *RedPhiR) {
5619 // Get the backedge value from the reduction PHI and find the
5620 // ComputeReductionResult that uses it (directly or through a select for
5621 // predicated reductions).
5622 auto *RdxResult = vputils::findComputeReductionResult(RedPhiR);
5623 if (!RdxResult)
5624 return std::nullopt;
5625 VPValue *ExitValue = RdxResult->getOperand(0);
5626 match(ExitValue, m_Select(m_VPValue(), m_VPValue(ExitValue), m_VPValue()));
5627
5629 RecurKind RK = RedPhiR->getRecurrenceKind();
5630 Type *PhiType = RedPhiR->getScalarType();
5631 TypeSize PHISize = PhiType->getPrimitiveSizeInBits();
5632
5633 // Work backwards from the ExitValue examining each reduction operation.
5634 VPValue *CurrentValue = ExitValue;
5635 while (CurrentValue != RedPhiR) {
5636 VPBlendRecipe *Blend = dyn_cast<VPBlendRecipe>(CurrentValue);
5637 std::optional<unsigned> BlendReductionIdx;
5638 if (Blend) {
5639 assert(!Blend->isNormalized() && "Expect Blend not to be normalized.");
5640 if (Blend->getNumIncomingValues() != 2)
5641 return std::nullopt;
5642
5643 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
5644 if (!BlendReductionIdx)
5645 return std::nullopt;
5646
5647 CurrentValue = Blend->getIncomingValue(*BlendReductionIdx);
5648 }
5649
5650 auto *UpdateR = dyn_cast<VPWidenRecipe>(CurrentValue);
5651 if (!UpdateR || !Instruction::isBinaryOp(UpdateR->getOpcode()))
5652 return std::nullopt;
5653
5654 VPValue *Op = UpdateR->getOperand(1);
5655 VPValue *PrevValue = UpdateR->getOperand(0);
5656
5657 // Find the extended operand. The other operand (PrevValue) is the next link
5658 // in the reduction chain.
5659 std::optional<ExtendedReductionOperand> ExtendedOp =
5660 matchExtendedReductionOperand(UpdateR, Op);
5661 if (!ExtendedOp) {
5662 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
5663 if (!ExtendedOp)
5664 return std::nullopt;
5665 std::swap(Op, PrevValue);
5666 }
5667
5668 // Look for VPBlend(reduce(PrevValue, Op), PrevValue), where
5669 // reduce is equal to CurrentValue. This can be lowered as
5670 // a conditional reduction by hoisting the select to the inputs.
5671 if (Blend && Blend->getIncomingValue(1 - *BlendReductionIdx) != PrevValue)
5672 return std::nullopt;
5673
5674 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
5675 TypeSize ExtSrcSize = ExtSrcType->getPrimitiveSizeInBits();
5676 if (!PHISize.hasKnownScalarFactor(ExtSrcSize))
5677 return std::nullopt;
5678
5679 PartialReductionDescriptor Link(
5680 {UpdateR, *ExtendedOp, RK,
5681 PrevValue == UpdateR->getOperand(0) ? 0U : 1U,
5682 static_cast<unsigned>(PHISize.getKnownScalarFactor(ExtSrcSize)),
5683 Blend});
5684 Chain.push_back(Link);
5685 CurrentValue = PrevValue;
5686 }
5687
5688 // The chain links were collected by traversing backwards from the exit value.
5689 // Reverse the chain so the links follow program order.
5690 std::reverse(Chain.begin(), Chain.end());
5691 return Chain;
5692}
5693} // namespace
5694
5695// Scale the PHI and ReductionStartVector by \p Factor and if the recurrence is
5696// a sub-recurrence, negate the reduction result.
5699 unsigned Factor, RecurKind RK) {
5700 assert(Phi->getVFScaleFactor() == 1 && "scale factor must not be set");
5701 Phi->setVFScaleFactor(Factor);
5702
5703 auto *StartInst = cast<VPInstruction>(Phi->getStartValue());
5704 assert(StartInst->getOpcode() == VPInstruction::ReductionStartVector);
5705 auto *NewScaleFactor = Plan.getConstantInt(32, Factor);
5706 StartInst->setOperand(2, NewScaleFactor);
5707
5708 if (RK != RecurKind::Sub && RK != RecurKind::FSub)
5709 return;
5710
5711 // Update the PHI node to start at `0` and update the reduction-result
5712 // to subtract from the PHI's start value.
5713 VPValue *OldStartValue = StartInst->getOperand(0);
5714 StartInst->setOperand(0, StartInst->getOperand(1));
5715
5716 // Replace reduction_result by 'sub (startval, reductionresult)'.
5718 assert(RdxResult && "Could not find reduction result");
5719
5720 VPBuilder Builder = VPBuilder::getToInsertAfter(RdxResult);
5721 unsigned SubOpc = RK == RecurKind::FSub ? Instruction::BinaryOps::FSub
5722 : Instruction::BinaryOps::Sub;
5723 VPInstruction *NewResult = Builder.createNaryOp(
5724 SubOpc, {OldStartValue, RdxResult}, VPIRFlags::getDefaultFlags(SubOpc),
5725 Phi->getDebugLoc());
5726 RdxResult->replaceUsesWithIf(NewResult, not_equal_to(NewResult));
5727}
5728
5730 VPCostContext &CostCtx,
5731 VFRange &Range) {
5732 // Find all possible valid partial reductions, grouping chains by their PHI.
5733 // This grouping allows invalidating the whole chain, if any link is not a
5734 // valid partial reduction.
5736 PhiToChain;
5737 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
5738 SmallVector<VPReductionPHIRecipe *, 4> UnorderedReductions;
5739 for (VPReductionPHIRecipe &RedPhiR :
5741 if (auto Chain = getScaledReductionChain(&RedPhiR))
5742 PhiToChain.try_emplace(&RedPhiR, std::move(*Chain));
5743 else if (CostCtx.Opts.use_partial_reductions_by_default &&
5744 (RedPhiR.getRecurrenceKind() == RecurKind::Add ||
5745 (RedPhiR.getRecurrenceKind() == RecurKind::FAdd &&
5746 !RedPhiR.isOrdered() && !RedPhiR.isInLoop())))
5747 UnorderedReductions.push_back(&RedPhiR);
5748 }
5749
5750 // For general unordered reductions which aren't part of a candidate chain for
5751 // a scaled partial reduction, we can still use the intrinsic to allow for
5752 // more optimization later on.
5753 for (auto *Rdx : UnorderedReductions) {
5754 auto *Backedge = dyn_cast<VPWidenRecipe>(Rdx->getBackedgeValue());
5755 VPValue *OtherOp;
5756 if (!Backedge ||
5757 !match(Backedge,
5758 m_CombineOr(m_c_FAdd(m_Specific(Rdx), m_VPValue(OtherOp)),
5759 m_c_Add(m_Specific(Rdx), m_VPValue(OtherOp)))))
5760 continue;
5761
5762 // If the target indicates that the intrinsic is as cheap as (or cheaper
5763 // than) the add, then prefer the intrinsic.
5765 [&CostCtx, Rdx, Backedge](ElementCount VF) {
5766 InstructionCost CurrentCost = Backedge->computeCost(VF, CostCtx);
5767 Type *ScalarTy = Backedge->getScalarType();
5768 auto FMF = ScalarTy->isFloatingPointTy()
5769 ? std::make_optional(Rdx->getFastMathFlagsOrNone())
5770 : std::nullopt;
5771
5773 Backedge->getOpcode(), ScalarTy, /*InputTypeB=*/nullptr,
5774 ScalarTy, VF, TTI::PR_None, TTI::PR_None,
5775 /*BinOp=*/std::nullopt, CostCtx.CostKind, FMF);
5776 return PRCost <= CurrentCost;
5777 },
5778 Range))
5779 continue;
5780
5781 auto *Partial = new VPReductionRecipe(
5782 Rdx->getRecurrenceKind(), Rdx->getFastMathFlagsOrNone(),
5783 Backedge->getUnderlyingInstr(), Rdx, OtherOp, nullptr,
5784 getReductionStyle(/*InLoop=*/false, /*Ordered=*/false,
5785 /*ScaleFactor=*/1));
5786 Partial->insertBefore(Backedge);
5787 Backedge->replaceAllUsesWith(Partial);
5788 Backedge->eraseFromParent();
5789 }
5790
5791 if (PhiToChain.empty())
5792 return;
5793
5794 // Build set of partial reduction operations and blends for user validation
5795 // and a map of reduction bin ops to their scale factors for scale validation.
5796 SmallPtrSet<VPRecipeBase *, 4> PartialReductionOps;
5797 SmallPtrSet<VPBlendRecipe *, 4> PartialReductionBlends;
5798 DenseMap<VPSingleDefRecipe *, unsigned> ScaledReductionMap;
5799 for (auto &[_, Chain] : PhiToChain)
5800 for (const PartialReductionDescriptor &Link : Chain) {
5801 PartialReductionOps.insert(Link.ExtendedOp.ExtendsUser);
5802 if (Link.Blend)
5803 PartialReductionBlends.insert(Link.Blend);
5804 ScaledReductionMap[Link.ReductionBinOp] = Link.ScaleFactor;
5805 }
5806
5807 // A partial reduction is invalid if any of its extends are used by
5808 // something that isn't another partial reduction. This is because the
5809 // extends are intended to be lowered along with the reduction itself.
5810 auto ExtendUsersValid = [&](VPValue *Ext) {
5811 return !isa<VPWidenCastRecipe>(Ext) || all_of(Ext->users(), [&](VPUser *U) {
5812 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
5813 });
5814 };
5815
5816 auto IsProfitablePartialReductionChainForVF =
5817 [&](ArrayRef<PartialReductionDescriptor> Chain, ElementCount VF) -> bool {
5818 InstructionCost PartialCost = 0, RegularCost = 0;
5819
5820 // The chain is a profitable partial reduction chain if the cost of handling
5821 // the entire chain is cheaper when using partial reductions than when
5822 // handling the entire chain using regular reductions.
5823 for (const PartialReductionDescriptor &Link : Chain) {
5824 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5825 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
5826 if (!LinkCost.isValid())
5827 return false;
5828
5829 PartialCost += LinkCost;
5830 RegularCost += Link.ReductionBinOp->computeCost(VF, CostCtx);
5831 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
5832 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5833 RegularCost += ExtendedOp.ExtendsUser->computeCost(VF, CostCtx);
5834 for (VPValue *Op : ExtendedOp.ExtendsUser->operands())
5835 if (auto *Extend = dyn_cast<VPWidenCastRecipe>(Op))
5836 RegularCost += Extend->computeCost(VF, CostCtx);
5837 }
5838 return PartialCost.isValid() && PartialCost < RegularCost;
5839 };
5840
5841 // Validate chains: check that extends are only used by partial reductions,
5842 // and that reduction bin ops are only used by other partial reductions with
5843 // matching scale factors, are outside the loop region or the select
5844 // introduced by tail-folding. Otherwise we would create users of scaled
5845 // reductions where the types of the other operands don't match.
5846 for (auto &[RedPhiR, Chain] : PhiToChain) {
5847 for (const PartialReductionDescriptor &Link : Chain) {
5848 if (!all_of(Link.ExtendedOp.ExtendsUser->operands(), ExtendUsersValid)) {
5849 Chain.clear();
5850 break;
5851 }
5852 auto UseIsValid = [&, RedPhiR = RedPhiR](VPUser *U) {
5853 if (auto *PhiR = dyn_cast<VPReductionPHIRecipe>(U))
5854 return PhiR == RedPhiR;
5855 auto *R = cast<VPSingleDefRecipe>(U);
5856
5857 if (auto *Blend = dyn_cast<VPBlendRecipe>(R))
5858 return Blend == Link.Blend || PartialReductionBlends.contains(Blend);
5859
5860 return Link.ScaleFactor == ScaledReductionMap.lookup_or(R, 0) ||
5862 m_Specific(Link.ReductionBinOp))) ||
5863 match(R, m_Select(m_VPValue(), m_Specific(Link.ReductionBinOp),
5864 m_Specific(RedPhiR)));
5865 };
5866 if (!all_of(Link.ReductionBinOp->users(), UseIsValid)) {
5867 Chain.clear();
5868 break;
5869 }
5870
5871 // Check if the compute-reduction-result is used by a sunk store.
5872 // TODO: Also form partial reductions in those cases.
5873 if (auto *RdxResult = vputils::findComputeReductionResult(RedPhiR)) {
5874 if (any_of(RdxResult->users(), [](VPUser *U) {
5875 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
5876 return RepR && RepR->getOpcode() == Instruction::Store;
5877 })) {
5878 Chain.clear();
5879 break;
5880 }
5881 }
5882 }
5883
5884 // Clear the chain if it is not profitable.
5886 [&, &Chain = Chain](ElementCount VF) {
5887 return IsProfitablePartialReductionChainForVF(Chain, VF);
5888 },
5889 Range))
5890 Chain.clear();
5891 }
5892
5893 for (auto &[Phi, Chain] : PhiToChain) {
5894 if (Chain.empty())
5895 continue;
5896
5897 for (const PartialReductionDescriptor &Link : Chain)
5898 transformToPartialReduction(Link, Plan, Phi);
5899
5900 // After transforming all links in the chain, the PHI node and result need
5901 // updating. Note that we can pick any link in the chain for this, as the
5902 // ScaleFactor and RecurKind must match for all links in the chain.
5903 const PartialReductionDescriptor &Link = Chain[0];
5904 updatePartialReductionPhiAndResult(Plan, Phi, Link.ScaleFactor, Link.RK);
5905 }
5906}
5907
5909 VPRecipeBuilder &RecipeBuilder,
5910 VPCostContext &CostCtx) {
5911 // Collect all loads/stores first. We will start with ones having simpler
5912 // decisions followed by more complex ones that are potentially
5913 // guided/dependent on the simpler ones.
5915 for (VPBasicBlock *VPBB :
5918 for (VPInstruction &VPI : make_isa_range<VPInstruction>(*VPBB)) {
5919 if (VPI.getUnderlyingValue() &&
5920 is_contained({Instruction::Load, Instruction::Store},
5921 VPI.getOpcode()))
5922 MemOps.push_back(&VPI);
5923 }
5924 }
5925
5926 // Few helpers to process different kinds of memory operations.
5927
5928 // To be used as argument to `VPlanTransforms::runPass` which explicitly
5929 // specified pass name, hence `VPlan &` parameter.
5930 auto ProcessSubset = [&](VPlan &, auto ProcessVPInst) {
5931 SmallVector<VPInstruction *> RemainingMemOps;
5932 for (VPInstruction *VPI : MemOps) {
5933 if (!ProcessVPInst(VPI))
5934 RemainingMemOps.push_back(VPI);
5935 }
5936
5937 MemOps.clear();
5938 std::swap(MemOps, RemainingMemOps);
5939 };
5940
5941 auto ReplaceWith = [&](VPInstruction *VPI, VPRecipeBase *New) {
5942 assert(New->getParent() && "New recipe must have been inserted");
5943 if (VPI->getOpcode() == Instruction::Load)
5944 VPI->replaceAllUsesWith(New->getVPSingleValue());
5945 VPI->eraseFromParent();
5946
5947 // VPI has been processed.
5948 return true;
5949 };
5950
5951 auto Scalarize = [&](VPInstruction *VPI) {
5952 return ReplaceWith(VPI, VPBuilder(VPI).insert(
5953 RecipeBuilder.handleReplication(VPI, Range)));
5954 };
5955
5956 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
5957 VPBuilder FinalRedStoresBuilder(MiddleVPBB->getFirstNonPhi());
5959 "lowerMemoryIdioms", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5960 if (RecipeBuilder.replaceWithFinalIfReductionStore(
5961 VPI, FinalRedStoresBuilder))
5962 return true;
5963
5964 // Filter out scalar VPlan for the remaining idioms.
5966 [](ElementCount VF) { return VF.isScalar(); }, Range))
5967 return false;
5968
5969 if (VPHistogramRecipe *Histogram = RecipeBuilder.widenIfHistogram(VPI))
5970 return ReplaceWith(VPI, VPBuilder(VPI).insert(Histogram));
5971
5972 return false;
5973 });
5974
5975 // Filter out scalar VPlan for the remaining memory operations.
5977 [](ElementCount VF) { return VF.isScalar(); }, Range))
5978 return;
5979
5980 // If the instruction's allocated size doesn't equal it's type size, it
5981 // requires padding and will be scalarized.
5983 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
5984 [&](VPInstruction *VPI) {
5986 if (hasIrregularType(getLoadStoreType(I), I->getDataLayout()))
5987 return Scalarize(VPI);
5988
5989 return false;
5990 });
5991
5992 if (!RecipeBuilder.prefersVectorizedAddressing()) {
5994 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5996 bool IsLoad = VPI->getOpcode() == Instruction::Load;
5997 if (RecipeBuilder.isPredicatedInst(I) || !IsLoad ||
5999 return false;
6000
6001 // Scalarize loads used as addresses, matching the legacy CM. The load
6002 // is single-scalar if the pointer is loop-invariant, otherwise it is
6003 // replicated per-lane. No mask is needed as the load is not
6004 // predicated.
6005 VPValue *Ptr = VPI->getOperand(0);
6006 const SCEV *PtrSCEV =
6007 vputils::getSCEVExprForVPValue(Ptr, CostCtx.PSE, CostCtx.L);
6008 bool IsSingleScalarLoad =
6009 !isa<SCEVCouldNotCompute>(PtrSCEV) &&
6010 CostCtx.PSE.getSE()->isLoopInvariant(PtrSCEV, CostCtx.L);
6011
6012 ReplaceWith(VPI,
6013 VPBuilder(VPI).insert(new VPReplicateRecipe(
6014 I, Ptr, /*IsSingleScalar=*/IsSingleScalarLoad,
6015 /*Mask=*/nullptr, *VPI, *VPI, VPI->getDebugLoc())));
6016 return true;
6017 });
6018 }
6019
6020 // Widen unit-stride consecutive accesses, matching the legacy CM. Both
6021 // forward (stride +1) and reverse (stride -1) accesses are handled.
6023 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](VPInstruction *VPI) {
6025 bool IsLoad = VPI->getOpcode() == Instruction::Load;
6026 VPValue *Ptr = VPI->getOperand(!IsLoad);
6027 Type *ScalarTy =
6028 IsLoad ? VPI->getScalarType() : VPI->getOperand(0)->getScalarType();
6029 std::optional<int64_t> Stride =
6030 vputils::getConstantStride(Ptr, ScalarTy, CostCtx.PSE, CostCtx.L);
6031 if (Stride != 1 && Stride != -1)
6032 return false;
6033 bool Reverse = Stride == -1;
6034
6035 // A predicated access can only be widened (rather than scalarized) if
6036 // the target supports a masked load/store for it.
6037 // TODO: Determine if a load/store needs predication directly in VPlan.
6038 bool IsPredicated = RecipeBuilder.isPredicatedInst(I);
6039 Align Alignment = getLoadStoreAlignment(I);
6040 if (IsPredicated &&
6042 IsLoad, ScalarTy, Alignment, getLoadStoreAddressSpace(I)))
6043 return false;
6044
6045 VPBuilder Builder(VPI);
6046 VPSingleDefRecipe *VectorPtr = Builder.createConsecutiveVectorPointer(
6047 Ptr, ScalarTy, Reverse, VPI->getDebugLoc());
6048
6049 VPValue *Mask = IsPredicated ? VPI->getMask() : nullptr;
6050 // Reverse the mask so it matches the reversed access order.
6051 if (Reverse && Mask)
6052 Mask = Builder.createNaryOp(VPInstruction::Reverse, Mask,
6053 VPI->getDebugLoc());
6054
6055 if (IsLoad) {
6056 VPSingleDefRecipe *Load = Builder.createWidenLoad(
6057 *cast<LoadInst>(I), VectorPtr, Mask,
6058 /*Consecutive=*/true, Alignment, *VPI, VPI->getDebugLoc());
6059 // Reverse the loaded values back into program order.
6060 if (Reverse)
6061 Load = Builder.createNaryOp(VPInstruction::Reverse, Load,
6062 VPI->getDebugLoc());
6063 return ReplaceWith(VPI, Load);
6064 }
6065
6066 VPValue *StoredVal = VPI->getOperand(0);
6067 if (Reverse)
6068 // Reverse the stored values so they are written in descending order.
6069 StoredVal = Builder.createNaryOp(VPInstruction::Reverse, StoredVal,
6070 VPI->getDebugLoc());
6071
6072 auto *StoreR = Builder.createWidenStore(
6073 *cast<StoreInst>(I), VectorPtr, StoredVal, Mask,
6074 /*Consecutive=*/true, Alignment, *VPI, VPI->getDebugLoc());
6075 return ReplaceWith(VPI, StoreR);
6076 });
6077
6078 VPlanTransforms::runPass("delegateMemOpWideningToLegacyCM", ProcessSubset,
6079 Plan, [&](VPInstruction *VPI) {
6080 if (VPRecipeBase *Recipe =
6081 RecipeBuilder.tryToWidenMemory(VPI, Range))
6082 return ReplaceWith(VPI, Recipe);
6083
6084 return Scalarize(VPI);
6085 });
6086}
6087
6090 [&](ElementCount VF) { return VF.isScalar(); }, Range))
6091 return;
6092
6094 Plan.getEntry());
6096 for (VPInstruction &VPI :
6098 auto *I = cast_or_null<Instruction>(VPI.getUnderlyingValue());
6099 // Wouldn't be able to create a `VPReplicateRecipe` anyway.
6100 if (!I)
6101 continue;
6102
6103 // If executing other lanes produces side-effects we can't avoid them.
6104 if (VPI.mayHaveSideEffects())
6105 continue;
6106
6107 // ExtractValue takes the shape of its aggregate, decided in
6108 // tryToCreateWidenNonPhiRecipe.
6109 if (VPI.getOpcode() == Instruction::ExtractValue)
6110 continue;
6111
6112 // We want to drop the mask operand, verify we can safely do that.
6113 if (VPI.isMasked() && !VPI.isSafeToSpeculativelyExecute())
6114 continue;
6115
6116 // Other lanes are needed - can't drop them.
6117 if (!vputils::onlyFirstLaneUsed(&VPI))
6118 continue;
6119
6120 auto *Recipe = VPBuilder::createSingleScalarOp(
6121 VPI.getOpcode(), VPI.operandsWithoutMask(), /*Mask=*/nullptr, VPI,
6122 VPI, VPI.getDebugLoc(), VPI.getScalarType(), I);
6123 Recipe->insertBefore(&VPI);
6124 VPI.replaceAllUsesWith(Recipe);
6125 VPI.eraseFromParent();
6126 }
6127 }
6128}
6129
6130/// Returns true if \p Info's parameter kinds are compatible with \p Args.
6131static bool areVFParamsOk(const VFInfo &Info, ArrayRef<VPValue *> Args,
6132 PredicatedScalarEvolution &PSE, const Loop *L) {
6133 ScalarEvolution *SE = PSE.getSE();
6134 return all_of(Info.Shape.Parameters, [&](VFParameter Param) {
6135 switch (Param.ParamKind) {
6136 case VFParamKind::Vector:
6137 case VFParamKind::GlobalPredicate:
6138 return true;
6139 case VFParamKind::OMP_Uniform:
6140 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
6141 SE->isLoopInvariant(
6142 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6143 L);
6144 case VFParamKind::OMP_Linear:
6145 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6146 m_scev_AffineAddRec(
6147 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
6148 m_SpecificLoop(L)));
6149 default:
6150 return false;
6151 }
6152 });
6153}
6154
6155/// Find a vector variant of \p CI for \p VF, respecting \p MaskRequired.
6156/// Returns the variant function, or nullptr. Masked variants are assumed to
6157/// take the mask as a trailing parameter.
6159 ElementCount VF, bool MaskRequired,
6161 const Loop *L) {
6162 if (CI->isNoBuiltin())
6163 return nullptr;
6164 auto Mappings = VFDatabase::getMappings(*CI);
6165 const auto *It = find_if(Mappings, [&](const VFInfo &Info) {
6166 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
6167 areVFParamsOk(Info, Args, PSE, L);
6168 });
6169 if (It == Mappings.end())
6170 return nullptr;
6171 return CI->getModule()->getFunction(It->VectorName);
6172}
6173
6174namespace {
6175/// The outcome of choosing how to widen a call at a given VF.
6176struct CallWideningDecision {
6177 enum class KindTy { Scalarize, Intrinsic, VectorVariant };
6178 CallWideningDecision(KindTy Kind, Function *Variant = nullptr)
6179 : Kind(Kind), Variant(Variant) {}
6180 KindTy Kind;
6181
6182 /// Set when Kind == VectorVariant.
6184
6185 bool operator==(const CallWideningDecision &Other) const {
6186 return Kind == Other.Kind && Variant == Other.Variant;
6187 }
6188};
6189} // namespace
6190
6191/// Pick the cheapest widening for the call \p VPI at \p VF among scalarization,
6192/// vector intrinsic, and vector library variant.
6193static CallWideningDecision decideCallWidening(VPInstruction &VPI,
6195 ElementCount VF,
6196 VPCostContext &CostCtx) {
6197 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
6198
6199 // Scalar VFs and calls forced or known to scalarize always replicate.
6200 if (VF.isScalar() || CostCtx.willBeScalarized(CI, VF))
6201 return CallWideningDecision::KindTy::Scalarize;
6202
6203 auto *CalledFn = cast<Function>(
6205 Type *ResultTy = VPI.getScalarType();
6207 bool MaskRequired = CostCtx.isMaskRequired(CI);
6208
6209 // Pseudo intrinsics (assume, lifetime, ...) are always scalarized.
6211 return CallWideningDecision::KindTy::Scalarize;
6212
6213 InstructionCost ScalarCost =
6214 VPReplicateRecipe::computeCallCost(CalledFn, ResultTy, Ops,
6215 /*IsSingleScalar=*/false, VF, CostCtx);
6216
6217 Function *VecFunc =
6218 findVectorVariant(CI, Ops, VF, MaskRequired, CostCtx.PSE, CostCtx.L);
6220 if (VecFunc)
6221 VecCallCost = VPWidenCallRecipe::computeCallCost(VecFunc, CostCtx);
6222
6223 // Prefer the intrinsic if it is at least as cheap as scalarizing and any
6224 // available vector variant.
6225 if (ID) {
6227 VPWidenIntrinsicRecipe::computeCallCost(ID, Ops, VPI, VF, CostCtx);
6228 if (IntrinsicCost.isValid() && ScalarCost >= IntrinsicCost &&
6229 (!VecFunc || VecCallCost >= IntrinsicCost))
6230 return CallWideningDecision::KindTy::Intrinsic;
6231 }
6232
6233 // Otherwise, use a vector library variant when it beats scalarizing.
6234 if (VecFunc && ScalarCost >= VecCallCost)
6235 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
6236
6237 return CallWideningDecision::KindTy::Scalarize;
6238}
6239
6241 VPRecipeBuilder &RecipeBuilder,
6242 VPCostContext &CostCtx) {
6243 bool Widened = false;
6246 for (VPInstruction &VPI :
6248 if (!VPI.getUnderlyingValue() || VPI.getOpcode() != Instruction::Call)
6249 continue;
6250
6251 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
6252 SmallVector<VPValue *, 4> Ops(VPI.op_begin(),
6253 VPI.op_begin() + CI->arg_size());
6254
6255 CallWideningDecision Decision =
6256 decideCallWidening(VPI, Ops, Range.Start, CostCtx);
6258 [&](ElementCount VF) {
6259 return Decision == decideCallWidening(VPI, Ops, VF, CostCtx);
6260 },
6261 Range);
6262
6263 assert((Decision.Kind == CallWideningDecision::KindTy::Scalarize ||
6264 !CI->hasOperandBundles()) &&
6265 "calls with operand bundles must not be widened");
6266 VPSingleDefRecipe *Replacement = nullptr;
6267 switch (Decision.Kind) {
6268 case CallWideningDecision::KindTy::Intrinsic: {
6270 Type *ResultTy = VPI.getScalarType();
6271 Replacement = new VPWidenIntrinsicRecipe(*CI, ID, Ops, ResultTy, VPI,
6272 VPI, VPI.getDebugLoc());
6273 Widened = true;
6274 break;
6275 }
6276 case CallWideningDecision::KindTy::VectorVariant: {
6277 // Masked variants take the mask as a trailing parameter, so they have
6278 // one more parameter than the original call's arguments.
6279 if (Decision.Variant->arg_size() > Ops.size()) {
6280 VPValue *Mask = VPI.isMasked() ? VPI.getMask() : Plan.getTrue();
6281 Ops.push_back(Mask);
6282 }
6283 Ops.push_back(VPI.getOperand(VPI.getNumOperandsWithoutMask() - 1));
6284 VPIRAttributes Attrs(VPI, Decision.Variant->getFunctionType());
6285 Replacement = new VPWidenCallRecipe(CI, Decision.Variant, Ops, VPI, VPI,
6286 Attrs, VPI.getDebugLoc());
6287 Widened = true;
6288 break;
6289 }
6290 case CallWideningDecision::KindTy::Scalarize:
6291 Replacement = RecipeBuilder.handleReplication(&VPI, Range);
6292 break;
6293 }
6294
6295 Replacement->insertBefore(&VPI);
6296 VPI.replaceAllUsesWith(Replacement);
6297 VPI.eraseFromParent();
6298 }
6299 }
6300 return Widened;
6301}
6302
6304 const TargetTransformInfo &TTI,
6306 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
6307 VPBasicBlock *HeaderVPBB = LoopRegion->getEntryBasicBlock();
6309 vp_depth_first_shallow(LoopRegion->getEntry()))) {
6310 for (VPInstruction &VPI :
6312 // Only truncates are handled, as sext/zext may wrap, FP conversions lose
6313 // precision and other casts depend on the pointer size.
6314 if (VPI.getOpcode() != Instruction::Trunc)
6315 continue;
6316
6317 VPValue *Op = VPI.getOperand(0);
6318 auto *WideIV = getOptimizableIVOf(Op, PSE);
6319 if (!WideIV)
6320 continue;
6321
6322 // getOptimizableIVOf also matches an add of the IV and its step, which
6323 // is not handled here.
6324 // TODO: Also narrow truncates of the incremented IV.
6325 if (Op != WideIV)
6326 continue;
6327
6328 // A truncate that is not widened is left to the scalarization decisions
6329 // made earlier.
6331 continue;
6332
6333 // Replacing a free truncate would add an induction update instruction to
6334 // each iteration of the loop. The canonical induction is exempt, as it
6335 // needs an update instruction regardless.
6336 auto IsNarrowingProfitable = [&](ElementCount VF) {
6337 return match(WideIV, m_CanonicalWidenIV()) ||
6338 !TTI.isTruncateFree(
6339 toVectorTy(VPI.getOperand(0)->getScalarType(), VF),
6340 toVectorTy(VPI.getScalarType(), VF));
6341 };
6343 IsNarrowingProfitable, Range))
6344 continue;
6345
6346 // Wrap flags of the original induction do not hold in the truncated
6347 // type, so do not propagate them.
6348 auto *NarrowIV = new VPWidenIntOrFpInductionRecipe(
6349 WideIV->getPHINode(), WideIV->getStartValue(), WideIV->getStepValue(),
6350 WideIV->getVFValue(), WideIV->getInductionDescriptor(),
6351 VPI.getScalarType(), VPIRFlags::WrapFlagsTy(false, false),
6352 VPI.getDebugLoc());
6353 NarrowIV->insertBefore(HeaderVPBB->getFirstNonPhi());
6354 VPI.replaceAllUsesWith(NarrowIV);
6355 VPI.eraseFromParent();
6356 }
6357 }
6358}
6359
6362 Loop &L, VPCostContext &Ctx,
6363 VFRange &Range) {
6364 if (Plan.hasScalarVFOnly())
6365 return;
6366
6367 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
6368 VPValue *I32VF = nullptr;
6370 vp_depth_first_shallow(VectorLoop->getEntry()))) {
6371 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
6372 auto *MemR = dyn_cast<VPWidenMemoryRecipe>(&R);
6373 // TODO: Transform reverse access into strided access with -1 stride.
6374 // TODO: Transform gather/scatter with uniform address into strided access
6375 // with 0 stride.
6376 // TODO: Transform interleave access into multiple strided accesses.
6377 if (!MemR || MemR->isConsecutive())
6378 continue;
6379
6380 VPValue *Ptr = MemR->getAddr();
6381 // Check if this is a strided access by analyzing the address SCEV for an
6382 // affine addRec.
6383 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, &L);
6384 const SCEV *Start;
6385 const SCEVConstant *Step;
6386 // TODO: Support non-constant loop invariant stride.
6387 if (!match(PtrSCEV,
6389 m_SpecificLoop(&L))))
6390 continue;
6391
6392 VPValue *StoredValue = nullptr;
6393 Type *DataTy;
6394 Intrinsic::ID IntrinID;
6395 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(&R)) {
6396 StoredValue = StoreR->getStoredValue();
6397 DataTy = StoredValue->getScalarType();
6398 IntrinID = Intrinsic::experimental_vp_strided_store;
6399 } else {
6400 auto *LoadR = cast<VPWidenLoadRecipe>(&R);
6401 DataTy = LoadR->getScalarType();
6402 IntrinID = Intrinsic::experimental_vp_strided_load;
6403 }
6404
6405 Align Alignment = MemR->getAlign();
6406 auto IsProfitable = [&](ElementCount VF) {
6407 Type *VectorTy = toVectorTy(DataTy, VF);
6408 if (!Ctx.TTI.isLegalStridedLoadStore(VectorTy, Alignment))
6409 return false;
6410 const InstructionCost CurrentCost = MemR->computeCost(VF, Ctx);
6411 const InstructionCost StridedLoadStoreCost =
6413 IntrinID, VectorTy, MemR->isMasked(), Alignment, Ctx);
6414 return StridedLoadStoreCost < CurrentCost;
6415 };
6416
6418 Range))
6419 continue;
6420
6421 // Invalidate the legacy widening decision so the cost of replaced load is
6422 // not counted during precomputeCosts.
6423 // TODO: Remove once the legacy exit cost computation is retired.
6424 for (ElementCount VF : Range)
6425 Ctx.invalidateWideningDecision(&MemR->getIngredient(), VF);
6426
6427 // Get VF as i32 for the vector length operand.
6428 if (!I32VF) {
6429 VPBuilder Builder(Plan.getVectorPreheader());
6430 I32VF = Builder.createScalarZExtOrTrunc(
6431 &Plan.getVF(), Type::getInt32Ty(Plan.getContext()),
6433 }
6434
6435 VPBuilder Builder(&R);
6436 // Create the base pointer of strided access.
6437 // TODO: reuse VPDerivedIVRecipe for base pointer computation when it
6438 // supports a general VPValue as the start value.
6439 VPValue *StartVPV =
6440 VPSCEVExpander(Builder, *PSE.getSE(), R.getDebugLoc()).expand(Start);
6441 VPValue *StrideInBytes = Plan.getOrAddLiveIn(Step->getValue());
6442 Type *IndexTy = Plan.getDataLayout().getIndexType(Ptr->getScalarType());
6443 assert(IndexTy == StrideInBytes->getScalarType() &&
6444 "Stride type from SCEV must match the index type");
6445 VPValue *CanIV = Builder.createScalarZExtOrTrunc(
6446 VectorLoop->getCanonicalIV(), IndexTy, DebugLoc::getUnknown());
6447 auto *AddRecPtr = cast<SCEVAddRecExpr>(PtrSCEV);
6448 auto *Offset = Builder.createOverflowingOp(
6449 Instruction::Mul, {CanIV, StrideInBytes},
6450 {AddRecPtr->hasNoUnsignedWrap(), /*HasNSW=*/false});
6451 GEPNoWrapFlags NWFlags = AddRecPtr->hasNoUnsignedWrap()
6454 VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV, Offset, NWFlags);
6455
6456 // Create a new vector pointer for strided access.
6457 VPValue *NewPtr = Builder.createVectorPointer(
6458 BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes, NWFlags,
6459 R.getDebugLoc());
6460
6461 VPValue *Mask = MemR->getMask();
6462 if (!Mask)
6463 Mask = Plan.getTrue();
6465 if (StoredValue)
6466 Ops.push_back(StoredValue);
6467 Ops.append({NewPtr, StrideInBytes, Mask, I32VF});
6468
6469 auto *StridedR = Builder.createWidenMemIntrinsic(
6470 IntrinID, Ops,
6471 StoredValue ? Type::getVoidTy(Plan.getContext()) : DataTy, Alignment,
6472 *MemR, R.getDebugLoc());
6473 if (!StoredValue)
6474 cast<VPWidenLoadRecipe>(&R)->replaceAllUsesWith(StridedR);
6475 R.eraseFromParent();
6476 }
6477 }
6478}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
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)
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
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")
@ Default
Hexagon Common GEP
#define _
iv Induction Variable Users
Definition IVUsers.cpp:48
iv users
Definition IVUsers.cpp:48
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
licm
Definition LICM.cpp:346
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:85
#define I(x, y, z)
Definition MD5.cpp:57
This file provides utility analysis objects describing memory locations.
This file contains the declarations for metadata subclasses.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
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
Func MI getDebugLoc()))
This file contains some templates that are useful if you are working with the STL at all.
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.
static SmallVector< SmallVector< VPReplicateRecipe *, 4 > > collectComplementaryPredicatedMemOps(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
static void removeCommonBlendMask(VPBlendRecipe *Blend)
Try to see if all of Blend's masks share a common value logically and'ed and remove it from the masks...
static void tryToCreateAbstractReductionRecipe(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries to create abstract recipes from the reduction recipe for following optimizations ...
static VPReplicateRecipe * findRecipeWithMinAlign(ArrayRef< VPReplicateRecipe * > Group)
static CallWideningDecision decideCallWidening(VPInstruction &VPI, ArrayRef< VPValue * > Ops, ElementCount VF, VPCostContext &CostCtx)
Pick the cheapest widening for the call VPI at VF among scalarization, vector intrinsic,...
static bool areVFParamsOk(const VFInfo &Info, ArrayRef< VPValue * > Args, PredicatedScalarEvolution &PSE, const Loop *L)
Returns true if Info's parameter kinds are compatible with Args.
static bool sinkScalarOperands(VPlan &Plan)
static bool isVectorLatchCheck(VPRecipeBase *Term, VPValue *Cond, VPlan &Plan)
Return true if the branch Term with condition Cond (null if Term has no condition operand) is the vec...
static bool simplifyBranchConditionForVFAndUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Try to simplify the branch condition of Plan.
static Align getLoadAlign(const VPSingleDefRecipe *R)
static void swapSelectBranchWeights(VPRecipeBase &R, VPlan &Plan)
Swap the branch weights recorded for R, a select whose two selected operands are being swapped,...
static VPValue * simplifyLogicalRecipe(VPlan &Plan, VPSingleDefRecipe *Def)
Try to simplify logical and bitwise recipes in Def.
static auto m_Countable(VPValue *&Cmp, PredicatedScalarEvolution &PSE, Loop *L)
Matches an exit condition formed by comparing the current value of a affine add recurrence in the giv...
static VPValue * cloneBinOpForScalarIV(VPWidenRecipe *BinOp, VPValue *ScalarIV, VPWidenIntOrFpInductionRecipe *WidenIV)
Create a scalar version of BinOp, with its WidenIV operand replaced by ScalarIV, and place it after S...
static VPWidenIntOrFpInductionRecipe * getExpressionIV(VPValue *V)
Check if V is a binary expression of a widened IV and a loop-invariant value.
static void removeRedundantInductionCasts(VPlan &Plan)
Remove redundant casts of inductions.
static bool isConditionTrueViaVFAndUF(VPValue *Cond, VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Return true if Cond is known to be true for given BestVF and BestUF.
static VPExpressionRecipe * tryToMatchAndCreateExtendedReduction(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries convert extended in-loop reductions to VPExpressionRecipe and clamp the Range if ...
static bool isAvailableAtEndOf(VPValue *V, const VPBasicBlock *VPBB)
Returns true if V is available at the end of VPBB, i.e.
static std::optional< ElementCount > isConsecutiveInterleaveGroup(VPInterleaveRecipe *InterleaveR, ArrayRef< ElementCount > VFs, const TargetTransformInfo &TTI)
Returns VF from VFs if IR is a full interleave group with factor and number of members both equal to ...
static VPIRMetadata getCommonMetadata(ArrayRef< VPReplicateRecipe * > Recipes)
static bool mergeReplicateRegionsIntoSuccessors(VPlan &Plan)
static Function * findVectorVariant(CallInst *CI, ArrayRef< VPValue * > Args, ElementCount VF, bool MaskRequired, PredicatedScalarEvolution &PSE, const Loop *L)
Find a vector variant of CI for VF, respecting MaskRequired.
static bool canNarrowOps(ArrayRef< VPValue * > Ops, bool IsScalable, DenseMap< VPValue *, SmallVector< VPValue * > > &FirstMembersOf)
Returns true if the wide recipes in Ops and their operand trees can be narrowed.
TTI::PartialReductionExtendKind ExtendKind
static VPValue * getRecipesForUncountableExit(SmallVectorImpl< VPInstruction * > &Recipes, VPBasicBlock *LatchVPBB)
Returns the VPValue representing the uncountable exit comparison used by AnyOf if the recipes it depe...
static VPWidenInductionRecipe * getOptimizableIVOf(VPValue *VPV, PredicatedScalarEvolution &PSE)
Check if VPV is an untruncated wide induction, either before or after the increment.
static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx, VPValue *OpV, unsigned Idx, bool IsScalable)
Returns true if V is VPWidenLoadRecipe or VPInterleaveRecipe that can be converted to a narrower reci...
static bool handleUncountableExitsWithSideEffects(VPlan &Plan, SmallVectorImpl< EarlyExitInfo > &Exits, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB, OptimizationRemarkEmitter *ORE, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC)
Update Plan to mask memory operations in the loop based on whether the early exit is taken or not.
static void legalizeAndOptimizeInductions(VPlan &Plan)
Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd (IndStart, ScalarIVSteps (0,...
static void addReplicateRegions(VPlan &Plan)
static VPValue * optimizeLatchExitIVUserViaSCEV(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE, VPValue *ResumeTC, const Loop *L)
static ExtendKind getPartialReductionExtendKind(VPWidenCastRecipe *Cast)
static SmallVector< SmallVector< VPReplicateRecipe *, 4 > > collectGroupedReplicateMemOps(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L, function_ref< bool(VPReplicateRecipe *)> FilterFn)
Collect either replicated Loads or Stores grouped by their address SCEV and their load-store type,...
static VPValue * tryToComputeEndValueForInduction(VPWidenInductionRecipe *WideIV, VPBuilder &VectorPHBuilder, VPValue *VectorTC)
Compute the end value for WideIV, unless it is truncated.
static bool loopHasStores(VPBasicBlock *HeaderVPBB)
static bool replaceMaskWithCompareForScalarPlan(VPlan &Plan, ElementCount BestVF)
static VPValue * simplifyRecipe(VPlan &Plan, VPSingleDefRecipe *Def)
Return an existing value or a live in for VPSingleDefRecipe Def if possible.
static VPValue * optimizeEarlyExitInductionUser(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the early exit block.
static bool canFoldOuterExtendIntoMul(VPWidenRecipe *Mul)
Returns true if the narrow Mul in ext(mul(ext(A), ext(B))) or ext(mul(ext(A), C)) cannot wrap.
static VPValue * narrowInterleaveGroupOp(ArrayRef< VPValue * > Members, SmallPtrSetImpl< VPValue * > &NarrowedOps, VPBasicBlock *Preheader)
static VPValue * optimizeLatchExitInductionUser(VPlan &Plan, VPValue *Op, DenseMap< VPValue *, VPValue * > &EndValues, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the exit block coming from the l...
static void reassociateHeaderMask(VPlan &Plan)
Reassociate (headermask && x) && y -> headermask && (x && y) to allow the header mask to be simplifie...
static void updatePartialReductionPhiAndResult(VPlan &Plan, VPReductionPHIRecipe *Phi, unsigned Factor, RecurKind RK)
static VPSingleDefRecipe * combineRecipe(VPlan &Plan, VPSingleDefRecipe *Def, VPCombineBuilder &Builder)
Combine Def into a simpler recipe.
static VPBasicBlock * getPredicatedThenBlock(VPRegionBlock *R)
If R is a triangle region, return the 'then' block of the triangle.
static bool tryToRemoveDeadCycle(VPRecipeBase *R)
If R is a phi-like recipe starting a dead cycle of recipes, erase all reachable recipes of the dead c...
static bool canHoistOrSinkWithNoAliasCheck(const MemoryLocation &MemLoc, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, std::optional< SinkStoreInfo > SinkInfo={})
Check if a memory operation doesn't alias with memory operations using scoped noalias metadata,...
static VPRegionBlock * createReplicateRegion(VPReplicateRecipe *PredRecipe, VPRegionBlock *ParentRegion, VPlan &Plan)
static void simplifyBlends(VPlan &Plan)
Normalize and simplify VPBlendRecipes.
static bool cannotHoistOrSinkRecipe(VPRecipeBase &R, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink a non-memory or memory recipe R out...
static auto m_Uncountable(VPValue *&Cond)
Matches an exit condition formed by comparing a value loaded from memory with a loop-invariant term.
static std::optional< Instruction::BinaryOps > getUnmaskedDivRemOpcode(Intrinsic::ID ID)
static bool isAlreadyNarrow(VPValue *VPV)
Returns true if VPValue is a narrow VPValue.
static bool optimizeVectorInductionWidthForTCAndVFUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF)
Optimize the width of vector induction variables in Plan based on a known constant Trip Count,...
static VPExpressionRecipe * tryToMatchAndCreateMulAccumulateReduction(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries convert extended in-loop reductions to VPExpressionRecipe and clamp the Range if ...
static bool canSinkStoreWithNoAliasCheck(ArrayRef< VPReplicateRecipe * > StoresToSink, PredicatedScalarEvolution &PSE, const Loop &L)
static std::optional< bool > getStepDirection(const SCEV *S, ScalarEvolution &SE)
If S is an affine AddRec, returns true if its step is known to be positive and false if it is known t...
static VPIRMetadata getMetadataOf(VPRecipeBase *R)
Returns the metadata attached to R, or an empty set for a recipe that does not carry any.
static Type * getLoadStoreValueType(VPSingleDefRecipe *R)
Get the value type of a VPInstruction or VPReplicateRecipe load or store.
static void narrowToSingleScalarRecipes(VPlan &Plan)
This file provides utility VPlan to VPlan transformations.
#define RUN_VPLAN_PASS(PASS,...)
This file contains the declarations of the Vectorization Plan base classes:
static const X86InstrFMA3Group Groups[]
Value * RHS
Value * LHS
BinaryOperator * Mul
static const uint32_t IV[8]
Definition blake3_impl.h:83
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.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
APInt abs() const
Get the absolute value.
Definition APInt.h:1815
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
int32_t exactLogBase2() const
Definition APInt.h:1803
bool isNonNegative() const
Determine if this APInt Value is non-negative (>= 0)
Definition APInt.h:330
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1030
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:436
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
Definition APInt.h:1225
An arbitrary precision integer that knows its signedness.
Definition APSInt.h:24
static APSInt getMinValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the minimum integer value with the given bit width and signedness.
Definition APSInt.h:310
static APSInt getMaxValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the maximum integer value with the given bit width and signedness.
Definition APSInt.h:302
@ NoAlias
The two locations do not alias at all.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & back() const
Get the last element.
Definition ArrayRef.h:150
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:194
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
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
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
Definition InstrTypes.h:852
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.
Definition DataLayout.h:64
LLVM_ABI IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const
Returns the type of a GEP index in AddressSpace.
A debug info location.
Definition DebugLoc.h:126
static DebugLoc getUnknown()
Definition DebugLoc.h:153
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:803
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.
Definition DenseMap.h:793
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
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.
Definition Dominators.h:122
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:309
constexpr bool isScalar() const
Exactly one element.
Definition TypeSize.h:317
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
size_t arg_size() const
Definition Function.h:886
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...
bool isBinaryOp() const
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
bool isIntDivRem() const
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
The group of interleaved loads/stores sharing the same stride and close to each other.
InstTy * getInsertPos() const
Align getAlign() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
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.
Definition VPlan.cpp:1646
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
LLVM_ABI MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight, bool IsExpected=false)
Return metadata containing two branch weights.
Definition MDBuilder.cpp:38
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
ValueT lookup(const KeyT &Key) const
Definition MapVector.h:110
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Definition MapVector.h:118
bool empty() const
Definition MapVector.h:79
Representation for a specific memory location.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Definition Module.cpp:235
The optimization diagnostic interface.
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.
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.
Definition Regex.cpp:84
RegionT * getParent() const
Get the parent of the Region.
Definition RegionInfo.h:365
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.
Definition SetVector.h:57
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
size_type size() const
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.
iterator begin() const
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.
Definition StringRef.h:56
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
static LLVM_ABI PartialReductionExtendKind getPartialReductionExtendKind(Instruction *I)
Get the kind of extension that an instruction represents.
TargetCostKind
The kind of cost model.
@ TCK_RecipThroughput
Reciprocal throughput.
LLVM_ABI InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, PartialReductionExtendKind OpAExtend, PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:363
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:222
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
Definition Type.h:265
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
op_range operands()
Definition User.h:267
static SmallVector< VFInfo, 8 > getMappings(const CallInst &CI)
Retrieve all the VFInfo instances associated to the CallInst CI.
Definition VectorUtils.h:76
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.
Definition VPlan.h:4494
void appendRecipe(VPRecipeBase *Recipe)
Augment the existing recipes of a VPBasicBlock with an additional Recipe as the last recipe.
Definition VPlan.h:4575
RecipeListTy::iterator iterator
Instruction iterators...
Definition VPlan.h:4525
iterator end()
Definition VPlan.h:4535
iterator begin()
Recipe iterator methods.
Definition VPlan.h:4533
iterator_range< iterator > phis()
Returns an iterator range over the PHI-like recipes in the block.
Definition VPlan.h:4588
iterator getFirstNonPhi()
Return the position of the first non-phi node recipe in the block.
Definition VPlan.cpp:228
VPBasicBlock * splitAt(iterator SplitAt)
Split current block at SplitAt by inserting a new block between the current block and its successors ...
Definition VPlan.cpp:528
const VPRecipeBase & front() const
Definition VPlan.h:4545
VPRecipeBase * getTerminator()
If the block has multiple successors, return the branch recipe terminating the block.
Definition VPlan.cpp:607
const VPRecipeBase & back() const
Definition VPlan.h:4547
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
Definition VPlan.h:3013
VPValue * getIncomingValue(unsigned Idx) const
Return incoming value number Idx.
Definition VPlan.h:3060
VPValue * getMask(unsigned Idx) const
Return mask number Idx.
Definition VPlan.h:3065
unsigned getNumIncomingValues() const
Return the number of incoming values, taking into account when normalized the first incoming value wi...
Definition VPlan.h:3055
void setMask(unsigned Idx, VPValue *V)
Set mask number Idx to V.
Definition VPlan.h:3071
bool isNormalized() const
A normalized blend is one that has an odd number of operands, whereby the first operand does not have...
Definition VPlan.h:3051
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
Definition VPlan.h:99
void setSuccessors(ArrayRef< VPBlockBase * > NewSuccs)
Set each VPBasicBlock in NewSuccss as successor of this VPBlockBase.
Definition VPlan.h:309
VPRegionBlock * getParent()
Definition VPlan.h:197
const VPBasicBlock * getExitingBasicBlock() const
Definition VPlan.cpp:198
size_t getNumSuccessors() const
Definition VPlan.h:247
void setPredecessors(ArrayRef< VPBlockBase * > NewPreds)
Set each VPBasicBlock in NewPreds as predecessor of this VPBlockBase.
Definition VPlan.h:300
const VPBlocksTy & getPredecessors() const
Definition VPlan.h:232
VPBlockBase * getSinglePredecessor() const
Definition VPlan.h:243
void clearPredecessors()
Remove all the predecessor of this block.
Definition VPlan.h:316
const VPBasicBlock * getEntryBasicBlock() const
Definition VPlan.cpp:183
VPBlockBase * getSingleSuccessor() const
Definition VPlan.h:237
const VPBlocksTy & getSuccessors() const
Definition VPlan.h:221
static auto blocksAs(T &&Range)
Return an iterator range over Range with each block cast to BlockTy.
Definition VPlanUtils.h:448
static void insertOnEdge(VPBlockBase *From, VPBlockBase *To, VPBlockBase *BlockPtr)
Inserts BlockPtr on the edge between From and To.
Definition VPlanUtils.h:467
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.
Definition VPlanUtils.h:357
static void connectBlocks(VPBlockBase *From, VPBlockBase *To, unsigned PredIdx=-1u, unsigned SuccIdx=-1u)
Connect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:375
static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To)
Disconnect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:393
static auto blocksOnly(T &&Range)
Return an iterator range over Range which only includes BlockTy blocks.
Definition VPlanUtils.h:441
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.
Definition VPlanUtils.h:425
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.
Definition VPlan.h:3564
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)
VPWidenLoadRecipe * createWidenLoad(LoadInst &Load, VPValue *Addr, VPValue *Mask, bool Consecutive, Align Alignment, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Load, loading from Addr with Mask (may be null).
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="")
void setInsertPoint(const VPInsertPoint &IP)
Set the current insert point.
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="")
VPWidenStoreRecipe * createWidenStore(StoreInst &Store, VPValue *Addr, VPValue *StoredVal, VPValue *Mask, bool Consecutive, Align Alignment, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Store, storing StoredVal to Addr with Mask (may be null).
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.
Definition VPlanValue.h:577
VPValue * getVPSingleValue()
Returns the only VPValue defined by the VPDef.
Definition VPlanValue.h:550
VPValue * getVPValue(unsigned I)
Returns the VPValue with index I defined by the VPDef.
Definition VPlanValue.h:562
ArrayRef< VPRecipeValue * > definedValues()
Returns an ArrayRef of the values defined by the VPDef.
Definition VPlanValue.h:572
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.
Definition VPlan.h:4089
A recipe to combine multiple recipes into a single 'expression' recipe, which should be considered a ...
Definition VPlan.h:3611
A pure virtual base class for all recipes modeling header phis, including phis for first order recurr...
Definition VPlan.h:2504
virtual VPValue * getBackedgeValue()
Returns the incoming value from the loop backedge.
Definition VPlan.h:2547
VPValue * getStartValue()
Returns the start value of the phi, if one is set.
Definition VPlan.h:2536
A recipe representing a sequence of load -> update -> store as part of a histogram operation.
Definition VPlan.h:2215
Manage IR attributes for call recipes.
Definition VPlan.h:1271
A special type of VPBasicBlock that wraps an existing IR basic block.
Definition VPlan.h:4653
Class to record and manage LLVM IR flags.
Definition VPlan.h:685
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
Helper to manage IR metadata for recipes.
Definition VPlan.h:1154
std::optional< VPExecutionFrequency > getExecutionFrequency() const
Returns the frequency recorded by setExecutionFrequency, if any.
void intersect(const VPIRMetadata &MD)
Intersect this VPIRMetadata object with MD, keeping only metadata nodes that are common to both.
void clearExecutionFrequency()
Drop the frequency recorded by setExecutionFrequency, if any.
void setExecutionFrequency(std::optional< VPExecutionFrequency > Freq, LLVMContext &Ctx)
Record that the recipe executes with frequency Freq, relative to the entry of the loop region.
This is a concrete Recipe that models a single VPlan-level instruction.
Definition VPlan.h:1324
unsigned getNumOperandsWithoutMask() const
Returns the number of operands, excluding the mask if the VPInstruction is masked.
Definition VPlan.h:1573
@ ExtractLane
Extracts a single lane (first operand) from a set of vector operands.
Definition VPlan.h:1429
@ ReductionStartVector
Start vector for reductions with 3 operands: the original start value, the identity value for the red...
Definition VPlan.h:1425
@ BuildVector
Creates a fixed-width vector containing all operands.
Definition VPlan.h:1375
@ ComputeReductionResult
Reduce the operands to the final reduction result using the operation specified via the operation's V...
Definition VPlan.h:1383
unsigned getOpcode() const
Definition VPlan.h:1516
VPValue * getMask() const
Returns the mask for the VPInstruction.
Definition VPlan.h:1589
const InterleaveGroup< Instruction > * getInterleaveGroup() const
Definition VPlan.h:3166
VPValue * getMask() const
Return the mask used by this recipe.
Definition VPlan.h:3158
ArrayRef< VPValue * > getStoredValues() const
Return the VPValues stored by this interleave group.
Definition VPlan.h:3187
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
Definition VPlan.h:3197
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
Definition VPlan.h:3772
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition VPlan.h:406
void moveBefore(RecipeListTy::iterator I)
Unlink this recipe and insert it before I.
VPRegionBlock * getRegion()
Definition VPlan.h:4899
RecipeListTy::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
DebugLoc getDebugLoc() const
Returns the debug location of the recipe.
Definition VPlan.h:550
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.
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.
Definition VPlanValue.h:349
A recipe for handling reduction phis.
Definition VPlan.h:2907
bool isOrdered() const
Returns true, if the phi is part of an ordered reduction.
Definition VPlan.h:2979
bool isInLoop() const
Returns true if the phi is part of an in-loop reduction.
Definition VPlan.h:2982
RecurKind getRecurrenceKind() const
Returns the recurrence kind of the reduction.
Definition VPlan.h:2976
A recipe to represent inloop, ordered or partial reduction operations.
Definition VPlan.h:3290
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition VPlan.h:4725
const VPBlockBase * getEntry() const
Definition VPlan.h:4769
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
Definition VPlan.h:4801
void setExiting(VPBlockBase *ExitingBlock)
Set ExitingBlock as the exiting VPBlockBase of this VPRegionBlock.
Definition VPlan.h:4786
void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override
Print this VPRegionBlock to O (recursively), prefixing all lines with Indent.
Definition VPlan.cpp:835
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
Definition VPlan.h:4853
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
Definition VPlan.h:4845
const VPBlockBase * getExiting() const
Definition VPlan.h:4781
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
Definition VPlan.h:4858
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition VPlan.h:3457
bool isSingleScalar() const
Returns true if the recipe produces a single scalar value.
Definition VPlan.h:3514
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.
Definition VPlan.h:3542
bool isPredicated() const
Definition VPlan.h:3519
VPValue * getMask()
Return the mask of a predicated VPReplicateRecipe.
Definition VPlan.h:3536
Lightweight SCEV-to-VPlan expander.
Definition VPlanUtils.h:276
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...
Definition VPlan.h:4326
VPSingleDefRecipe is a base class for recipes that model a sequence of one or more output IR that def...
Definition VPlan.h:608
Instruction * getUnderlyingInstr()
Returns the underlying instruction.
Definition VPlan.h:670
VPSingleDefRecipe * clone() override=0
Clone the current recipe.
A symbolic live-in VPValue, used for values like vector trip count, VF, and VFxUF.
Definition VPlanValue.h:212
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition VPlanValue.h:396
operand_range operands()
Definition VPlanValue.h:472
void setOperand(unsigned I, VPValue *New)
Definition VPlanValue.h:445
unsigned getNumOperands() const
Definition VPlanValue.h:436
VPValue * getOperand(unsigned N) const
Definition VPlanValue.h:437
This is the base class of the VPlan Def/Use graph, used for modeling the data flow into,...
Definition VPlanValue.h:50
Type * getScalarType() const
Returns the scalar type of this VPValue, dispatching based on the concrete subclass.
Definition VPlan.cpp:142
Value * getLiveInIRValue() const
Return the underlying IR value for a VPIRValue.
Definition VPlan.cpp:136
bool isDefinedOutsideLoopRegions() const
Returns true if the VPValue is defined outside any loop.
Definition VPlan.cpp:1472
VPRecipeBase * getDefiningRecipe()
Returns the recipe defining this VPValue or nullptr if it is not defined by a recipe,...
Definition VPlan.cpp:123
bool hasMoreThanOneUniqueUser() const
Returns true if the value has more than one unique user.
Definition VPlanValue.h:164
Value * getUnderlyingValue() const
Return the underlying Value attached to this VPValue.
Definition VPlanValue.h:75
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...
Definition VPlan.cpp:1481
bool user_empty() const
Definition VPlanValue.h:161
bool hasOneUse() const
Definition VPlanValue.h:175
VPUser * getSingleUser()
Return the single user of this value, or nullptr if there is not exactly one user.
Definition VPlanValue.h:179
void replaceAllUsesWith(VPValue *New)
Definition VPlan.cpp:1475
user_range users()
Definition VPlanValue.h:157
A recipe to compute a pointer to the last element of each part of a widened memory access for widened...
Definition VPlan.h:2334
A recipe for widening Call instructions using library calls.
Definition VPlan.h:2149
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.
Definition VPlan.h:1916
Instruction::CastOps getOpcode() const
Definition VPlan.h:1952
A recipe for handling GEP instructions.
Definition VPlan.h:2274
Base class for widened induction (VPWidenIntOrFpInductionRecipe and VPWidenPointerInductionRecipe),...
Definition VPlan.h:2572
PHINode * getPHINode() const
Returns the underlying PHINode if one exists, or null otherwise.
Definition VPlan.h:2626
VPValue * getStepValue()
Returns the step value of the induction.
Definition VPlan.h:2614
const InductionDescriptor & getInductionDescriptor() const
Returns the induction descriptor for the recipe.
Definition VPlan.h:2631
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
Definition VPlan.h:2660
bool isTruncated() const
Returns true if this induction is evaluated in a narrower type than the start value.
Definition VPlan.h:2713
A recipe for widening vector intrinsics.
Definition VPlan.h:1964
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.
Definition VPlan.h:3808
virtual VPRecipeBase * getAsRecipe()=0
Return a VPRecipeBase* to the current object.
A recipe for widened phis.
Definition VPlan.h:2794
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition VPlan.h:1849
InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const override
Return the cost of this VPWidenRecipe.
VPWidenRecipe * clone() override
Clone the current recipe.
Definition VPlan.h:1875
unsigned getOpcode() const
Definition VPlan.h:1894
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition VPlan.h:4912
VPIRValue * getLiveIn(Value *V) const
Return the live-in VPIRValue for V, if there is one or nullptr otherwise.
Definition VPlan.h:5242
bool hasVF(ElementCount VF) const
Definition VPlan.h:5135
const DataLayout & getDataLayout() const
Definition VPlan.h:5113
LLVMContext & getContext() const
Definition VPlan.h:5109
VPBasicBlock * getEntry()
Definition VPlan.h:5004
bool hasScalableVF() const
Definition VPlan.h:5136
VPValue * getTripCount() const
The trip count of the original loop.
Definition VPlan.h:5076
iterator_range< SmallSetVector< ElementCount, 2 >::iterator > vectorFactors() const
Returns an iterator range over all VFs of the plan.
Definition VPlan.h:5142
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
Definition VPlan.h:5208
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
Definition VPlan.h:5107
VPIRValue * getAllOnesValue(Type *Ty)
Return a VPIRValue wrapping the AllOnes value of type Ty.
Definition VPlan.h:5214
VPRegionBlock * createReplicateRegion(VPBlockBase *Entry, VPBlockBase *Exiting, const std::string &Name="")
Create a new replicate region with Entry, Exiting and Name.
Definition VPlan.h:5295
auto getLiveIns() const
Return the list of live-in VPValues available in the VPlan.
Definition VPlan.h:5245
bool hasUF(unsigned UF) const
Definition VPlan.h:5160
ArrayRef< VPIRBasicBlock * > getExitBlocks() const
Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of the original scalar loop.
Definition VPlan.h:5070
VPSymbolicValue & getVectorTripCount()
The vector trip count.
Definition VPlan.h:5097
VPIRValue * getOrAddLiveIn(Value *V)
Gets the live-in VPIRValue for V or adds a new live-in (if none exists yet) for V.
Definition VPlan.h:5185
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
Definition VPlan.h:5211
void setVF(ElementCount VF)
Definition VPlan.h:5123
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
Definition VPlan.h:5176
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition VPlan.cpp:1065
unsigned getConcreteUF() const
Returns the concrete UF of the plan, after unrolling.
Definition VPlan.h:5163
void resetTripCount(VPValue *NewTripCount)
Resets the trip count for the VPlan.
Definition VPlan.h:5090
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
Definition VPlan.h:5046
VPBasicBlock * createVPBasicBlock(const Twine &Name, VPRecipeBase *Recipe=nullptr)
Create a new VPBasicBlock with Name and containing Recipe if present.
Definition VPlan.h:5268
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
Definition VPlan.h:5205
VPBasicBlock * getVectorPreheader() const
Returns the preheader of the vector loop region, if one exists, or null otherwise.
Definition VPlan.h:5009
VPSymbolicValue & getUF()
Returns the UF of the vector loop region.
Definition VPlan.h:5104
bool hasScalarVFOnly() const
Definition VPlan.h:5153
VPBasicBlock * getScalarPreheader() const
Return the VPBasicBlock for the preheader of the scalar loop.
Definition VPlan.h:5060
bool hasTailFolded() const
Returns true if the vector loop region is tail-folded.
Definition VPlan.h:5025
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
Definition VPlan.h:5100
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...
Definition VPlan.cpp:1225
VPIRValue * getConstantInt(Type *Ty, uint64_t Val, bool IsSigned=false)
Return a VPIRValue wrapping a ConstantInt with the given type and value.
Definition VPlan.h:5219
LLVM Value Representation.
Definition Value.h:75
iterator_range< user_iterator > users()
Definition Value.h:428
bool hasName() const
Definition Value.h:263
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
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 ...
Definition TypeSize.h:266
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:201
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS*X will result in a value whose quantity matches our own.
Definition TypeSize.h:274
static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition TypeSize.h:217
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition TypeSize.h:169
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
Definition TypeSize.h:172
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
#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.
Definition APInt.cpp:2801
std::variant< std::monostate, Loc::Single, Loc::Multi, Loc::MMI, Loc::EntryValue > Variant
Alias for the std::variant specialization base class of DbgVariable.
Definition DwarfDebug.h:190
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_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)
FNeg_match< OpTy, false > m_FNeg(const OpTy &X)
Match fneg X only.
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)
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()
RecipeTy * findSingleUser(VPValue *V, const MatchT &P)
Return the sole user of V matching pattern P, casting it to RecipeTy, or nullptr.
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)
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
Definition RDFGraph.h:384
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...
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.
Definition VPlanUtils.h:151
LLVM_ABI_FOR_TEST bool isUniformAcrossVFsAndUFs(const VPValue *V)
Checks if V is uniform across all VF lanes and UF parts.
VPValue * getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr, bool ExpandInIR=false)
Get or create a VPValue that corresponds to the expansion of Expr.
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...
Definition VPlanUtils.h:260
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.
Definition STLExtras.h:316
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...
Definition VPlanCFG.h:262
@ Offset
Definition DWP.cpp:577
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...
Definition STLExtras.h:2196
void stable_sort(R &&Range)
Definition STLExtras.h:2132
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2094
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
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.
Definition STLExtras.h:1685
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.
Definition STLExtras.h:856
ReductionStyle getReductionStyle(bool InLoop, bool Ordered, unsigned ScaleFactor)
Definition VPlan.h:2894
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,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
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
Definition VPlan.h:69
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 ...
Definition Casting.h:732
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.
Definition STLExtras.h:2224
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...
Definition STLExtras.h:649
auto cast_or_null(const Y &Val)
Definition Casting.h:714
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.
Definition VPlanCFG.h:250
bool isa_and_nonnull(const Y &Val)
Definition Casting.h:676
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...
Definition VPlanCFG.h:285
constexpr auto equal_to(T &&Arg)
Functor variant of std::equal_to that can be used as a UnaryPredicate in functional algorithms like a...
Definition STLExtras.h:2189
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.
Definition STLExtras.h:366
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
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.
Definition STLExtras.h:567
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2216
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
constexpr size_t range_size(R &&Range)
Returns the size of the Range, i.e., the number of elements.
Definition STLExtras.h:1710
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
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.
Definition VPlan.h:85
@ ReadOnly
No side effects to worry about, so we can process any uncountable exits in the loop and branch either...
Definition VPlan.h:89
@ MaskedHandleExitInScalarLoop
All memory operations other than the load(s) required to determine whether an uncountable exit occurr...
Definition VPlan.h:94
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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...
Definition STLExtras.h:552
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...
Definition VPlan.cpp:1828
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...
Definition STLExtras.h:1853
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...
Definition Casting.h:547
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
Definition STLExtras.h:323
@ Other
Any other memory.
Definition ModRef.h:68
TargetTransformInfo TTI
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.
@ FMul
Product 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.
@ Add
Sum of integers.
@ AddChainWithSubs
A chain of adds and subs.
@ FAdd
Sum of floats.
@ 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...
Definition STLExtras.h:2028
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...
Definition STLExtras.h:2104
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.
Definition Casting.h:559
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
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.
Definition STLExtras.h:2182
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Definition STLExtras.h:2162
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...
Definition Loads.cpp:306
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
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.
Definition Hashing.h:287
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
VPBasicBlock * EarlyExitingVPBB
VPIRBasicBlock * EarlyExitVPBB
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
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.
Definition VPlan.h:2889
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.
Definition VPlan.cpp:1932
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.
Definition VPlan.h:2845
WrapFlagsTy withoutNoSignedWrap()
Definition VPlan.h:707
A VPValue representing a live-in from the input IR or a constant.
Definition VPlanValue.h:274
Type * getType() const
Returns the type of the underlying IR value.
Definition VPlan.cpp:140
A recipe for widening load operations, using the address to load from and an optional mask.
Definition VPlan.h:3872
A recipe for widening store operations, using the stored value, the address to store to and an option...
Definition VPlan.h:3980
static LLVM_ABI_FOR_TEST void printIfRequested(VPlan &Plan, Function *Fn, StringRef NumberedPassName, bool After)
Print Plan of Fn before or after the pass NumberedPassName if requested.
static void simplifyLiveInsWithSCEV(VPlan &Plan, PredicatedScalarEvolution &PSE)
Check Plan's live-ins and replace them with constants, if they can be simplified via SCEV.
static bool makeCallWideningDecisions(VPlan &Plan, VFRange &Range, VPRecipeBuilder &RecipeBuilder, VPCostContext &CostCtx)
Convert call VPInstructions in Plan into widened call, vector intrinsic or replicate recipes based on...
static decltype(auto) runPass(StringRef PassName, PassTy &&Pass, VPlan &Plan, ArgsTy &&...Args)
Helper to run a VPlan pass Pass on VPlan, forwarding extra arguments to the pass.
static void createInterleaveGroups(VPlan &Plan, const SmallPtrSetImpl< const InterleaveGroup< Instruction > * > &InterleaveGroups, const bool &EpilogueAllowed)
static LLVM_ABI_FOR_TEST bool handleUncountableEarlyExits(VPlan &Plan, OptimizationRemarkEmitter *ORE, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC, UncountableExitStyle Style)
Update Plan to account for uncountable early exits by introducing appropriate branching logic in the ...
static LLVM_ABI_FOR_TEST bool tryToConvertVPInstructionsToVPRecipes(VPlan &Plan, const TargetLibraryInfo &TLI, PredicatedScalarEvolution &PSE, Loop *OuterLoop)
Replaces the VPInstructions in Plan with corresponding widen recipes.
static void createAndOptimizeReplicateRegions(VPlan &Plan)
Wrap predicated VPReplicateRecipes with a mask operand in an if-then region block and remove the mask...
static std::unique_ptr< VPlan > narrowInterleaveGroups(VPlan &Plan, const TargetTransformInfo &TTI)
Try to find a single VF among Plan's VFs for which all interleave groups (with known minimum VF eleme...
static void makeMemOpWideningDecisions(VPlan &Plan, VFRange &Range, VPRecipeBuilder &RecipeBuilder, VPCostContext &CostCtx)
Convert load/store VPInstructions in Plan into widened or replicate recipes.
static void narrowInductionTruncates(VPlan &Plan, VFRange &Range, const TargetTransformInfo &TTI, PredicatedScalarEvolution &PSE)
Replace truncates of a wide induction, or of that induction's increment, by a VPWidenIntOrFpInduction...
static void hoistPredicatedLoads(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
Hoist predicated loads from the same address to the loop entry block, if they are guaranteed to execu...
static bool mergeBlocksIntoPredecessors(VPlan &Plan)
Remove redundant VPBasicBlocks by merging them into their single predecessor if the latter has a sing...
static void optimizeFindIVReductions(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &L)
Optimize FindLast reductions selecting IVs (or expressions of IVs) by converting them to FindIV reduc...
static void convertToAbstractRecipes(VPlan &Plan, VPCostContext &Ctx, VFRange &Range)
This function converts initial recipes to the abstract recipes and clamps Range based on cost model f...
static void makeScalarizationDecisions(VPlan &Plan, VFRange &Range)
Make VPlan-based scalarization decision prior to delegating to the ones made by the legacy CM.
static bool areAllLoadsDereferenceable(VPBasicBlock *HeaderVPBB, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC)
Check if all loads in the loop are dereferenceable.
static LLVM_ABI_FOR_TEST void verifyIfRequested(VPlan &Plan)
Abort if -vplan-verify-each is set and Plan is invalid.
static void optimizeInductionLiveOutUsers(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
If there's a single exit block, optimize its phi recipes that use exiting IV values by feeding them p...
static void simplifyReverses(VPlan &Plan)
Cancel out redundant reverses in Plan, e.g. reverse(reverse(x)) -> x.
static void adjustFirstOrderRecurrenceMiddleUsers(VPlan &Plan, VFRange &Range)
Adjust first-order recurrence users in the middle block: create penultimate element extracts for LCSS...
static void removeDeadRecipes(VPlan &Plan)
Remove dead recipes from Plan.
static void sinkPredicatedStores(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
Sink predicated stores to the same address with complementary predicates (P and NOT P) to an uncondit...
static bool removeBranchOnConst(VPlan &Plan, bool OnlyLatches=false)
Remove BranchOnCond recipes with true or false conditions together with removing dead edges to their ...
static void convertToStridedAccesses(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &L, VPCostContext &Ctx, VFRange &Range)
Transform widen memory recipes into strided access recipes when legal and profitable.
static void clearReductionWrapFlags(VPlan &Plan)
Clear NSW/NUW flags from reduction instructions if necessary.
static LLVM_ABI_FOR_TEST bool isPrintingRequested(const VPlan &Plan)
static void createPartialReductions(VPlan &Plan, VPCostContext &CostCtx, VFRange &Range)
Detect and create partial reduction recipes for scaled or unordered reductions in Plan.
static void cse(VPlan &Plan, const VPDominatorTree &VPDT)
Perform common-subexpression-elimination on Plan.
static void replaceSymbolicStrides(VPlan &Plan, PredicatedScalarEvolution &PSE, const SymbolicStrideMap &StridesMap, const VPDominatorTree &VPDT)
Replace symbolic strides from StridesMap in Plan with constants when possible.
static LLVM_ABI_FOR_TEST void optimize(VPlan &Plan)
Apply VPlan-to-VPlan optimizations to Plan, including induction recipe optimizations,...
static void truncateToMinimalBitwidths(VPlan &Plan, const MapVector< Instruction *, uint64_t > &MinBWs)
Insert truncates and extends for any truncated recipe.
static void dropPoisonGeneratingRecipes(VPlan &Plan)
Drop poison flags from recipes that may generate a poison value that is used after vectorization,...
static void optimizeForVFAndUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Optimize Plan based on BestVF and BestUF.
static void widenMemoryAccessesByUF(VPlan &Plan, ElementCount VF, unsigned UF, const TargetTransformInfo &TTI)
Widens memory operations by a factor of UF based on a target hook.
static bool splitCombinedExits(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop *TheLoop)
If a single exit has multiple conditions combined together, split them and create new exiting blocks.
static void combineRecipes(VPlan &Plan)
Perform instcombine-like simplifications on recipes in Plan.