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