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