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