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