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