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