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