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