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