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