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