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