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// Replaces ExtractVectorForPart instructions with ICMP when the VF is scalar
2041// and the source is a WideActiveLaneMask. The unused mask is removed later
2042// when removing dead recipes.
2043static bool replaceMaskWithCompare(VPlan &Plan, ElementCount BestVF) {
2044 if (!BestVF.isScalar())
2045 return false;
2046
2047 bool MadeChange = false;
2048 VPBuilder Builder;
2049 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2050 VPBasicBlock *PreheaderVPBB = Plan.getVectorPreheader();
2051 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2052
2053 VPValue *Start, *TC;
2054 uint64_t Idx;
2055 for (VPBasicBlock *VPBB : {PreheaderVPBB, ExitingVPBB}) {
2056 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2059 m_VPValue()),
2060 m_ConstantInt(Idx))))
2061 continue;
2062
2063 auto *Extract = cast<VPInstruction>(&R);
2064 Builder.setInsertPoint(Extract);
2065
2066 if (Idx > 0)
2067 Start = Builder.createAdd(
2068 Start, Plan.getConstantInt(Start->getScalarType(), Idx));
2069
2070 VPValue *ICmp = Builder.createICmp(CmpInst::ICMP_ULT, Start, TC);
2071 Extract->replaceAllUsesWith(ICmp);
2072 Extract->eraseFromParent();
2073 MadeChange = true;
2074 }
2075 }
2076
2077 return MadeChange;
2078}
2079
2080/// Try to simplify the branch condition of \p Plan. This may restrict the
2081/// resulting plan to \p BestVF and \p BestUF.
2083 unsigned BestUF,
2085 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2086 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2087 auto *Term = &ExitingVPBB->back();
2088 VPValue *Cond;
2089 auto m_CanIVInc = m_Add(m_VPValue(), m_Specific(&Plan.getVFxUF()));
2090 // Check if the branch condition compares the canonical IV increment (for main
2091 // loop), or the canonical IV increment plus an offset (for epilog loop).
2092 if (match(Term, m_BranchOnCount(
2093 m_CombineOr(m_CanIVInc, m_c_Add(m_CanIVInc, m_LiveIn())),
2094 m_VPValue())) ||
2095 match(Term,
2098 m_ZeroInt()))))) {
2099 // Try to simplify the branch condition if VectorTC <= VF * UF when the
2100 // latch terminator is BranchOnCount or
2101 // BranchOnCond(Not(ExtractVectorForPart(WideActiveLaneMask), 0))
2102 const SCEV *VectorTripCount =
2104 if (isa<SCEVCouldNotCompute>(VectorTripCount))
2105 VectorTripCount =
2107 assert(!isa<SCEVCouldNotCompute>(VectorTripCount) &&
2108 "Trip count SCEV must be computable");
2109 ScalarEvolution &SE = *PSE.getSE();
2110 ElementCount NumElements = BestVF.multiplyCoefficientBy(BestUF);
2111 const SCEV *C = SE.getElementCount(VectorTripCount->getType(), NumElements);
2112 if (!SE.isKnownPredicate(CmpInst::ICMP_ULE, VectorTripCount, C))
2113 return false;
2114 } else if (match(Term, m_BranchOnCond(m_VPValue(Cond))) ||
2116 // For BranchOnCond, check if we can prove the condition to be true using VF
2117 // and UF.
2118 if (!isConditionTrueViaVFAndUF(Cond, Plan, BestVF, BestUF, PSE))
2119 return false;
2120 } else {
2121 return false;
2122 }
2123
2124 // The vector loop region only executes once. Convert terminator of the
2125 // exiting block to exit in the first iteration.
2126 if (match(Term, m_BranchOnTwoConds())) {
2127 Term->setOperand(1, Plan.getTrue());
2128 return true;
2129 }
2130
2131 auto *BOC = new VPInstruction(VPInstruction::BranchOnCond, Plan.getTrue(), {},
2132 {}, Term->getDebugLoc());
2133 ExitingVPBB->appendRecipe(BOC);
2134 Term->eraseFromParent();
2135
2136 return true;
2137}
2138
2140 unsigned BestUF,
2142 assert(Plan.hasVF(BestVF) && "BestVF is not available in Plan");
2143 assert(Plan.hasUF(BestUF) && "BestUF is not available in Plan");
2144
2145 bool MadeChange =
2146 simplifyBranchConditionForVFAndUF(Plan, BestVF, BestUF, PSE);
2147 MadeChange |= replaceMaskWithCompare(Plan, BestVF);
2148 MadeChange |= optimizeVectorInductionWidthForTCAndVFUF(Plan, BestVF, BestUF);
2149
2150 if (MadeChange) {
2151 Plan.setVF(BestVF);
2152 assert(Plan.getConcreteUF() == BestUF && "BestUF must match the Plan's UF");
2153 }
2154}
2155
2157 for (VPRecipeBase &R :
2159 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&R);
2160 if (!PhiR)
2161 continue;
2162 RecurKind RK = PhiR->getRecurrenceKind();
2163 if (RK != RecurKind::Add && RK != RecurKind::Mul && RK != RecurKind::Sub &&
2165 continue;
2166
2168 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(U)) {
2169 RecWithFlags->dropPoisonGeneratingFlags();
2170 }
2171 }
2172}
2173
2174namespace {
2175struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
2176 /// If recipe \p R will lower to a GEP with a non-i8 source element type,
2177 /// return that source element type.
2178 static Type *getGEPSourceElementType(const VPSingleDefRecipe *R) {
2179 // All VPInstructions that lower to GEPs must have the i8 source element
2180 // type (as they are PtrAdds), so we omit it.
2182 .Case([](const VPReplicateRecipe *I) -> Type * {
2183 if (auto *GEP = dyn_cast<GetElementPtrInst>(I->getUnderlyingValue()))
2184 return GEP->getSourceElementType();
2185 return nullptr;
2186 })
2187 .Case<VPVectorPointerRecipe, VPWidenGEPRecipe>(
2188 [](auto *I) { return I->getSourceElementType(); })
2189 .Default([](auto *) { return nullptr; });
2190 }
2191
2192 /// Returns true if recipe \p Def can be safely handed for CSE.
2193 static bool canHandle(const VPSingleDefRecipe *Def) {
2194 // We can extend the list of handled recipes in the future,
2195 // provided we account for the data embedded in them while checking for
2196 // equality or hashing.
2198
2199 // The issue with (Insert|Extract)Value is that the index of the
2200 // insert/extract is not a proper operand in LLVM IR, and hence also not in
2201 // VPlan.
2202 if (!C || (!C->first && (C->second == Instruction::InsertValue ||
2203 C->second == Instruction::ExtractValue)))
2204 return false;
2205
2206 // During CSE, we can only handle non-memory recipes, as memory can alias.
2207 return !Def->mayReadOrWriteMemory();
2208 }
2209
2210 /// Hash the underlying data of \p Def.
2211 static unsigned getHashValue(const VPSingleDefRecipe *Def) {
2212 hash_code Result = hash_combine(
2213 Def->getVPRecipeID(), vputils::getOpcodeOrIntrinsicID(Def),
2214 getGEPSourceElementType(Def), Def->getScalarType(),
2216 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
2217 if (RFlags->hasPredicate())
2218 return hash_combine(Result, RFlags->getPredicate());
2219 if (auto *SIVSteps = dyn_cast<VPScalarIVStepsRecipe>(Def))
2220 return hash_combine(Result, SIVSteps->getInductionOpcode());
2221 return Result;
2222 }
2223
2224 /// Check equality of underlying data of \p L and \p R.
2225 static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
2226 if (L->getVPRecipeID() != R->getVPRecipeID() ||
2229 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2231 !equal(L->operands(), R->operands()))
2232 return false;
2235 "must have valid opcode info for both recipes");
2236 if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
2237 if (LFlags->hasPredicate() &&
2238 LFlags->getPredicate() !=
2239 cast<VPRecipeWithIRFlags>(R)->getPredicate())
2240 return false;
2241 if (auto *LSIV = dyn_cast<VPScalarIVStepsRecipe>(L))
2242 if (LSIV->getInductionOpcode() !=
2243 cast<VPScalarIVStepsRecipe>(R)->getInductionOpcode())
2244 return false;
2245 // Phi recipes can only be equal if they are in the same VPBB, as they
2246 // implicitly depend on their predecessors.
2247 if (isa<VPWidenPHIRecipe>(L) && L->getParent() != R->getParent())
2248 return false;
2249 // Recipes in replicate regions implicitly depend on predicate. If either
2250 // recipe is in a replicate region, only consider them equal if both have
2251 // the same parent.
2252 const VPRegionBlock *RegionL = L->getRegion();
2253 const VPRegionBlock *RegionR = R->getRegion();
2254 if (((RegionL && RegionL->isReplicator()) ||
2255 (RegionR && RegionR->isReplicator())) &&
2256 L->getParent() != R->getParent())
2257 return false;
2258 return L->getScalarType() == R->getScalarType();
2259 }
2260};
2261} // end anonymous namespace
2262
2263/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
2264/// Plan.
2266 VPDominatorTree VPDT(Plan);
2268
2270 Plan.getEntry());
2272 for (VPRecipeBase &R : *VPBB) {
2273 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2274 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2275 continue;
2276 if (VPSingleDefRecipe *V = CSEMap.lookup(Def)) {
2277 // V must dominate Def for a valid replacement.
2278 if (!VPDT.dominates(V->getParent(), VPBB))
2279 continue;
2280 // Only keep flags present on both V and Def.
2281 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(V))
2282 RFlags->intersectFlags(*cast<VPRecipeWithIRFlags>(Def));
2283 Def->replaceAllUsesWith(V);
2284 continue;
2285 }
2286 CSEMap[Def] = Def;
2287 }
2288 }
2289}
2290
2291/// Return true if we do not know how to (mechanically) hoist or sink a
2292/// non-memory or memory recipe \p R out of a loop region. When sinking, passing
2293/// \p Sinking = true ensures that assumes aren't sunk.
2295 VPBasicBlock *LastBB,
2296 bool Sinking = false) {
2297 if (!isa<VPReplicateRecipe>(R) || !R.mayReadOrWriteMemory() ||
2299 return vputils::cannotHoistOrSinkRecipe(R, Sinking);
2300
2301 // Check that the memory operation doesn't alias between FirstBB and LastBB.
2302 auto MemLoc = vputils::getMemoryLocation(R);
2303
2304 // TODO: Could make use of SinkStoreInfo::isNoAliasViaDistance by collecting
2305 // stores upfront, and constructing a full SinkStoreInfo.
2306 auto SinkInfo =
2307 Sinking ? std::make_optional(SinkStoreInfo(cast<VPReplicateRecipe>(R)))
2308 : std::nullopt;
2309
2310 return !MemLoc ||
2311 !canHoistOrSinkWithNoAliasCheck(*MemLoc, FirstBB, LastBB, SinkInfo);
2312}
2313
2314/// Move loop-invariant recipes out of the vector loop region in \p Plan.
2315static void licm(VPlan &Plan) {
2316 VPBasicBlock *Preheader = Plan.getVectorPreheader();
2317
2318 // Hoist any loop invariant recipes from the vector loop region to the
2319 // preheader. Preform a shallow traversal of the vector loop region, to
2320 // exclude recipes in replicate regions. Since the top-level blocks in the
2321 // vector loop region are guaranteed to execute if the vector pre-header is,
2322 // we don't need to check speculation safety.
2323 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
2324 assert(Preheader->getSingleSuccessor() == LoopRegion &&
2325 "Expected vector prehader's successor to be the vector loop region");
2327 vp_depth_first_shallow(LoopRegion->getEntry()))) {
2328 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2329 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2330 LoopRegion->getExitingBasicBlock()))
2331 continue;
2332 if (any_of(R.operands(), [](VPValue *Op) {
2333 return !Op->isDefinedOutsideLoopRegions();
2334 }))
2335 continue;
2336 R.moveBefore(*Preheader, Preheader->end());
2337 }
2338 }
2339
2340#ifndef NDEBUG
2341 VPDominatorTree VPDT(Plan);
2342#endif
2343 // Sink recipes with no users inside the vector loop region if all users are
2344 // in the same exit block of the region.
2345 // TODO: Extend to sink recipes from inner loops.
2347 LoopRegion->getEntry());
2349 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
2350 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2351 LoopRegion->getExitingBasicBlock(),
2352 /*Sinking=*/true))
2353 continue;
2354
2355 if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
2356 assert(!RepR->isPredicated() &&
2357 "Expected prior transformation of predicated replicates to "
2358 "replicate regions");
2359 // narrowToSingleScalarRecipes should have already maximally narrowed
2360 // replicates to single-scalar replicates.
2361 // TODO: When unrolling, replicateByVF doesn't handle sunk
2362 // non-single-scalar replicates correctly.
2363 if (!RepR->isSingleScalar())
2364 continue;
2365
2366 // The pointer operand of stores must be loop-invariant.
2367 if (RepR->getOpcode() == Instruction::Store &&
2368 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2369 continue;
2370 }
2371
2372 [[maybe_unused]] auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
2373 assert((!R.mayWriteToMemory() ||
2374 (RepR && RepR->getOpcode() == Instruction::Store &&
2375 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2376 "The only recipes that may write to memory are expected to be "
2377 "stores with invariant pointer-operand");
2378
2379 // TODO: Use R.definedValues() instead of casting to VPSingleDefRecipe to
2380 // support recipes with multiple defined values (e.g., interleaved loads).
2381 auto *Def = cast<VPSingleDefRecipe>(&R);
2382
2383 // Cannot sink the recipe if the user is defined in a loop region or a
2384 // non-successor of the vector loop region. Cannot sink if user is a phi
2385 // either.
2386 VPBasicBlock *SinkBB = nullptr;
2387 if (any_of(Def->users(), [&SinkBB, &LoopRegion](VPUser *U) {
2388 auto *UserR = cast<VPRecipeBase>(U);
2389 VPBasicBlock *Parent = UserR->getParent();
2390 // TODO: Support sinking when users are in multiple blocks.
2391 if (SinkBB && SinkBB != Parent)
2392 return true;
2393 SinkBB = Parent;
2394 // TODO: If the user is a PHI node, we should check the block of
2395 // incoming value. Support PHI node users if needed.
2396 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2397 Parent->getSinglePredecessor() != LoopRegion;
2398 }))
2399 continue;
2400
2401 if (!SinkBB)
2402 SinkBB = cast<VPBasicBlock>(LoopRegion->getSingleSuccessor());
2403
2404 // TODO: This will need to be a check instead of a assert after
2405 // conditional branches in vectorized loops are supported.
2406 assert(VPDT.properlyDominates(VPBB, SinkBB) &&
2407 "Defining block must dominate sink block");
2408 // TODO: Clone the recipe if users are on multiple exit paths, instead of
2409 // just moving.
2410 Def->moveBefore(*SinkBB, SinkBB->getFirstNonPhi());
2411 }
2412 }
2413}
2414
2416 VPlan &Plan, const MapVector<Instruction *, uint64_t> &MinBWs) {
2417 if (Plan.hasScalarVFOnly())
2418 return;
2419 // Keep track of created truncates, so they can be re-used. Note that we
2420 // cannot use RAUW after creating a new truncate, as this would could make
2421 // other uses have different types for their operands, making them invalidly
2422 // typed.
2424 VPBasicBlock *PH = Plan.getVectorPreheader();
2427 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2430 continue;
2431
2432 VPValue *ResultVPV = R.getVPSingleValue();
2433 auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
2434 unsigned NewResSizeInBits = MinBWs.lookup(UI);
2435 if (!NewResSizeInBits)
2436 continue;
2437
2438 // If the value wasn't vectorized, we must maintain the original scalar
2439 // type. Skip those here, after incrementing NumProcessedRecipes. Also
2440 // skip casts which do not need to be handled explicitly here, as
2441 // redundant casts will be removed during recipe simplification.
2443 continue;
2444
2445 Type *OldResTy = ResultVPV->getScalarType();
2446 unsigned OldResSizeInBits = OldResTy->getScalarSizeInBits();
2447 assert(OldResTy->isIntegerTy() && "only integer types supported");
2448 (void)OldResSizeInBits;
2449
2450 auto *NewResTy = IntegerType::get(Plan.getContext(), NewResSizeInBits);
2451
2452 // Any wrapping introduced by shrinking this operation shouldn't be
2453 // considered undefined behavior. So, we can't unconditionally copy
2454 // arithmetic wrapping flags to VPW.
2455 if (auto *VPW = dyn_cast<VPRecipeWithIRFlags>(&R))
2456 VPW->dropPoisonGeneratingFlags();
2457
2458 assert((OldResSizeInBits != NewResSizeInBits ||
2459 match(&R, m_ICmp(m_VPValue(), m_VPValue()))) &&
2460 "Only ICmps should not need extending the result.");
2461 assert(!isa<VPWidenStoreRecipe>(&R) && "stores cannot be narrowed");
2462
2463 // For loads/intrinsics we don't recreate the recipe; just wrap the
2464 // original wide result in a ZExt to OldResTy.
2466 if (OldResSizeInBits != NewResSizeInBits) {
2468 Instruction::ZExt, ResultVPV, OldResTy);
2469 ResultVPV->replaceAllUsesWith(Ext);
2470 Ext->setOperand(0, ResultVPV);
2471 }
2472 continue;
2473 }
2474
2475 // Shrink operands by introducing truncates as needed.
2476 unsigned StartIdx =
2477 match(&R, m_Select(m_VPValue(), m_VPValue(), m_VPValue())) ? 1 : 0;
2478 SmallVector<VPValue *> NewOperands(R.operands());
2479 for (VPValue *&Op : drop_begin(NewOperands, StartIdx)) {
2480 unsigned OpSizeInBits = Op->getScalarType()->getScalarSizeInBits();
2481 if (OpSizeInBits == NewResSizeInBits)
2482 continue;
2483 assert(OpSizeInBits > NewResSizeInBits && "nothing to truncate");
2484 auto [ProcessedIter, Inserted] = ProcessedTruncs.try_emplace(Op);
2485 if (Inserted) {
2486 VPBuilder Builder;
2487 if (isa<VPIRValue>(Op))
2488 Builder.setInsertPoint(PH);
2489 else
2490 Builder.setInsertPoint(&R);
2491 ProcessedIter->second =
2492 Builder.createWidenCast(Instruction::Trunc, Op, NewResTy);
2493 }
2494 Op = ProcessedIter->second;
2495 }
2496
2497 auto *NWR = cast<VPWidenRecipe>(&R)->cloneWithOperands(NewOperands);
2498 NWR->insertBefore(&R);
2499
2500 // Wrap NWR in a ZExt to preserve the original wide type for downstream
2501 // users (unless this is an ICmp, which produces i1 regardless).
2502 VPValue *Replacement = NWR->getVPSingleValue();
2503 if (OldResSizeInBits != NewResSizeInBits)
2504 Replacement =
2506 .createWidenCast(Instruction::ZExt, Replacement, OldResTy)
2507 ->getVPSingleValue();
2508 ResultVPV->replaceAllUsesWith(Replacement);
2509 R.eraseFromParent();
2510 }
2511 }
2512}
2513
2514bool VPlanTransforms::removeBranchOnConst(VPlan &Plan, bool OnlyLatches) {
2515 std::optional<VPDominatorTree> VPDT;
2516 if (OnlyLatches)
2517 VPDT.emplace(Plan);
2518
2519 // Collect all blocks before modifying the CFG so we can identify unreachable
2520 // ones after constant branch removal.
2522
2523 bool SimplifiedPhi = false;
2524 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(AllBlocks)) {
2525 VPValue *Cond;
2526 // Skip blocks that are not terminated by BranchOnCond.
2527 if (VPBB->empty() || !match(&VPBB->back(), m_BranchOnCond(m_VPValue(Cond))))
2528 continue;
2529
2530 if (OnlyLatches && !VPBlockUtils::isLatch(VPBB, *VPDT))
2531 continue;
2532
2533 assert(VPBB->getNumSuccessors() == 2 &&
2534 "Two successors expected for BranchOnCond");
2535 unsigned RemovedIdx;
2536 if (match(Cond, m_True()))
2537 RemovedIdx = 1;
2538 else if (match(Cond, m_False()))
2539 RemovedIdx = 0;
2540 else
2541 continue;
2542
2543 VPBasicBlock *RemovedSucc =
2544 cast<VPBasicBlock>(VPBB->getSuccessors()[RemovedIdx]);
2545 assert(count(RemovedSucc->getPredecessors(), VPBB) == 1 &&
2546 "There must be a single edge between VPBB and its successor");
2547 // Values coming from VPBB into phi recipes of RemovedSucc are removed from
2548 // these recipes.
2549 auto Phis = RemovedSucc->phis();
2550 for (VPRecipeBase &R : Phis)
2551 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(VPBB);
2552 SimplifiedPhi |= !std::empty(Phis);
2553
2554 // Disconnect blocks and remove the terminator.
2555 VPBlockUtils::disconnectBlocks(VPBB, RemovedSucc);
2556 VPBB->back().eraseFromParent();
2557 }
2558
2559 // Compute which blocks are still reachable from the entry after constant
2560 // branch removal.
2563
2564 // Detach all unreachable blocks from their successors, removing their recipes
2565 // and incoming values from phi recipes.
2566 VPSymbolicValue Tmp(nullptr);
2567 for (VPBlockBase *B : AllBlocks) {
2568 if (Reachable.contains(B))
2569 continue;
2570 for (VPBlockBase *Succ : to_vector(B->successors())) {
2571 if (auto *SuccBB = dyn_cast<VPBasicBlock>(Succ))
2572 for (VPRecipeBase &R : SuccBB->phis())
2573 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(B);
2575 }
2576 for (VPBasicBlock *DeadBB :
2578 for (VPRecipeBase &R : make_early_inc_range(*DeadBB)) {
2579 for (VPValue *Def : R.definedValues())
2580 Def->replaceAllUsesWith(&Tmp);
2581 R.eraseFromParent();
2582 }
2583 }
2584 }
2585 return SimplifiedPhi;
2586}
2587
2608
2610 VPlan &Plan, PredicatedScalarEvolution &PSE,
2611 const DenseMap<Value *, const SCEV *> &StridesMap,
2612 const VPDominatorTree &VPDT) {
2613 // Replace VPValues for known constant strides guaranteed by predicated scalar
2614 // evolution that are guaranteed to be guarded by the runtime checks; that is,
2615 // blocks dominated by the vector header.
2616 assert(!Plan.getVectorLoopRegion() &&
2617 "expected to run before loop regions are created");
2618 const auto &[Header, _] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
2619 auto CanUseVersionedStride = [&VPDT, Header = Header, &Plan](VPUser &U,
2620 unsigned Idx) {
2621 auto *R = cast<VPRecipeBase>(&U);
2622 // Skip phis if the loop if loop is not yet guarded.
2623 if (isa<VPPhiAccessors>(R) &&
2624 Header == Plan.getEntry()->getSingleSuccessor())
2625 return false;
2626 return VPDT.dominates(Header, R->getParent());
2627 };
2628 ValueToSCEVMapTy RewriteMap;
2629 for (const SCEV *Stride : StridesMap.values()) {
2630 using namespace SCEVPatternMatch;
2631 auto *StrideV = cast<SCEVUnknown>(Stride)->getValue();
2632 const APInt *StrideConst;
2633 if (!match(PSE.getSCEV(StrideV), m_scev_APInt(StrideConst)))
2634 // Only handle constant strides for now.
2635 continue;
2636
2637 auto *CI = Plan.getConstantInt(*StrideConst);
2638 if (VPValue *StrideVPV = Plan.getLiveIn(StrideV))
2639 StrideVPV->replaceUsesWithIf(CI, CanUseVersionedStride);
2640
2641 // The versioned value may not be used in the loop directly but through a
2642 // sext/zext. Add new live-ins in those cases.
2643 for (Value *U : StrideV->users()) {
2645 continue;
2646 VPValue *StrideVPV = Plan.getLiveIn(U);
2647 if (!StrideVPV)
2648 continue;
2649 unsigned BW = U->getType()->getScalarSizeInBits();
2650 APInt C =
2651 isa<SExtInst>(U) ? StrideConst->sext(BW) : StrideConst->zext(BW);
2652 VPValue *CI = Plan.getConstantInt(C);
2653 StrideVPV->replaceUsesWithIf(CI, CanUseVersionedStride);
2654 }
2655 RewriteMap[StrideV] = PSE.getSCEV(StrideV);
2656 }
2657
2658 for (VPRecipeBase &R : *Plan.getEntry()) {
2659 auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(&R);
2660 if (!ExpSCEV)
2661 continue;
2662 const SCEV *ScevExpr = ExpSCEV->getSCEV();
2663 auto *NewSCEV =
2664 SCEVParameterRewriter::rewrite(ScevExpr, *PSE.getSE(), RewriteMap);
2665 if (NewSCEV != ScevExpr) {
2666 VPValue *NewExp = vputils::getOrCreateVPValueForSCEVExpr(Plan, NewSCEV);
2667 ExpSCEV->replaceAllUsesWith(NewExp);
2668 if (Plan.getTripCount() == ExpSCEV)
2669 Plan.resetTripCount(NewExp);
2670 }
2671 }
2672}
2673
2675 // Collect recipes in the backward slice of `Root` that may generate a poison
2676 // value that is used after vectorization.
2678 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](VPRecipeBase *Root) {
2680 Worklist.push_back(Root);
2681
2682 // Traverse the backward slice of Root through its use-def chain.
2683 while (!Worklist.empty()) {
2684 VPRecipeBase *CurRec = Worklist.pop_back_val();
2685
2686 if (!Visited.insert(CurRec).second)
2687 continue;
2688
2689 // Prune search if we find another recipe generating a widen memory
2690 // instruction. Widen memory instructions involved in address computation
2691 // will lead to gather/scatter instructions, which don't need to be
2692 // handled.
2694 VPHeaderPHIRecipe>(CurRec))
2695 continue;
2696
2697 // This recipe contributes to the address computation of a widen
2698 // load/store. If the underlying instruction has poison-generating flags,
2699 // drop them directly.
2700 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(CurRec)) {
2701 VPValue *A, *B;
2702 // Dropping disjoint from an OR may yield incorrect results, as some
2703 // analysis may have converted it to an Add implicitly (e.g. SCEV used
2704 // for dependence analysis). Instead, replace it with an equivalent Add.
2705 // This is possible as all users of the disjoint OR only access lanes
2706 // where the operands are disjoint or poison otherwise.
2707 if (match(RecWithFlags, m_BinaryOr(m_VPValue(A), m_VPValue(B))) &&
2708 RecWithFlags->isDisjoint()) {
2709 VPBuilder Builder(RecWithFlags);
2710 VPInstruction *New =
2711 Builder.createAdd(A, B, RecWithFlags->getDebugLoc());
2712 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
2713 RecWithFlags->replaceAllUsesWith(New);
2714 RecWithFlags->eraseFromParent();
2715 CurRec = New;
2716 } else
2717 RecWithFlags->dropPoisonGeneratingFlags();
2718 } else {
2721 (void)Instr;
2722 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
2723 "found instruction with poison generating flags not covered by "
2724 "VPRecipeWithIRFlags");
2725 }
2726
2727 // Add new definitions to the worklist.
2728 for (VPValue *Operand : CurRec->operands())
2729 if (VPRecipeBase *OpDef = Operand->getDefiningRecipe())
2730 Worklist.push_back(OpDef);
2731 }
2732 });
2733
2734 // We want to exclude the tail folding case, as we don't need to drop flags
2735 // for operations computing the first lane in this case: the first lane of the
2736 // header mask must always be true. For reverse memory accesses, the mask is
2737 // wrapped in a Reverse, which is just a permutation of the header mask, so
2738 // peel it off before checking. The header mask is still the abstract region
2739 // value at this point (materialization happens later).
2740 auto m_UnlessHdrMask = m_Unless( // NOLINT
2742
2743 // Traverse all the recipes in the VPlan and collect the poison-generating
2744 // recipes in the backward slice starting at the address of a VPWidenRecipe or
2745 // VPInterleaveRecipe.
2746 auto Iter =
2749 for (VPRecipeBase &Recipe : *VPBB) {
2750 if (auto *WidenRec = dyn_cast<VPWidenMemoryRecipe>(&Recipe)) {
2751 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
2752 if (AddrDef && WidenRec->isConsecutive() && WidenRec->getMask() &&
2753 match(WidenRec->getMask(), m_UnlessHdrMask))
2754 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2755 } else if (auto *InterleaveRec = dyn_cast<VPInterleaveRecipe>(&Recipe)) {
2756 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
2757 if (AddrDef && InterleaveRec->getMask() &&
2758 match(InterleaveRec->getMask(), m_UnlessHdrMask))
2759 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2760 }
2761 }
2762 }
2763}
2764
2766 VPlan &Plan,
2768 &InterleaveGroups,
2769 const bool &EpilogueAllowed) {
2770 if (InterleaveGroups.empty())
2771 return;
2772
2774 for (VPBasicBlock *VPBB :
2777 for (VPRecipeBase &R : make_filter_range(*VPBB, [](VPRecipeBase &R) {
2778 return isa<VPWidenMemoryRecipe>(&R);
2779 })) {
2780 auto *MemR = cast<VPWidenMemoryRecipe>(&R);
2781 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
2782 }
2783
2784 // Interleave memory: for each Interleave Group we marked earlier as relevant
2785 // for this VPlan, replace the Recipes widening its memory instructions with a
2786 // single VPInterleaveRecipe at its insertion point.
2787 VPDominatorTree VPDT(Plan);
2788 for (const auto *IG : InterleaveGroups) {
2789 VPWidenMemoryRecipe *Start = nullptr;
2790 Instruction *StartMember = nullptr;
2791 for (auto *Member : IG->members())
2792 if (VPWidenMemoryRecipe *R = IRMemberToRecipe.lookup(Member)) {
2793 StartMember = Member;
2794 Start = R;
2795 break;
2796 }
2797 if (!StartMember) // All member recipes are dead, so the group is dead.
2798 continue;
2799 VPIRMetadata InterleaveMD(*Start);
2800 SmallVector<VPValue *, 4> StoredValues;
2801 for (unsigned I = 0; I < IG->getFactor(); ++I) {
2802 Instruction *MemberI = IG->getMember(I);
2803 if (!MemberI)
2804 continue;
2805 if (VPWidenMemoryRecipe *MemoryR = IRMemberToRecipe.lookup(MemberI)) {
2806 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(MemoryR->getAsRecipe()))
2807 StoredValues.push_back(StoreR->getStoredValue());
2808 InterleaveMD.intersect(*MemoryR);
2809 } else {
2810 InterleaveMD.intersect(VPIRMetadata(*MemberI));
2811 }
2812 }
2813
2814 bool NeedsMaskForGaps =
2815 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
2816 (!StoredValues.empty() && !IG->isFull());
2817
2818 Instruction *IRInsertPos = IG->getInsertPos();
2819 auto *InsertPos = IRMemberToRecipe.lookup(IRInsertPos);
2820 if (!InsertPos) {
2821 // InsertPos member is dead: find a new member that is alive.
2822 assert(isa<VPWidenLoadRecipe>(Start->getAsRecipe()) &&
2823 "Dead member in non-load group?");
2824 InsertPos = Start;
2825 for (Instruction *Member : IG->members())
2826 if (VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member))
2827 if (VPDT.properlyDominates(MemberR->getAsRecipe(),
2828 InsertPos->getAsRecipe()))
2829 InsertPos = MemberR;
2830 IRInsertPos = &InsertPos->getIngredient();
2831 }
2832 VPRecipeBase *InsertPosR = InsertPos->getAsRecipe();
2833
2835 if (auto *Gep = dyn_cast<GetElementPtrInst>(
2836 getLoadStorePointerOperand(IRInsertPos)->stripPointerCasts()))
2837 NW = Gep->getNoWrapFlags().withoutNoUnsignedWrap();
2838
2839 // Get or create the start address for the interleave group.
2840 VPValue *Addr = Start->getAddr();
2841 VPRecipeBase *AddrDef = Addr->getDefiningRecipe();
2842 if (IG->getIndex(StartMember) != 0 ||
2843 (AddrDef && !VPDT.properlyDominates(AddrDef, InsertPosR))) {
2844 // Either member zero's recipe is dead, or we cannot re-use the address of
2845 // member zero because it does not dominate the insert position. Instead,
2846 // use the address of the insert position and create a PtrAdd adjusting it
2847 // to the address of member zero.
2848 // TODO: Hoist Addr's defining recipe (and any operands as needed) to
2849 // InsertPos or sink loads above zero members to join it.
2850 assert(IG->getIndex(IRInsertPos) != 0 &&
2851 "index of insert position shouldn't be zero");
2852 auto &DL = IRInsertPos->getDataLayout();
2853 APInt Offset(32,
2854 DL.getTypeAllocSize(getLoadStoreType(IRInsertPos)) *
2855 IG->getIndex(IRInsertPos),
2856 /*IsSigned=*/true);
2857 VPValue *OffsetVPV = Plan.getConstantInt(-Offset);
2858 VPBuilder B(InsertPosR);
2859 Addr = B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
2860 }
2861 // If the group is reverse, adjust the index to refer to the last vector
2862 // lane instead of the first. We adjust the index from the first vector
2863 // lane, rather than directly getting the pointer for lane VF - 1, because
2864 // the pointer operand of the interleaved access is supposed to be uniform.
2865 if (IG->isReverse()) {
2866 auto *ReversePtr = new VPVectorEndPointerRecipe(
2867 Addr, &Plan.getVF(), getLoadStoreType(IRInsertPos),
2868 -(int64_t)IG->getFactor(), NW, InsertPosR->getDebugLoc());
2869 ReversePtr->insertBefore(InsertPosR);
2870 Addr = ReversePtr;
2871 }
2872 auto *VPIG = new VPInterleaveRecipe(
2873 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
2874 InterleaveMD, InsertPosR->getDebugLoc());
2875 VPIG->insertBefore(InsertPosR);
2876
2877 unsigned J = 0;
2878 for (unsigned i = 0; i < IG->getFactor(); ++i)
2879 if (Instruction *Member = IG->getMember(i)) {
2880 VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member);
2881 if (!Member->getType()->isVoidTy()) {
2882 if (MemberR) {
2883 VPValue *OriginalV = MemberR->getAsRecipe()->getVPSingleValue();
2884 OriginalV->replaceAllUsesWith(VPIG->getVPValue(J));
2885 }
2886 J++;
2887 }
2888 if (MemberR)
2889 MemberR->getAsRecipe()->eraseFromParent();
2890 }
2891 }
2892}
2893
2894/// Returns the VPValue representing the uncountable exit comparison used by
2895/// AnyOf if the recipes it depends on can be traced back to live-ins and
2896/// the addresses (in GEP/PtrAdd form) of any (non-masked) load used in
2897/// generating the values for the comparison. The recipes are stored in
2898/// \p Recipes.
2899static std::optional<VPValue *>
2901 VPBasicBlock *LatchVPBB) {
2902 // Given a plain CFG VPlan loop with countable latch exiting block
2903 // \p LatchVPBB, we're looking to match the recipes contributing to the
2904 // uncountable exit condition comparison (here, vp<%4>) back to either
2905 // live-ins or the address nodes for the load used as part of the uncountable
2906 // exit comparison so that we can either move them within the loop, or copy
2907 // them to the preheader depending on the chosen method for dealing with
2908 // stores in uncountable exit loops.
2909 //
2910 // Currently, the address of the load is restricted to a GEP with 2 operands
2911 // and a live-in base address. This constraint may be relaxed later.
2912 //
2913 // VPlan ' for UF>=1' {
2914 // Live-in vp<%0> = VF * UF
2915 // Live-in vp<%1> = vector-trip-count
2916 // Live-in ir<20> = original trip-count
2917 //
2918 // ir-bb<entry>:
2919 // Successor(s): scalar.ph, vector.ph
2920 //
2921 // vector.ph:
2922 // Successor(s): for.body
2923 //
2924 // for.body:
2925 // EMIT vp<%2> = phi ir<0>, vp<%index.next>
2926 // EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, for.inc ]
2927 // EMIT ir<%uncountable.addr> = getelementptr inbounds nuw ir<%pred>,ir<%iv>
2928 // EMIT ir<%uncountable.val> = load ir<%uncountable.addr>
2929 // EMIT ir<%uncountable.cond> = icmp sgt ir<%uncountable.val>, ir<500>
2930 // EMIT vp<%3> = masked-cond ir<%uncountable.cond>
2931 // Successor(s): for.inc
2932 //
2933 // for.inc:
2934 // EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1>
2935 // EMIT ir<%countable.cond> = icmp eq ir<%iv.next>, ir<20>
2936 // EMIT vp<%index.next> = add nuw vp<%2>, vp<%0>
2937 // EMIT vp<%4> = any-of ir<%3>
2938 // EMIT vp<%5> = icmp eq vp<%index.next>, vp<%1>
2939 // EMIT branch-on-two-conds vp<%4>, vp<%5>
2940 // Successor(s): middle.block, middle.block, for.body
2941 //
2942 // middle.block:
2943 // Successor(s): ir-bb<exit>, scalar.ph
2944 //
2945 // ir-bb<exit>:
2946 // No successors
2947 //
2948 // scalar.ph:
2949 // }
2950
2951 // Find the uncountable loop exit condition.
2952 VPValue *UncountableCondition = nullptr;
2953 if (!match(LatchVPBB->getTerminator(),
2954 m_BranchOnTwoConds(m_AnyOf(m_VPValue(UncountableCondition)),
2955 m_VPValue())))
2956 return std::nullopt;
2957
2959 Worklist.push_back(UncountableCondition);
2960 while (!Worklist.empty()) {
2961 VPValue *V = Worklist.pop_back_val();
2962
2963 // Any value defined outside the loop does not need to be copied.
2964 if (V->isDefinedOutsideLoopRegions())
2965 continue;
2966
2967 // FIXME: Remove the single user restriction; it's here because we're
2968 // starting with the simplest set of loops we can, and multiple
2969 // users means needing to add PHI nodes in the transform.
2970 if (V->getNumUsers() > 1)
2971 return std::nullopt;
2972
2973 VPValue *Op1, *Op2;
2974 // Walk back through recipes until we find at least one load from memory.
2975 if (match(V, m_ICmp(m_VPValue(Op1), m_VPValue(Op2)))) {
2976 Worklist.push_back(Op1);
2977 Worklist.push_back(Op2);
2978 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
2979 } else if (match(V, m_VPInstruction<Instruction::Load>(m_VPValue(Op1)))) {
2980 VPRecipeBase *GepR = Op1->getDefiningRecipe();
2981 // Only matching base + single offset term for now.
2982 if (GepR->getNumOperands() != 2)
2983 return std::nullopt;
2984 // Matching a GEP with a loop-invariant base ptr.
2986 m_LiveIn(), m_VPValue())))
2987 return std::nullopt;
2988 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
2989 Recipes.push_back(cast<VPInstruction>(GepR));
2991 m_VPValue(Op1)))) {
2992 Worklist.push_back(Op1);
2993 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
2994 } else
2995 return std::nullopt;
2996 }
2997
2998 // If we couldn't match anything, don't return the condition. It may be
2999 // defined outside the loop.
3000 if (Recipes.empty() ||
3002 return std::nullopt;
3003
3004 return UncountableCondition;
3005}
3006
3012
3013/// Update \p Plan to mask memory operations in the loop based on whether the
3014/// early exit is taken or not.
3015///
3016/// We're currently expecting to find a loop with properties similar to the
3017/// following:
3018///
3019/// for.body:
3020/// ir<%indvars.iv> = WIDEN-INDUCTION nuw nsw ir<0>, ir<1>, vp<%0>
3021/// EMIT ir<%arrayidx> = getelementptr inbounds nuw ir<@c>, ir<%indvars.iv>
3022/// EMIT-SCALAR ir<%0> = load ir<%arrayidx>
3023/// EMIT ir<%cmp1> = icmp sgt ir<%0>, ir<5>
3024/// EMIT vp<%1> = masked-cond ir<%cmp1>
3025/// Successor(s): if.end
3026///
3027/// if.end:
3028/// EMIT ir<%arrayidx3> = getelementptr inbounds nuw ir<@src>, ir<%indvars.iv>
3029/// EMIT-SCALAR ir<%2> = load ir<%arrayidx3>
3030/// EMIT ir<%add> = add nsw ir<%2>, ir<42>
3031/// EMIT ir<%arrayidx5> = getelementptr inbounds nuw ir<@dst>, ir<%indvars.iv>
3032/// EMIT store ir<%add>, ir<%arrayidx5>
3033/// EMIT ir<%indvars.iv.next> = add nuw nsw ir<%indvars.iv>, ir<1>
3034/// EMIT vp<%3> = any-of ir<%1>
3035/// EMIT ir<%exitcond.not> = icmp eq ir<%indvars.iv.next>, ir<10000>
3036/// EMIT branch-on-two-conds vp<%3>, ir<%exitcond.not>
3037/// Successor(s): middle.block, middle.block, for.body
3038///
3039/// We currently expect LoopVectorizationLegality to ensure that:
3040/// * There must also be a counted exit. We will need to support speculative
3041/// or first-faulting loads before we can remove this restriction.
3042/// * Any stores within the loop must not alias with the load used for the
3043/// uncountable exit. We can relax this a bit with runtime aliasing checks.
3044/// * Other memory operations in the loop can take place before or after the
3045/// uncountable exit, but must also be unconditional. We need to support
3046/// combining the conditions in VPlanPredicator.
3047/// * The loop must have a single unconditional load contributing to the
3048/// uncountable exit comparison, and the other term must be loop-invariant.
3049/// Improving upon this requires work in getRecipesForUncountableExit to
3050/// handle more complex recipe graphs.
3053 VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB,
3054 Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT,
3055 AssumptionCache *AC) {
3056
3057 // Disconnect early exiting blocks from successors, remove branches. We
3058 // currently don't support multiple uses for recipes involved in creating
3059 // the uncountable exit condition.
3060 for (auto &Exit : Exits) {
3061 if (Exit.EarlyExitingVPBB == LatchVPBB)
3062 continue;
3063
3064 for (VPRecipeBase &R : Exit.EarlyExitVPBB->phis())
3065 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
3066 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
3067 VPBlockUtils::disconnectBlocks(Exit.EarlyExitingVPBB, Exit.EarlyExitVPBB);
3068 }
3069
3070 VPDominatorTree VPDT(Plan);
3071
3072 // We can abandon a VPlan entirely if we return false here, so we shouldn't
3073 // crash if some earlier assumptions on scalar IR don't hold for the vplan
3074 // version of the loop.
3075 SmallVector<VPInstruction *, 8> ConditionRecipes;
3076
3077 std::optional<VPValue *> Cond =
3078 getRecipesForUncountableExit(ConditionRecipes, LatchVPBB);
3079 if (!Cond)
3080 return false;
3081
3082 // Find load contributing to condition.
3083 // At the moment LoopVectorizationLegality only supports a single
3084 // early-exit expression with a compare and a single load that must
3085 // be unconditional.
3086 // TODO: Support more than one load.
3087 auto *Load =
3088 find_singleton<VPInstruction>(ConditionRecipes, [](auto *I, bool _) {
3090 ? I
3091 : nullptr;
3092 });
3093 assert(Load && "Couldn't find exactly one load");
3094 // TODO: Support conditional loads for uncountable exits.
3095 assert(VPDT.dominates(Load->getParent(), LatchVPBB) &&
3096 "Uncountable exit condition load is conditional.");
3097 VPInstruction *Ptr = cast<VPInstruction>(Load->getOperand(0));
3098
3099 // Ensure that we are guaranteed to be able to dereference the memory used
3100 // for determining the uncountable exit for the maximum possible number of
3101 // scalar iterations of the loop.
3102 //
3103 // TODO: Support first-faulting loads in cases where we don't know whether
3104 // all possible addresses are dereferenceable.
3105 {
3107 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, TheLoop);
3108 const DataLayout &DL = Plan.getDataLayout();
3109 APInt EltSize(DL.getIndexTypeSizeInBits(Ptr->getScalarType()),
3110 DL.getTypeStoreSize(Load->getScalarType()).getFixedValue());
3112 PtrSCEV, cast<LoadInst>(Load->getUnderlyingInstr())->getAlign(),
3113 PSE.getSE()->getConstant(EltSize), TheLoop, *PSE.getSE(), DT, AC,
3114 &Predicates))
3115 return false;
3116 }
3117
3118 // Check for a single GEP for the condition load to see if we can link it to
3119 // a widen IV recipe with a step of 1; we're only interested in contiguous
3120 // accesses for the condition load right now.
3121 auto *IV = cast<VPWidenInductionRecipe>(&HeaderVPBB->front());
3122 if (!match(IV->getStartValue(), m_SpecificInt(0)) ||
3123 !match(IV->getStepValue(), m_SpecificInt(1)))
3124 return false;
3126 m_Specific(IV))))
3127 return false;
3128
3129 // We want to guarantee that the uncountable exit condition (and the mask
3130 // we will generate from it) are available for all operations in the loop
3131 // that need to be masked. If the condition recipes are not already the first
3132 // recipes in the header after the last phi, move them there.
3133 auto InsertIt = HeaderVPBB->getFirstNonPhi();
3134 while (InsertIt != HeaderVPBB->end() &&
3135 is_contained(ConditionRecipes, &*InsertIt)) {
3136 erase(ConditionRecipes, &*InsertIt);
3137 InsertIt++;
3138 }
3139 for (auto *Recipe : reverse(ConditionRecipes))
3140 Recipe->moveBefore(*HeaderVPBB, InsertIt);
3141
3142 // Create a mask to represent all lanes that fully execute in the vector loop,
3143 // stopping short of any early exit.
3144 VPBuilder MaskBuilder(HeaderVPBB, InsertIt);
3145 VPValue *FirstActive = MaskBuilder.createFirstActiveLane(*Cond);
3146 Type *IVScalarTy = IV->getScalarType();
3147 VPValue *Zero = Plan.getZero(IVScalarTy);
3148 FirstActive =
3149 MaskBuilder.createScalarZExtOrTrunc(FirstActive, IVScalarTy, DebugLoc());
3151 {Zero, FirstActive}, DebugLoc(),
3152 "uncountable.exit.mask");
3153
3154 // Convert all other memory operations to use the mask.
3155 for (VPBasicBlock *VPBB : vp_rpo_plain_cfg_loop_body(HeaderVPBB))
3156 for (VPRecipeBase &R : *VPBB)
3157 if (R.mayReadOrWriteMemory() && &R != Load) {
3158 // TODO: Handle conditional memory operations in the loop.
3159 if (!VPDT.dominates(R.getParent(), LatchVPBB))
3160 return false;
3161 cast<VPInstruction>(&R)->addMask(Mask);
3162 }
3163
3164 // Update middle block branch to compare (IV + however many lanes were active)
3165 // against the full trip count, since we may be exiting the vector loop early.
3166 // If we didn't take an early exit, we should get the equivalent of VF from
3167 // the FirstActiveLane.
3168 assert(match(MiddleVPBB->getTerminator(), m_BranchOnCond()) &&
3169 "Expected BranchOnCond terminator for MiddleVPBB");
3170 VPBuilder MiddleBuilder(MiddleVPBB->getTerminator());
3171 VPValue *ScalarIV = MiddleBuilder.createNaryOp(VPInstruction::ExtractLane,
3172 {Zero, IV}, DebugLoc());
3173 VPValue *ExitIV = MiddleBuilder.createAdd(ScalarIV, FirstActive);
3174 VPValue *FullTC =
3175 MiddleBuilder.createICmp(CmpInst::ICMP_EQ, ExitIV, Plan.getTripCount());
3176 MiddleVPBB->getTerminator()->setOperand(0, FullTC);
3177
3178 // Update resume phi in scalar.ph.
3179 VPBasicBlock *ScalarPH = Plan.getScalarPreheader();
3180 auto Phis = ScalarPH->phis();
3181 // TODO: Handle more than one Phi; re-derive from IV.
3182 // TODO: Handle reductions.
3183 if (range_size(Phis) != 1)
3184 return false;
3185 VPPhi *ContinueIV = cast<VPPhi>(Phis.begin());
3186 // Make sure we're referring to the same IV.
3187 assert(
3188 match(ContinueIV->getOperand(0),
3190 "Continuing from different IV");
3191 ContinueIV->setOperand(0, ExitIV);
3192 return true;
3193}
3194
3196 VPlan &Plan, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB,
3197 VPBasicBlock *MiddleVPBB, Loop *TheLoop, PredicatedScalarEvolution &PSE,
3199#ifndef NDEBUG
3200 VPDominatorTree VPDT(Plan);
3201#endif
3202 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
3204 for (auto [EarlyExitingVPBB, ExitBlock] :
3205 vputils::getEarlyExits(Plan, MiddleVPBB)) {
3206 // Collect condition for this early exit.
3207 VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors()[0];
3208 VPValue *CondOfEarlyExitingVPBB;
3209 [[maybe_unused]] bool Matched =
3210 match(EarlyExitingVPBB->getTerminator(),
3211 m_BranchOnCond(m_VPValue(CondOfEarlyExitingVPBB)));
3212 assert(Matched && "Terminator must be BranchOnCond");
3213
3214 // Insert the MaskedCond in the EarlyExitingVPBB so the predicator adds
3215 // the correct block mask.
3216 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
3217 auto *CondToEarlyExit = EarlyExitingBuilder.createNaryOp(
3219 TrueSucc == ExitBlock
3220 ? CondOfEarlyExitingVPBB
3221 : EarlyExitingBuilder.createNot(CondOfEarlyExitingVPBB));
3222 assert((isa<VPIRValue>(CondOfEarlyExitingVPBB) ||
3223 !VPDT.properlyDominates(EarlyExitingVPBB, LatchVPBB) ||
3224 VPDT.properlyDominates(
3225 CondOfEarlyExitingVPBB->getDefiningRecipe()->getParent(),
3226 LatchVPBB)) &&
3227 "exit condition must dominate the latch");
3228 Exits.push_back({
3229 EarlyExitingVPBB,
3230 ExitBlock,
3231 CondToEarlyExit,
3232 });
3233 }
3234
3235 assert(!Exits.empty() && "must have at least one early exit");
3236 // Sort exits by RPO order to get correct program order. RPO gives a
3237 // topological ordering of the CFG, ensuring upstream exits are checked
3238 // before downstream exits in the dispatch chain.
3240 HeaderVPBB);
3242 for (const auto &[Num, VPB] : enumerate(RPOT))
3243 RPOIdx[VPB] = Num;
3244 llvm::sort(Exits, [&RPOIdx](const EarlyExitInfo &A, const EarlyExitInfo &B) {
3245 return RPOIdx[A.EarlyExitingVPBB] < RPOIdx[B.EarlyExitingVPBB];
3246 });
3247#ifndef NDEBUG
3248 // After RPO sorting, verify that for any pair where one exit dominates
3249 // another, the dominating exit comes first. This is guaranteed by RPO
3250 // (topological order) and is required for the dispatch chain correctness.
3251 for (unsigned I = 0; I + 1 < Exits.size(); ++I)
3252 for (unsigned J = I + 1; J < Exits.size(); ++J)
3253 assert(!VPDT.properlyDominates(Exits[J].EarlyExitingVPBB,
3254 Exits[I].EarlyExitingVPBB) &&
3255 "RPO sort must place dominating exits before dominated ones");
3256#endif
3257
3258 // Build the AnyOf condition for the latch terminator using logical OR
3259 // to avoid poison propagation from later exit conditions when an earlier
3260 // exit is taken.
3261 VPValue *Combined = Exits[0].CondToExit;
3262 for (const EarlyExitInfo &Info : drop_begin(Exits))
3263 Combined = LatchBuilder.createLogicalOr(Combined, Info.CondToExit);
3264
3265 VPValue *IsAnyExitTaken =
3266 LatchBuilder.createNaryOp(VPInstruction::AnyOf, {Combined});
3267
3268 // Create a comparison for the latch exit condition and replace the
3269 // BranchOnCond with a BranchOnTwoConds. The original BranchOnCond's condition
3270 // is used as the latch-exit condition; canonical IV recipes have not been
3271 // introduced yet, so there is no BranchOnCount to derive the condition from.
3272 auto *LatchExitingBranch = cast<VPInstruction>(LatchVPBB->getTerminator());
3273 assert(LatchExitingBranch->getOpcode() == VPInstruction::BranchOnCond &&
3274 "Unexpected terminator");
3275 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
3276 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
3277 LatchExitingBranch->eraseFromParent();
3278 LatchBuilder.setInsertPoint(LatchVPBB);
3280 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
3281 LatchVPBB->clearSuccessors();
3282
3284 // If handling the exiting lane in the scalar loop, combine the exit
3285 // conditions into a single BranchOnCond.
3286 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
3287 MiddleVPBB->clearPredecessors();
3288 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
3290 Plan, Exits, HeaderVPBB, LatchVPBB, MiddleVPBB, TheLoop, PSE, DT, AC);
3291 }
3292
3293 // Create the vector.early.exit blocks.
3294 SmallVector<VPBasicBlock *> VectorEarlyExitVPBBs(Exits.size());
3295 for (unsigned Idx = 0; Idx != Exits.size(); ++Idx) {
3296 Twine BlockSuffix = Exits.size() == 1 ? "" : Twine(".") + Twine(Idx);
3297 VPBasicBlock *VectorEarlyExitVPBB =
3298 Plan.createVPBasicBlock("vector.early.exit" + BlockSuffix);
3299 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
3300 }
3301
3302 // Create the dispatch block (or reuse the single exit block if only one
3303 // exit). The dispatch block computes the first active lane of the combined
3304 // condition and, for multiple exits, chains through conditions to determine
3305 // which exit to take.
3306 VPBasicBlock *DispatchVPBB =
3307 Exits.size() == 1 ? VectorEarlyExitVPBBs[0]
3308 : Plan.createVPBasicBlock("vector.early.exit.check");
3309 DispatchVPBB->setPredecessors({LatchVPBB});
3310 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
3311 VPBuilder DispatchBuilder(DispatchVPBB, DispatchVPBB->begin());
3312 VPValue *FirstActiveLane = DispatchBuilder.createFirstActiveLane(
3313 {Combined}, DebugLoc::getUnknown(), "first.active.lane");
3314
3315 // For each early exit, disconnect the original exiting block
3316 // (early.exiting.I) from the exit block (ir-bb<exit.I>) and route through a
3317 // new vector.early.exit block. Update ir-bb<exit.I>'s phis to extract their
3318 // values at the first active lane:
3319 //
3320 // Input:
3321 // early.exiting.I:
3322 // ...
3323 // EMIT branch-on-cond vp<%cond.I>
3324 // Successor(s): in.loop.succ, ir-bb<exit.I>
3325 //
3326 // ir-bb<exit.I>:
3327 // IR %phi = phi [ vp<%incoming.I>, early.exiting.I ], ...
3328 //
3329 // Output:
3330 // early.exiting.I:
3331 // ...
3332 // Successor(s): in.loop.succ
3333 //
3334 // vector.early.exit.I:
3335 // EMIT vp<%exit.val> = extract-lane vp<%first.lane>, vp<%incoming.I>
3336 // Successor(s): ir-bb<exit.I>
3337 //
3338 // ir-bb<exit.I>:
3339 // IR %phi = phi ... (extra operand: vp<%exit.val> from
3340 // vector.early.exit.I)
3341 //
3342 for (auto [Exit, VectorEarlyExitVPBB] :
3343 zip_equal(Exits, VectorEarlyExitVPBBs)) {
3344 auto &[EarlyExitingVPBB, EarlyExitVPBB, _] = Exit;
3345 // Adjust the phi nodes in EarlyExitVPBB.
3346 // 1. remove incoming values from EarlyExitingVPBB,
3347 // 2. extract the incoming value at FirstActiveLane
3348 // 3. add back the extracts as last operands for the phis
3349 // Then adjust the CFG, removing the edge between EarlyExitingVPBB and
3350 // EarlyExitVPBB and adding a new edge between VectorEarlyExitVPBB and
3351 // EarlyExitVPBB. The extracts at FirstActiveLane are now the incoming
3352 // values from VectorEarlyExitVPBB.
3353 for (VPRecipeBase &R : EarlyExitVPBB->phis()) {
3354 auto *ExitIRI = cast<VPIRPhi>(&R);
3355 VPValue *IncomingVal =
3356 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
3357 VPValue *NewIncoming = IncomingVal;
3358 if (!isa<VPIRValue>(IncomingVal)) {
3359 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
3360 NewIncoming = EarlyExitBuilder.createNaryOp(
3361 VPInstruction::ExtractLane, {FirstActiveLane, IncomingVal},
3362 DebugLoc::getUnknown(), "early.exit.value");
3363 }
3364 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
3365 ExitIRI->addIncoming(NewIncoming);
3366 }
3367
3368 EarlyExitingVPBB->getTerminator()->eraseFromParent();
3369 VPBlockUtils::disconnectBlocks(EarlyExitingVPBB, EarlyExitVPBB);
3370 VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, EarlyExitVPBB);
3371 }
3372
3373 // Chain through exits: for each exit, check if its condition is true at
3374 // the first active lane. If so, take that exit; otherwise, try the next.
3375 // The last exit needs no check since it must be taken if all others fail.
3376 //
3377 // For 3 exits (cond.0, cond.1, cond.2), this creates:
3378 //
3379 // latch:
3380 // ...
3381 // EMIT vp<%combined> = logical-or vp<%cond.0>, vp<%cond.1>, vp<%cond.2>
3382 // ...
3383 //
3384 // vector.early.exit.check:
3385 // EMIT vp<%first.lane> = first-active-lane vp<%combined>
3386 // EMIT vp<%at.cond.0> = extract-lane vp<%first.lane>, vp<%cond.0>
3387 // EMIT branch-on-cond vp<%at.cond.0>
3388 // Successor(s): vector.early.exit.0, vector.early.exit.check.0
3389 //
3390 // vector.early.exit.check.0:
3391 // EMIT vp<%at.cond.1> = extract-lane vp<%first.lane>, vp<%cond.1>
3392 // EMIT branch-on-cond vp<%at.cond.1>
3393 // Successor(s): vector.early.exit.1, vector.early.exit.2
3394 VPBasicBlock *CurrentBB = DispatchVPBB;
3395 for (auto [I, Exit] : enumerate(ArrayRef(Exits).drop_back())) {
3396 VPValue *LaneVal = DispatchBuilder.createNaryOp(
3397 VPInstruction::ExtractLane, {FirstActiveLane, Exit.CondToExit},
3398 DebugLoc::getUnknown(), "exit.cond.at.lane");
3399
3400 // For the last dispatch, branch directly to the last exit on false;
3401 // otherwise, create a new check block.
3402 bool IsLastDispatch = (I + 2 == Exits.size());
3403 VPBasicBlock *FalseBB =
3404 IsLastDispatch ? VectorEarlyExitVPBBs.back()
3405 : Plan.createVPBasicBlock(
3406 Twine("vector.early.exit.check.") + Twine(I));
3407
3408 DispatchBuilder.createNaryOp(VPInstruction::BranchOnCond, {LaneVal});
3409 CurrentBB->setSuccessors({VectorEarlyExitVPBBs[I], FalseBB});
3410 VectorEarlyExitVPBBs[I]->setPredecessors({CurrentBB});
3411 FalseBB->setPredecessors({CurrentBB});
3412
3413 CurrentBB = FalseBB;
3414 DispatchBuilder.setInsertPoint(CurrentBB);
3415 }
3416
3417 return true;
3418}
3419
3420/// This function tries convert extended in-loop reductions to
3421/// VPExpressionRecipe and clamp the \p Range if it is beneficial and
3422/// valid. The created recipe must be decomposed to its constituent
3423/// recipes before execution.
3424static VPExpressionRecipe *
3426 VFRange &Range) {
3427 Type *RedTy = Red->getScalarType();
3428 VPValue *VecOp = Red->getVecOp();
3429
3430 assert(!Red->isPartialReduction() &&
3431 "This path does not support partial reductions");
3432
3433 // Clamp the range if using extended-reduction is profitable.
3434 auto IsExtendedRedValidAndClampRange =
3435 [&](unsigned Opcode, Instruction::CastOps ExtOpc, Type *SrcTy) -> bool {
3437 [&](ElementCount VF) {
3438 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3440
3442 InstructionCost ExtCost =
3443 cast<VPWidenCastRecipe>(VecOp)->computeCost(VF, Ctx);
3444 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3445
3446 assert(!RedTy->isFloatingPointTy() &&
3447 "getExtendedReductionCost only supports integer types");
3448 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
3449 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
3450 Red->getFastMathFlagsOrNone(), CostKind);
3451 return ExtRedCost.isValid() && ExtRedCost < ExtCost + RedCost;
3452 },
3453 Range);
3454 };
3455
3456 VPValue *A;
3457 // Match reduce(ext)).
3459 IsExtendedRedValidAndClampRange(
3460 RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()),
3461 cast<VPWidenCastRecipe>(VecOp)->getOpcode(), A->getScalarType()))
3462 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
3463
3464 return nullptr;
3465}
3466
3467/// This function tries convert extended in-loop reductions to
3468/// VPExpressionRecipe and clamp the \p Range if it is beneficial
3469/// and valid. The created VPExpressionRecipe must be decomposed to its
3470/// constituent recipes before execution. Patterns of the
3471/// VPExpressionRecipe:
3472/// reduce.add(mul(...)),
3473/// reduce.add(mul(ext(A), ext(B))),
3474/// reduce.add(ext(mul(ext(A), ext(B)))).
3475/// reduce.fadd(fmul(ext(A), ext(B)))
3476static VPExpressionRecipe *
3478 VPCostContext &Ctx, VFRange &Range) {
3479 unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());
3480 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3481 Opcode != Instruction::FAdd)
3482 return nullptr;
3483
3484 assert(!Red->isPartialReduction() &&
3485 "This path does not support partial reductions");
3486 Type *RedTy = Red->getScalarType();
3487
3488 // Clamp the range if using multiply-accumulate-reduction is profitable.
3489 auto IsMulAccValidAndClampRange =
3491 VPWidenCastRecipe *OuterExt) -> bool {
3493 [&](ElementCount VF) {
3495 Type *SrcTy = Ext0 ? Ext0->getOperand(0)->getScalarType() : RedTy;
3496 InstructionCost MulAccCost;
3497
3498 // getMulAccReductionCost for in-loop reductions does not support
3499 // mixed or floating-point extends.
3500 if (Ext0 && Ext1 &&
3501 (Ext0->getOpcode() != Ext1->getOpcode() ||
3502 Ext0->getOpcode() == Instruction::CastOps::FPExt))
3503 return false;
3504
3505 bool IsZExt =
3506 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
3507 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3508 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
3509 SrcVecTy, CostKind);
3510
3511 InstructionCost MulCost = Mul->computeCost(VF, Ctx);
3512 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3513 InstructionCost ExtCost = 0;
3514 if (Ext0)
3515 ExtCost += Ext0->computeCost(VF, Ctx);
3516 if (Ext1)
3517 ExtCost += Ext1->computeCost(VF, Ctx);
3518 if (OuterExt)
3519 ExtCost += OuterExt->computeCost(VF, Ctx);
3520
3521 return MulAccCost.isValid() &&
3522 MulAccCost < ExtCost + MulCost + RedCost;
3523 },
3524 Range);
3525 };
3526
3527 VPValue *VecOp = Red->getVecOp();
3528 VPRecipeBase *Sub = nullptr;
3529 VPValue *A, *B;
3530 VPValue *Tmp = nullptr;
3531
3532 if (RedTy->isFloatingPointTy())
3533 return nullptr;
3534
3535 // Sub reductions could have a sub between the add reduction and vec op.
3536 if (match(VecOp, m_Sub(m_ZeroInt(), m_VPValue(Tmp)))) {
3537 Sub = VecOp->getDefiningRecipe();
3538 VecOp = Tmp;
3539 }
3540
3541 // If ValB is a constant and can be safely extended, truncate it to the same
3542 // type as ExtA's operand, then extend it to the same type as ExtA. This
3543 // creates two uniform extends that can more easily be matched by the rest of
3544 // the bundling code. The ExtB reference, ValB and operand 1 of Mul are all
3545 // replaced with the new extend of the constant.
3546 auto ExtendAndReplaceConstantOp = [](VPWidenCastRecipe *ExtA,
3547 VPWidenCastRecipe *&ExtB, VPValue *&ValB,
3548 VPWidenRecipe *Mul) {
3549 if (!ExtA || ExtB || !isa<VPIRValue>(ValB))
3550 return;
3551 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
3552 Instruction::CastOps ExtOpc = ExtA->getOpcode();
3553 const APInt *Const;
3554 if (!match(ValB, m_APInt(Const)) ||
3556 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
3557 return;
3558 // The truncate ensures that the type of each extended operand is the
3559 // same, and it's been proven that the constant can be extended from
3560 // NarrowTy safely. Necessary since ExtA's extended operand would be
3561 // e.g. an i8, while the const will likely be an i32. This will be
3562 // elided by later optimisations.
3563 VPBuilder Builder(Mul);
3564 auto *Trunc =
3565 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
3566 Type *WideTy = ExtA->getScalarType();
3567 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
3568 Mul->setOperand(1, ExtB);
3569 };
3570
3571 // Try to match reduce.add(mul(...)).
3572 if (match(VecOp, m_Mul(m_VPValue(A), m_VPValue(B)))) {
3573 auto *RecipeA = dyn_cast<VPWidenCastRecipe>(A);
3574 auto *RecipeB = dyn_cast<VPWidenCastRecipe>(B);
3575 auto *Mul = cast<VPWidenRecipe>(VecOp);
3576
3577 // Convert reduce.add(mul(ext, const)) to reduce.add(mul(ext, ext(const)))
3578 ExtendAndReplaceConstantOp(RecipeA, RecipeB, B, Mul);
3579
3580 // Match reduce.add/sub(mul(ext, ext)).
3581 if (RecipeA && RecipeB && match(RecipeA, m_ZExtOrSExt(m_VPValue())) &&
3582 match(RecipeB, m_ZExtOrSExt(m_VPValue())) &&
3583 IsMulAccValidAndClampRange(Mul, RecipeA, RecipeB, nullptr)) {
3584 if (Sub)
3585 return new VPExpressionRecipe(RecipeA, RecipeB, Mul,
3586 cast<VPWidenRecipe>(Sub), Red);
3587 return new VPExpressionRecipe(RecipeA, RecipeB, Mul, Red);
3588 }
3589 // TODO: Add an expression type for this variant with a negated mul
3590 if (!Sub && IsMulAccValidAndClampRange(Mul, nullptr, nullptr, nullptr))
3591 return new VPExpressionRecipe(Mul, Red);
3592 }
3593 // TODO: Add an expression type for negated versions of other expression
3594 // variants.
3595 if (Sub)
3596 return nullptr;
3597
3598 // Match reduce.add(ext(mul(A, B))).
3599 if (match(VecOp, m_ZExtOrSExt(m_Mul(m_VPValue(A), m_VPValue(B))))) {
3600 auto *Ext = cast<VPWidenCastRecipe>(VecOp);
3601 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
3602 auto *Ext0 = dyn_cast<VPWidenCastRecipe>(A);
3603 auto *Ext1 = dyn_cast<VPWidenCastRecipe>(B);
3604
3605 // reduce.add(ext(mul(ext, const)))
3606 // -> reduce.add(ext(mul(ext, ext(const))))
3607 ExtendAndReplaceConstantOp(Ext0, Ext1, B, Mul);
3608
3609 // reduce.add(ext(mul(ext(A), ext(B))))
3610 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
3611 // The inner extends must either have the same opcode as the outer extend or
3612 // be the same, in which case the multiply can never result in a negative
3613 // value and the outer extend can be folded away by doing wider
3614 // extends for the operands of the mul.
3615 if (Ext0 && Ext1 &&
3616 (Ext->getOpcode() == Ext0->getOpcode() || Ext0 == Ext1) &&
3617 Ext0->getOpcode() == Ext1->getOpcode() &&
3618 IsMulAccValidAndClampRange(Mul, Ext0, Ext1, Ext) && Mul->hasOneUse()) {
3619 auto *NewExt0 = new VPWidenCastRecipe(
3620 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(), nullptr,
3621 *Ext0, *Ext0, Ext0->getDebugLoc());
3622 NewExt0->insertBefore(Ext0);
3623
3624 VPWidenCastRecipe *NewExt1 = NewExt0;
3625 if (Ext0 != Ext1) {
3626 NewExt1 = new VPWidenCastRecipe(Ext1->getOpcode(), Ext1->getOperand(0),
3627 Ext->getScalarType(), nullptr, *Ext1,
3628 *Ext1, Ext1->getDebugLoc());
3629 NewExt1->insertBefore(Ext1);
3630 }
3631 auto *NewMul = Mul->cloneWithOperands({NewExt0, NewExt1});
3632 NewMul->insertBefore(Mul);
3633 Ext->replaceAllUsesWith(NewMul);
3634 Ext->eraseFromParent();
3635 Mul->eraseFromParent();
3636 return new VPExpressionRecipe(NewExt0, NewExt1, NewMul, Red);
3637 }
3638 }
3639 return nullptr;
3640}
3641
3642/// This function tries to create abstract recipes from the reduction recipe for
3643/// following optimizations and cost estimation.
3645 VPCostContext &Ctx,
3646 VFRange &Range) {
3647 // Creation of VPExpressions for partial reductions is entirely handled in
3648 // transformToPartialReduction.
3649 assert(!Red->isPartialReduction() &&
3650 "This path does not support partial reductions");
3651
3652 VPExpressionRecipe *AbstractR = nullptr;
3653 auto IP = std::next(Red->getIterator());
3654 auto *VPBB = Red->getParent();
3655 if (auto *MulAcc = tryToMatchAndCreateMulAccumulateReduction(Red, Ctx, Range))
3656 AbstractR = MulAcc;
3657 else if (auto *ExtRed = tryToMatchAndCreateExtendedReduction(Red, Ctx, Range))
3658 AbstractR = ExtRed;
3659 // Cannot create abstract inloop reduction recipes.
3660 if (!AbstractR)
3661 return;
3662
3663 AbstractR->insertBefore(*VPBB, IP);
3664 Red->replaceAllUsesWith(AbstractR);
3665}
3666
3677
3678// Collect common metadata from a group of replicate recipes by intersecting
3679// metadata from all recipes in the group.
3681 VPIRMetadata CommonMetadata = *Recipes.front();
3682 for (VPReplicateRecipe *Recipe : drop_begin(Recipes))
3683 CommonMetadata.intersect(*Recipe);
3684 return CommonMetadata;
3685}
3686
3687template <unsigned Opcode>
3691 const Loop *L) {
3692 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
3693 "Only Load and Store opcodes supported");
3694 [[maybe_unused]] constexpr bool IsLoad = (Opcode == Instruction::Load);
3695
3696 // For each address, collect operations with the same or complementary masks.
3699 Plan, PSE, L,
3700 [](VPReplicateRecipe *RepR) { return RepR->isPredicated(); });
3701 for (auto Recipes : Groups) {
3702 if (Recipes.size() < 2)
3703 continue;
3704
3706 map_range(Recipes, bind_back<getLoadStoreValueType>(IsLoad))) &&
3707 "Expected all recipes in group to have the same load-store type");
3708
3709 // Collect groups with the same or complementary masks.
3710 for (VPReplicateRecipe *&RecipeI : Recipes) {
3711 if (!RecipeI)
3712 continue;
3713
3714 VPValue *MaskI = RecipeI->getMask();
3716 Group.push_back(RecipeI);
3717 RecipeI = nullptr;
3718
3719 // Find all operations with the same or complementary masks.
3720 bool HasComplementaryMask = false;
3721 for (VPReplicateRecipe *&RecipeJ : Recipes) {
3722 if (!RecipeJ)
3723 continue;
3724
3725 VPValue *MaskJ = RecipeJ->getMask();
3726 // Check if any operation in the group has a complementary mask with
3727 // another, that is M1 == NOT(M2) or M2 == NOT(M1).
3728 HasComplementaryMask |= match(MaskI, m_Not(m_Specific(MaskJ))) ||
3729 match(MaskJ, m_Not(m_Specific(MaskI)));
3730 Group.push_back(RecipeJ);
3731 RecipeJ = nullptr;
3732 }
3733
3734 if (HasComplementaryMask) {
3735 assert(Group.size() >= 2 && "must have at least 2 entries");
3736 AllGroups.push_back(std::move(Group));
3737 }
3738 }
3739 }
3740
3741 return AllGroups;
3742}
3743
3744// Find the recipe with minimum alignment in the group.
3745template <typename InstType>
3746static VPReplicateRecipe *
3748 return *min_element(Group, [](VPReplicateRecipe *A, VPReplicateRecipe *B) {
3749 return cast<InstType>(A->getUnderlyingInstr())->getAlign() <
3750 cast<InstType>(B->getUnderlyingInstr())->getAlign();
3751 });
3752}
3753
3756 const Loop *L) {
3757 auto Groups =
3759 if (Groups.empty())
3760 return;
3761
3762 // Process each group of loads.
3763 for (auto &Group : Groups) {
3764 // Try to use the earliest (most dominating) load to replace all others.
3765 VPReplicateRecipe *EarliestLoad = Group[0];
3766 VPBasicBlock *FirstBB = EarliestLoad->getParent();
3767 VPBasicBlock *LastBB = Group.back()->getParent();
3768
3769 // Check that the load doesn't alias with stores between first and last.
3770 auto LoadLoc = vputils::getMemoryLocation(*EarliestLoad);
3771 if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck(*LoadLoc, FirstBB, LastBB))
3772 continue;
3773
3774 // Collect common metadata from all loads in the group.
3775 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
3776
3777 // Find the load with minimum alignment to use.
3778 auto *LoadWithMinAlign = findRecipeWithMinAlign<LoadInst>(Group);
3779
3780 bool IsSingleScalar = EarliestLoad->isSingleScalar();
3781 assert(all_of(Group,
3782 [IsSingleScalar](VPReplicateRecipe *R) {
3783 return R->isSingleScalar() == IsSingleScalar;
3784 }) &&
3785 "all members in group must agree on IsSingleScalar");
3786
3787 // Create an unpredicated version of the earliest load with common
3788 // metadata.
3789 auto *UnpredicatedLoad = new VPReplicateRecipe(
3790 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
3791 IsSingleScalar, /*Mask=*/nullptr, *EarliestLoad, CommonMetadata);
3792
3793 UnpredicatedLoad->insertBefore(EarliestLoad);
3794
3795 // Replace all loads in the group with the unpredicated load.
3796 for (VPReplicateRecipe *Load : Group) {
3797 Load->replaceAllUsesWith(UnpredicatedLoad);
3798 Load->eraseFromParent();
3799 }
3800 }
3801}
3802
3803static bool
3805 PredicatedScalarEvolution &PSE, const Loop &L) {
3806 auto StoreLoc = vputils::getMemoryLocation(*StoresToSink.front());
3807 if (!StoreLoc || !StoreLoc->AATags.Scope)
3808 return false;
3809
3810 // When sinking a group of stores, all members of the group alias each other.
3811 // Skip them during the alias checks.
3812 VPBasicBlock *FirstBB = StoresToSink.front()->getParent();
3813 VPBasicBlock *LastBB = StoresToSink.back()->getParent();
3814 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
3815 return canHoistOrSinkWithNoAliasCheck(*StoreLoc, FirstBB, LastBB, SinkInfo);
3816}
3817
3820 const Loop *L) {
3821 auto Groups =
3823 if (Groups.empty())
3824 return;
3825
3826 for (auto &Group : Groups) {
3827 if (!canSinkStoreWithNoAliasCheck(Group, PSE, *L))
3828 continue;
3829
3830 // Use the last (most dominated) store's location for the unconditional
3831 // store.
3832 VPReplicateRecipe *LastStore = Group.back();
3833 VPBasicBlock *InsertBB = LastStore->getParent();
3834
3835 // Collect common alias metadata from all stores in the group.
3836 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
3837
3838 // Build select chain for stored values.
3839 VPValue *SelectedValue = Group[0]->getOperand(0);
3840 VPBuilder Builder(InsertBB, LastStore->getIterator());
3841
3842 bool IsSingleScalar = Group[0]->isSingleScalar();
3843 for (unsigned I = 1; I < Group.size(); ++I) {
3844 assert(IsSingleScalar == Group[I]->isSingleScalar() &&
3845 "all members in group must agree on IsSingleScalar");
3846 VPValue *Mask = Group[I]->getMask();
3847 VPValue *Value = Group[I]->getOperand(0);
3848 SelectedValue = Builder.createSelect(
3849 Mask, Value, SelectedValue, Group[I]->getDebugLoc(), "",
3850 VPIRFlags::getDefaultFlags(Instruction::Select,
3851 Value->getScalarType()));
3852 }
3853
3854 // Find the store with minimum alignment to use.
3855 auto *StoreWithMinAlign = findRecipeWithMinAlign<StoreInst>(Group);
3856
3857 // Create unconditional store with selected value and common metadata.
3858 auto *UnpredicatedStore = new VPReplicateRecipe(
3859 StoreWithMinAlign->getUnderlyingInstr(),
3860 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
3861 /*Mask=*/nullptr, *LastStore, CommonMetadata);
3862 UnpredicatedStore->insertBefore(*InsertBB, LastStore->getIterator());
3863
3864 // Remove all predicated stores from the group.
3865 for (VPReplicateRecipe *Store : Group)
3866 Store->eraseFromParent();
3867 }
3868}
3869
3870/// Returns true if \p V is VPWidenLoadRecipe or VPInterleaveRecipe that can be
3871/// converted to a narrower recipe. \p V is used by a wide recipe that feeds a
3872/// store interleave group at index \p Idx, \p WideMember0 is the recipe feeding
3873/// the same interleave group at index 0. A VPWidenLoadRecipe can be narrowed to
3874/// an index-independent load if it feeds all wide ops at all indices (\p OpV
3875/// must be the operand at index \p OpIdx for both the recipe at lane 0, \p
3876/// WideMember0). A VPInterleaveRecipe can be narrowed to a wide load, if \p V
3877/// is defined at \p Idx of a load interleave group.
3878/// A live-in or recipe defined outside the loop region can be converted, if it
3879/// is the same across all lanes, or we can create a BuildVector for it.
3880static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx,
3881 VPValue *OpV, unsigned Idx, bool IsScalable) {
3882 VPValue *Member0Op = WideMember0->getOperand(OpIdx);
3883 if (Member0Op->isDefinedOutsideLoopRegions()) {
3884 // Operand matches Member0, broadcast across all fields for both live-ins
3885 // and recipes.
3886 if (Member0Op == OpV)
3887 return true;
3888 // Otherwise distinct per-field VPValues are assembled into a BuildVector.
3889 return !IsScalable && OpV->isDefinedOutsideLoopRegions() &&
3890 OpV->getScalarType() == Member0Op->getScalarType();
3891 }
3892 VPRecipeBase *Member0OpR = Member0Op->getDefiningRecipe();
3893 if (auto *W = dyn_cast<VPWidenLoadRecipe>(Member0OpR))
3894 // For scalable VFs, the narrowed plan processes vscale iterations at once,
3895 // so a shared wide load cannot be narrowed to a uniform scalar; bail out.
3896 return !IsScalable && !W->getMask() && W->isConsecutive() &&
3897 Member0Op == OpV;
3898 if (auto *IR = dyn_cast<VPInterleaveRecipe>(Member0OpR))
3899 return IR->getInterleaveGroup()->isFull() && IR->getVPValue(Idx) == OpV;
3900 return false;
3901}
3902
3903static bool canNarrowOps(ArrayRef<VPValue *> Ops, bool IsScalable) {
3905 auto *WideMember0 = dyn_cast<VPRecipeWithIRFlags>(Ops[0]);
3906 if (!WideMember0)
3907 return false;
3908 for (VPValue *V : Ops) {
3910 return false;
3911 auto *R = cast<VPRecipeWithIRFlags>(V);
3912 if (vputils::getOpcode(R) != vputils::getOpcode(WideMember0))
3913 return false;
3914 if (R->getScalarType() != WideMember0->getScalarType())
3915 return false;
3916 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
3917 return false;
3918 }
3919
3920 for (unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
3922 for (VPValue *Op : Ops)
3923 OpsI.push_back(Op->getDefiningRecipe()->getOperand(Idx));
3924
3925 if (canNarrowOps(OpsI, IsScalable))
3926 continue;
3927
3928 if (any_of(enumerate(OpsI), [WideMember0, Idx, IsScalable](const auto &P) {
3929 const auto &[OpIdx, OpV] = P;
3930 return !canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
3931 }))
3932 return false;
3933 }
3934
3935 return true;
3936}
3937
3938/// Returns VF from \p VFs if \p IR is a full interleave group with factor and
3939/// number of members both equal to VF. The interleave group must also access
3940/// the full vector width.
3941static std::optional<ElementCount>
3944 const TargetTransformInfo &TTI) {
3945 if (!InterleaveR || InterleaveR->getMask())
3946 return std::nullopt;
3947
3948 Type *GroupElementTy = nullptr;
3949 if (InterleaveR->getStoredValues().empty()) {
3950 GroupElementTy = InterleaveR->getVPValue(0)->getScalarType();
3951 if (!all_of(InterleaveR->definedValues(), [GroupElementTy](VPValue *Op) {
3952 return Op->getScalarType() == GroupElementTy;
3953 }))
3954 return std::nullopt;
3955 } else {
3956 GroupElementTy = InterleaveR->getStoredValues()[0]->getScalarType();
3957 if (!all_of(InterleaveR->getStoredValues(), [GroupElementTy](VPValue *Op) {
3958 return Op->getScalarType() == GroupElementTy;
3959 }))
3960 return std::nullopt;
3961 }
3962
3963 auto IG = InterleaveR->getInterleaveGroup();
3964 if (IG->getFactor() != IG->getNumMembers())
3965 return std::nullopt;
3966
3967 auto GetVectorBitWidthForVF = [&TTI](ElementCount VF) {
3968 TypeSize Size = TTI.getRegisterBitWidth(
3971 assert(Size.isScalable() == VF.isScalable() &&
3972 "if Size is scalable, VF must be scalable and vice versa");
3973 return Size.getKnownMinValue();
3974 };
3975
3976 for (ElementCount VF : VFs) {
3977 unsigned MinVal = VF.getKnownMinValue();
3978 unsigned GroupSize = GroupElementTy->getScalarSizeInBits() * MinVal;
3979 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
3980 return {VF};
3981 }
3982 return std::nullopt;
3983}
3984
3985/// Returns true if \p VPValue is a narrow VPValue.
3986static bool isAlreadyNarrow(VPValue *VPV) {
3987 if (isa<VPIRValue>(VPV))
3988 return true;
3989 auto *RepR = dyn_cast<VPReplicateRecipe>(VPV);
3990 return RepR && RepR->isSingleScalar();
3991}
3992
3993// Convert the wide recipes defining the VPValues in \p Members feeding an
3994// interleave group to a single narrow variant. The first member is reused as
3995// the narrowed recipe. BuildVectors for live-in operands are inserted into \p
3996// Preheader.
3998 SmallPtrSetImpl<VPValue *> &NarrowedOps,
3999 VPBasicBlock *Preheader) {
4000 VPValue *V = Members.front();
4001 if (NarrowedOps.contains(V))
4002 return V;
4003
4004 if (V->isDefinedOutsideLoopRegions()) {
4005 assert(all_of(Members,
4006 [V](VPValue *M) {
4007 return M->isDefinedOutsideLoopRegions() &&
4008 M->getScalarType() == V->getScalarType();
4009 }) &&
4010 "expected distinct loop-invariant values of matching scalar type");
4011 auto *BV = new VPInstruction(VPInstruction::BuildVector, Members);
4012 Preheader->appendRecipe(BV);
4013 NarrowedOps.insert(BV);
4014 return BV;
4015 }
4016
4017 if (isAlreadyNarrow(V))
4018 return V;
4019
4020 VPRecipeBase *R = V->getDefiningRecipe();
4022 auto *WideMember0 = cast<VPRecipeWithIRFlags>(R);
4023 for (VPValue *Member : Members.drop_front())
4024 WideMember0->intersectFlags(*cast<VPRecipeWithIRFlags>(Member));
4025 for (unsigned Idx = 0, E = WideMember0->getNumOperands(); Idx != E; ++Idx) {
4027 for (VPValue *Member : Members)
4028 OpsI.push_back(Member->getDefiningRecipe()->getOperand(Idx));
4029 WideMember0->setOperand(
4030 Idx, narrowInterleaveGroupOp(OpsI, NarrowedOps, Preheader));
4031 }
4032 return V;
4033 }
4034
4035 if (auto *LoadGroup = dyn_cast<VPInterleaveRecipe>(R)) {
4036 // Narrow interleave group to wide load, as transformed VPlan will only
4037 // process one original iteration.
4038 auto *LI = cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos());
4039 auto *L = VPBuilder(LoadGroup).createWidenLoad(
4040 *LI, LoadGroup->getAddr(), LoadGroup->getMask(), /*Consecutive=*/true,
4041 *LoadGroup, LoadGroup->getDebugLoc());
4042 NarrowedOps.insert(L);
4043 return L;
4044 }
4045
4046 if (auto *RepR = dyn_cast<VPReplicateRecipe>(R)) {
4047 assert(RepR->isSingleScalar() && RepR->getOpcode() == Instruction::Load &&
4048 "must be a single scalar load");
4049 NarrowedOps.insert(RepR);
4050 return RepR;
4051 }
4052
4053 auto *WideLoad = cast<VPWidenLoadRecipe>(R);
4054 VPValue *PtrOp = WideLoad->getAddr();
4055 if (auto *VecPtr = dyn_cast<VPVectorPointerRecipe>(PtrOp))
4056 PtrOp = VecPtr->getOperand(0);
4057 // Narrow wide load to uniform scalar load, as transformed VPlan will only
4058 // process one original iteration.
4059 auto *N = new VPReplicateRecipe(&WideLoad->getIngredient(), {PtrOp},
4060 /*IsUniform*/ true,
4061 /*Mask*/ nullptr, {}, *WideLoad);
4062 N->insertBefore(WideLoad);
4063 NarrowedOps.insert(N);
4064 return N;
4065}
4066
4067std::unique_ptr<VPlan>
4069 const TargetTransformInfo &TTI) {
4070 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
4071
4072 if (!VectorLoop)
4073 return nullptr;
4074
4075 // Only handle single-block loops for now.
4076 if (VectorLoop->getEntryBasicBlock() != VectorLoop->getExitingBasicBlock())
4077 return nullptr;
4078
4079 // Skip plans when we may not be able to properly narrow.
4080 VPBasicBlock *Exiting = VectorLoop->getExitingBasicBlock();
4081 if (!match(&Exiting->back(), m_BranchOnCount()))
4082 return nullptr;
4083
4084 assert(match(&Exiting->back(),
4086 m_Specific(&Plan.getVectorTripCount()))) &&
4087 "unexpected branch-on-count");
4088
4090 std::optional<ElementCount> VFToOptimize;
4091 for (auto &R : *VectorLoop->getEntryBasicBlock()) {
4094 continue;
4095
4096 // Bail out on recipes not supported at the moment:
4097 // * phi recipes other than the canonical induction
4098 // * recipes writing to memory except interleave groups
4099 // Only support plans with a canonical induction phi.
4100 if (R.isPhi())
4101 return nullptr;
4102
4103 auto *InterleaveR = dyn_cast<VPInterleaveRecipe>(&R);
4104 if (R.mayWriteToMemory() && !InterleaveR)
4105 return nullptr;
4106
4107 // Bail out if any recipe defines a vector value used outside the
4108 // vector loop region.
4109 if (any_of(R.definedValues(), [&](VPValue *V) {
4110 return any_of(V->users(), [&](VPUser *U) {
4111 auto *UR = cast<VPRecipeBase>(U);
4112 return UR->getParent()->getParent() != VectorLoop;
4113 });
4114 }))
4115 return nullptr;
4116
4117 // All other ops are allowed, but we reject uses that cannot be converted
4118 // when checking all allowed consumers (store interleave groups) below.
4119 if (!InterleaveR)
4120 continue;
4121
4122 // Try to find a single VF, where all interleave groups are consecutive and
4123 // saturate the full vector width. If we already have a candidate VF, check
4124 // if it is applicable for the current InterleaveR, otherwise look for a
4125 // suitable VF across the Plan's VFs.
4127 VFToOptimize ? SmallVector<ElementCount>({*VFToOptimize})
4128 : to_vector(Plan.vectorFactors());
4129 std::optional<ElementCount> NarrowedVF =
4130 isConsecutiveInterleaveGroup(InterleaveR, VFs, TTI);
4131 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
4132 return nullptr;
4133 VFToOptimize = NarrowedVF;
4134
4135 // Skip read interleave groups.
4136 if (InterleaveR->getStoredValues().empty())
4137 continue;
4138
4139 // Narrow interleave groups, if all operands are already matching narrow
4140 // ops.
4141 auto *Member0 = InterleaveR->getStoredValues()[0];
4142 if (isAlreadyNarrow(Member0) &&
4143 all_of(InterleaveR->getStoredValues(), equal_to(Member0))) {
4144 StoreGroups.push_back(InterleaveR);
4145 continue;
4146 }
4147
4148 // For now, we only support full interleave groups storing load interleave
4149 // groups.
4150 if (all_of(enumerate(InterleaveR->getStoredValues()), [](auto Op) {
4151 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
4152 if (!DefR)
4153 return false;
4154 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
4155 return IR && IR->getInterleaveGroup()->isFull() &&
4156 IR->getVPValue(Op.index()) == Op.value();
4157 })) {
4158 StoreGroups.push_back(InterleaveR);
4159 continue;
4160 }
4161
4162 // Check if all values feeding InterleaveR are matching wide recipes, which
4163 // operands that can be narrowed.
4164 if (!canNarrowOps(InterleaveR->getStoredValues(),
4165 VFToOptimize->isScalable()))
4166 return nullptr;
4167 StoreGroups.push_back(InterleaveR);
4168 }
4169
4170 if (StoreGroups.empty())
4171 return nullptr;
4172
4173 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
4174 bool RequiresScalarEpilogue =
4175 MiddleVPBB->getNumSuccessors() == 1 &&
4176 MiddleVPBB->getSingleSuccessor() == Plan.getScalarPreheader();
4177 // Bail out for tail-folding (middle block with a single successor to exit).
4178 if (MiddleVPBB->getNumSuccessors() != 2 && !RequiresScalarEpilogue)
4179 return nullptr;
4180
4181 // All interleave groups in Plan can be narrowed for VFToOptimize. Split the
4182 // original Plan into 2: a) a new clone which contains all VFs of Plan, except
4183 // VFToOptimize, and b) the original Plan with VFToOptimize as single VF.
4184 // TODO: Handle cases where only some interleave groups can be narrowed.
4185 std::unique_ptr<VPlan> NewPlan;
4186 if (size(Plan.vectorFactors()) != 1) {
4187 NewPlan = std::unique_ptr<VPlan>(Plan.duplicate());
4188 Plan.setVF(*VFToOptimize);
4189 NewPlan->removeVF(*VFToOptimize);
4190 }
4191
4192 // Convert InterleaveGroup \p R to a single VPWidenLoadRecipe.
4193 SmallPtrSet<VPValue *, 4> NarrowedOps;
4194 VPBasicBlock *Preheader = Plan.getVectorPreheader();
4195 // Narrow operation tree rooted at store groups.
4196 for (auto *StoreGroup : StoreGroups) {
4197 VPValue *Res = narrowInterleaveGroupOp(StoreGroup->getStoredValues(),
4198 NarrowedOps, Preheader);
4199 auto *SI =
4200 cast<StoreInst>(StoreGroup->getInterleaveGroup()->getInsertPos());
4201 VPBuilder(StoreGroup)
4202 .createWidenStore(*SI, StoreGroup->getAddr(), Res, nullptr,
4203 /*Consecutive=*/true, *StoreGroup,
4204 StoreGroup->getDebugLoc());
4205 StoreGroup->eraseFromParent();
4206 }
4207
4208 // Adjust induction to reflect that the transformed plan only processes one
4209 // original iteration.
4211 Type *CanIVTy = VectorLoop->getCanonicalIVType();
4212 VPBasicBlock *VectorPH = Plan.getVectorPreheader();
4213 VPBuilder PHBuilder(VectorPH, VectorPH->begin());
4214
4215 VPValue *UF = &Plan.getUF();
4216 VPValue *Step;
4217 if (VFToOptimize->isScalable()) {
4218 VPValue *VScale =
4219 PHBuilder.createElementCount(CanIVTy, ElementCount::getScalable(1));
4220 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale, UF},
4221 {true, false});
4222 Plan.getVF().replaceAllUsesWith(VScale);
4223 } else {
4224 Step = UF;
4225 Plan.getVF().replaceAllUsesWith(Plan.getConstantInt(CanIVTy, 1));
4226 }
4227 // Materialize vector trip count with the narrowed step.
4228 materializeVectorTripCount(Plan, VectorPH, /*TailByMasking=*/false,
4229 RequiresScalarEpilogue, Step);
4230
4231 CanIVInc->setOperand(1, Step);
4232 Plan.getVFxUF().replaceAllUsesWith(Step);
4233
4234 removeDeadRecipes(Plan);
4235 assert(none_of(*VectorLoop->getEntryBasicBlock(),
4237 "All VPVectorPointerRecipes should have been removed");
4238 return NewPlan;
4239}
4240
4242 VFRange &Range) {
4243 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
4244 auto *MiddleVPBB = Plan.getMiddleBlock();
4245 VPBuilder MiddleBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
4246
4247 auto IsScalableOne = [](ElementCount VF) -> bool {
4248 return VF == ElementCount::getScalable(1);
4249 };
4250
4251 for (auto &HeaderPhi : VectorRegion->getEntryBasicBlock()->phis()) {
4252 auto *FOR = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&HeaderPhi);
4253 if (!FOR)
4254 continue;
4255
4256 assert(VectorRegion->getSingleSuccessor() == Plan.getMiddleBlock() &&
4257 "Cannot handle loops with uncountable early exits");
4258
4259 // Find the existing splice for this FOR, created in
4260 // createHeaderPhiRecipes. All uses of FOR have already been replaced with
4261 // RecurSplice there; only RecurSplice itself still references FOR.
4262 auto *RecurSplice =
4264 assert(RecurSplice && "expected FirstOrderRecurrenceSplice");
4265
4266 // For VF vscale x 1, if vscale = 1, we are unable to extract the
4267 // penultimate value of the recurrence. Instead we rely on the existing
4268 // extract of the last element from the result of
4269 // VPInstruction::FirstOrderRecurrenceSplice.
4270 // TODO: Consider vscale_range info and UF.
4271 if (any_of(RecurSplice->users(),
4272 [](VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
4274 Range))
4275 return;
4276
4277 // This is the second phase of vectorizing first-order recurrences, creating
4278 // extracts for users outside the loop. An overview of the transformation is
4279 // described below. Suppose we have the following loop with some use after
4280 // the loop of the last a[i-1],
4281 //
4282 // for (int i = 0; i < n; ++i) {
4283 // t = a[i - 1];
4284 // b[i] = a[i] - t;
4285 // }
4286 // use t;
4287 //
4288 // There is a first-order recurrence on "a". For this loop, the shorthand
4289 // scalar IR looks like:
4290 //
4291 // scalar.ph:
4292 // s.init = a[-1]
4293 // br scalar.body
4294 //
4295 // scalar.body:
4296 // i = phi [0, scalar.ph], [i+1, scalar.body]
4297 // s1 = phi [s.init, scalar.ph], [s2, scalar.body]
4298 // s2 = a[i]
4299 // b[i] = s2 - s1
4300 // br cond, scalar.body, exit.block
4301 //
4302 // exit.block:
4303 // use = lcssa.phi [s1, scalar.body]
4304 //
4305 // In this example, s1 is a recurrence because it's value depends on the
4306 // previous iteration. In the first phase of vectorization, we created a
4307 // VPFirstOrderRecurrencePHIRecipe v1 for s1. Now we create the extracts
4308 // for users in the scalar preheader and exit block.
4309 //
4310 // vector.ph:
4311 // v_init = vector(..., ..., ..., a[-1])
4312 // br vector.body
4313 //
4314 // vector.body
4315 // i = phi [0, vector.ph], [i+4, vector.body]
4316 // v1 = phi [v_init, vector.ph], [v2, vector.body]
4317 // v2 = a[i, i+1, i+2, i+3]
4318 // v1' = splice(v1(3), v2(0, 1, 2))
4319 // b[i, i+1, i+2, i+3] = v2 - v1'
4320 // br cond, vector.body, middle.block
4321 //
4322 // middle.block:
4323 // vector.recur.extract.for.phi = v2(2)
4324 // vector.recur.extract = v2(3)
4325 // br cond, scalar.ph, exit.block
4326 //
4327 // scalar.ph:
4328 // scalar.recur.init = phi [vector.recur.extract, middle.block],
4329 // [s.init, otherwise]
4330 // br scalar.body
4331 //
4332 // scalar.body:
4333 // i = phi [0, scalar.ph], [i+1, scalar.body]
4334 // s1 = phi [scalar.recur.init, scalar.ph], [s2, scalar.body]
4335 // s2 = a[i]
4336 // b[i] = s2 - s1
4337 // br cond, scalar.body, exit.block
4338 //
4339 // exit.block:
4340 // lo = lcssa.phi [s1, scalar.body],
4341 // [vector.recur.extract.for.phi, middle.block]
4342 //
4343 // Update extracts of the splice in the middle block: they extract the
4344 // penultimate element of the recurrence.
4346 make_range(MiddleVPBB->getFirstNonPhi(), MiddleVPBB->end()))) {
4347 if (!match(&R, m_ExtractLastLaneOfLastPart(m_Specific(RecurSplice))))
4348 continue;
4349
4350 auto *ExtractR = cast<VPInstruction>(&R);
4351 VPValue *PenultimateElement = MiddleBuilder.createNaryOp(
4352 VPInstruction::ExtractPenultimateElement, RecurSplice->getOperand(1),
4353 {}, "vector.recur.extract.for.phi");
4354 for (VPUser *ExitU : to_vector(ExtractR->users())) {
4355 if (auto *ExitPhi = dyn_cast<VPIRPhi>(ExitU))
4356 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
4357 }
4358 }
4359 }
4360}
4361
4362/// Check if \p V is a binary expression of a widened IV and a loop-invariant
4363/// value. Returns the widened IV if found, nullptr otherwise.
4365 auto *BinOp = dyn_cast<VPWidenRecipe>(V);
4366 if (!BinOp || !Instruction::isBinaryOp(BinOp->getOpcode()) ||
4367 Instruction::isIntDivRem(BinOp->getOpcode()))
4368 return nullptr;
4369
4370 VPValue *WidenIVCandidate = BinOp->getOperand(0);
4371 VPValue *InvariantCandidate = BinOp->getOperand(1);
4372 if (!isa<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate))
4373 std::swap(WidenIVCandidate, InvariantCandidate);
4374
4375 if (!InvariantCandidate->isDefinedOutsideLoopRegions())
4376 return nullptr;
4377
4378 return dyn_cast<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate);
4379}
4380
4381/// Create a scalar version of \p BinOp, with its \p WidenIV operand replaced
4382/// by \p ScalarIV, and place it after \p ScalarIV's defining recipe.
4386 BinOp->getNumOperands() == 2 && "BinOp must have 2 operands");
4387 auto *ClonedOp = BinOp->clone();
4388 if (ClonedOp->getOperand(0) == WidenIV) {
4389 ClonedOp->setOperand(0, ScalarIV);
4390 } else {
4391 assert(ClonedOp->getOperand(1) == WidenIV && "one operand must be WideIV");
4392 ClonedOp->setOperand(1, ScalarIV);
4393 }
4394 ClonedOp->insertAfter(ScalarIV->getDefiningRecipe());
4395 return ClonedOp;
4396}
4397
4398/// If \p S is an affine AddRec, returns true if its step is known to be
4399/// positive and false if it is known to be negative. Returns std::nullopt if
4400/// \p S is not an affine AddRec, or if the sign of its step cannot be
4401/// determined.
4402static std::optional<bool> getStepDirection(const SCEV *S,
4403 ScalarEvolution &SE) {
4404 const SCEV *Step;
4405 if (!match(S, m_scev_AffineAddRec(m_SCEV(), m_SCEV(Step))))
4406 return std::nullopt;
4407 if (SE.isKnownPositive(Step))
4408 return true;
4409 if (SE.isKnownNegative(Step))
4410 return false;
4411 return std::nullopt;
4412}
4413
4416 Loop &L) {
4417 ScalarEvolution &SE = *PSE.getSE();
4418 VPRegionBlock *VectorLoopRegion = Plan.getVectorLoopRegion();
4419
4420 // Helper lambda to check if the IV range excludes the sentinel value. Try
4421 // signed first, then unsigned. Return an excluded sentinel if found,
4422 // otherwise return std::nullopt.
4423 auto CheckSentinel = [&SE](const SCEV *IVSCEV,
4424 bool UseMax) -> std::optional<APSInt> {
4425 unsigned BW = IVSCEV->getType()->getScalarSizeInBits();
4426 for (bool Signed : {true, false}) {
4427 APSInt Sentinel = UseMax ? APSInt::getMinValue(BW, /*Unsigned=*/!Signed)
4428 : APSInt::getMaxValue(BW, /*Unsigned=*/!Signed);
4429
4430 ConstantRange IVRange =
4431 Signed ? SE.getSignedRange(IVSCEV) : SE.getUnsignedRange(IVSCEV);
4432 if (!IVRange.contains(Sentinel))
4433 return Sentinel;
4434 }
4435 return std::nullopt;
4436 };
4437
4438 VPValue *HeaderMask = VectorLoopRegion->getHeaderMask();
4439 for (VPRecipeBase &Phi :
4440 make_early_inc_range(VectorLoopRegion->getEntryBasicBlock()->phis())) {
4441 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&Phi);
4443 PhiR->getRecurrenceKind()))
4444 continue;
4445
4446 Type *PhiTy = PhiR->getScalarType();
4447 if (PhiTy->isPointerTy() || PhiTy->isFloatingPointTy())
4448 continue;
4449
4450 // If there's a header mask, the backedge select will not be the find-last
4451 // select.
4452 VPValue *BackedgeVal = PhiR->getBackedgeValue();
4453 auto *FindLastSelect = cast<VPSingleDefRecipe>(BackedgeVal);
4454 if (HeaderMask &&
4455 !match(BackedgeVal,
4456 m_Select(m_Specific(HeaderMask),
4457 m_VPSingleDefRecipe(FindLastSelect), m_Specific(PhiR))))
4458 continue;
4459
4460 // Get the find-last expression from the find-last select of the reduction
4461 // phi. The find-last select should be a select between the phi and the
4462 // find-last expression.
4463 VPValue *Cond, *FindLastExpression;
4464 if (!match(FindLastSelect, m_SelectLike(m_VPValue(Cond), m_Specific(PhiR),
4465 m_VPValue(FindLastExpression))) &&
4466 !match(FindLastSelect,
4467 m_SelectLike(m_VPValue(Cond), m_VPValue(FindLastExpression),
4468 m_Specific(PhiR))))
4469 continue;
4470
4471 // Check if FindLastExpression is a simple expression of a widened IV. If
4472 // so, we can track the underlying IV instead and sink the expression.
4473 auto *IVOfExpressionToSink = getExpressionIV(FindLastExpression);
4474 const SCEV *IVSCEV = vputils::getSCEVExprForVPValue(
4475 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
4476 &L);
4477 if (!match(IVSCEV, m_scev_AffineAddRec(m_SCEV(), m_SCEV()))) {
4478 assert(!match(vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L),
4480 "IVOfExpressionToSink not being an AddRec must imply "
4481 "FindLastExpression not being an AddRec.");
4482 continue;
4483 }
4484
4485 // Determine direction from the step of IVSCEV, if possible.
4486 std::optional<bool> StepDirection = getStepDirection(IVSCEV, SE);
4487 if (!StepDirection)
4488 continue;
4489
4490 bool UseMax = *StepDirection;
4491 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
4492 bool UseSigned = SentinelVal && SentinelVal->isSigned();
4493
4494 // Sinking an expression will disable epilogue vectorization. Only use it,
4495 // if FindLastExpression cannot be vectorized via a sentinel. Sinking may
4496 // also prevent vectorizing using a sentinel (e.g., if the expression is a
4497 // multiply or divide by large constant, respectively), which also makes
4498 // sinking undesirable.
4499 if (IVOfExpressionToSink) {
4500 const SCEV *FindLastExpressionSCEV =
4501 vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L);
4502 if (std::optional<bool> NewUseMax =
4503 getStepDirection(FindLastExpressionSCEV, SE)) {
4504 if (auto NewSentinel =
4505 CheckSentinel(FindLastExpressionSCEV, *NewUseMax)) {
4506 // The original expression already has a sentinel, so prefer not
4507 // sinking to keep epilogue vectorization possible.
4508 SentinelVal = *NewSentinel;
4509 UseSigned = NewSentinel->isSigned();
4510 UseMax = *NewUseMax;
4511 IVSCEV = FindLastExpressionSCEV;
4512 IVOfExpressionToSink = nullptr;
4513 }
4514 }
4515 }
4516
4517 // If no sentinel was found, fall back to a boolean AnyOf reduction to track
4518 // if the condition was ever true. Requires the IV to not wrap, otherwise we
4519 // cannot use min/max.
4520 if (!SentinelVal) {
4521 auto *AR = cast<SCEVAddRecExpr>(IVSCEV);
4522 if (AR->hasNoSignedWrap())
4523 UseSigned = true;
4524 else if (AR->hasNoUnsignedWrap())
4525 UseSigned = false;
4526 else
4527 continue;
4528 }
4529
4531 BackedgeVal,
4533
4534 VPValue *NewFindLastSelect = BackedgeVal;
4535 VPValue *SelectCond = Cond;
4536 if (!SentinelVal || IVOfExpressionToSink) {
4537 // When we need to create a new select, normalize the condition so that
4538 // PhiR is the last operand and include the header mask if needed.
4539 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
4540 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
4541 if (match(FindLastSelect,
4543 SelectCond = LoopBuilder.createNot(SelectCond);
4544
4545 // When tail folding, mask the condition with the header mask to prevent
4546 // propagating poison from inactive lanes in the last vector iteration.
4547 if (HeaderMask)
4548 SelectCond = LoopBuilder.createLogicalAnd(HeaderMask, SelectCond);
4549
4550 if (SelectCond != Cond || IVOfExpressionToSink) {
4551 NewFindLastSelect = LoopBuilder.createSelect(
4552 SelectCond,
4553 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
4554 PhiR, DL);
4555 }
4556 }
4557
4558 // Create the reduction result in the middle block using sentinel directly.
4559 RecurKind MinMaxKind =
4560 UseMax ? (UseSigned ? RecurKind::SMax : RecurKind::UMax)
4561 : (UseSigned ? RecurKind::SMin : RecurKind::UMin);
4562 VPIRFlags Flags(MinMaxKind, /*IsOrdered=*/false, /*IsInLoop=*/false,
4563 FastMathFlags());
4564 DebugLoc ExitDL = RdxResult->getDebugLoc();
4565 VPBuilder MiddleBuilder(RdxResult);
4566 VPValue *ReducedIV =
4568 NewFindLastSelect, Flags, ExitDL);
4569
4570 // If IVOfExpressionToSink is an expression to sink, sink it now.
4571 VPValue *VectorRegionExitingVal = ReducedIV;
4572 if (IVOfExpressionToSink)
4573 VectorRegionExitingVal =
4574 cloneBinOpForScalarIV(cast<VPWidenRecipe>(FindLastExpression),
4575 ReducedIV, IVOfExpressionToSink);
4576
4577 VPValue *NewRdxResult;
4578 VPValue *StartVPV = PhiR->getStartValue();
4579 if (SentinelVal) {
4580 // Sentinel-based approach: reduce IVs with min/max, compare against
4581 // sentinel to detect if condition was ever true, select accordingly.
4582 VPValue *Sentinel = Plan.getConstantInt(*SentinelVal);
4583 auto *Cmp = MiddleBuilder.createICmp(CmpInst::ICMP_NE, ReducedIV,
4584 Sentinel, ExitDL);
4585 NewRdxResult = MiddleBuilder.createSelect(Cmp, VectorRegionExitingVal,
4586 StartVPV, ExitDL);
4587 StartVPV = Sentinel;
4588 } else {
4589 // Introduce a boolean AnyOf reduction to track if the condition was ever
4590 // true in the loop. Use it to select the initial start value, if it was
4591 // never true.
4592 auto *AnyOfPhi = new VPReductionPHIRecipe(
4593 /*Phi=*/nullptr, RecurKind::Or, *Plan.getFalse(), *Plan.getFalse(),
4594 RdxUnordered{1}, {}, /*HasUsesOutsideReductionChain=*/false);
4595 AnyOfPhi->insertAfter(PhiR);
4596
4597 VPBuilder LoopBuilder(BackedgeVal->getDefiningRecipe());
4598 VPValue *OrVal = LoopBuilder.createOr(AnyOfPhi, SelectCond);
4599 AnyOfPhi->setOperand(1, OrVal);
4600
4601 NewRdxResult = MiddleBuilder.createAnyOfReduction(
4602 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
4603
4604 // Initialize the IV reduction phi with the neutral element, not the
4605 // original start value, to ensure correct min/max reduction results.
4606 StartVPV = Plan.getOrAddLiveIn(
4607 getRecurrenceIdentity(MinMaxKind, IVSCEV->getType(), {}));
4608 }
4609 RdxResult->replaceAllUsesWith(NewRdxResult);
4610 RdxResult->eraseFromParent();
4611
4612 auto *NewPhiR = new VPReductionPHIRecipe(
4613 cast<PHINode>(PhiR->getUnderlyingInstr()), RecurKind::FindIV, *StartVPV,
4614 *NewFindLastSelect, RdxUnordered{1}, {},
4615 PhiR->hasUsesOutsideReductionChain());
4616 NewPhiR->insertBefore(PhiR);
4617 PhiR->replaceAllUsesWith(NewPhiR);
4618 PhiR->eraseFromParent();
4619 }
4620}
4621
4622namespace {
4623
4624using ExtendKind = TTI::PartialReductionExtendKind;
4625struct ReductionExtend {
4626 Type *SrcType = nullptr;
4627 ExtendKind Kind = ExtendKind::PR_None;
4628};
4629
4630/// Describes the extends used to compute the extended reduction operand.
4631/// ExtendB is optional. If ExtendB is present, ExtendsUser is a binary
4632/// operation.
4633struct ExtendedReductionOperand {
4634 /// The recipe that consumes the extends.
4635 VPWidenRecipe *ExtendsUser = nullptr;
4636 /// Extend descriptions (inputs to getPartialReductionCost).
4637 ReductionExtend ExtendA, ExtendB;
4638};
4639
4640/// A chain of recipes that form a partial reduction. Matches either
4641/// reduction_bin_op (extended op, accumulator), or
4642/// reduction_bin_op (accumulator, extended op).
4643/// The possible forms of the "extended op" are listed in
4644/// matchExtendedReductionOperand.
4645struct VPPartialReductionChain {
4646 /// The top-level binary operation that forms the reduction to a scalar
4647 /// after the loop body.
4648 VPWidenRecipe *ReductionBinOp = nullptr;
4649 /// The user of the extends that is then reduced.
4650 ExtendedReductionOperand ExtendedOp;
4651 /// The recurrence kind for the entire partial reduction chain.
4652 /// This allows distinguishing between Sub and AddWithSub recurrences,
4653 /// when the ReductionBinOp is a Instruction::Sub.
4654 RecurKind RK;
4655 /// The index of the accumulator operand of ReductionBinOp. The extended op
4656 /// is `1 - AccumulatorOpIdx`.
4657 unsigned AccumulatorOpIdx;
4658 unsigned ScaleFactor;
4659 /// Optional blend to represent predication for the block that updates the
4660 /// reduction.
4661 VPBlendRecipe *Blend = nullptr;
4662};
4663
4664// Return the incoming index of the single-use value in the blend, which is
4665// expected to be the predicated reduction update.
4666static std::optional<unsigned>
4667getBlendReductionUpdateValueIdx(VPBlendRecipe *Blend) {
4668 assert(Blend && !Blend->isNormalized() &&
4669 Blend->getNumIncomingValues() == 2 &&
4670 "Expected a non-normalized blend with two incoming values");
4671 bool FirstIncomingHasOneUse = Blend->getIncomingValue(0)->hasOneUse();
4672
4673 // Only the update value should have one use (the blend). The previous
4674 // value should always have at least two uses, the blend and the reduction.
4675 if (FirstIncomingHasOneUse == Blend->getIncomingValue(1)->hasOneUse())
4676 return std::nullopt;
4677 return FirstIncomingHasOneUse ? 0 : 1;
4678}
4679
4680static VPSingleDefRecipe *
4681optimizeExtendsForPartialReduction(VPSingleDefRecipe *Op) {
4682 // reduce.add(mul(ext(A), C))
4683 // -> reduce.add(mul(ext(A), ext(trunc(C))))
4684 const APInt *Const;
4685 if (match(Op, m_Mul(m_ZExtOrSExt(m_VPValue()), m_APInt(Const)))) {
4686 auto *ExtA = cast<VPWidenCastRecipe>(Op->getOperand(0));
4687 Instruction::CastOps ExtOpc = ExtA->getOpcode();
4688 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
4689 if (!Op->hasOneUse() ||
4691 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
4692 return Op;
4693
4694 VPBuilder Builder(Op);
4695 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
4696 Op->getOperand(1), NarrowTy);
4697 Type *WideTy = ExtA->getScalarType();
4698 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
4699 return Op;
4700 }
4701
4702 // reduce.add(abs(sub(ext(A), ext(B))))
4703 // -> reduce.add(ext(absolute-difference(A, B)))
4704 VPValue *X, *Y;
4707 auto *Sub = Op->getOperand(0)->getDefiningRecipe();
4708 auto *Ext = cast<VPWidenCastRecipe>(Sub->getOperand(0));
4709 assert(Ext->getOpcode() ==
4710 cast<VPWidenCastRecipe>(Sub->getOperand(1))->getOpcode() &&
4711 "Expected both the LHS and RHS extends to be the same");
4712 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
4713 VPBuilder Builder(Op);
4714 Type *SrcTy = X->getScalarType();
4715 auto *FreezeX = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {X}));
4716 auto *FreezeY = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {Y}));
4717 auto *Max = Builder.insert(
4718 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smax : Intrinsic::umax,
4719 {FreezeX, FreezeY}, SrcTy));
4720 auto *Min = Builder.insert(
4721 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smin : Intrinsic::umin,
4722 {FreezeX, FreezeY}, SrcTy));
4723 auto *AbsDiff =
4724 Builder.insert(new VPWidenRecipe(Instruction::Sub, {Max, Min}));
4725 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
4726 Op->getScalarType());
4727 }
4728
4729 // reduce.add(ext(mul(ext(A), ext(B))))
4730 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
4731 // TODO: Support this optimization for float types.
4733 m_ZExtOrSExt(m_VPValue()))))) {
4734 auto *Ext = cast<VPWidenCastRecipe>(Op);
4735 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
4736 auto *MulLHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
4737 auto *MulRHS = cast<VPWidenCastRecipe>(Mul->getOperand(1));
4738 if (!Mul->hasOneUse() ||
4739 (Ext->getOpcode() != MulLHS->getOpcode() && MulLHS != MulRHS) ||
4740 MulLHS->getOpcode() != MulRHS->getOpcode())
4741 return Op;
4742 VPBuilder Builder(Mul);
4743 auto *NewLHS = Builder.createWidenCast(
4744 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
4745 auto *NewRHS = MulLHS == MulRHS
4746 ? NewLHS
4747 : Builder.createWidenCast(MulRHS->getOpcode(),
4748 MulRHS->getOperand(0),
4749 Ext->getScalarType());
4750 auto *NewMul = Mul->cloneWithOperands({NewLHS, NewRHS});
4751 Builder.insert(NewMul);
4752 Op->replaceAllUsesWith(NewMul);
4753 Op->eraseFromParent();
4754 Mul->eraseFromParent();
4755 return NewMul;
4756 }
4757
4758 return Op;
4759}
4760
4761static VPExpressionRecipe *
4762createPartialReductionExpression(VPReductionRecipe *Red) {
4763 VPValue *VecOp = Red->getVecOp();
4764
4765 // reduce.[f]add(ext(op))
4766 // -> VPExpressionRecipe(op, red)
4767 if (match(VecOp, m_WidenAnyExtend(m_VPValue())))
4768 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
4769
4770 // reduce.[f]add(neg(ext(op)))
4771 // -> VPExpressionRecipe(op, sub/neg, red)
4772 if (match(VecOp, m_AnyNeg(m_WidenAnyExtend(m_VPValue())))) {
4773 auto *Neg = cast<VPWidenRecipe>(VecOp);
4774 auto *Ext =
4775 cast<VPWidenCastRecipe>(Neg->getOperand(Neg->getNumOperands() - 1));
4776 return new VPExpressionRecipe(Ext, Neg, Red);
4777 }
4778
4779 // reduce.[f]add([f]mul(ext(a), ext(b)))
4780 // -> VPExpressionRecipe(a, b, mul, red)
4781 if (match(VecOp, m_FMul(m_FPExt(m_VPValue()), m_FPExt(m_VPValue()))) ||
4782 match(VecOp,
4784 auto *Mul = cast<VPWidenRecipe>(VecOp);
4785 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
4786 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
4787 return new VPExpressionRecipe(ExtA, ExtB, Mul, Red);
4788 }
4789
4790 // reduce.fadd(fneg(fmul(fpext(a), fpext(b))))
4791 // -> VPExpressionRecipe(a, b, fmul, fsub, red)
4792 if (match(VecOp,
4794 auto *FNeg = cast<VPWidenRecipe>(VecOp);
4795 auto *FMul = cast<VPWidenRecipe>(FNeg->getOperand(0));
4796 auto *ExtA = cast<VPWidenCastRecipe>(FMul->getOperand(0));
4797 auto *ExtB = cast<VPWidenCastRecipe>(FMul->getOperand(1));
4798 return new VPExpressionRecipe(ExtA, ExtB, FMul, FNeg, Red);
4799 }
4800
4801 // reduce.add(neg(mul(ext(a), ext(b))))
4802 // -> VPExpressionRecipe(a, b, mul, sub, red)
4804 m_ZExtOrSExt(m_VPValue()))))) {
4805 auto *Sub = cast<VPWidenRecipe>(VecOp);
4806 auto *Mul = cast<VPWidenRecipe>(Sub->getOperand(1));
4807 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
4808 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
4809 return new VPExpressionRecipe(ExtA, ExtB, Mul, Sub, Red);
4810 }
4811
4812 llvm_unreachable("Unsupported expression");
4813}
4814
4815// Helper to transform a partial reduction chain into a partial reduction
4816// recipe. Assumes profitability has been checked.
4817static void transformToPartialReduction(const VPPartialReductionChain &Chain,
4818 VPlan &Plan,
4819 VPReductionPHIRecipe *RdxPhi) {
4820 VPWidenRecipe *WidenRecipe = Chain.ReductionBinOp;
4821 assert(WidenRecipe->getNumOperands() == 2 && "Expected binary operation");
4822
4823 VPValue *Accumulator = WidenRecipe->getOperand(Chain.AccumulatorOpIdx);
4824 auto *ExtendedOp = cast<VPSingleDefRecipe>(
4825 WidenRecipe->getOperand(1 - Chain.AccumulatorOpIdx));
4826
4827 // FIXME: Do these transforms before invoking the cost-model.
4828 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
4829
4830 // Sub-reductions can be implemented in two ways:
4831 // (1) negate the operand in the vector loop (the default way).
4832 // (2) subtract the reduced value from the init value in the middle block.
4833 // Both ways keep the reduction itself as an 'add' reduction.
4834 //
4835 // The ISD nodes for partial reductions don't support folding the
4836 // sub/negation into its operands because the following is not a valid
4837 // transformation:
4838 // sub(0, mul(ext(a), ext(b)))
4839 // -> mul(ext(a), ext(sub(0, b)))
4840 //
4841 // It's therefore better to choose option (2) such that the partial
4842 // reduction is always positive (starting at '0') and to do a final
4843 // subtract in the middle block.
4844 if ((WidenRecipe->getOpcode() == Instruction::Sub &&
4845 Chain.RK != RecurKind::Sub) ||
4846 (WidenRecipe->getOpcode() == Instruction::FSub &&
4847 Chain.RK != RecurKind::FSub)) {
4848 VPBuilder Builder(WidenRecipe);
4849 Type *ElemTy = ExtendedOp->getScalarType();
4850 VPWidenRecipe *NegRecipe;
4851 if (WidenRecipe->getOpcode() == Instruction::FSub) {
4852 NegRecipe =
4853 new VPWidenRecipe(Instruction::FNeg, {ExtendedOp}, VPIRFlags(),
4855 } else {
4856 auto *Zero = Plan.getZero(ElemTy);
4857 NegRecipe =
4858 new VPWidenRecipe(Instruction::Sub, {Zero, ExtendedOp}, VPIRFlags(),
4860 }
4861 Builder.insert(NegRecipe);
4862 ExtendedOp = NegRecipe;
4863 }
4864
4865 // Check if WidenRecipe is the final result of the reduction. If so, look
4866 // through the Select recipe introduced by tail-folding, otherwise look
4867 // through any Blend recipe introduced by predication for the block.
4868 VPValue *ExitSearch =
4869 Chain.Blend ? cast<VPValue>(Chain.Blend) : cast<VPValue>(WidenRecipe);
4870
4871 VPValue *Cond = nullptr;
4873 findUserOf(ExitSearch, m_Select(m_VPValue(Cond), m_Specific(ExitSearch),
4874 m_Specific(RdxPhi))));
4875
4876 if (Chain.Blend) {
4877 std::optional<unsigned> BlendReductionIdx =
4878 getBlendReductionUpdateValueIdx(Chain.Blend);
4879 assert(BlendReductionIdx &&
4880 Chain.Blend->getIncomingValue(*BlendReductionIdx) == WidenRecipe &&
4881 "Expected blend to contain the reduction update");
4882 VPValue *BlendCond = Chain.Blend->getMask(*BlendReductionIdx);
4883 Cond = ExitValue ? VPBuilder(WidenRecipe)
4884 .createLogicalAnd(Cond, BlendCond,
4885 WidenRecipe->getDebugLoc())
4886 : BlendCond;
4887 }
4888
4889 bool IsLastInChain = RdxPhi->getBackedgeValue() == WidenRecipe ||
4890 RdxPhi->getBackedgeValue() == ExitValue ||
4891 RdxPhi->getBackedgeValue() == Chain.Blend;
4892 assert((!ExitValue || IsLastInChain) &&
4893 "if we found ExitValue, it must match RdxPhi's backedge value");
4894
4895 Type *PhiType = RdxPhi->getScalarType();
4896 RecurKind RdxKind =
4898 auto *PartialRed = new VPReductionRecipe(
4899 RdxKind,
4900 RdxKind == RecurKind::FAdd ? WidenRecipe->getFastMathFlagsOrNone()
4901 : FastMathFlags(),
4902 WidenRecipe->getUnderlyingInstr(), Accumulator, ExtendedOp, Cond,
4903 RdxUnordered{/*VFScaleFactor=*/Chain.ScaleFactor});
4904 PartialRed->insertBefore(WidenRecipe);
4905
4906 if (ExitValue)
4907 ExitValue->replaceAllUsesWith(PartialRed);
4908 if (Chain.Blend)
4909 Chain.Blend->replaceAllUsesWith(PartialRed);
4910 WidenRecipe->replaceAllUsesWith(PartialRed);
4911
4912 // For cost-model purposes, fold this into a VPExpression.
4913 VPExpressionRecipe *E = createPartialReductionExpression(PartialRed);
4914 E->insertBefore(WidenRecipe);
4915 PartialRed->replaceAllUsesWith(E);
4916
4917 // We only need to update the PHI node once, which is when we find the
4918 // last reduction in the chain.
4919 if (!IsLastInChain)
4920 return;
4921
4922 // Scale the PHI and ReductionStartVector by the VFScaleFactor
4923 assert(RdxPhi->getVFScaleFactor() == 1 && "scale factor must not be set");
4924 RdxPhi->setVFScaleFactor(Chain.ScaleFactor);
4925
4926 auto *StartInst = cast<VPInstruction>(RdxPhi->getStartValue());
4927 assert(StartInst->getOpcode() == VPInstruction::ReductionStartVector);
4928 auto *NewScaleFactor = Plan.getConstantInt(32, Chain.ScaleFactor);
4929 StartInst->setOperand(2, NewScaleFactor);
4930
4931 // If this is the last value in a sub-reduction chain, then update the PHI
4932 // node to start at `0` and update the reduction-result to subtract from
4933 // the PHI's start value.
4934 if (Chain.RK != RecurKind::Sub && Chain.RK != RecurKind::FSub)
4935 return;
4936
4937 VPValue *OldStartValue = StartInst->getOperand(0);
4938 StartInst->setOperand(0, StartInst->getOperand(1));
4939
4940 // Replace reduction_result by 'sub (startval, reductionresult)'.
4942 assert(RdxResult && "Could not find reduction result");
4943
4944 VPBuilder Builder = VPBuilder::getToInsertAfter(RdxResult);
4945 unsigned SubOpc = Chain.RK == RecurKind::FSub ? Instruction::BinaryOps::FSub
4946 : Instruction::BinaryOps::Sub;
4947 VPInstruction *NewResult = Builder.createNaryOp(
4948 SubOpc, {OldStartValue, RdxResult}, VPIRFlags::getDefaultFlags(SubOpc),
4949 RdxPhi->getDebugLoc());
4950 RdxResult->replaceUsesWithIf(
4951 NewResult,
4952 [&NewResult](VPUser &U, unsigned Idx) { return &U != NewResult; });
4953}
4954
4955/// Returns the cost of a link in a partial-reduction chain for a given VF.
4956static InstructionCost
4957getPartialReductionLinkCost(VPCostContext &CostCtx,
4958 const VPPartialReductionChain &Link,
4959 ElementCount VF) {
4960 Type *RdxType = Link.ReductionBinOp->getScalarType();
4961 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
4962 std::optional<unsigned> BinOpc = std::nullopt;
4963 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
4964 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
4965 BinOpc = ExtendedOp.ExtendsUser->getOpcode();
4966
4967 std::optional<llvm::FastMathFlags> Flags;
4968 if (RdxType->isFloatingPointTy())
4969 Flags = Link.ReductionBinOp->getFastMathFlagsOrNone();
4970
4971 auto GetLinkOpcode = [&Link]() -> unsigned {
4972 switch (Link.RK) {
4973 case RecurKind::Sub:
4974 return Instruction::Add;
4975 case RecurKind::FSub:
4976 return Instruction::FAdd;
4977 default:
4978 return Link.ReductionBinOp->getOpcode();
4979 }
4980 };
4981
4982 return CostCtx.TTI.getPartialReductionCost(
4983 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
4984 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
4985 CostCtx.CostKind, Flags);
4986}
4987
4988static ExtendKind getPartialReductionExtendKind(VPWidenCastRecipe *Cast) {
4990}
4991
4992/// Checks if \p Op (which is an operand of \p UpdateR) is an extended reduction
4993/// operand. This is an operand where the source of the value (e.g. a load) has
4994/// been extended (sext, zext, or fpext) before it is used in the reduction.
4995///
4996/// Possible forms matched by this function:
4997/// - UpdateR(PrevValue, ext(...))
4998/// - UpdateR(PrevValue, mul(ext(...), ext(...)))
4999/// - UpdateR(PrevValue, mul(ext(...), Constant))
5000/// - UpdateR(PrevValue, ext(mul(ext(...), ext(...))))
5001/// - UpdateR(PrevValue, ext(mul(ext(...), Constant)))
5002/// - UpdateR(PrevValue, abs(sub(ext(...), ext(...)))
5003///
5004/// Note: The second operand of UpdateR corresponds to \p Op in the examples.
5005static std::optional<ExtendedReductionOperand>
5006matchExtendedReductionOperand(VPWidenRecipe *UpdateR, VPValue *Op) {
5007 assert(is_contained(UpdateR->operands(), Op) &&
5008 "Op should be operand of UpdateR");
5009
5010 // Try matching an absolute difference operand of the form
5011 // `abs(sub(ext(A), ext(B)))`. This will be later transformed into
5012 // `ext(absolute-difference(A, B))`. This allows us to perform the absolute
5013 // difference on a wider type and get the extend for "free" from the partial
5014 // reduction.
5015 VPValue *X, *Y;
5016 if (Op->hasOneUse() &&
5020 auto *Abs = cast<VPWidenIntrinsicRecipe>(Op);
5021 auto *Sub = cast<VPWidenRecipe>(Abs->getOperand(0));
5022 auto *LHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(0));
5023 auto *RHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(1));
5024 Type *LHSInputType = X->getScalarType();
5025 Type *RHSInputType = Y->getScalarType();
5026 if (LHSInputType != RHSInputType ||
5027 LHSExt->getOpcode() != RHSExt->getOpcode())
5028 return std::nullopt;
5029 // Note: This is essentially the same as matching ext(...) as we will
5030 // rewrite this operand to ext(absolute-difference(A, B)).
5031 return ExtendedReductionOperand{
5032 Sub,
5033 /*ExtendA=*/{LHSInputType, getPartialReductionExtendKind(LHSExt)},
5034 /*ExtendB=*/{}};
5035 }
5036
5037 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
5039 auto *CastRecipe = cast<VPWidenCastRecipe>(Op);
5040 VPValue *CastSource = CastRecipe->getOperand(0);
5041 OuterExtKind = getPartialReductionExtendKind(CastRecipe);
5042 if (match(CastSource, m_Mul(m_VPValue(), m_VPValue())) ||
5043 match(CastSource, m_FMul(m_VPValue(), m_VPValue()))) {
5044 // Match: ext(mul(...))
5045 // Record the outer extend kind and set `Op` to the mul. We can then match
5046 // this as a binary operation. Note: We can optimize out the outer extend
5047 // by widening the inner extends to match it. See
5048 // optimizeExtendsForPartialReduction.
5049 Op = CastSource;
5050 } else {
5051 return ExtendedReductionOperand{
5052 UpdateR,
5053 /*ExtendA=*/{CastSource->getScalarType(), *OuterExtKind},
5054 /*ExtendB=*/{}};
5055 }
5056 }
5057
5058 if (!Op->hasOneUse())
5059 return std::nullopt;
5060
5062 if (!MulOp ||
5063 !is_contained({Instruction::Mul, Instruction::FMul}, MulOp->getOpcode()))
5064 return std::nullopt;
5065
5066 // The rest of the matching assumes `Op` is a (possibly extended) mul
5067 // operation.
5068
5069 VPValue *LHS = MulOp->getOperand(0);
5070 VPValue *RHS = MulOp->getOperand(1);
5071
5072 // The LHS of the operation must always be an extend.
5074 return std::nullopt;
5075
5076 auto *LHSCast = cast<VPWidenCastRecipe>(LHS);
5077 Type *LHSInputType = LHSCast->getOperand(0)->getScalarType();
5078 ExtendKind LHSExtendKind = getPartialReductionExtendKind(LHSCast);
5079
5080 // The RHS of the operation can be an extend or a constant integer.
5081 const APInt *RHSConst = nullptr;
5082 VPWidenCastRecipe *RHSCast = nullptr;
5084 RHSCast = cast<VPWidenCastRecipe>(RHS);
5085 else if (!match(RHS, m_APInt(RHSConst)) ||
5086 !canConstantBeExtended(RHSConst, LHSInputType, LHSExtendKind))
5087 return std::nullopt;
5088
5089 // The outer extend kind must match the inner extends for folding.
5090 for (VPWidenCastRecipe *Cast : {LHSCast, RHSCast})
5091 if (Cast && OuterExtKind &&
5092 getPartialReductionExtendKind(Cast) != OuterExtKind)
5093 return std::nullopt;
5094
5095 Type *RHSInputType = LHSInputType;
5096 ExtendKind RHSExtendKind = LHSExtendKind;
5097 if (RHSCast) {
5098 RHSInputType = RHSCast->getOperand(0)->getScalarType();
5099 RHSExtendKind = getPartialReductionExtendKind(RHSCast);
5100 }
5101
5102 return ExtendedReductionOperand{
5103 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
5104}
5105
5106/// Examines each operation in the reduction chain corresponding to \p RedPhiR,
5107/// and determines if the target can use a cheaper operation with a wider
5108/// per-iteration input VF and narrower PHI VF. If successful, returns the chain
5109/// of operations in the reduction.
5110static std::optional<SmallVector<VPPartialReductionChain>>
5111getScaledReductions(VPReductionPHIRecipe *RedPhiR) {
5112 // Get the backedge value from the reduction PHI and find the
5113 // ComputeReductionResult that uses it (directly or through a select for
5114 // predicated reductions).
5115 auto *RdxResult = vputils::findComputeReductionResult(RedPhiR);
5116 if (!RdxResult)
5117 return std::nullopt;
5118 VPValue *ExitValue = RdxResult->getOperand(0);
5119 match(ExitValue, m_Select(m_VPValue(), m_VPValue(ExitValue), m_VPValue()));
5120
5122 RecurKind RK = RedPhiR->getRecurrenceKind();
5123 Type *PhiType = RedPhiR->getScalarType();
5124 TypeSize PHISize = PhiType->getPrimitiveSizeInBits();
5125
5126 // Work backwards from the ExitValue examining each reduction operation.
5127 VPValue *CurrentValue = ExitValue;
5128 while (CurrentValue != RedPhiR) {
5129 VPBlendRecipe *Blend = dyn_cast<VPBlendRecipe>(CurrentValue);
5130 std::optional<unsigned> BlendReductionIdx;
5131 if (Blend) {
5132 assert(!Blend->isNormalized() && "Expect Blend not to be normalized.");
5133 if (Blend->getNumIncomingValues() != 2)
5134 return std::nullopt;
5135
5136 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
5137 if (!BlendReductionIdx)
5138 return std::nullopt;
5139
5140 CurrentValue = Blend->getIncomingValue(*BlendReductionIdx);
5141 }
5142
5143 auto *UpdateR = dyn_cast<VPWidenRecipe>(CurrentValue);
5144 if (!UpdateR || !Instruction::isBinaryOp(UpdateR->getOpcode()))
5145 return std::nullopt;
5146
5147 VPValue *Op = UpdateR->getOperand(1);
5148 VPValue *PrevValue = UpdateR->getOperand(0);
5149
5150 // Find the extended operand. The other operand (PrevValue) is the next link
5151 // in the reduction chain.
5152 std::optional<ExtendedReductionOperand> ExtendedOp =
5153 matchExtendedReductionOperand(UpdateR, Op);
5154 if (!ExtendedOp) {
5155 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
5156 if (!ExtendedOp)
5157 return std::nullopt;
5158 std::swap(Op, PrevValue);
5159 }
5160
5161 // Look for VPBlend(reduce(PrevValue, Op), PrevValue), where
5162 // reduce is equal to CurrentValue. This can be lowered as
5163 // a conditional reduction by hoisting the select to the inputs.
5164 if (Blend && Blend->getIncomingValue(1 - *BlendReductionIdx) != PrevValue)
5165 return std::nullopt;
5166
5167 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
5168 TypeSize ExtSrcSize = ExtSrcType->getPrimitiveSizeInBits();
5169 if (!PHISize.hasKnownScalarFactor(ExtSrcSize))
5170 return std::nullopt;
5171
5172 VPPartialReductionChain Link(
5173 {UpdateR, *ExtendedOp, RK,
5174 PrevValue == UpdateR->getOperand(0) ? 0U : 1U,
5175 static_cast<unsigned>(PHISize.getKnownScalarFactor(ExtSrcSize)),
5176 Blend});
5177 Chain.push_back(Link);
5178 CurrentValue = PrevValue;
5179 }
5180
5181 // The chain links were collected by traversing backwards from the exit value.
5182 // Reverse the chains so they are in program order.
5183 std::reverse(Chain.begin(), Chain.end());
5184 return Chain;
5185}
5186} // namespace
5187
5189 VPCostContext &CostCtx,
5190 VFRange &Range) {
5191 // Find all possible valid partial reductions, grouping chains by their PHI.
5192 // This grouping allows invalidating the whole chain, if any link is not a
5193 // valid partial reduction.
5195 ChainsByPhi;
5196 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
5197 for (VPRecipeBase &R : HeaderVPBB->phis()) {
5198 auto *RedPhiR = dyn_cast<VPReductionPHIRecipe>(&R);
5199 if (!RedPhiR)
5200 continue;
5201
5202 if (auto Chains = getScaledReductions(RedPhiR))
5203 ChainsByPhi.try_emplace(RedPhiR, std::move(*Chains));
5204 }
5205
5206 if (ChainsByPhi.empty())
5207 return;
5208
5209 // Build set of partial reduction operations and blends for user validation
5210 // and a map of reduction bin ops to their scale factors for scale validation.
5211 SmallPtrSet<VPRecipeBase *, 4> PartialReductionOps;
5212 SmallPtrSet<VPBlendRecipe *, 4> PartialReductionBlends;
5213 DenseMap<VPSingleDefRecipe *, unsigned> ScaledReductionMap;
5214 for (const auto &[_, Chains] : ChainsByPhi)
5215 for (const VPPartialReductionChain &Chain : Chains) {
5216 PartialReductionOps.insert(Chain.ExtendedOp.ExtendsUser);
5217 if (Chain.Blend)
5218 PartialReductionBlends.insert(Chain.Blend);
5219 ScaledReductionMap[Chain.ReductionBinOp] = Chain.ScaleFactor;
5220 }
5221
5222 // A partial reduction is invalid if any of its extends are used by
5223 // something that isn't another partial reduction. This is because the
5224 // extends are intended to be lowered along with the reduction itself.
5225 auto ExtendUsersValid = [&](VPValue *Ext) {
5226 return !isa<VPWidenCastRecipe>(Ext) || all_of(Ext->users(), [&](VPUser *U) {
5227 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
5228 });
5229 };
5230
5231 auto IsProfitablePartialReductionChainForVF =
5232 [&](ArrayRef<VPPartialReductionChain> Chain, ElementCount VF) -> bool {
5233 InstructionCost PartialCost = 0, RegularCost = 0;
5234
5235 // The chain is a profitable partial reduction chain if the cost of handling
5236 // the entire chain is cheaper when using partial reductions than when
5237 // handling the entire chain using regular reductions.
5238 for (const VPPartialReductionChain &Link : Chain) {
5239 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5240 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
5241 if (!LinkCost.isValid())
5242 return false;
5243
5244 PartialCost += LinkCost;
5245 RegularCost += Link.ReductionBinOp->computeCost(VF, CostCtx);
5246 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
5247 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5248 RegularCost += ExtendedOp.ExtendsUser->computeCost(VF, CostCtx);
5249 for (VPValue *Op : ExtendedOp.ExtendsUser->operands())
5250 if (auto *Extend = dyn_cast<VPWidenCastRecipe>(Op))
5251 RegularCost += Extend->computeCost(VF, CostCtx);
5252 }
5253 return PartialCost.isValid() && PartialCost < RegularCost;
5254 };
5255
5256 // Validate chains: check that extends are only used by partial reductions,
5257 // and that reduction bin ops are only used by other partial reductions with
5258 // matching scale factors, are outside the loop region or the select
5259 // introduced by tail-folding. Otherwise we would create users of scaled
5260 // reductions where the types of the other operands don't match.
5261 for (auto &[RedPhiR, Chains] : ChainsByPhi) {
5262 for (const VPPartialReductionChain &Chain : Chains) {
5263 if (!all_of(Chain.ExtendedOp.ExtendsUser->operands(), ExtendUsersValid)) {
5264 Chains.clear();
5265 break;
5266 }
5267 auto UseIsValid = [&, RedPhiR = RedPhiR](VPUser *U) {
5268 if (auto *PhiR = dyn_cast<VPReductionPHIRecipe>(U))
5269 return PhiR == RedPhiR;
5270 auto *R = cast<VPSingleDefRecipe>(U);
5271
5272 if (auto *Blend = dyn_cast<VPBlendRecipe>(R))
5273 return Blend == Chain.Blend || PartialReductionBlends.contains(Blend);
5274
5275 return Chain.ScaleFactor == ScaledReductionMap.lookup_or(R, 0) ||
5277 m_Specific(Chain.ReductionBinOp))) ||
5278 match(R, m_Select(m_VPValue(), m_Specific(Chain.ReductionBinOp),
5279 m_Specific(RedPhiR)));
5280 };
5281 if (!all_of(Chain.ReductionBinOp->users(), UseIsValid)) {
5282 Chains.clear();
5283 break;
5284 }
5285
5286 // Check if the compute-reduction-result is used by a sunk store.
5287 // TODO: Also form partial reductions in those cases.
5288 if (auto *RdxResult = vputils::findComputeReductionResult(RedPhiR)) {
5289 if (any_of(RdxResult->users(), [](VPUser *U) {
5290 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
5291 return RepR && RepR->getOpcode() == Instruction::Store;
5292 })) {
5293 Chains.clear();
5294 break;
5295 }
5296 }
5297 }
5298
5299 // Clear the chain if it is not profitable.
5301 [&, &Chains = Chains](ElementCount VF) {
5302 return IsProfitablePartialReductionChainForVF(Chains, VF);
5303 },
5304 Range))
5305 Chains.clear();
5306 }
5307
5308 for (auto &[Phi, Chains] : ChainsByPhi)
5309 for (const VPPartialReductionChain &Chain : Chains)
5310 transformToPartialReduction(Chain, Plan, Phi);
5311}
5312
5314 VPRecipeBuilder &RecipeBuilder,
5315 VPCostContext &CostCtx) {
5316 // Collect all loads/stores first. We will start with ones having simpler
5317 // decisions followed by more complex ones that are potentially
5318 // guided/dependent on the simpler ones.
5320 for (VPBasicBlock *VPBB :
5323 for (VPRecipeBase &R : *VPBB) {
5324 auto *VPI = dyn_cast<VPInstruction>(&R);
5325 if (VPI && VPI->getUnderlyingValue() &&
5326 is_contained({Instruction::Load, Instruction::Store},
5327 VPI->getOpcode()))
5328 MemOps.push_back(VPI);
5329 }
5330 }
5331
5332 // Few helpers to process different kinds of memory operations.
5333
5334 // To be used as argument to `VPlanTransforms::runPass` which explicitly
5335 // specified pass name, hence `VPlan &` parameter.
5336 auto ProcessSubset = [&](VPlan &, auto ProcessVPInst) {
5337 SmallVector<VPInstruction *> RemainingMemOps;
5338 for (VPInstruction *VPI : MemOps) {
5339 if (!ProcessVPInst(VPI))
5340 RemainingMemOps.push_back(VPI);
5341 }
5342
5343 MemOps.clear();
5344 std::swap(MemOps, RemainingMemOps);
5345 };
5346
5347 auto ReplaceWith = [&](VPInstruction *VPI, VPRecipeBase *New) {
5348 assert(New->getParent() && "New recipe must have been inserted");
5349 if (VPI->getOpcode() == Instruction::Load)
5350 VPI->replaceAllUsesWith(New->getVPSingleValue());
5351 VPI->eraseFromParent();
5352
5353 // VPI has been processed.
5354 return true;
5355 };
5356
5357 auto Scalarize = [&](VPInstruction *VPI) {
5358 return ReplaceWith(VPI, VPBuilder(VPI).insert(
5359 RecipeBuilder.handleReplication(VPI, Range)));
5360 };
5361
5362 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
5363 VPBuilder FinalRedStoresBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
5365 "lowerMemoryIdioms", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5366 if (RecipeBuilder.replaceWithFinalIfReductionStore(
5367 VPI, FinalRedStoresBuilder))
5368 return true;
5369
5370 // Filter out scalar VPlan for the remaining idioms.
5372 [](ElementCount VF) { return VF.isScalar(); }, Range))
5373 return false;
5374
5375 if (VPHistogramRecipe *Histogram = RecipeBuilder.widenIfHistogram(VPI))
5376 return ReplaceWith(VPI, VPBuilder(VPI).insert(Histogram));
5377
5378 return false;
5379 });
5380
5381 // Filter out scalar VPlan for the remaining memory operations.
5383 [](ElementCount VF) { return VF.isScalar(); }, Range))
5384 return;
5385
5386 // If the instruction's allocated size doesn't equal it's type size, it
5387 // requires padding and will be scalarized.
5389 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
5390 [&](VPInstruction *VPI) {
5392 if (hasIrregularType(getLoadStoreType(I), I->getDataLayout()))
5393 return Scalarize(VPI);
5394
5395 return false;
5396 });
5397
5398 if (!RecipeBuilder.prefersVectorizedAddressing()) {
5400 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5402 bool IsLoad = VPI->getOpcode() == Instruction::Load;
5403 if (RecipeBuilder.isPredicatedInst(I) || !IsLoad ||
5405 return false;
5406
5407 // Scalarize loads used as addresses, matching the legacy CM. The load
5408 // is single-scalar if the pointer is loop-invariant, otherwise it is
5409 // replicated per-lane. No mask is needed as the load is not
5410 // predicated.
5411 VPValue *Ptr = VPI->getOperand(0);
5412 const SCEV *PtrSCEV =
5413 vputils::getSCEVExprForVPValue(Ptr, CostCtx.PSE, CostCtx.L);
5414 bool IsSingleScalarLoad =
5415 !isa<SCEVCouldNotCompute>(PtrSCEV) &&
5416 CostCtx.PSE.getSE()->isLoopInvariant(PtrSCEV, CostCtx.L);
5417
5418 ReplaceWith(VPI,
5419 VPBuilder(VPI).insert(new VPReplicateRecipe(
5420 I, Ptr, /*IsSingleScalar=*/IsSingleScalarLoad,
5421 /*Mask=*/nullptr, *VPI, *VPI, VPI->getDebugLoc())));
5422 return true;
5423 });
5424 }
5425
5426 // Widen unit-stride consecutive accesses, matching the legacy CM. Both
5427 // forward (stride +1) and reverse (stride -1) accesses are handled.
5429 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5431 bool IsLoad = VPI->getOpcode() == Instruction::Load;
5432 VPValue *Ptr = VPI->getOperand(!IsLoad);
5433 Type *ScalarTy =
5434 IsLoad ? VPI->getScalarType() : VPI->getOperand(0)->getScalarType();
5435 std::optional<int64_t> Stride =
5436 getConstantStride(Ptr, ScalarTy, CostCtx.PSE, CostCtx.L);
5437 if (Stride != 1 && Stride != -1)
5438 return false;
5439 bool Reverse = Stride == -1;
5440
5441 // A predicated access can only be widened (rather than scalarized) if
5442 // the target supports a masked load/store for it.
5443 // TODO: Determine if a load/store needs predication directly in VPlan.
5444 bool IsPredicated = RecipeBuilder.isPredicatedInst(I);
5445 if (IsPredicated && !CostCtx.Config.isLegalMaskedLoadOrStore(
5446 IsLoad, ScalarTy, getLoadStoreAlignment(I),
5448 return false;
5449
5450 VPBuilder Builder(VPI);
5451 VPSingleDefRecipe *VectorPtr = Builder.createConsecutiveVectorPointer(
5452 Ptr, ScalarTy, Reverse, VPI->getDebugLoc());
5453
5454 VPValue *Mask = IsPredicated ? VPI->getMask() : nullptr;
5455 // Reverse the mask so it matches the reversed access order.
5456 if (Reverse && Mask)
5457 Mask = Builder.createNaryOp(VPInstruction::Reverse, Mask,
5458 VPI->getDebugLoc());
5459
5460 if (IsLoad) {
5461 VPSingleDefRecipe *Load = Builder.createWidenLoad(
5462 *cast<LoadInst>(I), VectorPtr, Mask,
5463 /*Consecutive=*/true, *VPI, VPI->getDebugLoc());
5464 // Reverse the loaded values back into program order.
5465 if (Reverse)
5466 Load = Builder.createNaryOp(VPInstruction::Reverse, Load,
5467 VPI->getDebugLoc());
5468 return ReplaceWith(VPI, Load);
5469 }
5470
5471 VPValue *StoredVal = VPI->getOperand(0);
5472 if (Reverse)
5473 // Reverse the stored values so they are written in descending order.
5474 StoredVal = Builder.createNaryOp(VPInstruction::Reverse, StoredVal,
5475 VPI->getDebugLoc());
5476
5477 auto *StoreR = Builder.createWidenStore(
5478 *cast<StoreInst>(I), VectorPtr, StoredVal, Mask,
5479 /*Consecutive=*/true, *VPI, VPI->getDebugLoc());
5480 return ReplaceWith(VPI, StoreR);
5481 });
5482
5483 VPlanTransforms::runPass("delegateMemOpWideningToLegacyCM", ProcessSubset,
5484 Plan, [&](VPInstruction *VPI) {
5485 if (VPRecipeBase *Recipe =
5486 RecipeBuilder.tryToWidenMemory(VPI, Range))
5487 return ReplaceWith(VPI, Recipe);
5488
5489 return Scalarize(VPI);
5490 });
5491}
5492
5495 [&](ElementCount VF) { return VF.isScalar(); }, Range))
5496 return;
5497
5499 Plan.getEntry());
5501 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
5502 auto *VPI = dyn_cast<VPInstruction>(&R);
5503 if (!VPI)
5504 continue;
5505
5506 auto *I = cast_or_null<Instruction>(VPI->getUnderlyingValue());
5507 // Wouldn't be able to create a `VPReplicateRecipe` anyway.
5508 if (!I)
5509 continue;
5510
5511 // If executing other lanes produces side-effects we can't avoid them.
5512 if (VPI->mayHaveSideEffects())
5513 continue;
5514
5515 // We want to drop the mask operand, verify we can safely do that.
5516 if (VPI->isMasked() && !VPI->isSafeToSpeculativelyExecute())
5517 continue;
5518
5519 // Avoid rewriting IV increment as that interferes with
5520 // `removeRedundantCanonicalIVs`.
5521 if (VPI->getOpcode() == Instruction::Add &&
5523 continue;
5524
5525 // Other lanes are needed - can't drop them.
5527 continue;
5528
5529 auto *Recipe = VPBuilder::createSingleScalarOp(
5530 VPI->getOpcode(), VPI->operandsWithoutMask(), /*Mask=*/nullptr, *VPI,
5531 *VPI, VPI->getDebugLoc(), I);
5532 Recipe->insertBefore(VPI);
5533 VPI->replaceAllUsesWith(Recipe);
5534 VPI->eraseFromParent();
5535 }
5536 }
5537}
5538
5539/// Returns true if \p Info's parameter kinds are compatible with \p Args.
5540static bool areVFParamsOk(const VFInfo &Info, ArrayRef<VPValue *> Args,
5541 PredicatedScalarEvolution &PSE, const Loop *L) {
5542 ScalarEvolution *SE = PSE.getSE();
5543 return all_of(Info.Shape.Parameters, [&](VFParameter Param) {
5544 switch (Param.ParamKind) {
5545 case VFParamKind::Vector:
5546 case VFParamKind::GlobalPredicate:
5547 return true;
5548 case VFParamKind::OMP_Uniform:
5549 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
5550 SE->isLoopInvariant(
5551 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
5552 L);
5553 case VFParamKind::OMP_Linear:
5554 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
5555 m_scev_AffineAddRec(
5556 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
5557 m_SpecificLoop(L)));
5558 default:
5559 return false;
5560 }
5561 });
5562}
5563
5564/// Find a vector variant of \p CI for \p VF, respecting \p MaskRequired.
5565/// Returns the variant function, or nullptr. Masked variants are assumed to
5566/// take the mask as a trailing parameter.
5568 ElementCount VF, bool MaskRequired,
5570 const Loop *L) {
5571 if (CI->isNoBuiltin())
5572 return nullptr;
5573 auto Mappings = VFDatabase::getMappings(*CI);
5574 const auto *It = find_if(Mappings, [&](const VFInfo &Info) {
5575 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
5576 areVFParamsOk(Info, Args, PSE, L);
5577 });
5578 if (It == Mappings.end())
5579 return nullptr;
5580 return CI->getModule()->getFunction(It->VectorName);
5581}
5582
5583namespace {
5584/// The outcome of choosing how to widen a call at a given VF.
5585struct CallWideningDecision {
5586 enum class KindTy { Scalarize, Intrinsic, VectorVariant };
5587 CallWideningDecision(KindTy Kind, Function *Variant = nullptr)
5588 : Kind(Kind), Variant(Variant) {}
5589 KindTy Kind;
5590
5591 /// Set when Kind == VectorVariant.
5593
5594 bool operator==(const CallWideningDecision &Other) const {
5595 return Kind == Other.Kind && Variant == Other.Variant;
5596 }
5597};
5598} // namespace
5599
5600/// Pick the cheapest widening for the call \p VPI at \p VF among scalarization,
5601/// vector intrinsic, and vector library variant.
5602static CallWideningDecision decideCallWidening(VPInstruction &VPI,
5604 ElementCount VF,
5605 VPCostContext &CostCtx) {
5606 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
5607
5608 // Scalar VFs and calls forced or known to scalarize always replicate.
5609 if (VF.isScalar() || CostCtx.willBeScalarized(CI, VF))
5610 return CallWideningDecision::KindTy::Scalarize;
5611
5612 auto *CalledFn = cast<Function>(
5614 Type *ResultTy = VPI.getScalarType();
5616 bool MaskRequired = CostCtx.isMaskRequired(CI);
5617
5618 // Pseudo intrinsics (assume, lifetime, ...) are always scalarized.
5620 return CallWideningDecision::KindTy::Scalarize;
5621
5622 InstructionCost ScalarCost =
5623 VPReplicateRecipe::computeCallCost(CalledFn, ResultTy, Ops,
5624 /*IsSingleScalar=*/false, VF, CostCtx);
5625
5626 Function *VecFunc =
5627 findVectorVariant(CI, Ops, VF, MaskRequired, CostCtx.PSE, CostCtx.L);
5629 if (VecFunc)
5630 VecCallCost = VPWidenCallRecipe::computeCallCost(VecFunc, CostCtx);
5631
5632 // Prefer the intrinsic if it is at least as cheap as scalarizing and any
5633 // available vector variant.
5634 if (ID) {
5636 VPWidenIntrinsicRecipe::computeCallCost(ID, Ops, VPI, VF, CostCtx);
5637 if (IntrinsicCost.isValid() && ScalarCost >= IntrinsicCost &&
5638 (!VecFunc || VecCallCost >= IntrinsicCost))
5639 return CallWideningDecision::KindTy::Intrinsic;
5640 }
5641
5642 // Otherwise, use a vector library variant when it beats scalarizing.
5643 if (VecFunc && ScalarCost >= VecCallCost)
5644 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
5645
5646 return CallWideningDecision::KindTy::Scalarize;
5647}
5648
5650 VPRecipeBuilder &RecipeBuilder,
5651 VPCostContext &CostCtx) {
5654 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
5655 auto *VPI = dyn_cast<VPInstruction>(&R);
5656 if (!VPI || !VPI->getUnderlyingValue() ||
5657 VPI->getOpcode() != Instruction::Call)
5658 continue;
5659
5660 auto *CI = cast<CallInst>(VPI->getUnderlyingInstr());
5661 SmallVector<VPValue *, 4> Ops(VPI->op_begin(),
5662 VPI->op_begin() + CI->arg_size());
5663
5664 CallWideningDecision Decision =
5665 decideCallWidening(*VPI, Ops, Range.Start, CostCtx);
5667 [&](ElementCount VF) {
5668 return Decision == decideCallWidening(*VPI, Ops, VF, CostCtx);
5669 },
5670 Range);
5671
5672 VPSingleDefRecipe *Replacement = nullptr;
5673 switch (Decision.Kind) {
5674 case CallWideningDecision::KindTy::Intrinsic: {
5676 Type *ResultTy = VPI->getScalarType();
5677 Replacement = new VPWidenIntrinsicRecipe(*CI, ID, Ops, ResultTy, *VPI,
5678 *VPI, VPI->getDebugLoc());
5679 break;
5680 }
5681 case CallWideningDecision::KindTy::VectorVariant: {
5682 // Masked variants take the mask as a trailing parameter, so they have
5683 // one more parameter than the original call's arguments.
5684 if (Decision.Variant->arg_size() > Ops.size()) {
5685 VPValue *Mask = VPI->isMasked() ? VPI->getMask() : Plan.getTrue();
5686 Ops.push_back(Mask);
5687 }
5688 Ops.push_back(VPI->getOperand(VPI->getNumOperandsWithoutMask() - 1));
5689 Replacement = new VPWidenCallRecipe(CI, Decision.Variant, Ops, *VPI,
5690 *VPI, VPI->getDebugLoc());
5691 break;
5692 }
5693 case CallWideningDecision::KindTy::Scalarize:
5694 Replacement = RecipeBuilder.handleReplication(VPI, Range);
5695 break;
5696 }
5697
5698 Replacement->insertBefore(VPI);
5699 VPI->replaceAllUsesWith(Replacement);
5700 VPI->eraseFromParent();
5701 }
5702 }
5703}
5704
5707 Loop &L, VPCostContext &Ctx,
5708 VFRange &Range) {
5709 if (Plan.hasScalarVFOnly())
5710 return;
5711
5712 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
5713 VPValue *I32VF = nullptr;
5715 vp_depth_first_shallow(VectorLoop->getEntry()))) {
5716 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
5717 auto *MemR = dyn_cast<VPWidenMemoryRecipe>(&R);
5718 // TODO: Transform reverse access into strided access with -1 stride.
5719 // TODO: Transform gather/scatter with uniform address into strided access
5720 // with 0 stride.
5721 // TODO: Transform interleave access into multiple strided accesses.
5722 if (!MemR || MemR->isConsecutive())
5723 continue;
5724
5725 VPValue *Ptr = MemR->getAddr();
5726 // Check if this is a strided access by analyzing the address SCEV for an
5727 // affine addRec.
5728 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, &L);
5729 const SCEV *Start;
5730 const SCEVConstant *Step;
5731 // TODO: Support non-constant loop invariant stride.
5732 if (!match(PtrSCEV,
5734 m_SpecificLoop(&L))))
5735 continue;
5736
5737 VPValue *StoredValue = nullptr;
5738 Type *DataTy;
5739 Intrinsic::ID IntrinID;
5740 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(&R)) {
5741 StoredValue = StoreR->getStoredValue();
5742 DataTy = StoredValue->getScalarType();
5743 IntrinID = Intrinsic::experimental_vp_strided_store;
5744 } else {
5745 auto *LoadR = cast<VPWidenLoadRecipe>(&R);
5746 DataTy = LoadR->getScalarType();
5747 IntrinID = Intrinsic::experimental_vp_strided_load;
5748 }
5749
5750 Align Alignment = MemR->getAlign();
5751 auto IsProfitable = [&](ElementCount VF) {
5752 Type *VectorTy = toVectorTy(DataTy, VF);
5753 if (!Ctx.TTI.isLegalStridedLoadStore(VectorTy, Alignment))
5754 return false;
5755 const InstructionCost CurrentCost = MemR->computeCost(VF, Ctx);
5756 const InstructionCost StridedLoadStoreCost =
5758 IntrinID, VectorTy, MemR->isMasked(), Alignment, Ctx);
5759 return StridedLoadStoreCost < CurrentCost;
5760 };
5761
5763 Range))
5764 continue;
5765
5766 // Invalidate the legacy widening decision so the cost of replaced load is
5767 // not counted during precomputeCosts.
5768 // TODO: Remove once the legacy exit cost computation is retired.
5769 for (ElementCount VF : Range)
5770 Ctx.invalidateWideningDecision(&MemR->getIngredient(), VF);
5771
5772 // Get VF as i32 for the vector length operand.
5773 if (!I32VF) {
5774 VPBuilder Builder(Plan.getVectorPreheader());
5775 I32VF = Builder.createScalarZExtOrTrunc(
5776 &Plan.getVF(), Type::getInt32Ty(Plan.getContext()),
5778 }
5779
5780 VPBuilder Builder(&R);
5781 // Create the base pointer of strided access.
5782 // TODO: reuse VPDerivedIVRecipe for base pointer computation when it
5783 // supports a general VPValue as the start value.
5784 VPValue *StartVPV = VPSCEVExpander(Builder, *PSE.getSE(), R.getDebugLoc())
5785 .tryToExpand(Start);
5786 if (!StartVPV)
5787 StartVPV = VPBuilder(Plan.getEntry()).createExpandSCEV(Start);
5788 VPValue *StrideInBytes = Plan.getOrAddLiveIn(Step->getValue());
5789 Type *IndexTy = Plan.getDataLayout().getIndexType(Ptr->getScalarType());
5790 assert(IndexTy == StrideInBytes->getScalarType() &&
5791 "Stride type from SCEV must match the index type");
5792 VPValue *CanIV = Builder.createScalarZExtOrTrunc(
5793 VectorLoop->getCanonicalIV(), IndexTy, DebugLoc::getUnknown());
5794 auto *AddRecPtr = cast<SCEVAddRecExpr>(PtrSCEV);
5795 auto *Offset = Builder.createOverflowingOp(
5796 Instruction::Mul, {CanIV, StrideInBytes},
5797 {AddRecPtr->hasNoUnsignedWrap(), /*HasNSW=*/false});
5798 GEPNoWrapFlags NWFlags = AddRecPtr->hasNoUnsignedWrap()
5801 VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV, Offset, NWFlags);
5802
5803 // Create a new vector pointer for strided access.
5804 VPValue *NewPtr = Builder.createVectorPointer(
5805 BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes, NWFlags,
5806 R.getDebugLoc());
5807
5808 VPValue *Mask = MemR->getMask();
5809 if (!Mask)
5810 Mask = Plan.getTrue();
5812 if (StoredValue)
5813 Ops.push_back(StoredValue);
5814 Ops.append({NewPtr, StrideInBytes, Mask, I32VF});
5815
5816 auto *StridedR = Builder.createWidenMemIntrinsic(
5817 IntrinID, Ops,
5818 StoredValue ? Type::getVoidTy(Plan.getContext()) : DataTy, Alignment,
5819 *MemR, R.getDebugLoc());
5820 if (!StoredValue)
5821 cast<VPWidenLoadRecipe>(&R)->replaceAllUsesWith(StridedR);
5822 R.eraseFromParent();
5823 }
5824 }
5825}
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.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
const SmallVectorImpl< MachineOperand > & Cond
Func MI getDebugLoc()))
This file contains some templates that are useful if you are working with the STL at all.
This is the interface for a metadata-based scoped no-alias analysis.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file implements the TypeSwitch template, which mimics a switch() statement whose cases are type ...
This file implements dominator tree analysis for a single level of a VPlan's H-CFG.
This file contains the declarations of different VPlan-related auxiliary helpers.
static SmallVector< SmallVector< VPReplicateRecipe *, 4 > > collectComplementaryPredicatedMemOps(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
static void removeCommonBlendMask(VPBlendRecipe *Blend)
Try to see if all of Blend's masks share a common value logically and'ed and remove it from the masks...
static void tryToCreateAbstractReductionRecipe(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries to create abstract recipes from the reduction recipe for following optimizations ...
static VPReplicateRecipe * findRecipeWithMinAlign(ArrayRef< VPReplicateRecipe * > Group)
static bool handleUncountableExitsWithSideEffects(VPlan &Plan, SmallVectorImpl< EarlyExitInfo > &Exits, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC)
Update Plan to mask memory operations in the loop based on whether the early exit is taken or not.
static CallWideningDecision decideCallWidening(VPInstruction &VPI, ArrayRef< VPValue * > Ops, ElementCount VF, VPCostContext &CostCtx)
Pick the cheapest widening for the call VPI at VF among scalarization, vector intrinsic,...
static bool areVFParamsOk(const VFInfo &Info, ArrayRef< VPValue * > Args, PredicatedScalarEvolution &PSE, const Loop *L)
Returns true if Info's parameter kinds are compatible with Args.
static std::optional< VPValue * > getRecipesForUncountableExit(SmallVectorImpl< VPInstruction * > &Recipes, VPBasicBlock *LatchVPBB)
Returns the VPValue representing the uncountable exit comparison used by AnyOf if the recipes it depe...
static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder, bool CanCreateNewRecipe)
Try to simplify logical and bitwise recipes in Def.
static bool sinkScalarOperands(VPlan &Plan)
static std::optional< int64_t > getConstantStride(VPValue *Addr, Type *AccessTy, PredicatedScalarEvolution &PSE, const Loop *L)
If the pointer operand Addr of a memory access is an affine AddRec w.r.t.
static bool simplifyBranchConditionForVFAndUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Try to simplify the branch condition of Plan.
static VPValue * cloneBinOpForScalarIV(VPWidenRecipe *BinOp, VPValue *ScalarIV, VPWidenIntOrFpInductionRecipe *WidenIV)
Create a scalar version of BinOp, with its WidenIV operand replaced by ScalarIV, and place it after S...
static VPWidenIntOrFpInductionRecipe * getExpressionIV(VPValue *V)
Check if V is a binary expression of a widened IV and a loop-invariant value.
static void removeRedundantInductionCasts(VPlan &Plan)
Remove redundant casts of inductions.
static bool isConditionTrueViaVFAndUF(VPValue *Cond, VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Return true if Cond is known to be true for given BestVF and BestUF.
static VPExpressionRecipe * tryToMatchAndCreateExtendedReduction(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries convert extended in-loop reductions to VPExpressionRecipe and clamp the Range if ...
static std::optional< ElementCount > isConsecutiveInterleaveGroup(VPInterleaveRecipe *InterleaveR, ArrayRef< ElementCount > VFs, const TargetTransformInfo &TTI)
Returns VF from VFs if IR is a full interleave group with factor and number of members both equal to ...
static Type * getLoadStoreValueType(VPReplicateRecipe *R, bool IsLoad)
Get the value type of the replicate load or store.
static bool replaceMaskWithCompare(VPlan &Plan, ElementCount BestVF)
static VPIRMetadata getCommonMetadata(ArrayRef< VPReplicateRecipe * > Recipes)
static bool mergeReplicateRegionsIntoSuccessors(VPlan &Plan)
static Function * findVectorVariant(CallInst *CI, ArrayRef< VPValue * > Args, ElementCount VF, bool MaskRequired, PredicatedScalarEvolution &PSE, const Loop *L)
Find a vector variant of CI for VF, respecting MaskRequired.
static VPWidenInductionRecipe * getOptimizableIVOf(VPValue *VPV, PredicatedScalarEvolution &PSE)
Check if VPV is an untruncated wide induction, either before or after the increment.
static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx, VPValue *OpV, unsigned Idx, bool IsScalable)
Returns true if V is VPWidenLoadRecipe or VPInterleaveRecipe that can be converted to a narrower reci...
static void simplifyRecipe(VPSingleDefRecipe *Def)
Try to simplify VPSingleDefRecipe Def.
static void legalizeAndOptimizeInductions(VPlan &Plan)
Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd (IndStart, ScalarIVSteps (0,...
static void addReplicateRegions(VPlan &Plan)
static VPValue * optimizeLatchExitIVUserViaSCEV(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE, VPValue *ResumeTC, const Loop *L)
static SmallVector< SmallVector< VPReplicateRecipe *, 4 > > collectGroupedReplicateMemOps(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L, function_ref< bool(VPReplicateRecipe *)> FilterFn)
Collect either replicated Loads or Stores grouped by their address SCEV and their load-store type,...
static VPValue * tryToComputeEndValueForInduction(VPWidenInductionRecipe *WideIV, VPBuilder &VectorPHBuilder, VPValue *VectorTC)
Compute the end value for WideIV, unless it is truncated.
static void removeRedundantExpandSCEVRecipes(VPlan &Plan)
Remove redundant ExpandSCEVRecipes in Plan's entry block by replacing them with already existing reci...
static VPValue * optimizeEarlyExitInductionUser(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the early exit block.
static VPValue * narrowInterleaveGroupOp(ArrayRef< VPValue * > Members, SmallPtrSetImpl< VPValue * > &NarrowedOps, VPBasicBlock *Preheader)
static VPValue * optimizeLatchExitInductionUser(VPlan &Plan, VPValue *Op, DenseMap< VPValue *, VPValue * > &EndValues, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the exit block coming from the l...
static void reassociateHeaderMask(VPlan &Plan)
Reassociate (headermask && x) && y -> headermask && (x && y) to allow the header mask to be simplifie...
static VPBasicBlock * getPredicatedThenBlock(VPRegionBlock *R)
If R is a triangle region, return the 'then' block of the triangle.
static bool canHoistOrSinkWithNoAliasCheck(const MemoryLocation &MemLoc, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, std::optional< SinkStoreInfo > SinkInfo={})
Check if a memory operation doesn't alias with memory operations using scoped noalias metadata,...
static VPRegionBlock * createReplicateRegion(VPReplicateRecipe *PredRecipe, VPRegionBlock *ParentRegion, VPlan &Plan)
static void simplifyBlends(VPlan &Plan)
Normalize and simplify VPBlendRecipes.
static bool cannotHoistOrSinkRecipe(VPRecipeBase &R, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink a non-memory or memory recipe R out...
static std::optional< Instruction::BinaryOps > getUnmaskedDivRemOpcode(Intrinsic::ID ID)
static bool isAlreadyNarrow(VPValue *VPV)
Returns true if VPValue is a narrow VPValue.
static bool canNarrowOps(ArrayRef< VPValue * > Ops, bool IsScalable)
static bool optimizeVectorInductionWidthForTCAndVFUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF)
Optimize the width of vector induction variables in Plan based on a known constant Trip Count,...
static VPExpressionRecipe * tryToMatchAndCreateMulAccumulateReduction(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries convert extended in-loop reductions to VPExpressionRecipe and clamp the Range if ...
static bool canSinkStoreWithNoAliasCheck(ArrayRef< VPReplicateRecipe * > StoresToSink, PredicatedScalarEvolution &PSE, const Loop &L)
static std::optional< bool > getStepDirection(const SCEV *S, ScalarEvolution &SE)
If S is an affine AddRec, returns true if its step is known to be positive and false if it is known t...
static void narrowToSingleScalarRecipes(VPlan &Plan)
This file provides utility VPlan to VPlan transformations.
#define RUN_VPLAN_PASS(PASS,...)
This file contains the declarations of the Vectorization Plan base classes:
static const X86InstrFMA3Group Groups[]
Value * RHS
Value * LHS
BinaryOperator * Mul
static const uint32_t IV[8]
Definition blake3_impl.h:83
Helper for extra no-alias checks via known-safe recipe and SCEV.
SinkStoreInfo(ArrayRef< VPReplicateRecipe * > ExcludeRecipes, VPReplicateRecipe &GroupLeader, PredicatedScalarEvolution &PSE, const Loop &L)
SinkStoreInfo(VPReplicateRecipe &GroupLeader)
bool shouldSkip(VPRecipeBase &R) const
Return true if R should be skipped during alias checking, either because it's in the exclude set or b...
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp: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_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
Definition InstrTypes.h:852
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
This class represents a range of values.
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
LLVM_ABI IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const
Returns the type of a GEP index in AddressSpace.
A debug info location.
Definition DebugLoc.h:126
static DebugLoc getUnknown()
Definition DebugLoc.h:153
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Definition DenseMap.h:250
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:260
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:312
constexpr bool isScalar() const
Exactly one element.
Definition TypeSize.h:320
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
size_t arg_size() const
Definition Function.h:885
Represents flags for the getelementptr instruction/expression.
static GEPNoWrapFlags noUnsignedWrap()
bool hasNoUnsignedWrap() const
GEPNoWrapFlags withoutNoUnsignedWrap() const
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
A struct for saving information about induction variables.
InductionKind
This enum represents the kinds of inductions that we support.
@ IK_PtrInduction
Pointer induction var. Step = C.
@ IK_IntInduction
Integer induction variable. Step = C.
static InstructionCost getInvalid(CostType Val=0)
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
bool isBinaryOp() const
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
bool isIntDivRem() const
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:348
The group of interleaved loads/stores sharing the same stride and close to each other.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
An instruction for reading from memory.
static bool getDecisionAndClampRange(const std::function< bool(ElementCount)> &Predicate, VFRange &Range)
Test a Predicate on a Range of VF's.
Definition VPlan.cpp:1681
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
ValueT lookup(const KeyT &Key) const
Definition MapVector.h:110
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Definition MapVector.h:118
bool empty() const
Definition MapVector.h:79
Representation for a specific memory location.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Definition Module.cpp:235
Post-order traversal of a graph.
An interface layer with SCEV used to manage how we see SCEV expressions for values in the context of ...
ScalarEvolution * getSE() const
Returns the ScalarEvolution analysis used.
LLVM_ABI const SCEV * getSCEV(Value *V)
Returns the SCEV expression of V, in the context of the current SCEV predicate.
static LLVM_ABI unsigned getOpcode(RecurKind Kind)
Returns the opcode corresponding to the RecurrenceKind.
static bool isFindLastRecurrenceKind(RecurKind Kind)
Returns true if the recurrence kind is of the form select(cmp(),x,y) where one of (x,...
RegionT * getParent() const
Get the parent of the Region.
Definition RegionInfo.h:362
This class represents a constant integer value.
ConstantInt * getValue() const
static const SCEV * rewrite(const SCEV *Scev, ScalarEvolution &SE, ValueToSCEVMapTy &Map)
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
const DataLayout & getDataLayout() const
Return the DataLayout associated with the module this SCEV instance is operating on.
LLVM_ABI const SCEV * getNegativeSCEV(const SCEV *V, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
Return the SCEV object corresponding to -V.
LLVM_ABI bool isKnownNegative(const SCEV *S)
Test if the given expression is known to be negative.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
ConstantRange getSignedRange(const SCEV *S)
Determine the signed range for a particular SCEV.
LLVM_ABI bool isLoopInvariant(const SCEV *S, const Loop *L)
Return true if the value of the given SCEV is unchanging in the specified loop.
LLVM_ABI bool isKnownPositive(const SCEV *S)
Test if the given expression is known to be positive.
LLVM_ABI const SCEV * getElementCount(Type *Ty, ElementCount EC, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
LLVM_ABI bool isKnownPredicate(CmpPredicate Pred, SCEVUse LHS, SCEVUse RHS)
Test if the given expression is known to satisfy the condition described by Pred, LHS,...
static LLVM_ABI AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A vector that has set insertion semantics.
Definition SetVector.h:57
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
size_type size() const
Definition SmallPtrSet.h:99
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
iterator begin() const
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
static LLVM_ABI PartialReductionExtendKind getPartialReductionExtendKind(Instruction *I)
Get the kind of extension that an instruction represents.
TargetCostKind
The kind of cost model.
@ TCK_RecipThroughput
Reciprocal throughput.
LLVM_ABI InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, PartialReductionExtendKind OpAExtend, PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class implements a switch-like dispatch statement for a value of 'T' using dyn_cast functionalit...
Definition TypeSwitch.h:89
TypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition TypeSwitch.h:98
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:282
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:282
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:368
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:197
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:232
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
Definition Type.h:270
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
op_range operands()
Definition User.h:267
static SmallVector< VFInfo, 8 > getMappings(const CallInst &CI)
Retrieve all the VFInfo instances associated to the CallInst CI.
Definition VectorUtils.h:76
bool isLegalMaskedLoadOrStore(bool IsLoad, Type *ScalarTy, Align Alignment, unsigned AddressSpace) const
Returns true if the target machine supports a masked load (if IsLoad) or masked store of scalar type ...
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
Definition VPlan.h:4389
void appendRecipe(VPRecipeBase *Recipe)
Augment the existing recipes of a VPBasicBlock with an additional Recipe as the last recipe.
Definition VPlan.h:4464
iterator end()
Definition VPlan.h:4426
iterator begin()
Recipe iterator methods.
Definition VPlan.h:4424
iterator_range< iterator > phis()
Returns an iterator range over the PHI-like recipes in the block.
Definition VPlan.h:4477
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:4436
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:4438
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
Definition VPlan.h:2958
VPValue * getIncomingValue(unsigned Idx) const
Return incoming value number Idx.
Definition VPlan.h:3003
VPValue * getMask(unsigned Idx) const
Return mask number Idx.
Definition VPlan.h:3008
unsigned getNumIncomingValues() const
Return the number of incoming values, taking into account when normalized the first incoming value wi...
Definition VPlan.h:2998
void setMask(unsigned Idx, VPValue *V)
Set mask number Idx to V.
Definition VPlan.h:3014
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:2994
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:3505
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:3550
A pure virtual base class for all recipes modeling header phis, including phis for first order recurr...
Definition VPlan.h:2446
virtual VPValue * getBackedgeValue()
Returns the incoming value from the loop backedge.
Definition VPlan.h:2493
VPValue * getStartValue()
Returns the start value of the phi, if one is set.
Definition VPlan.h:2482
A recipe representing a sequence of load -> update -> store as part of a histogram operation.
Definition VPlan.h:2173
A special type of VPBasicBlock that wraps an existing IR basic block.
Definition VPlan.h:4542
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:1485
@ ExtractLane
Extracts a single lane (first operand) from a set of vector operands.
Definition VPlan.h:1336
@ ReductionStartVector
Start vector for reductions with 3 operands: the original start value, the identity value for the red...
Definition VPlan.h:1332
@ BuildVector
Creates a fixed-width vector containing all operands.
Definition VPlan.h:1281
@ ComputeReductionResult
Reduce the operands to the final reduction result using the operation specified via the operation's V...
Definition VPlan.h:1289
unsigned getOpcode() const
Definition VPlan.h:1429
VPValue * getMask() const
Returns the mask for the VPInstruction.
Definition VPlan.h:1501
const InterleaveGroup< Instruction > * getInterleaveGroup() const
Definition VPlan.h:3109
VPValue * getMask() const
Return the mask used by this recipe.
Definition VPlan.h:3101
ArrayRef< VPValue * > getStoredValues() const
Return the VPValues stored by this interleave group.
Definition VPlan.h:3130
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
Definition VPlan.h:3140
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
Definition VPlan.h:3708
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:2865
void setVFScaleFactor(unsigned ScaleFactor)
Set the VFScaleFactor for this reduction phi.
Definition VPlan.h:2916
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:2909
RecurKind getRecurrenceKind() const
Returns the recurrence kind of the reduction.
Definition VPlan.h:2922
A recipe to represent inloop, ordered or partial reduction operations.
Definition VPlan.h:3233
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition VPlan.h:4614
const VPBlockBase * getEntry() const
Definition VPlan.h:4658
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
Definition VPlan.h:4690
void setExiting(VPBlockBase *ExitingBlock)
Set ExitingBlock as the exiting VPBlockBase of this VPRegionBlock.
Definition VPlan.h:4675
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
Definition VPlan.h:4742
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
Definition VPlan.h:4734
const VPBlockBase * getExiting() const
Definition VPlan.h:4670
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
Definition VPlan.h:4747
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition VPlan.h:3397
bool isSingleScalar() const
Returns true if the recipe produces a single scalar value.
Definition VPlan.h:3456
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:3484
bool isPredicated() const
Definition VPlan.h:3461
VPValue * getMask()
Return the mask of a predicated VPReplicateRecipe.
Definition VPlan.h:3478
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:4244
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:2276
A recipe for widening Call instructions using library calls.
Definition VPlan.h:2107
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:1889
Instruction::CastOps getOpcode() const
Definition VPlan.h:1925
A recipe for handling GEP instructions.
Definition VPlan.h:2216
Base class for widened induction (VPWidenIntOrFpInductionRecipe and VPWidenPointerInductionRecipe),...
Definition VPlan.h:2520
VPIRValue * getStartValue() const
Returns the start value of the induction.
Definition VPlan.h:2568
PHINode * getPHINode() const
Returns the underlying PHINode if one exists, or null otherwise.
Definition VPlan.h:2586
VPValue * getStepValue()
Returns the step value of the induction.
Definition VPlan.h:2571
const InductionDescriptor & getInductionDescriptor() const
Returns the induction descriptor for the recipe.
Definition VPlan.h:2591
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
Definition VPlan.h:2620
TruncInst * getTruncInst()
Returns the first defined value as TruncInst, if it is one or nullptr otherwise.
Definition VPlan.h:2679
A recipe for widening vector intrinsics.
Definition VPlan.h:1936
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:3744
virtual VPRecipeBase * getAsRecipe()=0
Return a VPRecipeBase* to the current object.
A recipe for widened phis.
Definition VPlan.h:2752
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition VPlan.h:1828
InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const override
Return the cost of this VPWidenRecipe.
VPWidenRecipe * clone() override
Clone the current recipe.
Definition VPlan.h:1849
unsigned getOpcode() const
Definition VPlan.h:1868
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition VPlan.h:4801
VPIRValue * getLiveIn(Value *V) const
Return the live-in VPIRValue for V, if there is one or nullptr otherwise.
Definition VPlan.h:5133
bool hasVF(ElementCount VF) const
Definition VPlan.h:5026
const DataLayout & getDataLayout() const
Definition VPlan.h:5008
LLVMContext & getContext() const
Definition VPlan.h:5004
VPBasicBlock * getEntry()
Definition VPlan.h:4897
bool hasScalableVF() const
Definition VPlan.h:5027
VPValue * getTripCount() const
The trip count of the original loop.
Definition VPlan.h:4962
VPValue * getOrCreateBackedgeTakenCount()
The backedge taken count of the original loop.
Definition VPlan.h:4983
iterator_range< SmallSetVector< ElementCount, 2 >::iterator > vectorFactors() const
Returns an iterator range over all VFs of the plan.
Definition VPlan.h:5033
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
Definition VPlan.h:5099
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
Definition VPlan.h:5002
VPIRValue * getAllOnesValue(Type *Ty)
Return a VPIRValue wrapping the AllOnes value of type Ty.
Definition VPlan.h:5105
VPRegionBlock * createReplicateRegion(VPBlockBase *Entry, VPBlockBase *Exiting, const std::string &Name="")
Create a new replicate region with Entry, Exiting and Name.
Definition VPlan.h:5184
bool hasUF(unsigned UF) const
Definition VPlan.h:5051
ArrayRef< VPIRBasicBlock * > getExitBlocks() const
Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of the original scalar loop.
Definition VPlan.h:4956
VPSymbolicValue & getVectorTripCount()
The vector trip count.
Definition VPlan.h:4992
VPValue * getBackedgeTakenCount() const
Definition VPlan.h:4989
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:5076
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
Definition VPlan.h:5102
void setVF(ElementCount VF)
Definition VPlan.h:5014
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
Definition VPlan.h:5067
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:5054
void resetTripCount(VPValue *NewTripCount)
Resets the trip count for the VPlan.
Definition VPlan.h:4976
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
Definition VPlan.h:4932
VPBasicBlock * createVPBasicBlock(const Twine &Name, VPRecipeBase *Recipe=nullptr)
Create a new VPBasicBlock with Name and containing Recipe if present.
Definition VPlan.h:5159
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
Definition VPlan.h:5096
VPBasicBlock * getVectorPreheader() const
Returns the preheader of the vector loop region, if one exists, or null otherwise.
Definition VPlan.h:4902
VPSymbolicValue & getUF()
Returns the UF of the vector loop region.
Definition VPlan.h:4999
bool hasScalarVFOnly() const
Definition VPlan.h:5044
VPBasicBlock * getScalarPreheader() const
Return the VPBasicBlock for the preheader of the scalar loop.
Definition VPlan.h:4946
bool hasTailFolded() const
Returns true if the vector loop region is tail-folded.
Definition VPlan.h:4918
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
Definition VPlan.h:4995
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:5110
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.
VPInstruction_match< VPInstruction::WideActiveLaneMask, Op0_t, Op1_t, Op2_t > m_WideActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
auto m_VPPhi(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
AllRecipe_match< Opcode, Op0_t, Op1_t > m_Binary(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::LastActiveLane, Op0_t > m_LastActiveLane(const Op0_t &Op0)
auto m_WidenIntrinsic(const T &...Ops)
canonical_widen_iv_match m_CanonicalWidenIV()
VPInstruction_match< VPInstruction::ExitingIVValue, Op0_t > m_ExitingIVValue(const Op0_t &Op0)
VPInstruction_match< Instruction::ExtractElement, Op0_t, Op1_t > m_ExtractElement(const Op0_t &Op0, const Op1_t &Op1)
specific_intval< 1 > m_False()
VPInstruction_match< VPInstruction::ExtractLastLane, Op0_t > m_ExtractLastLane(const Op0_t &Op0)
match_bind< VPSingleDefRecipe > m_VPSingleDefRecipe(VPSingleDefRecipe *&V)
Match a VPSingleDefRecipe, capturing if we match.
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
auto m_GetElementPtr(const Op0_t &Op0, const Op1_t &Op1)
specific_intval< 1 > m_True()
auto m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::ExtractVectorForPart, Op0_t, Op1_t > m_ExtractVectorForPart(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastPart, Op0_t > m_ExtractLastPart(const Op0_t &Op0)
VPRecipeBase * findUserOf(VPValue *V, const MatchT &P)
If V is used by a recipe matching pattern P, return it.
VPInstruction_match< VPInstruction::Broadcast, Op0_t > m_Broadcast(const Op0_t &Op0)
header_mask_match m_HeaderMask()
VPInstruction_match< VPInstruction::BuildVector > m_BuildVector()
BuildVector is matches only its opcode, w/o matching its operands as the number of operands is not fi...
VPInstruction_match< VPInstruction::ExtractPenultimateElement, Op0_t > m_ExtractPenultimateElement(const Op0_t &Op0)
match_bind< VPInstruction > m_VPInstruction(VPInstruction *&V)
Match a VPInstruction, capturing if we match.
VPInstruction_match< VPInstruction::FirstActiveLane, Op0_t > m_FirstActiveLane(const Op0_t &Op0)
auto m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
VPInstruction_match< VPInstruction::ExtractLane, Op0_t, Op1_t > m_ExtractLane(const Op0_t &Op0, const Op1_t &Op1)
auto m_AnyNeg(const Op0_t &Op0)
VPInstruction_match< VPInstruction::Reverse, Op0_t > m_Reverse(const Op0_t &Op0)
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
bool isSingleScalar(const VPValue *VPV)
Returns true if VPV is a single scalar, either because it produces the same value for all lanes or on...
VPValue * getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr)
Get or create a VPValue that corresponds to the expansion of Expr.
bool cannotHoistOrSinkRecipe(const VPRecipeBase &R, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink R.
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
VPInstruction * findComputeReductionResult(VPReductionPHIRecipe *PhiR)
Find the ComputeReductionResult recipe for PhiR, looking through selects inserted for predicated redu...
VPInstruction * findCanonicalIVIncrement(VPlan &Plan)
Find the canonical IV increment of Plan's vector loop region.
std::optional< MemoryLocation > getMemoryLocation(const VPRecipeBase &R)
Return a MemoryLocation for R with noalias metadata populated from R, if the recipe is supported and ...
bool onlyFirstLaneUsed(const VPValue *Def)
Returns true if only the first lane of Def is used.
VPIRValue * tryToFoldLiveIns(VPSingleDefRecipe &R, ArrayRef< VPValue * > Operands, const DataLayout &DL)
Try to fold R using InstSimplifyFolder.
SmallVector< std::pair< VPBasicBlock *, VPIRBasicBlock * > > getEarlyExits(const VPlan &Plan, const VPBlockBase *MiddleVPBB)
Returns the (early exiting block, exit block) pairs of Plan, i.e.
void recursivelyDeleteDeadRecipes(VPValue *V)
Recursively delete V and any of its operands that become dead.
bool isDeadRecipe(VPRecipeBase &R)
Returns true if R is dead, i.e.
VPRecipeBase * findRecipe(VPValue *Start, PredT Pred)
Search Start's users for a recipe satisfying Pred, looking through recipes with definitions.
Definition VPlanUtils.h:149
bool isUniformAcrossVFsAndUFs(const VPValue *V)
Checks if V is uniform across all VF lanes and UF parts.
bool isUsedByLoadStoreAddress(const VPValue *V)
Returns true if V is used as part of the address of another load or store.
std::optional< std::pair< bool, unsigned > > getOpcodeOrIntrinsicID(const VPValue *V)
Get the instruction opcode or intrinsic ID for the recipe defining V.
VPValue * scalarizeVPWidenPointerInduction(VPWidenPointerInductionRecipe *PtrIV, VPlan &Plan, VPBuilder &Builder)
Scalarize a VPWidenPointerInductionRecipe by replacing it with a PtrAdd (IndStart,...
const SCEV * getSCEVExprForVPValue(const VPValue *V, PredicatedScalarEvolution &PSE, const Loop *L=nullptr)
Return the SCEV expression for V.
void pullOutPermutations(VPlan &Plan, Match_t Perm, Builder Build)
Removes the permutation pattern Perm from any elementwise operations in the plan, by constructing a n...
Definition VPlanUtils.h:236
SmallVector< VPUser * > collectUsersRecursively(VPValue *V)
Collect all users of V, looking through recipes that define other values.
VPScalarIVStepsRecipe * createScalarIVSteps(VPlan &Plan, InductionDescriptor::InductionKind Kind, Instruction::BinaryOps InductionOpcode, FPMathOperator *FPBinOp, Instruction *TruncI, VPIRValue *StartV, VPValue *Step, DebugLoc DL, VPBuilder &Builder, const VPIRFlags::WrapFlagsTy &Flags={})
Create a scalar-iv-steps recipe over Plan's canonical IV for an induction of Kind with InductionOpcod...
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
SmallVector< VPBasicBlock * > vp_rpo_plain_cfg_loop_body(VPBasicBlock *Header)
Returns the VPBasicBlocks forming the loop body of a plain (pre-region) VPlan in reverse post-order s...
Definition VPlanCFG.h:262
@ Offset
Definition DWP.cpp:578
void stable_sort(R &&Range)
Definition STLExtras.h:2116
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2078
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
unsigned getLoadStoreAddressSpace(const Value *I)
A helper function that returns the address space of the pointer operand of load or store instruction.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1669
LLVM_ABI Intrinsic::ID getVectorIntrinsicIDForCall(const CallInst *CI, const TargetLibraryInfo *TLI)
Returns intrinsic ID for call.
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
Definition STLExtras.h:840
DenseMap< const Value *, const SCEV * > ValueToSCEVMapTy
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
constexpr from_range_t from_range
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
auto cast_or_null(const Y &Val)
Definition Casting.h:714
Align getLoadStoreAlignment(const Value *I)
A helper function that returns the alignment of load or store instruction.
iterator_range< df_iterator< VPBlockShallowTraversalWrapper< VPBlockBase * > > > vp_depth_first_shallow(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order.
Definition VPlanCFG.h:250
constexpr auto bind_back(FnT &&Fn, BindArgsT &&...BindArgs)
C++23 bind_back.
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.
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:2847
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:3808
A recipe for widening store operations, using the stored value, the address to store to and an option...
Definition VPlan.h:3907
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.