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