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