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(*Load, Ingredient.getOperand(0),
132 nullptr /*Mask*/, IsConsecutive,
133 *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, *VPI, Ingredient.getDebugLoc());
141 NewRecipe = new VPWidenGEPRecipe(GEP->getSourceElementType(),
142 Ingredient.operands(), *VPI,
143 Ingredient.getDebugLoc(), GEP);
144 } else if (CallInst *CI = dyn_cast<CallInst>(Inst)) {
145 Intrinsic::ID VectorID = getVectorIntrinsicIDForCall(CI, &TLI);
146 if (VectorID == Intrinsic::not_intrinsic)
147 return false;
148
149 // The noalias.scope.decl intrinsic declares a noalias scope that
150 // is valid for a single iteration. Emitting it as a single-scalar
151 // replicate would incorrectly extend the scope across multiple
152 // original iterations packed into one vector iteration.
153 // FIXME: If we want to vectorize this loop, then we have to drop
154 // all the associated !alias.scope and !noalias.
155 if (VectorID == Intrinsic::experimental_noalias_scope_decl)
156 return false;
157
158 // These intrinsics are recognized by getVectorIntrinsicIDForCall
159 // but are not widenable. Emit them as replicate instead of widening.
160 if (VectorID == Intrinsic::assume ||
161 VectorID == Intrinsic::lifetime_end ||
162 VectorID == Intrinsic::lifetime_start ||
163 VectorID == Intrinsic::sideeffect ||
164 VectorID == Intrinsic::pseudoprobe) {
165 // If the operand of llvm.assume holds before vectorization, it will
166 // also hold per lane.
167 // llvm.pseudoprobe requires to be duplicated per lane for accurate
168 // sample count.
169 const bool IsSingleScalar = VectorID != Intrinsic::assume &&
170 VectorID != Intrinsic::pseudoprobe;
171 NewRecipe = new VPReplicateRecipe(CI, Ingredient.operands(),
172 /*IsSingleScalar=*/IsSingleScalar,
173 /*Mask=*/nullptr, *VPI, *VPI,
174 Ingredient.getDebugLoc());
175 } else {
176 assert(!CI->hasOperandBundles() &&
177 "calls with operand bundles must not be widened");
178 NewRecipe = new VPWidenIntrinsicRecipe(
179 *CI, VectorID, drop_end(Ingredient.operands()), CI->getType(),
180 VPIRFlags(*CI), *VPI, CI->getDebugLoc());
181 }
182 } else if (auto *CI = dyn_cast<CastInst>(Inst)) {
183 NewRecipe = new VPWidenCastRecipe(
184 CI->getOpcode(), Ingredient.getOperand(0), CI->getType(), CI,
185 VPIRFlags(*CI), VPIRMetadata(*CI));
186 } else {
187 NewRecipe = new VPWidenRecipe(*Inst, Ingredient.operands(), *VPI,
188 *VPI, Ingredient.getDebugLoc());
189 }
190 } else {
191 assert(isa<VPWidenInductionRecipe>(&Ingredient) &&
192 "inductions must be created earlier");
193 continue;
194 }
195
196 NewRecipe->insertBefore(&Ingredient);
197 if (NewRecipe->getNumDefinedValues() == 1)
198 VPV->replaceAllUsesWith(NewRecipe->getVPSingleValue());
199 else
200 assert(NewRecipe->getNumDefinedValues() == 0 &&
201 "Only recpies with zero or one defined values expected");
202 Ingredient.eraseFromParent();
203 }
204 }
205 return true;
206}
207
208/// Helper for extra no-alias checks via known-safe recipe and SCEV.
211 VPReplicateRecipe &GroupLeader;
212 PredicatedScalarEvolution *PSE = nullptr;
213 const Loop *L = nullptr;
214
215 // Return true if \p A and \p B are known to not alias for all VFs in the
216 // plan, checked via the distance between the accesses
217 bool isNoAliasViaDistance(VPReplicateRecipe *A, VPReplicateRecipe *B) const {
218 if (A->getOpcode() != Instruction::Store ||
219 B->getOpcode() != Instruction::Store)
220 return false;
221
222 if (!PSE || !L)
223 return A == B;
224
225 VPValue *AddrA = A->getOperand(1);
226 const SCEV *SCEVA = vputils::getSCEVExprForVPValue(AddrA, *PSE, L);
227 VPValue *AddrB = B->getOperand(1);
228 const SCEV *SCEVB = vputils::getSCEVExprForVPValue(AddrB, *PSE, L);
230 return false;
231
232 const APInt *Distance;
233 ScalarEvolution &SE = *PSE->getSE();
234 if (!match(SE.getMinusSCEV(SCEVA, SCEVB), m_scev_APInt(Distance)))
235 return false;
236
237 const DataLayout &DL = SE.getDataLayout();
238 Type *TyA = A->getOperand(0)->getScalarType();
239 uint64_t SizeA = DL.getTypeStoreSize(TyA);
240 Type *TyB = B->getOperand(0)->getScalarType();
241 uint64_t SizeB = DL.getTypeStoreSize(TyB);
242
243 // Use the maximum store size to ensure no overlap from either direction.
244 // Currently only handles fixed sizes, as it is only used for
245 // replicating VPReplicateRecipes.
246 uint64_t MaxStoreSize = std::max(SizeA, SizeB);
247
248 auto VFs = B->getParent()->getPlan()->vectorFactors();
250 if (MaxVF.isScalable())
251 return false;
252 return Distance->abs().uge(MaxVF.getFixedValue() * MaxStoreSize);
253 }
254
255public:
258 const Loop &L)
259 : ExcludeRecipes(ExcludeRecipes.begin(), ExcludeRecipes.end()),
260 GroupLeader(GroupLeader), PSE(&PSE), L(&L) {}
261
262 SinkStoreInfo(VPReplicateRecipe &GroupLeader) : GroupLeader(GroupLeader) {}
263
264 /// Return true if \p R should be skipped during alias checking, either
265 /// because it's in the exclude set or because no-alias can be proven via
266 /// SCEV.
267 bool shouldSkip(VPRecipeBase &R) const {
269 return ExcludeRecipes.contains(Store) ||
270 (Store && isNoAliasViaDistance(Store, &GroupLeader));
271 }
272};
273
274/// Check if a memory operation doesn't alias with memory operations using
275/// scoped noalias metadata, in blocks in the single-successor chain between \p
276/// FirstBB and \p LastBB. If \p SinkInfo is std::nullopt, only recipes that may
277/// write to memory are checked (for load hoisting). Otherwise recipes that both
278/// read and write memory are checked, and SCEV is used to prove no-alias
279/// between the group leader and other replicate recipes (for store sinking).
280static bool
282 VPBasicBlock *FirstBB, VPBasicBlock *LastBB,
283 std::optional<SinkStoreInfo> SinkInfo = {}) {
284 bool CheckReads = SinkInfo.has_value();
285 for (VPBasicBlock *VPBB :
287 for (VPRecipeBase &R : *VPBB) {
288 if (SinkInfo && SinkInfo->shouldSkip(R))
289 continue;
290
291 // Skip recipes that don't need checking.
292 if (!R.mayWriteToMemory() && !(CheckReads && R.mayReadFromMemory()))
293 continue;
294
296 if (!Loc)
297 // Conservatively assume aliasing for memory operations without
298 // location.
299 return false;
300
302 return false;
303 }
304 }
305 return true;
306}
307
308/// Get the value type of a VPInstruction or VPReplicateRecipe load or store.
310 bool IsLoad = vputils::getOpcode(R) == Instruction::Load;
311 return (IsLoad ? R : R->getOperand(0))->getScalarType();
312}
313
314/// Collect either replicated Loads or Stores grouped by their address SCEV and
315/// their load-store type, in a deep-traversal of the vector loop region in \p
316/// Plan.
317template <unsigned Opcode>
320 VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L,
321 function_ref<bool(VPReplicateRecipe *)> FilterFn) {
322 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
323 "Only Load and Store opcodes supported");
324 constexpr bool IsLoad = (Opcode == Instruction::Load);
327 RecipesByAddressAndType;
331 if (RepR.getOpcode() != Opcode || !FilterFn(&RepR))
332 continue;
333
334 // For loads, operand 0 is address; for stores, operand 1 is address.
335 VPValue *Addr = RepR.getOperand(IsLoad ? 0 : 1);
336 const Type *LoadStoreTy = getLoadStoreValueType(&RepR);
337 const SCEV *AddrSCEV = vputils::getSCEVExprForVPValue(Addr, PSE, L);
338 if (!isa<SCEVCouldNotCompute>(AddrSCEV))
339 RecipesByAddressAndType[{AddrSCEV, LoadStoreTy}].push_back(&RepR);
340 }
341 }
342 auto Groups = to_vector(RecipesByAddressAndType.values());
343 VPDominatorTree VPDT(Plan);
344 for (auto &Group : Groups) {
345 // Sort mem ops by dominance order, with earliest (most dominating) first.
347 return VPDT.properlyDominates(A, B);
348 });
349 }
350 return Groups;
351}
352
353static bool sinkScalarOperands(VPlan &Plan) {
354 auto Iter = vp_depth_first_deep(Plan.getEntry());
355 bool ScalarVFOnly = Plan.hasScalarVFOnly();
356 bool Changed = false;
357
359 auto InsertIfValidSinkCandidate = [ScalarVFOnly, &WorkList](
360 VPBasicBlock *SinkTo, VPValue *Op) {
361 auto *Candidate = dyn_cast<VPSingleDefRecipe>(Op);
363 VPInstruction>(Candidate))
364 return;
365
366 if (Candidate->getParent() == SinkTo ||
367 all_of(Candidate->operands(),
368 [](VPValue *Op) { return Op->isDefinedOutsideLoopRegions(); }) ||
369 vputils::cannotHoistOrSinkRecipe(*Candidate, /*Sinking=*/true))
370 return;
371
372 if (!ScalarVFOnly && !vputils::doesGeneratePerAllLanes(Candidate))
373 return;
374
375 // Only single-scalar VPInstructions can be sunk.
376 if (auto *VPI = dyn_cast<VPInstruction>(Candidate))
377 if (!vputils::isSingleScalar(VPI))
378 return;
379
380 WorkList.insert({SinkTo, Candidate});
381 };
382
383 // First, collect the operands of all recipes in replicate blocks as seeds for
384 // sinking.
386 VPBasicBlock *EntryVPBB = VPR->getEntryBasicBlock();
387 if (!VPR->isReplicator() || EntryVPBB->getSuccessors().size() != 2)
388 continue;
389 VPBasicBlock *VPBB = cast<VPBasicBlock>(EntryVPBB->getSuccessors().front());
390 if (VPBB->getSingleSuccessor() != VPR->getExitingBasicBlock())
391 continue;
392 for (auto &Recipe : *VPBB)
393 for (VPValue *Op : Recipe.operands())
394 InsertIfValidSinkCandidate(VPBB, Op);
395 }
396
397 // Try to sink each replicate or scalar IV steps recipe in the worklist.
398 for (unsigned I = 0; I != WorkList.size(); ++I) {
399 VPBasicBlock *SinkTo;
400 VPSingleDefRecipe *SinkCandidate;
401 std::tie(SinkTo, SinkCandidate) = WorkList[I];
402
403 // All recipe users of SinkCandidate must be in the same block SinkTo or all
404 // users outside of SinkTo must only use the first lane of SinkCandidate. In
405 // the latter case, we need to duplicate SinkCandidate.
406 auto UsersOutsideSinkTo =
407 make_filter_range(SinkCandidate->users(), [SinkTo](VPUser *U) {
408 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
409 });
410 if (any_of(UsersOutsideSinkTo, [SinkCandidate](VPUser *U) {
411 return !U->usesFirstLaneOnly(SinkCandidate);
412 }))
413 continue;
414 bool NeedsDuplicating = !UsersOutsideSinkTo.empty();
415
416 if (NeedsDuplicating) {
417 if (ScalarVFOnly)
418 continue;
419 VPSingleDefRecipe *Clone;
420 if (auto *SinkCandidateRepR =
421 dyn_cast<VPReplicateRecipe>(SinkCandidate)) {
422 // TODO: Handle converting to uniform recipes as separate transform,
423 // then cloning should be sufficient here.
425 SinkCandidateRepR->getOpcode(), SinkCandidate->operands(),
426 /*Mask=*/nullptr, *SinkCandidateRepR, *SinkCandidateRepR,
427 SinkCandidate->getDebugLoc(), SinkCandidate->getScalarType(),
428 SinkCandidate->getUnderlyingInstr());
429 // TODO: add ".cloned" suffix to name of Clone's VPValue.
430 } else {
431 Clone = SinkCandidate->clone();
432 }
433
434 Clone->insertBefore(SinkCandidate);
435 SinkCandidate->replaceUsesWithIf(Clone, [SinkTo](VPUser *U) {
436 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
437 });
438 }
439 SinkCandidate->moveBefore(*SinkTo, SinkTo->getFirstNonPhi());
440 for (VPValue *Op : SinkCandidate->operands())
441 InsertIfValidSinkCandidate(SinkTo, Op);
442 Changed = true;
443 }
444 return Changed;
445}
446
447/// If \p R is a triangle region, return the 'then' block of the triangle.
449 auto *EntryBB = cast<VPBasicBlock>(R->getEntry());
450 if (EntryBB->getNumSuccessors() != 2)
451 return nullptr;
452
453 auto *Succ0 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[0]);
454 auto *Succ1 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[1]);
455 if (!Succ0 || !Succ1)
456 return nullptr;
457
458 if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
459 return nullptr;
460 if (Succ0->getSingleSuccessor() == Succ1)
461 return Succ0;
462 if (Succ1->getSingleSuccessor() == Succ0)
463 return Succ1;
464 return nullptr;
465}
466
467// Merge replicate regions in their successor region, if a replicate region
468// is connected to a successor replicate region with the same predicate by a
469// single, empty VPBasicBlock.
471 SmallPtrSet<VPRegionBlock *, 4> TransformedRegions;
472
473 // Collect replicate regions followed by an empty block, followed by another
474 // replicate region with matching masks to process front. This is to avoid
475 // iterator invalidation issues while merging regions.
478 vp_depth_first_deep(Plan.getEntry()))) {
479 if (!Region1->isReplicator())
480 continue;
481 auto *MiddleBasicBlock =
482 dyn_cast_or_null<VPBasicBlock>(Region1->getSingleSuccessor());
483 if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
484 continue;
485
486 auto *Region2 =
487 dyn_cast_or_null<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
488 if (!Region2 || !Region2->isReplicator())
489 continue;
490
491 VPValue *Mask1 = Region1->getEntryBranchOnMask()->getOperand(0);
492 VPValue *Mask2 = Region2->getEntryBranchOnMask()->getOperand(0);
493 if (!Mask1 || Mask1 != Mask2)
494 continue;
495
496 assert(Mask1 && Mask2 && "both region must have conditions");
497 WorkList.push_back(Region1);
498 }
499
500 // Move recipes from Region1 to its successor region, if both are triangles.
501 for (VPRegionBlock *Region1 : WorkList) {
502 if (TransformedRegions.contains(Region1))
503 continue;
504 auto *MiddleBasicBlock = cast<VPBasicBlock>(Region1->getSingleSuccessor());
505 auto *Region2 = cast<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
506
507 VPBasicBlock *Then1 = getPredicatedThenBlock(Region1);
508 VPBasicBlock *Then2 = getPredicatedThenBlock(Region2);
509 if (!Then1 || !Then2)
510 continue;
511
512 // The merged region is entered whenever either of the original regions was,
513 // so use the higher, i.e. more conservative, of their entry frequencies.
514 // If only one of the two is known, the higher one is unknown, so the
515 // result must be unknown too.
516 VPBranchOnMaskRecipe *Guard2 = Region2->getEntryBranchOnMask();
517 std::optional<VPExecutionFrequency> Freq1 =
518 Region1->getEntryBranchOnMask()->getExecutionFrequency();
519 std::optional<VPExecutionFrequency> Freq2 = Guard2->getExecutionFrequency();
520 if (Freq1 && Freq2) {
521 if (Freq2->Freq < Freq1->Freq) {
522 // Freq1's frequency is taken, but it is only as trustworthy as the
523 // less trustworthy of the two.
524 Freq1.emplace(Freq1->Freq, Freq1->IsEstimated || Freq2->IsEstimated);
525 Guard2->setExecutionFrequency(Freq1, Plan.getContext());
526 }
527 } else if (Freq2) {
528 Guard2->clearExecutionFrequency();
529 }
530
531 // Note: No fusion-preventing memory dependencies are expected in either
532 // region. Such dependencies should be rejected during earlier dependence
533 // checks, which guarantee accesses can be re-ordered for vectorization.
534 //
535 // Move recipes to the successor region.
536 for (VPRecipeBase &ToMove : make_early_inc_range(reverse(*Then1)))
537 ToMove.moveBefore(*Then2, Then2->getFirstNonPhi());
538
539 auto *Merge1 = cast<VPBasicBlock>(Then1->getSingleSuccessor());
540 auto *Merge2 = cast<VPBasicBlock>(Then2->getSingleSuccessor());
541
542 // Move VPPredInstPHIRecipes from the merge block to the successor region's
543 // merge block. Update all users inside the successor region to use the
544 // original values.
545 for (VPRecipeBase &Phi1ToMove : make_early_inc_range(reverse(*Merge1))) {
546 VPValue *PredInst1 =
547 cast<VPPredInstPHIRecipe>(&Phi1ToMove)->getOperand(0);
548 VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
549 Phi1ToMoveV->replaceUsesWithIf(PredInst1, [Then2](VPUser *U) {
550 return cast<VPRecipeBase>(U)->getParent() == Then2;
551 });
552
553 // Remove phi recipes that are unused after merging the regions.
554 if (Phi1ToMove.getVPSingleValue()->user_empty()) {
555 Phi1ToMove.eraseFromParent();
556 continue;
557 }
558 Phi1ToMove.moveBefore(*Merge2, Merge2->begin());
559 }
560
561 // Remove the dead recipes in Region1's entry block.
562 for (VPRecipeBase &R :
563 make_early_inc_range(reverse(*Region1->getEntryBasicBlock())))
564 R.eraseFromParent();
565
566 // Finally, remove the first region.
567 for (VPBlockBase *Pred : make_early_inc_range(Region1->getPredecessors())) {
568 VPBlockUtils::disconnectBlocks(Pred, Region1);
569 VPBlockUtils::connectBlocks(Pred, MiddleBasicBlock);
570 }
571 VPBlockUtils::disconnectBlocks(Region1, MiddleBasicBlock);
572 TransformedRegions.insert(Region1);
573 }
574
575 return !TransformedRegions.empty();
576}
577
579 VPRegionBlock *ParentRegion,
580 VPlan &Plan) {
581 Instruction *Instr = PredRecipe->getUnderlyingInstr();
582 // Build the triangular if-then region.
583 std::string RegionName = (Twine("pred.") + Instr->getOpcodeName()).str();
584 assert(Instr->getParent() && "Predicated instruction not in any basic block");
585 auto *BlockInMask = PredRecipe->getMask();
586 auto *MaskDef = BlockInMask->getDefiningRecipe();
587 auto *BOMRecipe = new VPBranchOnMaskRecipe(
588 BlockInMask, MaskDef ? MaskDef->getDebugLoc() : DebugLoc::getUnknown());
589 auto *Entry =
590 Plan.createVPBasicBlock(Twine(RegionName) + ".entry", BOMRecipe);
591
592 // Replace predicated replicate recipe with a replicate recipe without a
593 // mask but in the replicate region.
594 auto *RecipeWithoutMask = new VPReplicateRecipe(
595 PredRecipe->getUnderlyingInstr(), PredRecipe->operandsWithoutMask(),
596 PredRecipe->isSingleScalar(), nullptr /*Mask*/, *PredRecipe, *PredRecipe,
597 PredRecipe->getDebugLoc());
598 // The predicated recipe executes exactly when the guarding branch-on-mask is
599 // taken, so move its execution frequency there.
600 BOMRecipe->setExecutionFrequency(RecipeWithoutMask->getExecutionFrequency(),
601 Plan.getContext());
602 RecipeWithoutMask->clearExecutionFrequency();
603 auto *Pred =
604 Plan.createVPBasicBlock(Twine(RegionName) + ".if", RecipeWithoutMask);
605 auto *Exiting = Plan.createVPBasicBlock(Twine(RegionName) + ".continue");
607 Plan.createReplicateRegion(Entry, Exiting, RegionName);
608
609 // Note: first set Entry as region entry and then connect successors starting
610 // from it in order, to propagate the "parent" of each VPBasicBlock.
611 Region->setParent(ParentRegion);
612 VPBlockUtils::insertTwoBlocksAfter(Pred, Exiting, Entry);
613 VPBlockUtils::connectBlocks(Pred, Exiting);
614
615 PredRecipe->replaceAllUsesWith(RecipeWithoutMask);
616 // Move the extracts of a struct result into the region, so only scalars
617 // leave it.
618 SmallVector<VPUser *> Defs = {RecipeWithoutMask};
619 if (RecipeWithoutMask->getScalarType()->isStructTy())
620 Defs = to_vector(RecipeWithoutMask->users());
621 for (VPUser *U : Defs) {
622 auto *Def = cast<VPReplicateRecipe>(U);
623 assert((Def == RecipeWithoutMask ||
624 Def->getOpcode() == Instruction::ExtractValue) &&
625 "only extracts can use a predicated struct");
626 Def->moveBefore(*Pred, Pred->end());
627 if (Def->user_empty())
628 continue;
629 auto *PHIRecipe = new VPPredInstPHIRecipe(Def, Def->getDebugLoc());
630 Exiting->appendRecipe(PHIRecipe);
631 Def->replaceAllUsesWith(PHIRecipe);
632 PHIRecipe->setOperand(0, Def);
633 }
634 PredRecipe->eraseFromParent();
635 return Region;
636}
637
638static void addReplicateRegions(VPlan &Plan) {
641 vp_depth_first_deep(Plan.getEntry()))) {
643 if (RepR.isPredicated())
644 WorkList.push_back(&RepR);
645 }
646
647 unsigned BBNum = 0;
648 for (VPReplicateRecipe *RepR : WorkList) {
649 VPBasicBlock *CurrentBlock = RepR->getParent();
650 VPBasicBlock *SplitBlock = CurrentBlock->splitAt(RepR->getIterator());
651
652 BasicBlock *OrigBB = RepR->getUnderlyingInstr()->getParent();
653 SplitBlock->setName(
654 OrigBB->hasName() ? OrigBB->getName() + "." + Twine(BBNum++) : "");
655 // Record predicated instructions for above packing optimizations.
657 createReplicateRegion(RepR, CurrentBlock->getParent(), Plan);
659
660 VPRegionBlock *ParentRegion = Region->getParent();
661 if (ParentRegion && ParentRegion->getExiting() == CurrentBlock)
662 ParentRegion->setExiting(SplitBlock);
663 }
664}
665
668
669 // Collect single-successor chains in the loop region.
670 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
672 vp_depth_first_deep(LoopRegion->getEntry()))) {
673 if (!VPBB->getParent())
674 continue;
675 VPBlockBase *PredBlock = VPBB->getSinglePredecessor();
676 if (!isa_and_nonnull<VPBasicBlock>(PredBlock) ||
677 !PredBlock->getSingleSuccessor())
678 continue;
679 WorkList.push_back(VPBB);
680 }
681
682 for (VPBasicBlock *VPBB : WorkList) {
683 VPBasicBlock *PredVPBB = cast<VPBasicBlock>(VPBB->getSinglePredecessor());
684 for (VPRecipeBase &R : make_early_inc_range(*VPBB))
685 R.moveBefore(*PredVPBB, PredVPBB->end());
686 VPBlockUtils::disconnectBlocks(PredVPBB, VPBB);
687 auto *ParentRegion = VPBB->getParent();
688 if (ParentRegion && ParentRegion->getExiting() == VPBB)
689 ParentRegion->setExiting(PredVPBB);
690 VPBlockUtils::transferSuccessors(VPBB, PredVPBB);
691 // VPBB is now dead and will be cleaned up when the plan gets destroyed.
692 }
693 return !WorkList.empty();
694}
695
697 // Convert masked VPReplicateRecipes to if-then region blocks.
699
700 bool ShouldSimplify = true;
701 while (ShouldSimplify) {
702 ShouldSimplify = sinkScalarOperands(Plan);
703 ShouldSimplify |= mergeReplicateRegionsIntoSuccessors(Plan);
704 ShouldSimplify |= mergeBlocksIntoPredecessors(Plan);
705 }
706}
707
708/// Remove redundant casts of inductions.
709///
710/// Such redundant casts are casts of induction variables that can be ignored,
711/// because we already proved that the casted phi is equal to the uncasted phi
712/// in the vectorized loop. There is no need to vectorize the cast - the same
713/// value can be used for both the phi and casts in the vector loop.
718 if (IV.isTruncated())
719 continue;
720
721 // A sequence of IR Casts has potentially been recorded for IV, which
722 // *must be bypassed* when the IV is vectorized, because the vectorized IV
723 // will produce the desired casted value. This sequence forms a def-use
724 // chain and is provided in reverse order, ending with the cast that uses
725 // the IV phi. Search for the recipe of the last cast in the chain and
726 // replace it with the original IV. Note that only the final cast is
727 // expected to have users outside the cast-chain and the dead casts left
728 // over will be cleaned up later.
729 ArrayRef<Instruction *> Casts = IV.getInductionDescriptor().getCastInsts();
730 VPValue *FindMyCast = &IV;
731 for (Instruction *IRCast : reverse(Casts)) {
732 VPSingleDefRecipe *FoundUserCast = nullptr;
733 for (auto *U : FindMyCast->users()) {
734 auto *UserCast = dyn_cast<VPSingleDefRecipe>(U);
735 if (UserCast && UserCast->getUnderlyingValue() == IRCast) {
736 FoundUserCast = UserCast;
737 break;
738 }
739 }
740 // A cast recipe in the chain may have been removed by earlier DCE.
741 if (!FoundUserCast)
742 break;
743 FindMyCast = FoundUserCast;
744 }
745 if (FindMyCast != &IV)
746 FindMyCast->replaceAllUsesWith(&IV);
747 }
748}
749
750/// If R is a phi-like recipe starting a dead cycle of recipes, erase all
751/// reachable recipes of the dead cycle and return true. Otherwise leave the
752/// plan unchanged and return false.
754 auto *PhiR = dyn_cast<VPSingleDefRecipe>(R);
755 if (!PhiR || !isa<VPPhi, VPReductionPHIRecipe>(R))
756 return false;
757
758 // The transitive users of PhiR are closed under users, so the cycle is dead
759 // if every one of them can be erased.
761 auto *R = cast<VPRecipeBase>(U);
762 // Bail out if a user must be retained, or if it is a phi-like recipe other
763 // than PhiR;
764 if (R->mayHaveSideEffects() || (R != PhiR && isa<VPPhiAccessors>(R)))
765 return false;
766 }
767
768 // Break the cycle by replacing PhiR with its first incoming value, which is
769 // defined outside the cycle. That leaves the rest of the cycle dead.
770 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
771 SmallVector<VPValue *> Incoming(PhiR->operands());
772 PhiR->eraseFromParent();
773 for (VPValue *Op : Incoming)
775 return true;
776}
777
780 Plan.getEntry());
782 // The recipes in the block are processed in reverse order, to catch chains
783 // of dead recipes.
784 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB)))
786 R.eraseFromParent();
787
788 // Erase dead cycles starting at one of VPBB's phi-like recipes. Erasing a
789 // cycle may also erase other phi-like recipes of VPBB, so restart the scan
790 // of the phi section after each removal. This terminates, as each removal
791 // erases the cycle's phi.
792 bool Changed = true;
793 while (Changed) {
794 Changed = false;
795 for (VPRecipeBase &R : VPBB->phis()) {
796 if (tryToRemoveDeadCycle(&R)) {
797 Changed = true;
798 break;
799 }
800 }
801 }
802 }
803}
804
805/// Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd
806/// (IndStart, ScalarIVSteps (0, Step)) if only its scalar values are used, as
807/// VPWidenPointerInductionRecipe will generate vectors only. If some users
808/// require vectors while other require scalars, the scalar uses need to extract
809/// the scalars from the generated vectors (Note that this is different to how
810/// int/fp inductions are handled). Legalize extract-from-ends using uniform
811/// VPReplicateRecipe of wide inductions to use regular VPReplicateRecipe, so
812/// the correct end value is available. Also optimize
813/// VPWidenIntOrFpInductionRecipe, if any of its users needs scalar values, by
814/// providing them scalar steps built on the canonical scalar IV and update the
815/// original IV's users. This is an optional optimization to reduce the needs of
816/// vector extracts.
819 bool HasOnlyVectorVFs = !Plan.hasScalarVFOnly();
820
822 for (VPWidenInductionRecipe &PhiR :
824 WideIVs.push_back(&PhiR);
825
826 // Try to narrow wide and replicating recipes to uniform recipes, based on
827 // VPlan analysis.
828 // TODO: Apply to all recipes in the future, to replace legacy uniformity
829 // analysis.
830 for (VPWidenInductionRecipe *PhiR : WideIVs) {
832 for (VPUser *U : reverse(Users)) {
833 auto *Def = dyn_cast<VPRecipeWithIRFlags>(U);
834 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
835 // Skip recipes that shouldn't be narrowed.
836 if (!Def ||
838 Def->user_empty() || !Def->getUnderlyingValue() ||
839 (RepR && (RepR->isSingleScalar() || RepR->isPredicated())))
840 continue;
841
842 // Skip recipes that may have other lanes than their first used.
844 continue;
845
846 // TODO: Support scalarizing ExtractValue.
847 if (match(Def,
849 continue;
850
852 Def->getUnderlyingInstr()->getOpcode(), Def->operands(),
853 /*Mask=*/nullptr, *Def, getMetadataOf(Def), DebugLoc::getUnknown(),
854 Def->getScalarType(), Def->getUnderlyingInstr());
855 Clone->insertAfter(Def);
856 Def->replaceAllUsesWith(Clone);
857 Def->eraseFromParent();
858 }
859 }
860
861 VPBuilder Builder(HeaderVPBB, HeaderVPBB->getFirstNonPhi());
862 for (VPWidenInductionRecipe *PhiR : WideIVs) {
863 // Replace wide pointer inductions which have only their scalars used by
864 // PtrAdd(IndStart, ScalarIVSteps (0, Step)).
865 if (auto *PtrIV = dyn_cast<VPWidenPointerInductionRecipe>(PhiR)) {
866 if (!Plan.hasScalarVFOnly() &&
867 !PtrIV->onlyScalarsGenerated(Plan.hasScalableVF()))
868 continue;
869
870 VPValue *PtrAdd =
871 vputils::scalarizeVPWidenPointerInduction(PtrIV, Plan, Builder);
872 PtrIV->replaceAllUsesWith(PtrAdd);
873 continue;
874 }
875
876 // Replace widened induction with scalar steps for users that only use
877 // scalars.
878 auto *WideIV = cast<VPWidenIntOrFpInductionRecipe>(PhiR);
879 if (HasOnlyVectorVFs && none_of(WideIV->users(), [WideIV](VPUser *U) {
880 return U->usesScalars(WideIV);
881 }))
882 continue;
883
884 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
885 VPIRFlags::WrapFlagsTy WrapFlags;
886 // We can preserve nuw when the step is non-negative.
887 const APInt *Step;
888 if (match(WideIV->getStepValue(), m_APInt(Step)) && Step->isNonNegative())
889 WrapFlags = WideIV->getNoWrapFlagsOrNone().withoutNoSignedWrap();
891 Plan, ID.getKind(), ID.getInductionOpcode(),
892 dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
893 WideIV->getScalarType(), WideIV->getStartValue(),
894 WideIV->getStepValue(), WideIV->getDebugLoc(), Builder, WrapFlags);
895
896 // Update scalar users of IV to use Step instead.
897 if (!HasOnlyVectorVFs) {
898 assert(!Plan.hasScalableVF() &&
899 "plans containing a scalar VF cannot also include scalable VFs");
900 WideIV->replaceAllUsesWith(Steps);
901 } else {
902 bool HasScalableVF = Plan.hasScalableVF();
903 WideIV->replaceUsesWithIf(Steps, [WideIV, HasScalableVF](VPUser *U) {
904 if (HasScalableVF)
905 return U->usesFirstLaneOnly(WideIV);
906 return U->usesScalars(WideIV);
907 });
908 }
909 }
910}
911
912/// Check if \p VPV is an untruncated wide induction, either before or after the
913/// increment. If so return the header IV (before the increment), otherwise
914/// return null.
917 auto *WideIV = dyn_cast<VPWidenInductionRecipe>(VPV);
918 if (WideIV) {
919 // VPV itself is a wide induction, separately compute the end value for exit
920 // users if it is not a truncated IV.
921 auto *IntOrFpIV = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
922 return (IntOrFpIV && IntOrFpIV->isTruncated()) ? nullptr : WideIV;
923 }
924
925 // Check if VPV is an optimizable induction increment.
926 VPRecipeBase *Def = VPV->getDefiningRecipe();
927 if (!Def || Def->getNumOperands() != 2)
928 return nullptr;
929 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(0));
930 if (!WideIV)
931 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(1));
932 if (!WideIV)
933 return nullptr;
934
935 auto IsWideIVInc = [&]() {
936 auto &ID = WideIV->getInductionDescriptor();
937
938 // Check if VPV increments the induction by the induction step.
939 VPValue *IVStep = WideIV->getStepValue();
940 switch (ID.getInductionOpcode()) {
941 case Instruction::Add:
942 return match(VPV, m_c_Add(m_Specific(WideIV), m_Specific(IVStep)));
943 case Instruction::FAdd:
944 return match(VPV, m_c_FAdd(m_Specific(WideIV), m_Specific(IVStep)));
945 case Instruction::FSub:
946 return match(VPV, m_Binary<Instruction::FSub>(m_Specific(WideIV),
947 m_Specific(IVStep)));
948 case Instruction::Sub: {
949 // IVStep will be the negated step of the subtraction. Check if Step == -1
950 // * IVStep.
951 VPValue *Step;
952 if (!match(VPV, m_Sub(m_VPValue(), m_VPValue(Step))))
953 return false;
954 const SCEV *IVStepSCEV = vputils::getSCEVExprForVPValue(IVStep, PSE);
955 const SCEV *StepSCEV = vputils::getSCEVExprForVPValue(Step, PSE);
956 ScalarEvolution &SE = *PSE.getSE();
957 return !isa<SCEVCouldNotCompute>(IVStepSCEV) &&
958 !isa<SCEVCouldNotCompute>(StepSCEV) &&
959 IVStepSCEV == SE.getNegativeSCEV(StepSCEV);
960 }
961 default:
962 return ID.getKind() == InductionDescriptor::IK_PtrInduction &&
963 match(VPV, m_GetElementPtr(m_Specific(WideIV),
964 m_Specific(WideIV->getStepValue())));
965 }
966 llvm_unreachable("should have been covered by switch above");
967 };
968 return IsWideIVInc() ? WideIV : nullptr;
969}
970
971/// Attempts to optimize the induction variable exit values for users in the
972/// early exit block.
975 VPValue *Incoming, *Mask;
977 m_VPValue(Incoming))))
978 return nullptr;
979
980 auto *WideIV = getOptimizableIVOf(Incoming, PSE);
981 if (!WideIV)
982 return nullptr;
983
984 // Calculate the final index.
985 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
986 auto *CanonicalIV = LoopRegion->getCanonicalIV();
987 Type *CanonicalIVType = LoopRegion->getCanonicalIVType();
988 auto *ExtractR = cast<VPInstruction>(Op);
989 VPBuilder B(ExtractR);
990
991 DebugLoc DL = ExtractR->getDebugLoc();
992 VPValue *FirstActiveLane = B.createFirstActiveLane(Mask, DL);
993 FirstActiveLane =
994 B.createScalarZExtOrTrunc(FirstActiveLane, CanonicalIVType, DL);
995 VPValue *EndValue = B.createAdd(CanonicalIV, FirstActiveLane, DL);
996
997 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
998 // changed it means the exit is using the incremented value, so we need to
999 // add the step.
1000 if (Incoming != WideIV) {
1001 VPValue *One = Plan.getConstantInt(CanonicalIVType, 1);
1002 EndValue = B.createAdd(EndValue, One, DL);
1003 }
1004
1005 if (!match(WideIV, m_CanonicalWidenIV())) {
1006 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
1007 VPValue *Start = WideIV->getStartValue();
1008 VPValue *Step = WideIV->getStepValue();
1009 EndValue = B.createDerivedIV(
1010 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1011 Start, EndValue, Step);
1012 }
1013
1014 return EndValue;
1015}
1016
1017/// Compute the end value for \p WideIV, unless it is truncated. Creates a
1018/// VPDerivedIVRecipe for non-canonical inductions.
1020 VPBuilder &VectorPHBuilder,
1021 VPValue *VectorTC) {
1022 auto *WideIntOrFp = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
1023 // Truncated wide inductions resume from the last lane of their vector value
1024 // in the last vector iteration which is handled elsewhere.
1025 if (WideIntOrFp && WideIntOrFp->isTruncated())
1026 return nullptr;
1027
1028 VPValue *Start = WideIV->getStartValue();
1029 VPValue *Step = WideIV->getStepValue();
1030 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
1031 VPValue *EndValue = VectorTC;
1032 if (!match(WideIV, m_CanonicalWidenIV())) {
1033 EndValue = VectorPHBuilder.createDerivedIV(
1034 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1035 Start, VectorTC, Step);
1036 }
1037
1038 // EndValue is derived from the vector trip count (which has the same type as
1039 // the widest induction) and thus may be wider than the induction here.
1040 Type *ScalarTypeOfWideIV = WideIV->getScalarType();
1041 if (ScalarTypeOfWideIV != EndValue->getScalarType()) {
1042 EndValue = VectorPHBuilder.createScalarCast(Instruction::Trunc, EndValue,
1043 ScalarTypeOfWideIV,
1044 WideIV->getDebugLoc());
1045 }
1046
1047 return EndValue;
1048}
1049
1050/// Attempts to optimize the induction variable exit values for users in the
1051/// exit block coming from the latch in the original scalar loop.
1052static VPValue *
1056 VPValue *Incoming;
1059 m_VPValue(Incoming)))))
1060 return nullptr;
1061
1062 VPWidenInductionRecipe *WideIV = getOptimizableIVOf(Incoming, PSE);
1063 if (!WideIV)
1064 return nullptr;
1065
1066 VPValue *EndValue = EndValues.lookup(WideIV);
1067 assert(EndValue && "Must have computed the end value up front");
1068
1069 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
1070 // changed it means the exit is using the incremented value, so we don't
1071 // need to subtract the step.
1072 if (Incoming != WideIV)
1073 return EndValue;
1074
1075 // Otherwise, subtract the step from the EndValue.
1076 auto *ExtractR = cast<VPInstruction>(Op);
1077 VPBuilder B(ExtractR);
1078 VPValue *Step = WideIV->getStepValue();
1079 Type *ScalarTy = WideIV->getScalarType();
1080 if (ScalarTy->isIntegerTy())
1081 return B.createSub(EndValue, Step, DebugLoc::getUnknown(), "ind.escape");
1082 if (ScalarTy->isPointerTy()) {
1083 Type *StepTy = Step->getScalarType();
1084 auto *Zero = Plan.getZero(StepTy);
1085 return B.createPtrAdd(EndValue, B.createSub(Zero, Step),
1086 DebugLoc::getUnknown(), "ind.escape");
1087 }
1088 if (ScalarTy->isFloatingPointTy()) {
1089 const auto &ID = WideIV->getInductionDescriptor();
1090 return B.createNaryOp(
1091 ID.getInductionBinOp()->getOpcode() == Instruction::FAdd
1092 ? Instruction::FSub
1093 : Instruction::FAdd,
1094 {EndValue, Step}, {ID.getInductionBinOp()->getFastMathFlags()});
1095 }
1096 llvm_unreachable("all possible induction types must be handled");
1097 return nullptr;
1098}
1099
1102 VPValue *ResumeTC,
1103 const Loop *L) {
1104 VPValue *Incoming;
1107 m_VPValue(Incoming)))))
1108 return nullptr;
1109
1110 const SCEV *IncomingSCEV = vputils::getSCEVExprForVPValue(Incoming, PSE, L);
1111 const SCEV *Start, *Step;
1112 if (!match(IncomingSCEV, m_scev_AffineAddRec(m_SCEV(Start), m_SCEV(Step),
1113 m_SpecificLoop(L))))
1114 return nullptr;
1115
1116 auto *ExtractR = cast<VPInstruction>(Op);
1117 DebugLoc DL = ExtractR->getDebugLoc();
1118 VPBuilder Builder(ExtractR);
1119 VPSCEVExpander Expander(Builder, *PSE.getSE(), DL);
1120 VPValue *StartVPV = Expander.expand(Start);
1121 VPValue *StepVPV = Expander.expand(Step);
1122
1123 Type *StartTy = StartVPV->getScalarType();
1124 assert(StartTy->isIntOrPtrTy() && "The type must be SCEVable");
1128 Type *TCTy = ResumeTC->getScalarType();
1129 VPValue *ExitCount = Builder.createOverflowingOp(
1130 Instruction::Sub, {ResumeTC, Plan.getConstantInt(TCTy, 1)},
1131 {/*HasNUW=*/true, /*HasNSW=*/false}, DebugLoc::getUnknown());
1132 return Builder.createDerivedIV(Kind, /*FPBinOp=*/nullptr, StartVPV, ExitCount,
1133 StepVPV);
1134}
1135
1137 VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L) {
1138 // Compute end values for all inductions.
1139 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
1140 auto *VectorPH = cast<VPBasicBlock>(VectorRegion->getSinglePredecessor());
1141 VPBuilder VectorPHBuilder(VectorPH, VectorPH->getFirstNonPhi());
1143 VPValue *ResumeTC =
1144 Plan.hasTailFolded() ? Plan.getTripCount() : &Plan.getVectorTripCount();
1146 VectorRegion->getEntryBasicBlock()->phis())) {
1148 &WideIV, VectorPHBuilder, ResumeTC))
1149 EndValues[&WideIV] = EndValue;
1150 }
1151
1152 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
1153 for (VPRecipeBase &R : make_early_inc_range(*MiddleVPBB)) {
1154 VPValue *Op;
1155 if (!match(&R, m_ExitingIVValue(m_VPValue(Op))))
1156 continue;
1157 auto *WideIV = cast<VPWidenInductionRecipe>(Op);
1158 if (VPValue *EndValue = EndValues.lookup(WideIV)) {
1159 R.getVPSingleValue()->replaceAllUsesWith(EndValue);
1160 R.eraseFromParent();
1161 }
1162 }
1163
1164 // Then, optimize exit block users.
1165 for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
1166 for (VPRecipeBase &R : ExitVPBB->phis()) {
1167 auto *ExitIRI = cast<VPIRPhi>(&R);
1168
1169 for (auto [Idx, PredVPBB] : enumerate(ExitVPBB->getPredecessors())) {
1170 VPValue *Escape = nullptr;
1171 if (PredVPBB == MiddleVPBB) {
1173 Plan, ExitIRI->getOperand(Idx), EndValues, PSE);
1174 if (!Escape)
1176 Plan, ExitIRI->getOperand(Idx), PSE, ResumeTC, L);
1177 } else {
1179 Plan, ExitIRI->getOperand(Idx), PSE);
1180 }
1181 if (Escape)
1182 ExitIRI->setOperand(Idx, Escape);
1183 }
1184 }
1185 }
1186}
1187
1188/// Try to simplify logical and bitwise recipes in \p Def.
1190 VPValue *X;
1191
1192 // X | AllOnes -> AllOnes
1193 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_AllOnes())))
1194 return Plan.getAllOnesValue(Def->getScalarType());
1195
1196 // X | 0 -> X
1197 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_ZeroInt())))
1198 return X;
1199
1200 // X | !X -> AllOnes
1202 return Plan.getAllOnesValue(Def->getScalarType());
1203
1204 // X & 0 -> 0
1205 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_ZeroInt())))
1206 return Plan.getZero(Def->getScalarType());
1207
1208 // X & AllOnes -> X
1209 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_AllOnes())))
1210 return X;
1211
1212 // X && false -> false
1213 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False())))
1214 return Plan.getFalse();
1215
1216 // X && true -> X
1217 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True())))
1218 return X;
1219
1220 // X && (X && Y) -> X && Y
1221 if (match(Def, m_LogicalAnd(m_VPValue(X),
1223 return Def->getOperand(1);
1224
1225 // X && !X -> 0
1227 return Plan.getFalse();
1228
1229 if (match(Def, m_Select(m_VPValue(), m_VPValue(X), m_Deferred(X))))
1230 return X;
1231
1232 // X != false -> X
1234 assert(X->getScalarType()->isIntegerTy(1) && "must have boolean operands");
1235 return X;
1236 }
1237
1238 return nullptr;
1239}
1240
1241/// Swap the branch weights recorded for \p R, a select whose two selected
1242/// operands are being swapped,
1244 auto *MD = dyn_cast<VPIRMetadata>(&R);
1245 if (!MD)
1246 return;
1248 if (!extractBranchWeights(MD->getMetadata(LLVMContext::MD_prof), Weights))
1249 return;
1250 assert(Weights.size() == 2 && "unexpected branch weights");
1251 MD->setMetadata(
1252 LLVMContext::MD_prof,
1253 MDBuilder(Plan.getContext()).createBranchWeights(Weights[1], Weights[0]));
1254}
1255
1256/// Return an existing value or a live in for VPSingleDefRecipe \p Def if
1257/// possible. This shouldn't create or modify recipes.
1259 // Simplification of live-in IR values for SingleDef recipes using
1260 // InstSimplifyFolder.
1261 const DataLayout &DL = Plan.getDataLayout();
1262 if (VPValue *V = vputils::tryToFoldLiveIns(*Def, Def->operands(), DL))
1263 return V;
1264
1265 // Fold PredPHI LiveIn -> LiveIn.
1266 if (auto *PredPHI = dyn_cast<VPPredInstPHIRecipe>(Def)) {
1267 VPValue *Op = PredPHI->getOperand(0);
1268 if (isa<VPIRValue>(Op))
1269 return Op;
1270 }
1271
1272 if (VPValue *V = simplifyLogicalRecipe(Plan, Def))
1273 return V;
1274
1275 VPValue *A, *B;
1276
1277 if (match(Def, m_c_Add(m_VPValue(A), m_ZeroInt())))
1278 return A;
1279
1280 if (match(Def, m_c_Mul(m_VPValue(A), m_One())))
1281 return A;
1282
1283 if (match(Def, m_c_Mul(m_VPValue(), m_ZeroInt())))
1284 return Plan.getZero(Def->getScalarType());
1285
1286 // A bitcast to the same type is a no-op.
1287 if (match(Def, m_BitCast(m_VPValue(A))) &&
1288 Def->getScalarType() == A->getScalarType())
1289 return A;
1290
1291 // Shifting by zero is a no-op.
1294 m_AShr(m_VPValue(A), m_ZeroInt())))))
1295 return A;
1296
1297 if (match(Def, m_Trunc(m_ZExtOrSExt(m_VPValue(A)))))
1298 if (Def->getScalarType() == A->getScalarType())
1299 return A;
1300
1301 if (match(Def, m_Not(m_Not(m_VPValue(A)))))
1302 return A;
1303
1304 // Remove redundant DerviedIVs, that is 0 + A * 1 -> A and 0 + 0 * x -> 0.
1305 if ((match(Def, m_DerivedIV(m_ZeroInt(), m_VPValue(A), m_One())) ||
1307 m_VPValue()))) &&
1308 A->getScalarType() == Def->getScalarType())
1309 return A;
1310
1311 // Simplify MaskedCond with no block mask to its single operand.
1313 !cast<VPInstruction>(Def)->isMasked())
1314 return Def->getOperand(0);
1315
1316 // Look through ExtractLastLane.
1317 if (match(Def, m_ExtractLastLane(m_VPValue(A)))) {
1318 if (match(A, m_BuildVector())) {
1319 auto *BuildVector = cast<VPInstruction>(A);
1320 return BuildVector->getLastOperand();
1321 }
1322
1323 if (match(A, m_Broadcast(m_VPValue(B))))
1324 return B;
1325
1328 return A;
1329
1330 if (Plan.hasScalarVFOnly())
1331 return A;
1332 }
1333
1334 // Look through ExtractPenultimateElement (BuildVector ....).
1336 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1337 return BuildVector->getOperand(BuildVector->getNumOperands() - 2);
1338 }
1339
1340 uint64_t Idx;
1342 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1343 return BuildVector->getOperand(Idx);
1344 }
1345
1347 if (Def->getNumOperands() == 1) {
1348 return Def->getOperand(0);
1349 }
1350 if (auto *Phi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(Def)) {
1351 if (all_equal(Phi->incoming_values()))
1352 return Phi->getOperand(0);
1353 }
1354 return nullptr;
1355 }
1356
1357 VPIRValue *IRV;
1358 if (Def->getNumOperands() == 1 &&
1360 return IRV;
1361
1363 m_One())) &&
1364 A->getScalarType() == Def->getScalarType())
1365 return A;
1366
1367 // Some simplifications can only be applied after unrolling. Perform them
1368 // below.
1369 if (!Plan.isUnrolled())
1370 return nullptr;
1371
1372 // Simplify extracts of the same single-scalar.
1374 all_equal(drop_begin(Def->operands())) &&
1375 vputils::isSingleScalar(Def->getOperand(1)))
1376 return Def->getOperand(1);
1377
1378 // Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
1379 // scalar canonical IV.
1381 if (match(Def, m_ExtractLane(m_ZeroInt(), m_CanonicalWidenIV(WidenIV))))
1382 return WidenIV->getRegion()->getCanonicalIV();
1383
1384 // Simplify unrolled VectorPointer without offset, or with zero offset, to
1385 // just the pointer operand.
1386 if (auto *VPR = dyn_cast<VPVectorPointerRecipe>(Def))
1387 if (!VPR->getVFxPart() || match(VPR->getVFxPart(), m_ZeroInt()))
1388 return VPR->getOperand(0);
1389
1390 // VPScalarIVSteps after unrolling can be replaced by their start value, if
1391 // the start index is zero and only the first lane 0 is demanded.
1392 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Def))
1393 if (!Steps->getStartIndex() && vputils::onlyFirstLaneUsed(Steps))
1394 return Steps->getOperand(0);
1395
1396 if (Plan.getConcreteUF() == 1 && match(Def, m_ExtractLastPart(m_VPValue(A))))
1397 return A;
1398
1399 return nullptr;
1400}
1401
1402/// Returns true if \p V is available at the end of \p VPBB, i.e. it either is a
1403/// live-in from the original IR or defined in \p VPBB.
1404static bool isAvailableAtEndOf(VPValue *V, const VPBasicBlock *VPBB) {
1405 VPRecipeBase *DefR = V->getDefiningRecipe();
1406 return DefR ? DefR->getParent() == VPBB : isa<VPIRValue>(V);
1407}
1408
1409namespace {
1410/// Inserter for VPBuilderBase which appends all created VPSingleDefRecipes to a
1411/// worklist, so they get combined as well.
1412struct VPCombineInserter {
1413 SmallVectorImpl<VPSingleDefRecipe *> &Worklist;
1414
1415 void insertHelper(VPRecipeBase *R, VPBasicBlock *VPBB,
1417 VPBB->insert(R, 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.
1599 CmpPredicate Pred;
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 findUserOf(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 // Fold in the separately stored consecutive flag. Alignment is left out and
2363 // handled by cse.
2364 if (auto *Load = dyn_cast<VPWidenMemoryRecipe>(Def))
2365 return hash_combine(Result, Load->isConsecutive());
2366 if (auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(Def))
2367 return hash_combine(Result, ExpSCEV->getSCEV());
2368 return Result;
2369 }
2370
2371 /// Check equality of underlying data of \p L and \p R.
2372 static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
2373 if (L->getVPRecipeID() != R->getVPRecipeID() ||
2376 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2378 !equal(L->operands(), R->operands()))
2379 return false;
2382 "must have valid opcode info for both recipes");
2383 if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
2384 if (LFlags->hasPredicate() &&
2385 LFlags->getPredicate() !=
2386 cast<VPRecipeWithIRFlags>(R)->getPredicate())
2387 return false;
2388 if (auto *LSIV = dyn_cast<VPScalarIVStepsRecipe>(L))
2389 if (LSIV->getInductionOpcode() !=
2390 cast<VPScalarIVStepsRecipe>(R)->getInductionOpcode())
2391 return false;
2392 // Compare the separately stored consecutive flag. Alignment is left out and
2393 // handled by cse.
2394 if (auto *LL = dyn_cast<VPWidenMemoryRecipe>(L))
2395 if (LL->isConsecutive() != cast<VPWidenMemoryRecipe>(R)->isConsecutive())
2396 return false;
2397 if (auto *LExp = dyn_cast<VPExpandSCEVRecipe>(L))
2398 if (LExp->getSCEV() != cast<VPExpandSCEVRecipe>(R)->getSCEV())
2399 return false;
2400 // Phi recipes can only be equal if they are in the same VPBB, as they
2401 // implicitly depend on their predecessors.
2402 if (isa<VPWidenPHIRecipe>(L) && L->getParent() != R->getParent())
2403 return false;
2404 // Recipes in replicate regions implicitly depend on predicate. If either
2405 // recipe is in a replicate region, only consider them equal if both have
2406 // the same parent.
2407 const VPRegionBlock *RegionL = L->getRegion();
2408 const VPRegionBlock *RegionR = R->getRegion();
2409 if (((RegionL && RegionL->isReplicator()) ||
2410 (RegionR && RegionR->isReplicator())) &&
2411 L->getParent() != R->getParent())
2412 return false;
2413 return L->getScalarType() == R->getScalarType();
2414 }
2415};
2416} // end anonymous namespace
2417
2418/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
2419/// Plan.
2422 // CSE map for loads. Must be cleared on recipes that may write to memory, and
2423 // at the end of each VPBB.
2425 LoadCSEMap;
2426
2428 Plan.getEntry());
2430 for (VPRecipeBase &R : *VPBB) {
2431 if (R.mayWriteToMemory())
2432 LoadCSEMap.clear();
2433 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2434 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2435 continue;
2436 bool IsLoad = vputils::getOpcode(Def) == Instruction::Load;
2437 auto [It, Inserted] =
2438 (IsLoad ? LoadCSEMap : CSEMap).try_emplace(Def, Def);
2439 if (Inserted)
2440 continue;
2441 VPSingleDefRecipe *V = It->second;
2442 // V must dominate Def for a valid replacement.
2443 if (!VPDT.dominates(V->getParent(), VPBB))
2444 continue;
2445 if (IsLoad) {
2446 if (getLoadAlign(V) < getLoadAlign(Def)) {
2447 // Record Def as the candidate for subsequent loads, as it may be
2448 // reusable where V is not.
2449 It->second = Def;
2450 continue;
2451 }
2452 // Keep only metadata common to both loads on the survivor.
2453 cast<VPIRMetadata>(V)->intersect(*cast<VPIRMetadata>(Def));
2454 }
2455 // Only keep flags present on both V and Def.
2456 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(V))
2457 RFlags->intersectFlags(*cast<VPRecipeWithIRFlags>(Def));
2458 // Only keep call attributes valid for both V and Def.
2459 if (auto *Call = dyn_cast<VPWidenCallRecipe>(V))
2460 Call->intersectAttrs(*cast<VPWidenCallRecipe>(Def), Plan.getContext());
2461 Def->replaceAllUsesWith(V);
2462 // Reset Plan's TC when TC expressions are CSE'd.
2463 if (Def == Plan.getTripCount())
2464 Plan.resetTripCount(V);
2465 }
2466 LoadCSEMap.clear();
2467 }
2468}
2469
2470/// Return true if we do not know how to (mechanically) hoist or sink a
2471/// non-memory or memory recipe \p R out of a loop region. When sinking, passing
2472/// \p Sinking = true ensures that assumes aren't sunk.
2474 VPBasicBlock *LastBB,
2475 bool Sinking = false) {
2476 if (!isa<VPReplicateRecipe>(R) || !R.mayReadOrWriteMemory() ||
2478 return vputils::cannotHoistOrSinkRecipe(R, Sinking);
2479
2480 // Check that the memory operation doesn't alias between FirstBB and LastBB.
2481 auto MemLoc = vputils::getMemoryLocation(R);
2482
2483 // TODO: Could make use of SinkStoreInfo::isNoAliasViaDistance by collecting
2484 // stores upfront, and constructing a full SinkStoreInfo.
2485 auto SinkInfo =
2486 Sinking ? std::make_optional(SinkStoreInfo(cast<VPReplicateRecipe>(R)))
2487 : std::nullopt;
2488
2489 return !MemLoc ||
2490 !canHoistOrSinkWithNoAliasCheck(*MemLoc, FirstBB, LastBB, SinkInfo);
2491}
2492
2493/// Move loop-invariant recipes out of the vector loop region in \p Plan.
2494static void licm(VPlan &Plan, const VPDominatorTree &VPDT) {
2495 VPBasicBlock *Preheader = Plan.getVectorPreheader();
2496
2497 // Hoist any loop invariant recipes from the vector loop region to the
2498 // preheader. Perform a shallow traversal of the vector loop region, to
2499 // exclude recipes in replicate regions. Only hoist from blocks dominating the
2500 // exiting block, which are guaranteed to execute if the vector pre-header is,
2501 // so we don't need to check speculation safety.
2502 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
2503 assert(Preheader->getSingleSuccessor() == LoopRegion &&
2504 "Expected vector prehader's successor to be the vector loop region");
2505 VPBasicBlock *ExitingVPBB = LoopRegion->getExitingBasicBlock();
2507 vp_depth_first_shallow(LoopRegion->getEntry()))) {
2508 if (!VPDT.dominates(VPBB, ExitingVPBB))
2509 continue;
2510 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2511 if (any_of(R.operands(), [](VPValue *Op) {
2512 return !Op->isDefinedOutsideLoopRegions();
2513 }))
2514 continue;
2515 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2516 LoopRegion->getExitingBasicBlock()))
2517 continue;
2518 R.moveBefore(*Preheader, Preheader->end());
2519 }
2520 }
2521
2522 // Sink recipes with no users inside the vector loop region if all users are
2523 // in the same exit block of the region.
2524 // TODO: Extend to sink recipes from inner loops.
2526 LoopRegion->getEntry());
2528 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
2529 // TODO: Use R.definedValues() instead of casting to VPSingleDefRecipe to
2530 // support recipes with multiple defined values (e.g., interleaved loads).
2531 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2532 if (!Def)
2533 continue;
2534
2535 if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
2536 assert(!RepR->isPredicated() &&
2537 "Expected prior transformation of predicated replicates to "
2538 "replicate regions");
2539 // narrowToSingleScalarRecipes should have already maximally narrowed
2540 // replicates to single-scalar replicates.
2541 // TODO: When unrolling, replicateByVF doesn't handle sunk
2542 // non-single-scalar replicates correctly.
2543 if (!RepR->isSingleScalar())
2544 continue;
2545
2546 // The pointer operand of stores must be loop-invariant.
2547 if (RepR->getOpcode() == Instruction::Store &&
2548 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2549 continue;
2550 }
2551
2552 // Cannot sink the recipe if the user is defined in a loop region or a
2553 // non-successor of the vector loop region. Cannot sink if user is a phi
2554 // either.
2555 VPBasicBlock *SinkBB = nullptr;
2556 if (any_of(Def->users(), [&SinkBB, &LoopRegion](VPUser *U) {
2557 auto *UserR = cast<VPRecipeBase>(U);
2558 VPBasicBlock *Parent = UserR->getParent();
2559 // TODO: Support sinking when users are in multiple blocks.
2560 if (SinkBB && SinkBB != Parent)
2561 return true;
2562 SinkBB = Parent;
2563 // TODO: If the user is a PHI node, we should check the block of
2564 // incoming value. Support PHI node users if needed.
2565 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2566 Parent->getSinglePredecessor() != LoopRegion;
2567 }))
2568 continue;
2569
2570 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2571 LoopRegion->getExitingBasicBlock(),
2572 /*Sinking=*/true))
2573 continue;
2574
2575 [[maybe_unused]] auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
2576 assert((!R.mayWriteToMemory() ||
2577 (RepR && RepR->getOpcode() == Instruction::Store &&
2578 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2579 "The only recipes that may write to memory are expected to be "
2580 "stores with invariant pointer-operand");
2581
2582 if (!SinkBB)
2583 SinkBB = cast<VPBasicBlock>(LoopRegion->getSingleSuccessor());
2584
2585 // TODO: This will need to be a check instead of a assert after
2586 // conditional branches in vectorized loops are supported.
2587 assert(VPDT.properlyDominates(VPBB, SinkBB) &&
2588 "Defining block must dominate sink block");
2589 // TODO: Clone the recipe if users are on multiple exit paths, instead of
2590 // just moving.
2591 Def->moveBefore(*SinkBB, SinkBB->getFirstNonPhi());
2592 }
2593 }
2594}
2595
2597 VPlan &Plan, const MapVector<Instruction *, uint64_t> &MinBWs) {
2598 if (Plan.hasScalarVFOnly())
2599 return;
2600 // Keep track of created truncates, so they can be re-used. Note that we
2601 // cannot use RAUW after creating a new truncate, as this would could make
2602 // other uses have different types for their operands, making them invalidly
2603 // typed.
2605 VPBasicBlock *PH = Plan.getVectorPreheader();
2608 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2611 continue;
2612
2613 VPValue *ResultVPV = R.getVPSingleValue();
2614 auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
2615 unsigned NewResSizeInBits = MinBWs.lookup(UI);
2616 if (!NewResSizeInBits)
2617 continue;
2618
2619 // If the value wasn't vectorized, we must maintain the original scalar
2620 // type. Skip those here, after incrementing NumProcessedRecipes. Also
2621 // skip casts which do not need to be handled explicitly here, as
2622 // redundant casts will be removed during recipe simplification.
2624 continue;
2625
2626 Type *OldResTy = ResultVPV->getScalarType();
2627 unsigned OldResSizeInBits = OldResTy->getScalarSizeInBits();
2628 assert(OldResTy->isIntegerTy() && "only integer types supported");
2629 (void)OldResSizeInBits;
2630
2631 auto *NewResTy = IntegerType::get(Plan.getContext(), NewResSizeInBits);
2632
2633 // Any wrapping introduced by shrinking this operation shouldn't be
2634 // considered undefined behavior. So, we can't unconditionally copy
2635 // arithmetic wrapping flags to VPW.
2636 if (auto *VPW = dyn_cast<VPRecipeWithIRFlags>(&R))
2637 VPW->dropPoisonGeneratingFlags();
2638
2639 assert((OldResSizeInBits != NewResSizeInBits ||
2640 match(&R, m_ICmp(m_VPValue(), m_VPValue()))) &&
2641 "Only ICmps should not need extending the result.");
2642 assert(!isa<VPWidenStoreRecipe>(&R) && "stores cannot be narrowed");
2643
2644 // Loads/intrinsics are not recreated; they keep producing their original
2645 // wide result and narrowed users will truncate it as needed below.
2647 continue;
2648
2649 // Shrink operands by introducing truncates as needed.
2650 unsigned StartIdx =
2651 match(&R, m_Select(m_VPValue(), m_VPValue(), m_VPValue())) ? 1 : 0;
2652 SmallVector<VPValue *> NewOperands(R.operands());
2653 for (VPValue *&Op : drop_begin(NewOperands, StartIdx)) {
2654 unsigned OpSizeInBits = Op->getScalarType()->getScalarSizeInBits();
2655 if (OpSizeInBits == NewResSizeInBits)
2656 continue;
2657 assert(OpSizeInBits > NewResSizeInBits && "nothing to truncate");
2658 auto [ProcessedIter, Inserted] = ProcessedTruncs.try_emplace(Op);
2659 if (Inserted) {
2660 VPBuilder Builder;
2661 if (isa<VPIRValue>(Op))
2662 Builder.setInsertPoint(PH);
2663 else
2664 Builder.setInsertPoint(&R);
2665 ProcessedIter->second =
2666 Builder.createWidenCast(Instruction::Trunc, Op, NewResTy);
2667 }
2668 Op = ProcessedIter->second;
2669 }
2670
2671 auto *NWR = cast<VPWidenRecipe>(&R)->cloneWithOperands(NewOperands);
2672 NWR->insertBefore(&R);
2673
2674 // Wrap NWR in a ZExt to preserve the original wide type for downstream
2675 // users. Not needed for ICmps, whose result type is i1 irrespective of
2676 // the narrowing of their operands.
2677 VPValue *Replacement = NWR->getVPSingleValue();
2678 if (Replacement->getScalarType() != OldResTy)
2679 Replacement =
2681 .createWidenCast(Instruction::ZExt, Replacement, OldResTy)
2682 ->getVPSingleValue();
2683 ResultVPV->replaceAllUsesWith(Replacement);
2684 R.eraseFromParent();
2685 }
2686 }
2687}
2688
2689bool VPlanTransforms::removeBranchOnConst(VPlan &Plan, bool OnlyLatches) {
2690 std::optional<VPDominatorTree> VPDT;
2691 if (OnlyLatches)
2692 VPDT.emplace(Plan);
2693
2694 // Collect all blocks before modifying the CFG so we can identify unreachable
2695 // ones after constant branch removal.
2697
2698 bool SimplifiedPhi = false;
2699 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(AllBlocks)) {
2700 VPValue *Cond;
2701 // Skip blocks that are not terminated by BranchOnCond.
2702 if (VPBB->empty() || !match(&VPBB->back(), m_BranchOnCond(m_VPValue(Cond))))
2703 continue;
2704
2705 if (OnlyLatches && !VPBlockUtils::isLatch(VPBB, *VPDT))
2706 continue;
2707
2708 assert(VPBB->getNumSuccessors() == 2 &&
2709 "Two successors expected for BranchOnCond");
2710 unsigned RemovedIdx;
2711 if (match(Cond, m_True()))
2712 RemovedIdx = 1;
2713 else if (match(Cond, m_False()))
2714 RemovedIdx = 0;
2715 else
2716 continue;
2717
2718 VPBasicBlock *RemovedSucc =
2719 cast<VPBasicBlock>(VPBB->getSuccessors()[RemovedIdx]);
2720 assert(count(RemovedSucc->getPredecessors(), VPBB) == 1 &&
2721 "There must be a single edge between VPBB and its successor");
2722 // Values coming from VPBB into phi recipes of RemovedSucc are removed from
2723 // these recipes and single-entry header phis are removed.
2724 for (VPRecipeBase &R : make_early_inc_range(RemovedSucc->phis())) {
2725 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(VPBB);
2726 SimplifiedPhi = true;
2727 // Remove now invalid header phis that are left single-entry after
2728 // removing their backedges.
2729 auto *PhiR = dyn_cast<VPHeaderPHIRecipe>(&R);
2730 if (!PhiR || PhiR->getNumIncoming() != 1)
2731 continue;
2732 PhiR->replaceAllUsesWith(PhiR->getOperand(0));
2733 PhiR->eraseFromParent();
2734 }
2735
2736 // Disconnect blocks and remove the terminator.
2737 VPBlockUtils::disconnectBlocks(VPBB, RemovedSucc);
2738 VPBB->back().eraseFromParent();
2739 }
2740
2741 // Compute which blocks are still reachable from the entry after constant
2742 // branch removal.
2745
2746 // Detach all unreachable blocks from their successors, removing their recipes
2747 // and incoming values from phi recipes.
2748 VPSymbolicValue Tmp(nullptr);
2749 for (VPBlockBase *B : AllBlocks) {
2750 if (Reachable.contains(B))
2751 continue;
2752 for (VPBlockBase *Succ : to_vector(B->successors())) {
2753 if (auto *SuccBB = dyn_cast<VPBasicBlock>(Succ))
2754 for (VPRecipeBase &R : SuccBB->phis())
2755 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(B);
2757 }
2758 for (VPBasicBlock *DeadBB :
2760 for (VPRecipeBase &R : make_early_inc_range(*DeadBB)) {
2761 for (VPValue *Def : R.definedValues())
2762 Def->replaceAllUsesWith(&Tmp);
2763 R.eraseFromParent();
2764 }
2765 }
2766 }
2767 return SimplifiedPhi;
2768}
2769
2792
2795 auto GetSimplifiedLiveInViaSCEV = [&](VPValue *VPV) -> VPValue * {
2796 const SCEV *Expr = vputils::getSCEVExprForVPValue(VPV, PSE);
2797 const APInt *C;
2798 if (match(Expr, m_scev_APInt(C)))
2799 return Plan.getConstantInt(*C);
2800 return nullptr;
2801 };
2802
2803 for (VPValue *LiveIn : to_vector(Plan.getLiveIns())) {
2804 if (VPValue *SimplifiedLiveIn = GetSimplifiedLiveInViaSCEV(LiveIn))
2805 LiveIn->replaceAllUsesWith(SimplifiedLiveIn);
2806 }
2807}
2808
2810 VPlan &Plan, PredicatedScalarEvolution &PSE,
2811 const SymbolicStrideMap &StridesMap, const VPDominatorTree &VPDT) {
2812 // Replace VPValues for known constant strides guaranteed by predicated scalar
2813 // evolution that are guaranteed to be guarded by the runtime checks; that is,
2814 // blocks dominated by the vector header.
2815 assert(!Plan.getVectorLoopRegion() &&
2816 "expected to run before loop regions are created");
2817 const auto &[Header, _] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
2818 auto CanUseVersionedStride = [&VPDT, Header = Header, &Plan](VPUser *U) {
2819 auto *R = cast<VPRecipeBase>(U);
2820 // Skip phis if the loop if loop is not yet guarded.
2821 if (isa<VPPhiAccessors>(R) &&
2822 Header == Plan.getEntry()->getSingleSuccessor())
2823 return false;
2824 return VPDT.dominates(Header, R->getParent());
2825 };
2826 ValueToSCEVMapTy RewriteMap;
2827 for (const SCEVUnknown *Stride : StridesMap.values()) {
2828 Value *StrideV = Stride->getValue();
2829 const APInt *StrideConst;
2830 const SCEV *StrideExpr = PSE.getSCEV(StrideV);
2831 if (!match(StrideExpr, m_scev_APInt(StrideConst)))
2832 // Only handle constant strides for now.
2833 continue;
2834 if (VPValue *StrideVPV = Plan.getLiveIn(StrideV))
2835 StrideVPV->replaceUsesWithIf(Plan.getConstantInt(*StrideConst),
2836 CanUseVersionedStride);
2837
2838 // The versioned value may not be used in the loop directly but through an
2839 // integral cast (sext/zext/trunc). Add new live-ins in those cases.
2840 for (Value *U : StrideV->users()) {
2842 continue;
2843 VPValue *StrideVPV = Plan.getLiveIn(U);
2844 if (!StrideVPV)
2845 continue;
2846 unsigned BW = U->getType()->getScalarSizeInBits();
2847 APInt C = isa<SExtInst>(U) ? StrideConst->sext(BW)
2848 : StrideConst->zextOrTrunc(BW);
2849 StrideVPV->replaceUsesWithIf(Plan.getConstantInt(C),
2850 CanUseVersionedStride);
2851 }
2852 RewriteMap[StrideV] = StrideExpr;
2853 }
2854
2855 ScalarEvolution &SE = *PSE.getSE();
2856 for (VPExpandSCEVRecipe &ExpSCEV :
2858 const SCEV *ScevExpr = ExpSCEV.getSCEV();
2859 const SCEV *NewSCEV =
2860 SCEVParameterRewriter::rewrite(ScevExpr, SE, RewriteMap);
2861 if (NewSCEV == ScevExpr || !SE.isGuaranteedNotToCauseUB(NewSCEV))
2862 continue;
2863 VPValue *NewExp = vputils::getOrCreateVPValueForSCEVExpr(Plan, NewSCEV);
2864 ExpSCEV.replaceAllUsesWith(NewExp);
2865 if (Plan.getTripCount() == &ExpSCEV)
2866 Plan.resetTripCount(NewExp);
2867 }
2868}
2869
2871 // Collect recipes in the backward slice of `Root` that may generate a poison
2872 // value that is used after vectorization.
2874 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](VPRecipeBase *Root) {
2876 Worklist.push_back(Root);
2877
2878 // Traverse the backward slice of Root through its use-def chain.
2879 while (!Worklist.empty()) {
2880 VPRecipeBase *CurRec = Worklist.pop_back_val();
2881
2882 if (!Visited.insert(CurRec).second)
2883 continue;
2884
2885 // Prune search if we find another recipe generating a widen memory
2886 // instruction. Widen memory instructions involved in address computation
2887 // will lead to gather/scatter instructions, which don't need to be
2888 // handled.
2890 VPHeaderPHIRecipe>(CurRec))
2891 continue;
2892
2893 // This recipe contributes to the address computation of a widen
2894 // load/store. If the underlying instruction has poison-generating flags,
2895 // drop them directly.
2896 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(CurRec)) {
2897 VPValue *A, *B;
2898 // Dropping disjoint from an OR may yield incorrect results, as some
2899 // analysis may have converted it to an Add implicitly (e.g. SCEV used
2900 // for dependence analysis). Instead, replace it with an equivalent Add.
2901 // This is possible as all users of the disjoint OR only access lanes
2902 // where the operands are disjoint or poison otherwise.
2903 if (match(RecWithFlags, m_BinaryOr(m_VPValue(A), m_VPValue(B))) &&
2904 RecWithFlags->isDisjoint()) {
2905 VPBuilder Builder(RecWithFlags);
2906 VPInstruction *New =
2907 Builder.createAdd(A, B, RecWithFlags->getDebugLoc());
2908 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
2909 RecWithFlags->replaceAllUsesWith(New);
2910 RecWithFlags->eraseFromParent();
2911 CurRec = New;
2912 } else
2913 RecWithFlags->dropPoisonGeneratingFlags();
2914 } else {
2917 (void)Instr;
2918 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
2919 "found instruction with poison generating flags not covered by "
2920 "VPRecipeWithIRFlags");
2921 }
2922
2923 // Add new definitions to the worklist.
2924 for (VPValue *Operand : CurRec->operands())
2925 if (VPRecipeBase *OpDef = Operand->getDefiningRecipe())
2926 Worklist.push_back(OpDef);
2927 }
2928 });
2929
2930 // We want to exclude the tail folding case, as we don't need to drop flags
2931 // for operations computing the first lane in this case: the first lane of the
2932 // header mask must always be true. For reverse memory accesses, the mask is
2933 // wrapped in a Reverse, which is just a permutation of the header mask, so
2934 // peel it off before checking. The header mask is still the abstract region
2935 // value at this point (materialization happens later).
2936 auto m_UnlessHdrMask = m_Unless( // NOLINT
2938
2939 // Traverse all the recipes in the VPlan and collect the poison-generating
2940 // recipes in the backward slice starting at the address of a VPWidenRecipe or
2941 // VPInterleaveRecipe.
2942 auto Iter =
2945 for (VPRecipeBase &Recipe : *VPBB) {
2946 if (auto *WidenRec = dyn_cast<VPWidenMemoryRecipe>(&Recipe)) {
2947 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
2948 if (AddrDef && WidenRec->isConsecutive() && WidenRec->getMask() &&
2949 match(WidenRec->getMask(), m_UnlessHdrMask))
2950 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2951 } else if (auto *InterleaveRec = dyn_cast<VPInterleaveRecipe>(&Recipe)) {
2952 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
2953 if (AddrDef && InterleaveRec->getMask() &&
2954 match(InterleaveRec->getMask(), m_UnlessHdrMask))
2955 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
2956 }
2957 }
2958 }
2959}
2960
2962 VPlan &Plan,
2964 &InterleaveGroups,
2965 const bool &EpilogueAllowed) {
2966 if (InterleaveGroups.empty())
2967 return;
2968
2970 for (VPBasicBlock *VPBB :
2973 for (VPRecipeBase &R : make_filter_range(*VPBB, [](VPRecipeBase &R) {
2974 return isa<VPWidenMemoryRecipe>(&R);
2975 })) {
2976 auto *MemR = cast<VPWidenMemoryRecipe>(&R);
2977 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
2978 }
2979
2980 // Interleave memory: for each Interleave Group we marked earlier as relevant
2981 // for this VPlan, replace the Recipes widening its memory instructions with a
2982 // single VPInterleaveRecipe at its insertion point.
2983 VPDominatorTree VPDT(Plan);
2984 for (const auto *IG : InterleaveGroups) {
2985 VPWidenMemoryRecipe *Start = nullptr;
2986 Instruction *StartMember = nullptr;
2987 for (auto *Member : IG->members())
2988 if (VPWidenMemoryRecipe *R = IRMemberToRecipe.lookup(Member)) {
2989 StartMember = Member;
2990 Start = R;
2991 break;
2992 }
2993 if (!StartMember) // All member recipes are dead, so the group is dead.
2994 continue;
2995 VPIRMetadata InterleaveMD(*Start);
2996 SmallVector<VPValue *, 4> StoredValues;
2997 for (unsigned I = 0; I < IG->getFactor(); ++I) {
2998 Instruction *MemberI = IG->getMember(I);
2999 if (!MemberI)
3000 continue;
3001 if (VPWidenMemoryRecipe *MemoryR = IRMemberToRecipe.lookup(MemberI)) {
3002 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(MemoryR->getAsRecipe()))
3003 StoredValues.push_back(StoreR->getStoredValue());
3004 InterleaveMD.intersect(*MemoryR);
3005 } else {
3006 InterleaveMD.intersect(VPIRMetadata(*MemberI));
3007 }
3008 }
3009
3010 bool NeedsMaskForGaps =
3011 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
3012 (!StoredValues.empty() && !IG->isFull());
3013
3014 Instruction *IRInsertPos = IG->getInsertPos();
3015 auto *InsertPos = IRMemberToRecipe.lookup(IRInsertPos);
3016 if (!InsertPos) {
3017 // InsertPos member is dead: find a new member that is alive.
3018 assert(isa<VPWidenLoadRecipe>(Start->getAsRecipe()) &&
3019 "Dead member in non-load group?");
3020 InsertPos = Start;
3021 for (Instruction *Member : IG->members())
3022 if (VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member))
3023 if (VPDT.properlyDominates(MemberR->getAsRecipe(),
3024 InsertPos->getAsRecipe()))
3025 InsertPos = MemberR;
3026 IRInsertPos = &InsertPos->getIngredient();
3027 }
3028 VPRecipeBase *InsertPosR = InsertPos->getAsRecipe();
3029
3031 if (auto *Gep = dyn_cast<GetElementPtrInst>(
3032 getLoadStorePointerOperand(IRInsertPos)->stripPointerCasts()))
3033 NW = Gep->getNoWrapFlags().withoutNoUnsignedWrap();
3034
3035 // Get or create the start address for the interleave group.
3036 VPValue *Addr = Start->getAddr();
3037 VPRecipeBase *AddrDef = Addr->getDefiningRecipe();
3038 if (IG->getIndex(StartMember) != 0 ||
3039 (AddrDef && !VPDT.properlyDominates(AddrDef, InsertPosR))) {
3040 // Either member zero's recipe is dead, or we cannot re-use the address of
3041 // member zero because it does not dominate the insert position. Instead,
3042 // use the address of the insert position and create a PtrAdd adjusting it
3043 // to the address of member zero.
3044 // TODO: Hoist Addr's defining recipe (and any operands as needed) to
3045 // InsertPos or sink loads above zero members to join it.
3046 assert(IG->getIndex(IRInsertPos) != 0 &&
3047 "index of insert position shouldn't be zero");
3048 auto &DL = IRInsertPos->getDataLayout();
3049 APInt Offset(32,
3050 DL.getTypeAllocSize(getLoadStoreType(IRInsertPos)) *
3051 IG->getIndex(IRInsertPos),
3052 /*IsSigned=*/true);
3053 VPValue *OffsetVPV = Plan.getConstantInt(-Offset);
3054 VPBuilder B(InsertPosR);
3055 Addr = B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
3056 }
3057 // If the group is reverse, adjust the index to refer to the last vector
3058 // lane instead of the first. We adjust the index from the first vector
3059 // lane, rather than directly getting the pointer for lane VF - 1, because
3060 // the pointer operand of the interleaved access is supposed to be uniform.
3061 if (IG->isReverse()) {
3062 auto *ReversePtr = new VPVectorEndPointerRecipe(
3063 Addr, &Plan.getVF(), getLoadStoreType(IRInsertPos),
3064 -(int64_t)IG->getFactor(), NW, InsertPosR->getDebugLoc());
3065 ReversePtr->insertBefore(InsertPosR);
3066 Addr = ReversePtr;
3067 }
3068 auto *VPIG = new VPInterleaveRecipe(
3069 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
3070 InterleaveMD, InsertPosR->getDebugLoc());
3071 VPIG->insertBefore(InsertPosR);
3072
3073 unsigned J = 0;
3074 for (unsigned i = 0; i < IG->getFactor(); ++i)
3075 if (Instruction *Member = IG->getMember(i)) {
3076 VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member);
3077 if (!Member->getType()->isVoidTy()) {
3078 if (MemberR) {
3079 VPValue *OriginalV = MemberR->getAsRecipe()->getVPSingleValue();
3080 OriginalV->replaceAllUsesWith(VPIG->getVPValue(J));
3081 }
3082 J++;
3083 }
3084 if (MemberR)
3085 MemberR->getAsRecipe()->eraseFromParent();
3086 }
3087 }
3088}
3089
3090/// Matches an exit condition formed by comparing a value loaded from memory
3091/// with a loop-invariant term. Binds the comparison for the condition.
3097
3098namespace {
3099struct CountableConditionMatch {
3100 VPValue *&Cmp;
3101 PredicatedScalarEvolution &PSE;
3102 Loop *L;
3103
3104 CountableConditionMatch(VPValue *&Cmp, PredicatedScalarEvolution &PSE,
3105 Loop *L)
3106 : Cmp(Cmp), PSE(PSE), L(L) {}
3107
3108 template <typename ITy> bool match(ITy *V) const {
3109 VPValue *Update;
3111 V, m_VPValue(Cmp, m_c_ICmp(m_VPValue(Update, m_Add(m_VPValue(),
3112 m_VPValue())),
3113 m_LiveIn()))))
3114 return false;
3115
3116 const SCEV *S = vputils::getSCEVExprForVPValue(Update, PSE, L);
3119 }
3120};
3121} // end anonymous namespace
3122
3123/// Matches an exit condition formed by comparing the current value of a
3124/// affine add recurrence in the given loop with a stride of 1 against a
3125/// loop-invariant term. Binds the comparison for the condition.
3127 Loop *L) {
3128 return CountableConditionMatch(Cmp, PSE, L);
3129}
3130
3133 Loop *L) {
3134 // Check for a single combined exit in the latch block.
3135 // TODO: Generalize to other blocks besides the latch.
3136 // If we don't find a combined condition in the latch, just return true
3137 // to proceed with vectorization.
3138 auto [_, LatchVPBB] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
3139
3140 // We're looking for a conditional branch...
3141 auto *Term = dyn_cast<VPInstruction>(LatchVPBB->getTerminator());
3142 if (!Term || Term->getOpcode() != VPInstruction::BranchOnCond)
3143 return true;
3144
3145 // ...where the condition is a combination of both a countable and an
3146 // uncountable comparison.
3147 VPValue *Uncountable = nullptr;
3148 VPValue *Countable = nullptr;
3149 VPValue *Cond = Term->getOperand(0);
3151 m_Countable(Countable, PSE, L)),
3152 m_c_BinaryOr(m_Uncountable(Uncountable),
3153 m_Countable(Countable, PSE, L)))))
3154 return true;
3155
3156 // If the conditions are combined with a logical or (select), then we'll
3157 // need to freeze the individual terms when splitting.
3158 bool NeedsFreeze = match(Cond, m_LogicalOr(m_VPValue(), m_VPValue()));
3159
3160 // If we do have a combined exit condition, bail out if there's more than
3161 // one exit block.
3162 // TODO: Support additional exits.
3163 ArrayRef<VPIRBasicBlock *> ExitBlocks = Plan.getExitBlocks();
3164 if (ExitBlocks.size() != 1)
3165 return false;
3166
3167 // If there are any live-outs, bail out. The exit block is an existing IR
3168 // block, and if we split the exiting block then the incoming blocks and
3169 // values won't be correct.
3170 // TODO: Support live-outs with combined exits.
3171 if (!ExitBlocks.front()->phis().empty())
3172 return false;
3173
3174 // Split the latch block just before the terminator.
3175 VPBasicBlock *NewLatch = LatchVPBB->splitAt(Term->getIterator());
3176
3177 // Create new terminator for uncountable condition.
3178 VPBuilder EEBuilder(LatchVPBB);
3179 if (NeedsFreeze)
3180 Uncountable = EEBuilder.createFreeze(Uncountable);
3181 EEBuilder.createNaryOp(VPInstruction::BranchOnCond, {Uncountable});
3182
3183 // We need to connect the uncountable exit to the sole exit block. The
3184 // latch is expected to connect to the middle block instead.
3185 // In canonical form, the backedge is the last successor for the latch. So
3186 // the first successor (true path) should be the exit for both conditions.
3187 LatchVPBB->clearSuccessors();
3188 NewLatch->clearPredecessors();
3189 VPBlockUtils::connectBlocks(LatchVPBB, ExitBlocks.front());
3190 VPBlockUtils::connectBlocks(LatchVPBB, NewLatch);
3191
3192 // Set condition for latch block to countable condition.
3193 if (NeedsFreeze) {
3194 VPBuilder NewLatchBuilder(Term);
3195 Countable = NewLatchBuilder.createFreeze(Countable);
3196 }
3197 Term->setOperand(0, Countable);
3198
3199 return true;
3200}
3201
3202/// Returns the VPValue representing the uncountable exit comparison used by
3203/// AnyOf if the recipes it depends on can be traced back to live-ins and
3204/// the addresses (in GEP/PtrAdd form) of any (non-masked) load used in
3205/// generating the values for the comparison. The recipes are stored in
3206/// \p Recipes.
3207static VPValue *
3209 VPBasicBlock *LatchVPBB) {
3210 // Given a plain CFG VPlan loop with countable latch exiting block
3211 // \p LatchVPBB, we're looking to match the recipes contributing to the
3212 // uncountable exit condition comparison (here, vp<%4>) back to either
3213 // live-ins or the address nodes for the load used as part of the uncountable
3214 // exit comparison so that we can either move them within the loop, or copy
3215 // them to the preheader depending on the chosen method for dealing with
3216 // stores in uncountable exit loops.
3217 //
3218 // Currently, the address of the load is restricted to a GEP with 2 operands
3219 // and a live-in base address. This constraint may be relaxed later.
3220 //
3221 // VPlan ' for UF>=1' {
3222 // Live-in vp<%0> = VF * UF
3223 // Live-in vp<%1> = vector-trip-count
3224 // Live-in ir<20> = original trip-count
3225 //
3226 // ir-bb<entry>:
3227 // Successor(s): scalar.ph, vector.ph
3228 //
3229 // vector.ph:
3230 // Successor(s): for.body
3231 //
3232 // for.body:
3233 // EMIT vp<%2> = phi ir<0>, vp<%index.next>
3234 // EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, for.inc ]
3235 // EMIT ir<%uncountable.addr> = getelementptr inbounds nuw ir<%pred>,ir<%iv>
3236 // EMIT ir<%uncountable.val> = load ir<%uncountable.addr>
3237 // EMIT ir<%uncountable.cond> = icmp sgt ir<%uncountable.val>, ir<500>
3238 // EMIT vp<%3> = masked-cond ir<%uncountable.cond>
3239 // Successor(s): for.inc
3240 //
3241 // for.inc:
3242 // EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1>
3243 // EMIT ir<%countable.cond> = icmp eq ir<%iv.next>, ir<20>
3244 // EMIT vp<%index.next> = add nuw vp<%2>, vp<%0>
3245 // EMIT vp<%freeze> = freeze ir<%3>
3246 // EMIT vp<%4> = any-of ir<%freeze>
3247 // EMIT vp<%5> = icmp eq vp<%index.next>, vp<%1>
3248 // EMIT branch-on-two-conds vp<%4>, vp<%5>
3249 // Successor(s): middle.block, middle.block, for.body
3250 //
3251 // middle.block:
3252 // Successor(s): ir-bb<exit>, scalar.ph
3253 //
3254 // ir-bb<exit>:
3255 // No successors
3256 //
3257 // scalar.ph:
3258 // }
3259
3260 // Find the uncountable loop exit condition.
3261 VPValue *UncountableCondition = nullptr;
3262 if (!match(LatchVPBB->getTerminator(),
3263 m_BranchOnTwoConds(m_AnyOf(m_VPValue(UncountableCondition)),
3264 m_VPValue())))
3265 return nullptr;
3266
3268 Worklist.push_back(UncountableCondition);
3269 while (!Worklist.empty()) {
3270 VPValue *V = Worklist.pop_back_val();
3271
3272 // Any value defined outside the loop does not need to be copied.
3273 if (V->isDefinedOutsideLoopRegions())
3274 continue;
3275
3276 VPValue *Op1, *Op2;
3277 // Walk back through recipes until we find at least one load from memory.
3278 if (match(V, m_Cmp(m_VPValue(Op1), m_VPValue(Op2)))) {
3279 Worklist.push_back(Op1);
3280 Worklist.push_back(Op2);
3281 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3282 } else if (match(V, m_VPInstruction<Instruction::Load>(m_VPValue(Op1)))) {
3283 VPRecipeBase *GepR = Op1->getDefiningRecipe();
3284 // Only matching base + single offset term for now.
3285 if (GepR->getNumOperands() != 2)
3286 return nullptr;
3287 // Matching a GEP with a loop-invariant base ptr.
3289 m_LiveIn(), m_VPValue())))
3290 return nullptr;
3291 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3292 Recipes.push_back(cast<VPInstruction>(GepR));
3293 } else if (match(V, m_Freeze(m_VPValue(Op1)))) {
3294 Worklist.push_back(Op1);
3295 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3297 m_VPValue(Op1)))) {
3298 Worklist.push_back(Op1);
3299 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
3300 } else
3301 return nullptr;
3302 }
3303
3304 // If we couldn't match anything, don't return the condition. It may be
3305 // defined outside the loop.
3306 if (Recipes.empty() ||
3308 return nullptr;
3309
3310 return UncountableCondition;
3311}
3312
3318
3319/// Update \p Plan to mask memory operations in the loop based on whether the
3320/// early exit is taken or not.
3321///
3322/// We're currently expecting to find a loop with properties similar to the
3323/// following:
3324///
3325/// for.body:
3326/// ir<%indvars.iv> = WIDEN-INDUCTION nuw nsw ir<0>, ir<1>, vp<%0>
3327/// EMIT ir<%arrayidx> = getelementptr inbounds nuw ir<@c>, ir<%indvars.iv>
3328/// EMIT-SCALAR ir<%0> = load ir<%arrayidx>
3329/// EMIT ir<%cmp1> = icmp sgt ir<%0>, ir<5>
3330/// EMIT vp<%1> = masked-cond ir<%cmp1>
3331/// Successor(s): if.end
3332///
3333/// if.end:
3334/// EMIT ir<%arrayidx3> = getelementptr inbounds nuw ir<@src>, ir<%indvars.iv>
3335/// EMIT-SCALAR ir<%2> = load ir<%arrayidx3>
3336/// EMIT ir<%add> = add nsw ir<%2>, ir<42>
3337/// EMIT ir<%arrayidx5> = getelementptr inbounds nuw ir<@dst>, ir<%indvars.iv>
3338/// EMIT store ir<%add>, ir<%arrayidx5>
3339/// EMIT ir<%indvars.iv.next> = add nuw nsw ir<%indvars.iv>, ir<1>
3340/// EMIT vp<%freeze> = freeze ir<%1>
3341/// EMIT vp<%3> = any-of ir<%freeze>
3342/// EMIT ir<%exitcond.not> = icmp eq ir<%indvars.iv.next>, ir<10000>
3343/// EMIT branch-on-two-conds vp<%3>, ir<%exitcond.not>
3344/// Successor(s): middle.block, middle.block, for.body
3345///
3346/// We currently expect LoopVectorizationLegality to ensure that:
3347/// * There must also be a counted exit. We will need to support speculative
3348/// or first-faulting loads before we can remove this restriction.
3349/// * Any stores within the loop must not alias with the load used for the
3350/// uncountable exit. We can relax this a bit with runtime aliasing checks.
3351/// * Other memory operations in the loop can take place before or after the
3352/// uncountable exit, but must also be unconditional. We need to support
3353/// combining the conditions in VPlanPredicator.
3354/// * The loop must have a single unconditional load contributing to the
3355/// uncountable exit comparison, and the other term must be loop-invariant.
3356/// Improving upon this requires work in getRecipesForUncountableExit to
3357/// handle more complex recipe graphs.
3360 VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB,
3361 OptimizationRemarkEmitter *ORE, Loop *TheLoop,
3363
3364 // Disconnect early exiting blocks from successors, remove branches.
3365 for (auto &Exit : Exits) {
3366 if (Exit.EarlyExitingVPBB == LatchVPBB)
3367 continue;
3368
3369 for (VPRecipeBase &R : Exit.EarlyExitVPBB->phis())
3370 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
3371 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
3372 VPBlockUtils::disconnectBlocks(Exit.EarlyExitingVPBB, Exit.EarlyExitVPBB);
3373 }
3374
3375 VPDominatorTree VPDT(Plan);
3376
3377 // We can abandon a VPlan entirely if we return false here, so we shouldn't
3378 // crash if some earlier assumptions on scalar IR don't hold for the vplan
3379 // version of the loop.
3380 SmallVector<VPInstruction *, 8> ConditionRecipes;
3381
3382 VPValue *Cond = getRecipesForUncountableExit(ConditionRecipes, LatchVPBB);
3383 if (!Cond) {
3384 reportVectorizationFailure("Unable to determine early exit condition for "
3385 "loop with side effects",
3386 "EarlyExitSideEffectsCond", ORE, TheLoop);
3387 return false;
3388 }
3389
3390 // Find load contributing to condition.
3391 // At the moment LoopVectorizationLegality only supports a single
3392 // early-exit expression with a compare and a single load that must
3393 // be unconditional.
3394 // TODO: Support more than one load.
3395 auto *Load =
3396 find_singleton<VPInstruction>(ConditionRecipes, [](auto *I, bool _) {
3398 ? I
3399 : nullptr;
3400 });
3401 assert(Load && "Couldn't find exactly one load");
3402 // TODO: Support conditional loads for uncountable exits.
3403 assert(VPDT.dominates(Load->getParent(), LatchVPBB) &&
3404 "Uncountable exit condition load is conditional.");
3405 VPInstruction *Ptr = cast<VPInstruction>(Load->getOperand(0));
3406
3407 // Ensure that we are guaranteed to be able to dereference the memory used
3408 // for determining the uncountable exit for the maximum possible number of
3409 // scalar iterations of the loop.
3410 //
3411 // TODO: Support first-faulting loads in cases where we don't know whether
3412 // all possible addresses are dereferenceable.
3413 {
3415 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, TheLoop);
3416 const DataLayout &DL = Plan.getDataLayout();
3417 APInt EltSize(DL.getIndexTypeSizeInBits(Ptr->getScalarType()),
3418 DL.getTypeStoreSize(Load->getScalarType()).getFixedValue());
3420 PtrSCEV, cast<LoadInst>(Load->getUnderlyingInstr())->getAlign(),
3421 PSE.getSE()->getConstant(EltSize), TheLoop, *PSE.getSE(), DT, AC,
3422 &Predicates)) {
3423 reportVectorizationFailure("Early exit loop with side effects contains "
3424 "load used by the exit condition that may "
3425 "fault",
3426 "EarlyExitSideEffectsFaultingLoad", ORE,
3427 TheLoop);
3428 return false;
3429 }
3430 }
3431
3432 // Check for a single GEP for the condition load to see if we can link it to
3433 // a widen IV recipe with a step of 1; we're only interested in contiguous
3434 // accesses for the condition load right now.
3435 auto *IV = cast<VPWidenInductionRecipe>(&HeaderVPBB->front());
3436 if (!match(IV->getStartValue(), m_SpecificInt(0)) ||
3437 !match(IV->getStepValue(), m_SpecificInt(1))) {
3438 reportVectorizationFailure("Early exit loop with side effects contains "
3439 "load used by the exit condition with an "
3440 "unsupported memory access pattern",
3441 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3442 TheLoop);
3443 return false;
3444 }
3445
3447 m_LiveIn(), m_Specific(IV)))) {
3448 reportVectorizationFailure("Early exit loop with side effects contains "
3449 "load used by the exit condition with an "
3450 "unsupported memory access pattern",
3451 "EarlyExitSideEffectsBadLoadAccessPattern", ORE,
3452 TheLoop);
3453 return false;
3454 }
3455
3456 // We want to guarantee that the uncountable exit condition (and the mask
3457 // we will generate from it) are available for all operations in the loop
3458 // that need to be masked. If the condition recipes are not already the first
3459 // recipes in the header after the last phi, move them there.
3460 auto InsertIt = HeaderVPBB->getFirstNonPhi();
3461 while (InsertIt != HeaderVPBB->end() &&
3462 is_contained(ConditionRecipes, &*InsertIt)) {
3463 erase(ConditionRecipes, &*InsertIt);
3464 InsertIt++;
3465 }
3466 for (auto *Recipe : reverse(ConditionRecipes))
3467 Recipe->moveBefore(*HeaderVPBB, InsertIt);
3468
3469 // Create a mask to represent all lanes that fully execute in the vector loop,
3470 // stopping short of any early exit.
3471 VPBuilder MaskBuilder(HeaderVPBB, InsertIt);
3472 VPValue *FirstActive = MaskBuilder.createFirstActiveLane(Cond);
3473 Type *IVScalarTy = IV->getScalarType();
3474 VPValue *Zero = Plan.getZero(IVScalarTy);
3475 FirstActive =
3476 MaskBuilder.createScalarZExtOrTrunc(FirstActive, IVScalarTy, DebugLoc());
3478 {Zero, FirstActive}, DebugLoc(),
3479 "uncountable.exit.mask");
3480
3481 // Convert all other memory operations to use the mask.
3482 for (VPBasicBlock *VPBB : vp_rpo_plain_cfg_loop_body(HeaderVPBB))
3483 for (VPRecipeBase &R : *VPBB)
3484 if (R.mayReadOrWriteMemory() && &R != Load) {
3485 // TODO: Handle conditional memory operations in the loop.
3486 if (!VPDT.dominates(R.getParent(), LatchVPBB)) {
3488 "Early exit loop with side effects contains unsupported "
3489 "conditional memory operations",
3490 "EarlyExitSideEffectsUnsupportedConditionalMemOps", ORE, TheLoop);
3491 return false;
3492 }
3493 cast<VPInstruction>(&R)->addMask(Mask);
3494 }
3495
3496 // Update middle block branch to compare (IV + however many lanes were active)
3497 // against the full trip count, since we may be exiting the vector loop early.
3498 // If we didn't take an early exit, we should get the equivalent of VF from
3499 // the FirstActiveLane.
3500 assert(match(MiddleVPBB->getTerminator(), m_BranchOnCond()) &&
3501 "Expected BranchOnCond terminator for MiddleVPBB");
3502 VPBuilder MiddleBuilder(MiddleVPBB->getTerminator());
3503 VPValue *ScalarIV = MiddleBuilder.createNaryOp(VPInstruction::ExtractLane,
3504 {Zero, IV}, DebugLoc());
3505 VPValue *ExitIV = MiddleBuilder.createAdd(ScalarIV, FirstActive);
3506 VPValue *FullTC =
3507 MiddleBuilder.createICmp(CmpInst::ICMP_EQ, ExitIV, Plan.getTripCount());
3508 MiddleVPBB->getTerminator()->setOperand(0, FullTC);
3509
3510 // Update resume phi in scalar.ph.
3511 VPBasicBlock *ScalarPH = Plan.getScalarPreheader();
3512 auto Phis = ScalarPH->phis();
3513 // TODO: Handle more than one Phi; re-derive from IV.
3514 // TODO: Handle reductions.
3515 if (range_size(Phis) != 1) {
3517 "Early exit loop with side effects contains "
3518 "unsupported reductions, inductions or recurrences",
3519 "EarlyExitSideEffectsReductions", ORE, TheLoop);
3520 return false;
3521 }
3522 VPPhi *ContinueIV = cast<VPPhi>(Phis.begin());
3523 // Make sure we're referring to the same IV.
3524 assert(
3525 match(ContinueIV->getOperand(0),
3527 "Continuing from different IV");
3528 ContinueIV->setOperand(0, ExitIV);
3529 return true;
3530}
3531
3532// Returns true if any non-branch recipe in the loop may have side effects.
3533// For now this relies on LoopVectorizationLegality::isVectorizableEarlyExitLoop
3534// rejecting loops with side effects other than stores.
3535static bool loopMayHaveSideEffects(VPBasicBlock *HeaderVPBB) {
3536 return any_of(vp_rpo_plain_cfg_loop_body(HeaderVPBB), [](VPBasicBlock *VPBB) {
3537 return any_of(*VPBB, [](VPRecipeBase &R) {
3539 });
3540 });
3541}
3542
3544 VPlan &Plan, OptimizationRemarkEmitter *ORE, Loop *TheLoop,
3546 UncountableExitStyle Style) {
3547#ifndef NDEBUG
3548 VPDominatorTree VPDT(Plan);
3549#endif
3550
3551 auto *MiddleVPBB = VPBlockUtils::getPlainCFGMiddleBlock(Plan);
3552 auto [HeaderVPBB, LatchVPBB] = VPBlockUtils::getPlainCFGHeaderAndLatch(Plan);
3553
3554 if (loopMayHaveSideEffects(HeaderVPBB))
3556
3557 // Dereferenceability is checked separately for uncountable exit loops with
3558 // stores, as only the loads contributing to the exit condition need to
3559 // be checked.
3560 if (Style == UncountableExitStyle::ReadOnly &&
3561 !areAllLoadsDereferenceable(HeaderVPBB, TheLoop, PSE, DT, AC)) {
3563 "Auto-vectorization of early exit loops with potentially "
3564 "faulting loads is not supported",
3565 "EarlyExitFaultingLoads", ORE, TheLoop);
3566 return false;
3567 }
3568
3569 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
3571 for (auto [EarlyExitingVPBB, ExitBlock] :
3572 vputils::getEarlyExits(Plan, MiddleVPBB)) {
3573 // The final value of a reduction is computed in the middle block, which is
3574 // only reached when leaving the vector loop via the latch.
3575 // TODO: Support reductions used on early exits.
3576 for (VPRecipeBase &R : ExitBlock->phis()) {
3577 VPValue *ExitV =
3578 cast<VPIRPhi>(&R)->getIncomingValueForBlock(EarlyExitingVPBB);
3579 for (VPReductionPHIRecipe &PhiR :
3580 make_isa_range<VPReductionPHIRecipe>(HeaderVPBB->phis())) {
3581 if (ExitV != PhiR.getBackedgeValue())
3582 continue;
3584 "Found reduction used on an early exit",
3585 "Cannot vectorize early exit loop with reduction used on an "
3586 "early exit",
3587 "ReductionUsedOnEarlyExit", ORE, TheLoop);
3588 return false;
3589 }
3590 }
3591
3592 // Collect condition for this early exit.
3593 VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors()[0];
3594 VPValue *CondOfEarlyExitingVPBB;
3595 [[maybe_unused]] bool Matched =
3596 match(EarlyExitingVPBB->getTerminator(),
3597 m_BranchOnCond(m_VPValue(CondOfEarlyExitingVPBB)));
3598 assert(Matched && "Terminator must be BranchOnCond");
3599
3600 // Insert the MaskedCond in the EarlyExitingVPBB so the predicator adds
3601 // the correct block mask.
3602 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
3603 auto *CondToEarlyExit = EarlyExitingBuilder.createNaryOp(
3605 TrueSucc == ExitBlock
3606 ? CondOfEarlyExitingVPBB
3607 : EarlyExitingBuilder.createNot(CondOfEarlyExitingVPBB));
3608 assert((isa<VPIRValue>(CondOfEarlyExitingVPBB) ||
3609 !VPDT.properlyDominates(EarlyExitingVPBB, LatchVPBB) ||
3610 VPDT.properlyDominates(
3611 CondOfEarlyExitingVPBB->getDefiningRecipe()->getParent(),
3612 LatchVPBB)) &&
3613 "exit condition must dominate the latch");
3614 Exits.push_back({
3615 EarlyExitingVPBB,
3616 ExitBlock,
3617 CondToEarlyExit,
3618 });
3619 }
3620
3621 assert(!Exits.empty() && "must have at least one early exit");
3622 // Sort exits by RPO order to get correct program order. RPO gives a
3623 // topological ordering of the CFG, ensuring upstream exits are checked
3624 // before downstream exits in the dispatch chain.
3626 HeaderVPBB);
3628 for (const auto &[Num, VPB] : enumerate(RPOT))
3629 RPOIdx[VPB] = Num;
3630 llvm::sort(Exits, [&RPOIdx](const EarlyExitInfo &A, const EarlyExitInfo &B) {
3631 return RPOIdx[A.EarlyExitingVPBB] < RPOIdx[B.EarlyExitingVPBB];
3632 });
3633#ifndef NDEBUG
3634 // After RPO sorting, verify that for any pair where one exit dominates
3635 // another, the dominating exit comes first. This is guaranteed by RPO
3636 // (topological order) and is required for the dispatch chain correctness.
3637 for (unsigned I = 0; I + 1 < Exits.size(); ++I)
3638 for (unsigned J = I + 1; J < Exits.size(); ++J)
3639 assert(!VPDT.properlyDominates(Exits[J].EarlyExitingVPBB,
3640 Exits[I].EarlyExitingVPBB) &&
3641 "RPO sort must place dominating exits before dominated ones");
3642#endif
3643
3644 // Build the AnyOf condition for the latch terminator using logical OR
3645 // to avoid poison propagation from later exit conditions when an earlier
3646 // exit is taken.
3647 VPValue *Combined = Exits[0].CondToExit;
3648 for (const EarlyExitInfo &Info : drop_begin(Exits))
3649 Combined = LatchBuilder.createLogicalOr(Combined, Info.CondToExit);
3650 Combined = LatchBuilder.createFreeze(Combined);
3651
3652 // Even though the logical or prevents posion propagation, we need to freeze
3653 // Combined to prevent poisoning the entire AnyOf result:
3654 //
3655 // Exits[0].CondToExit = [0,1,0,0]
3656 // Exits[1].CondToExit = [0,0,p,p]
3657 // Combined = [0,1,p,p]
3658 // freeze(Combined) = [0,1,?,?]
3659 // AnyOf = 1
3660 VPValue *IsAnyExitTaken =
3661 LatchBuilder.createNaryOp(VPInstruction::AnyOf, Combined);
3662
3663 // Create a comparison for the latch exit condition and replace the
3664 // BranchOnCond with a BranchOnTwoConds. The original BranchOnCond's condition
3665 // is used as the latch-exit condition; canonical IV recipes have not been
3666 // introduced yet, so there is no BranchOnCount to derive the condition from.
3667 auto *LatchExitingBranch = cast<VPInstruction>(LatchVPBB->getTerminator());
3668 assert(LatchExitingBranch->getOpcode() == VPInstruction::BranchOnCond &&
3669 "Unexpected terminator");
3670 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
3671 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
3672 LatchExitingBranch->eraseFromParent();
3673 LatchBuilder.setInsertPoint(LatchVPBB);
3675 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
3676 LatchVPBB->clearSuccessors();
3677
3679 // If handling the exiting lane in the scalar loop, combine the exit
3680 // conditions into a single BranchOnCond.
3681 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
3682 MiddleVPBB->clearPredecessors();
3683 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
3684 return handleUncountableExitsWithSideEffects(Plan, Exits, HeaderVPBB,
3685 LatchVPBB, MiddleVPBB, ORE,
3686 TheLoop, PSE, DT, AC);
3687 }
3688
3689 // Create the vector.early.exit blocks.
3690 SmallVector<VPBasicBlock *> VectorEarlyExitVPBBs(Exits.size());
3691 for (unsigned Idx = 0; Idx != Exits.size(); ++Idx) {
3692 Twine BlockSuffix = Exits.size() == 1 ? "" : Twine(".") + Twine(Idx);
3693 VPBasicBlock *VectorEarlyExitVPBB =
3694 Plan.createVPBasicBlock("vector.early.exit" + BlockSuffix);
3695 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
3696 }
3697
3698 // Create the dispatch block (or reuse the single exit block if only one
3699 // exit). The dispatch block computes the first active lane of the combined
3700 // condition and, for multiple exits, chains through conditions to determine
3701 // which exit to take.
3702 VPBasicBlock *DispatchVPBB =
3703 Exits.size() == 1 ? VectorEarlyExitVPBBs[0]
3704 : Plan.createVPBasicBlock("vector.early.exit.check");
3705 DispatchVPBB->setPredecessors({LatchVPBB});
3706 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
3707 VPBuilder DispatchBuilder(DispatchVPBB, DispatchVPBB->begin());
3708 VPValue *FirstActiveLane = DispatchBuilder.createFirstActiveLane(
3709 {Combined}, DebugLoc::getUnknown(), "first.active.lane");
3710
3711 // For each early exit, disconnect the original exiting block
3712 // (early.exiting.I) from the exit block (ir-bb<exit.I>) and route through a
3713 // new vector.early.exit block. Update ir-bb<exit.I>'s phis to extract their
3714 // values at the first active lane:
3715 //
3716 // Input:
3717 // early.exiting.I:
3718 // ...
3719 // EMIT branch-on-cond vp<%cond.I>
3720 // Successor(s): in.loop.succ, ir-bb<exit.I>
3721 //
3722 // ir-bb<exit.I>:
3723 // IR %phi = phi [ vp<%incoming.I>, early.exiting.I ], ...
3724 //
3725 // Output:
3726 // early.exiting.I:
3727 // ...
3728 // Successor(s): in.loop.succ
3729 //
3730 // vector.early.exit.I:
3731 // EMIT vp<%exit.val> = extract-lane vp<%first.lane>, vp<%incoming.I>
3732 // Successor(s): ir-bb<exit.I>
3733 //
3734 // ir-bb<exit.I>:
3735 // IR %phi = phi ... (extra operand: vp<%exit.val> from
3736 // vector.early.exit.I)
3737 //
3738 for (auto [Exit, VectorEarlyExitVPBB] :
3739 zip_equal(Exits, VectorEarlyExitVPBBs)) {
3740 auto &[EarlyExitingVPBB, EarlyExitVPBB, _] = Exit;
3741 // Adjust the phi nodes in EarlyExitVPBB.
3742 // 1. remove incoming values from EarlyExitingVPBB,
3743 // 2. extract the incoming value at FirstActiveLane
3744 // 3. add back the extracts as last operands for the phis
3745 // Then adjust the CFG, removing the edge between EarlyExitingVPBB and
3746 // EarlyExitVPBB and adding a new edge between VectorEarlyExitVPBB and
3747 // EarlyExitVPBB. The extracts at FirstActiveLane are now the incoming
3748 // values from VectorEarlyExitVPBB.
3749 for (VPRecipeBase &R : EarlyExitVPBB->phis()) {
3750 auto *ExitIRI = cast<VPIRPhi>(&R);
3751 VPValue *IncomingVal =
3752 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
3753 VPValue *NewIncoming = IncomingVal;
3754 if (!isa<VPIRValue>(IncomingVal)) {
3755 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
3756 NewIncoming = EarlyExitBuilder.createNaryOp(
3757 VPInstruction::ExtractLane, {FirstActiveLane, IncomingVal},
3758 DebugLoc::getUnknown(), "early.exit.value");
3759 }
3760 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
3761 ExitIRI->addIncoming(NewIncoming);
3762 }
3763
3764 EarlyExitingVPBB->getTerminator()->eraseFromParent();
3765 VPBlockUtils::disconnectBlocks(EarlyExitingVPBB, EarlyExitVPBB);
3766 VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, EarlyExitVPBB);
3767 }
3768
3769 // Chain through exits: for each exit, check if its condition is true at
3770 // the first active lane. If so, take that exit; otherwise, try the next.
3771 // The last exit needs no check since it must be taken if all others fail.
3772 //
3773 // For 3 exits (cond.0, cond.1, cond.2), this creates:
3774 //
3775 // latch:
3776 // ...
3777 // EMIT vp<%combined> = logical-or vp<%cond.0>, vp<%cond.1>, vp<%cond.2>
3778 // EMIT vp<%combined.freeze> = freeze vp<%combined>
3779 // ...
3780 //
3781 // vector.early.exit.check:
3782 // EMIT vp<%first.lane> = first-active-lane vp<%combined.freeze>
3783 // EMIT vp<%at.cond.0> = extract-lane vp<%first.lane>, vp<%cond.0>
3784 // EMIT branch-on-cond vp<%at.cond.0>
3785 // Successor(s): vector.early.exit.0, vector.early.exit.check.0
3786 //
3787 // vector.early.exit.check.0:
3788 // EMIT vp<%at.cond.1> = extract-lane vp<%first.lane>, vp<%cond.1>
3789 // EMIT branch-on-cond vp<%at.cond.1>
3790 // Successor(s): vector.early.exit.1, vector.early.exit.2
3791 VPBasicBlock *CurrentBB = DispatchVPBB;
3792 for (auto [I, Exit] : enumerate(ArrayRef(Exits).drop_back())) {
3793 VPValue *LaneVal = DispatchBuilder.createNaryOp(
3794 VPInstruction::ExtractLane, {FirstActiveLane, Exit.CondToExit},
3795 DebugLoc::getUnknown(), "exit.cond.at.lane");
3796
3797 // For the last dispatch, branch directly to the last exit on false;
3798 // otherwise, create a new check block.
3799 bool IsLastDispatch = (I + 2 == Exits.size());
3800 VPBasicBlock *FalseBB =
3801 IsLastDispatch ? VectorEarlyExitVPBBs.back()
3802 : Plan.createVPBasicBlock(
3803 Twine("vector.early.exit.check.") + Twine(I));
3804
3805 DispatchBuilder.createNaryOp(VPInstruction::BranchOnCond, {LaneVal});
3806 CurrentBB->setSuccessors({VectorEarlyExitVPBBs[I], FalseBB});
3807 VectorEarlyExitVPBBs[I]->setPredecessors({CurrentBB});
3808 FalseBB->setPredecessors({CurrentBB});
3809
3810 CurrentBB = FalseBB;
3811 DispatchBuilder.setInsertPoint(CurrentBB);
3812 }
3813
3814 return true;
3815}
3816
3817/// This function tries convert extended in-loop reductions to
3818/// VPExpressionRecipe and clamp the \p Range if it is beneficial and
3819/// valid. The created recipe must be decomposed to its constituent
3820/// recipes before execution.
3821static VPExpressionRecipe *
3823 VFRange &Range) {
3824 Type *RedTy = Red->getScalarType();
3825 VPValue *VecOp = Red->getVecOp();
3826
3827 // We don't handle partial reductions here.
3828 if (Red->isPartialReduction())
3829 return nullptr;
3830
3831 // Clamp the range if using extended-reduction is profitable.
3832 auto IsExtendedRedValidAndClampRange =
3833 [&](unsigned Opcode, Instruction::CastOps ExtOpc, Type *SrcTy) -> bool {
3835 [&](ElementCount VF) {
3836 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3838
3840 InstructionCost ExtCost =
3841 cast<VPWidenCastRecipe>(VecOp)->computeCost(VF, Ctx);
3842 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3843
3844 assert(!RedTy->isFloatingPointTy() &&
3845 "getExtendedReductionCost only supports integer types");
3846 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
3847 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
3848 Red->getFastMathFlagsOrNone(), CostKind);
3849 return ExtRedCost.isValid() && ExtRedCost < ExtCost + RedCost;
3850 },
3851 Range);
3852 };
3853
3854 VPValue *A;
3855 // Match reduce(ext)).
3857 IsExtendedRedValidAndClampRange(
3858 RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()),
3859 cast<VPWidenCastRecipe>(VecOp)->getOpcode(), A->getScalarType()))
3860 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
3861
3862 return nullptr;
3863}
3864
3866
3870
3871/// Returns true if the narrow \p Mul in ext(mul(ext(A), ext(B))) or
3872/// ext(mul(ext(A), C)) cannot wrap. The kind of the inner extends selects
3873/// whether nuw (zext) or nsw (sext) is required on \p Mul.
3875 auto *LHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
3876 auto *RHS = dyn_cast<VPWidenCastRecipe>(Mul->getOperand(1));
3877 Type *LHSSrcTy = LHS->getOperand(0)->getScalarType();
3878 // A constant RHS must fit in the source type of the LHS.
3879 Type *RHSSrcTy = RHS ? RHS->getOperand(0)->getScalarType() : LHSSrcTy;
3881 if (Mul->getScalarType()->getScalarSizeInBits() >=
3882 LHSSrcTy->getScalarSizeInBits() + RHSSrcTy->getScalarSizeInBits())
3883 return true;
3884 if (ExtKind == ExtendKind::PR_ZeroExtend)
3885 return Mul->hasNoUnsignedWrap();
3886 return ExtKind == ExtendKind::PR_SignExtend && Mul->hasNoSignedWrap();
3887}
3888
3889/// This function tries convert extended in-loop reductions to
3890/// VPExpressionRecipe and clamp the \p Range if it is beneficial
3891/// and valid. The created VPExpressionRecipe must be decomposed to its
3892/// constituent recipes before execution. Patterns of the
3893/// VPExpressionRecipe:
3894/// reduce.add(mul(...)),
3895/// reduce.add(mul(ext(A), ext(B))),
3896/// reduce.add(ext(mul(ext(A), ext(B)))).
3897/// reduce.fadd(fmul(ext(A), ext(B)))
3898static VPExpressionRecipe *
3900 VPCostContext &Ctx, VFRange &Range) {
3901 unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());
3902 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3903 Opcode != Instruction::FAdd)
3904 return nullptr;
3905
3906 // We don't handle partial reductions here.
3907 if (Red->isPartialReduction())
3908 return nullptr;
3909
3910 Type *RedTy = Red->getScalarType();
3911
3912 // Clamp the range if using multiply-accumulate-reduction is profitable.
3913 auto IsMulAccValidAndClampRange =
3915 VPWidenCastRecipe *OuterExt) -> bool {
3917 [&](ElementCount VF) {
3919 Type *SrcTy = Ext0 ? Ext0->getOperand(0)->getScalarType() : RedTy;
3920 InstructionCost MulAccCost;
3921
3922 // getMulAccReductionCost for in-loop reductions does not support
3923 // mixed or floating-point extends.
3924 if (Ext0 && Ext1 &&
3925 (Ext0->getOpcode() != Ext1->getOpcode() ||
3926 Ext0->getOpcode() == Instruction::CastOps::FPExt))
3927 return false;
3928
3929 bool IsZExt =
3930 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
3931 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
3932 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
3933 SrcVecTy, CostKind);
3934
3935 InstructionCost MulCost = Mul->computeCost(VF, Ctx);
3936 InstructionCost RedCost = Red->computeCost(VF, Ctx);
3937 InstructionCost ExtCost = 0;
3938 if (Ext0)
3939 ExtCost += Ext0->computeCost(VF, Ctx);
3940 if (Ext1)
3941 ExtCost += Ext1->computeCost(VF, Ctx);
3942 if (OuterExt)
3943 ExtCost += OuterExt->computeCost(VF, Ctx);
3944
3945 return MulAccCost.isValid() &&
3946 MulAccCost < ExtCost + MulCost + RedCost;
3947 },
3948 Range);
3949 };
3950
3951 VPValue *VecOp = Red->getVecOp();
3952 VPRecipeBase *Sub = nullptr;
3953 VPValue *A, *B;
3954 VPValue *Tmp = nullptr;
3955
3956 if (RedTy->isFloatingPointTy())
3957 return nullptr;
3958
3959 // Sub reductions could have a sub between the add reduction and vec op.
3960 if (match(VecOp, m_Sub(m_ZeroInt(), m_VPValue(Tmp)))) {
3961 Sub = VecOp->getDefiningRecipe();
3962 VecOp = Tmp;
3963 }
3964
3965 // If ValB is a constant and can be safely extended, truncate it to the same
3966 // type as ExtA's operand, then extend it to the same type as ExtA. This
3967 // creates two uniform extends that can more easily be matched by the rest of
3968 // the bundling code. The ExtB reference, ValB and operand 1 of Mul are all
3969 // replaced with the new extend of the constant.
3970 auto ExtendAndReplaceConstantOp = [](VPWidenCastRecipe *ExtA,
3971 VPWidenCastRecipe *&ExtB, VPValue *&ValB,
3972 VPWidenRecipe *Mul) {
3973 if (!ExtA || ExtB || !isa<VPIRValue>(ValB))
3974 return;
3975 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
3976 Instruction::CastOps ExtOpc = ExtA->getOpcode();
3977 const APInt *Const;
3978 if (!match(ValB, m_APInt(Const)) ||
3980 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
3981 return;
3982 // The truncate ensures that the type of each extended operand is the
3983 // same, and it's been proven that the constant can be extended from
3984 // NarrowTy safely. Necessary since ExtA's extended operand would be
3985 // e.g. an i8, while the const will likely be an i32. This will be
3986 // elided by later optimisations.
3987 VPBuilder Builder(Mul);
3988 auto *Trunc =
3989 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
3990 Type *WideTy = ExtA->getScalarType();
3991 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
3992 Mul->setOperand(1, ExtB);
3993 };
3994
3995 // Try to match reduce.add(mul(...)).
3996 if (match(VecOp, m_Mul(m_VPValue(A), m_VPValue(B)))) {
3997 auto *RecipeA = dyn_cast<VPWidenCastRecipe>(A);
3998 auto *RecipeB = dyn_cast<VPWidenCastRecipe>(B);
3999 auto *Mul = cast<VPWidenRecipe>(VecOp);
4000
4001 // Convert reduce.add(mul(ext, const)) to reduce.add(mul(ext, ext(const)))
4002 ExtendAndReplaceConstantOp(RecipeA, RecipeB, B, Mul);
4003
4004 // Match reduce.add/sub(mul(ext, ext)).
4005 if (RecipeA && RecipeB && match(RecipeA, m_ZExtOrSExt(m_VPValue())) &&
4006 match(RecipeB, m_ZExtOrSExt(m_VPValue())) &&
4007 IsMulAccValidAndClampRange(Mul, RecipeA, RecipeB, nullptr)) {
4008 if (Sub)
4009 return new VPExpressionRecipe(RecipeA, RecipeB, Mul,
4010 cast<VPWidenRecipe>(Sub), Red);
4011 return new VPExpressionRecipe(RecipeA, RecipeB, Mul, Red);
4012 }
4013 // TODO: Add an expression type for this variant with a negated mul
4014 if (!Sub && IsMulAccValidAndClampRange(Mul, nullptr, nullptr, nullptr))
4015 return new VPExpressionRecipe(Mul, Red);
4016 }
4017 // TODO: Add an expression type for negated versions of other expression
4018 // variants.
4019 if (Sub)
4020 return nullptr;
4021
4022 // Match reduce.add(ext(mul(A, B))).
4023 if (match(VecOp, m_ZExtOrSExt(m_Mul(m_VPValue(A), m_VPValue(B))))) {
4024 auto *Ext = cast<VPWidenCastRecipe>(VecOp);
4025 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
4026 auto *Ext0 = dyn_cast<VPWidenCastRecipe>(A);
4027 auto *Ext1 = dyn_cast<VPWidenCastRecipe>(B);
4028
4029 // reduce.add(ext(mul(ext, const)))
4030 // -> reduce.add(ext(mul(ext, ext(const))))
4031 ExtendAndReplaceConstantOp(Ext0, Ext1, B, Mul);
4032
4033 // reduce.add(ext(mul(ext(A), ext(B))))
4034 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
4035 // The inner extends must either have the same opcode as the outer extend or
4036 // be the same sext, in which case the multiply cannot result in a negative
4037 // value without wrapping. If the narrow mul cannot wrap, the outer extend
4038 // can be folded away by doing wider extends for the operands of the mul.
4039 if (Ext0 && Ext1 &&
4040 (Ext->getOpcode() == Ext0->getOpcode() ||
4041 (Ext0 == Ext1 && Ext0->getOpcode() == Instruction::SExt)) &&
4042 Ext0->getOpcode() == Ext1->getOpcode() && Mul->hasOneUse() &&
4044 IsMulAccValidAndClampRange(Mul, Ext0, Ext1, Ext)) {
4045 auto *NewExt0 = new VPWidenCastRecipe(
4046 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(), nullptr,
4047 *Ext0, *Ext0, Ext0->getDebugLoc());
4048 NewExt0->insertBefore(Ext0);
4049
4050 VPWidenCastRecipe *NewExt1 = NewExt0;
4051 if (Ext0 != Ext1) {
4052 NewExt1 = new VPWidenCastRecipe(Ext1->getOpcode(), Ext1->getOperand(0),
4053 Ext->getScalarType(), nullptr, *Ext1,
4054 *Ext1, Ext1->getDebugLoc());
4055 NewExt1->insertBefore(Ext1);
4056 }
4057 auto *NewMul = Mul->cloneWithOperands({NewExt0, NewExt1});
4058 NewMul->insertBefore(Mul);
4059 Ext->replaceAllUsesWith(NewMul);
4060 Ext->eraseFromParent();
4061 Mul->eraseFromParent();
4062 return new VPExpressionRecipe(NewExt0, NewExt1, NewMul, Red);
4063 }
4064 }
4065 return nullptr;
4066}
4067
4068/// This function tries to create abstract recipes from the reduction recipe for
4069/// following optimizations and cost estimation.
4071 VPCostContext &Ctx,
4072 VFRange &Range) {
4073 // Creation of VPExpressions for partial reductions is entirely handled in
4074 // transformToPartialReduction.
4075 if (Red->isPartialReduction())
4076 return;
4077
4078 VPExpressionRecipe *AbstractR = nullptr;
4079 auto IP = std::next(Red->getIterator());
4080 auto *VPBB = Red->getParent();
4081 if (auto *MulAcc = tryToMatchAndCreateMulAccumulateReduction(Red, Ctx, Range))
4082 AbstractR = MulAcc;
4083 else if (auto *ExtRed = tryToMatchAndCreateExtendedReduction(Red, Ctx, Range))
4084 AbstractR = ExtRed;
4085 // Cannot create abstract inloop reduction recipes.
4086 if (!AbstractR)
4087 return;
4088
4089 AbstractR->insertBefore(*VPBB, IP);
4090 Red->replaceAllUsesWith(AbstractR);
4091}
4092
4102
4103// Collect common metadata from a group of replicate recipes by intersecting
4104// metadata from all recipes in the group.
4106 VPIRMetadata CommonMetadata = *Recipes.front();
4107 for (VPReplicateRecipe *Recipe : drop_begin(Recipes))
4108 CommonMetadata.intersect(*Recipe);
4109 // The recipe using the common metadata is not predicated, so it does not
4110 // share the group's execution frequency.
4111 CommonMetadata.clearExecutionFrequency();
4112 return CommonMetadata;
4113}
4114
4115template <unsigned Opcode>
4119 const Loop *L) {
4120 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
4121 "Only Load and Store opcodes supported");
4122
4123 // For each address, collect operations with the same or complementary masks.
4126 Plan, PSE, L,
4127 [](VPReplicateRecipe *RepR) { return RepR->isPredicated(); });
4128 for (auto Recipes : Groups) {
4129 if (Recipes.size() < 2)
4130 continue;
4131
4133 "Expected all recipes in group to have the same load-store type");
4134
4135 // Collect groups with the same or complementary masks.
4136 for (VPReplicateRecipe *&RecipeI : Recipes) {
4137 if (!RecipeI)
4138 continue;
4139
4140 VPValue *MaskI = RecipeI->getMask();
4142 Group.push_back(RecipeI);
4143 RecipeI = nullptr;
4144
4145 // Find all operations with the same or complementary masks.
4146 bool HasComplementaryMask = false;
4147 for (VPReplicateRecipe *&RecipeJ : Recipes) {
4148 if (!RecipeJ)
4149 continue;
4150
4151 VPValue *MaskJ = RecipeJ->getMask();
4152 // Check if any operation in the group has a complementary mask with
4153 // another, that is M1 == NOT(M2) or M2 == NOT(M1).
4154 HasComplementaryMask |= match(MaskI, m_Not(m_Specific(MaskJ))) ||
4155 match(MaskJ, m_Not(m_Specific(MaskI)));
4156 Group.push_back(RecipeJ);
4157 RecipeJ = nullptr;
4158 }
4159
4160 if (HasComplementaryMask) {
4161 assert(Group.size() >= 2 && "must have at least 2 entries");
4162 AllGroups.push_back(std::move(Group));
4163 }
4164 }
4165 }
4166
4167 return AllGroups;
4168}
4169
4170// Find the recipe with minimum alignment in the group.
4171template <typename InstType>
4172static VPReplicateRecipe *
4174 return *min_element(Group, [](VPReplicateRecipe *A, VPReplicateRecipe *B) {
4175 return cast<InstType>(A->getUnderlyingInstr())->getAlign() <
4176 cast<InstType>(B->getUnderlyingInstr())->getAlign();
4177 });
4178}
4179
4182 const Loop *L) {
4183 auto Groups =
4185 if (Groups.empty())
4186 return;
4187
4188 // Process each group of loads.
4189 for (auto &Group : Groups) {
4190 // Try to use the earliest (most dominating) load to replace all others.
4191 VPReplicateRecipe *EarliestLoad = Group[0];
4192 VPBasicBlock *FirstBB = EarliestLoad->getParent();
4193 VPBasicBlock *LastBB = Group.back()->getParent();
4194
4195 // Check that the load doesn't alias with stores between first and last.
4196 auto LoadLoc = vputils::getMemoryLocation(*EarliestLoad);
4197 if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck(*LoadLoc, FirstBB, LastBB))
4198 continue;
4199
4200 // Collect common metadata from all loads in the group.
4201 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
4202
4203 // Find the load with minimum alignment to use.
4204 auto *LoadWithMinAlign = findRecipeWithMinAlign<LoadInst>(Group);
4205
4206 bool IsSingleScalar = EarliestLoad->isSingleScalar();
4207 assert(all_of(Group,
4208 [IsSingleScalar](VPReplicateRecipe *R) {
4209 return R->isSingleScalar() == IsSingleScalar;
4210 }) &&
4211 "all members in group must agree on IsSingleScalar");
4212
4213 // Create an unpredicated version of the earliest load with common
4214 // metadata.
4215 auto *UnpredicatedLoad = new VPReplicateRecipe(
4216 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
4217 IsSingleScalar, /*Mask=*/nullptr, *EarliestLoad, CommonMetadata);
4218
4219 UnpredicatedLoad->insertBefore(EarliestLoad);
4220
4221 // Replace all loads in the group with the unpredicated load.
4222 for (VPReplicateRecipe *Load : Group) {
4223 Load->replaceAllUsesWith(UnpredicatedLoad);
4224 Load->eraseFromParent();
4225 }
4226 }
4227}
4228
4229static bool
4231 PredicatedScalarEvolution &PSE, const Loop &L) {
4232 auto StoreLoc = vputils::getMemoryLocation(*StoresToSink.front());
4233 if (!StoreLoc || !StoreLoc->AATags.Scope)
4234 return false;
4235
4236 // When sinking a group of stores, all members of the group alias each other.
4237 // Skip them during the alias checks.
4238 VPBasicBlock *FirstBB = StoresToSink.front()->getParent();
4239 VPBasicBlock *LastBB = StoresToSink.back()->getParent();
4240 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
4241 return canHoistOrSinkWithNoAliasCheck(*StoreLoc, FirstBB, LastBB, SinkInfo);
4242}
4243
4246 const Loop *L) {
4247 auto Groups =
4249 if (Groups.empty())
4250 return;
4251
4252 for (auto &Group : Groups) {
4253 if (!canSinkStoreWithNoAliasCheck(Group, PSE, *L))
4254 continue;
4255
4256 // Use the last (most dominated) store's location for the unconditional
4257 // store.
4258 VPReplicateRecipe *LastStore = Group.back();
4259 VPBasicBlock *InsertBB = LastStore->getParent();
4260
4261 // Collect common alias metadata from all stores in the group.
4262 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
4263
4264 // Build select chain for stored values.
4265 VPValue *SelectedValue = Group[0]->getOperand(0);
4266 VPBuilder Builder(InsertBB, LastStore->getIterator());
4267
4268 bool IsSingleScalar = Group[0]->isSingleScalar();
4269 for (unsigned I = 1; I < Group.size(); ++I) {
4270 assert(IsSingleScalar == Group[I]->isSingleScalar() &&
4271 "all members in group must agree on IsSingleScalar");
4272 VPValue *Mask = Group[I]->getMask();
4273 VPValue *Value = Group[I]->getOperand(0);
4274 SelectedValue = Builder.createSelect(
4275 Mask, Value, SelectedValue, Group[I]->getDebugLoc(), "",
4276 VPIRFlags::getDefaultFlags(Instruction::Select,
4277 Value->getScalarType()));
4278 }
4279
4280 // Find the store with minimum alignment to use.
4281 auto *StoreWithMinAlign = findRecipeWithMinAlign<StoreInst>(Group);
4282
4283 // Create unconditional store with selected value and common metadata.
4284 auto *UnpredicatedStore = new VPReplicateRecipe(
4285 StoreWithMinAlign->getUnderlyingInstr(),
4286 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
4287 /*Mask=*/nullptr, *LastStore, CommonMetadata);
4288 UnpredicatedStore->insertBefore(*InsertBB, LastStore->getIterator());
4289
4290 // Remove all predicated stores from the group.
4291 for (VPReplicateRecipe *Store : Group)
4292 Store->eraseFromParent();
4293 }
4294}
4295
4297 unsigned UF,
4298 const TargetTransformInfo &TTI) {
4299 assert(UF > 1 && "Expected plan to have an UF > 1");
4300
4301 auto m_ContiguousVecPtr = m_VecPtr(m_VPValue(), m_One());
4304 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
4305 VPValue *StoredValue = nullptr;
4306 if (!match(&R, m_WidenLoad(m_ContiguousVecPtr)) &&
4307 !match(&R, m_WidenStore(m_ContiguousVecPtr, m_VPValue(StoredValue))))
4308 continue;
4309
4310 auto *MemOp = cast<VPWidenMemoryRecipe>(&R);
4311 assert(MemOp->isConsecutive() && "Expected consecutive load/store");
4312
4313 // TODO: Support masked loads/stores. This requires widening the header
4314 // mask to the same factor as the memory operation.
4315 assert(!MemOp->isMasked() && "Masked accesses are not supported yet");
4316
4317 Type *AccessType = StoredValue ? StoredValue->getScalarType()
4318 : R.getVPSingleValue()->getScalarType();
4319 bool IsStore = isa<VPWidenStoreRecipe>(MemOp->getAsRecipe());
4320 std::optional<Instruction::CastOps> CastHint;
4321 VPUser *MaybeCast = IsStore ? StoredValue->getDefiningRecipe()
4322 : R.getVPSingleValue()->getSingleUser();
4323 if (auto *Cast = dyn_cast_if_present<VPWidenCastRecipe>(MaybeCast))
4324 CastHint = Cast->getOpcode();
4325
4326 VectorType *VectorAccessType = VectorType::get(AccessType, VF);
4327 if (!TTI.hasMultiVectorLoadStore(
4328 /*NumVectors=*/UF, TargetTransformInfo::MaskSource::None,
4329 VectorAccessType, IsStore, CastHint))
4330 continue;
4331
4332 DebugLoc DL = R.getDebugLoc();
4333 VPValue *Ptr = MemOp->getAddr();
4334 VPValue *Align = Plan.getConstantInt(64, MemOp->getAlign().value());
4335 VPValue *Multiplier = Plan.getConstantInt(64, 1);
4336
4337 VPBuilder Builder(VPBB, R.getIterator());
4338 if (IsStore) {
4339 VPValue *WideStoredValue = Builder.createNaryOp(
4340 VPInstruction::ConcatVectors, {StoredValue}, DL);
4341 Builder.createNaryOp(VPInstruction::WideVectorStore,
4342 {Multiplier, Ptr, Align, WideStoredValue}, nullptr,
4343 {}, *MemOp, R.getDebugLoc());
4344 } else {
4345 VPValue *OldLoad = R.getVPSingleValue();
4346 VPValue *Load = Builder.createNaryOp(
4347 VPInstruction::WideVectorLoad, {Multiplier, Ptr, Align}, nullptr,
4348 {}, *MemOp, R.getDebugLoc(), "", OldLoad->getScalarType());
4349 VPValue *Extract =
4350 Builder.createNaryOp(VPInstruction::ExtractVectorForPart,
4351 {Load, Plan.getConstantInt(64, 0)}, DL);
4352 OldLoad->replaceAllUsesWith(Extract);
4353 }
4354
4355 R.eraseFromParent();
4356 }
4357 }
4358}
4359
4360/// Returns true if \p V is VPWidenLoadRecipe or VPInterleaveRecipe that can be
4361/// converted to a narrower recipe. \p V is used by a wide recipe that feeds a
4362/// store interleave group at index \p Idx, \p WideMember0 is the recipe feeding
4363/// the same interleave group at index 0. A VPWidenLoadRecipe can be narrowed to
4364/// an index-independent load if it feeds all wide ops at all indices (\p OpV
4365/// must be the operand at index \p OpIdx for both the recipe at lane 0, \p
4366/// WideMember0). A VPInterleaveRecipe can be narrowed to a wide load, if \p V
4367/// is defined at \p Idx of a load interleave group.
4368/// A live-in or recipe defined outside the loop region can be converted, if it
4369/// is the same across all lanes, or we can create a BuildVector for it.
4370static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx,
4371 VPValue *OpV, unsigned Idx, bool IsScalable) {
4372 VPValue *Member0Op = WideMember0->getOperand(OpIdx);
4373 if (Member0Op->isDefinedOutsideLoopRegions()) {
4374 // Operand matches Member0, broadcast across all fields for both live-ins
4375 // and recipes.
4376 if (Member0Op == OpV)
4377 return true;
4378 // Otherwise distinct per-field VPValues are assembled into a BuildVector.
4379 return !IsScalable && OpV->isDefinedOutsideLoopRegions() &&
4380 OpV->getScalarType() == Member0Op->getScalarType();
4381 }
4382 VPRecipeBase *Member0OpR = Member0Op->getDefiningRecipe();
4383 if (auto *W = dyn_cast<VPWidenLoadRecipe>(Member0OpR))
4384 // For scalable VFs, the narrowed plan processes vscale iterations at once,
4385 // so a shared wide load cannot be narrowed to a uniform scalar; bail out.
4386 return !IsScalable && !W->getMask() && W->isConsecutive() &&
4387 Member0Op == OpV;
4388 if (auto *IR = dyn_cast<VPInterleaveRecipe>(Member0OpR))
4389 return IR->getInterleaveGroup()->isFull() && IR->getVPValue(Idx) == OpV;
4390 return false;
4391}
4392
4393/// Returns true if the wide recipes in \p Ops and their operand trees can be
4394/// narrowed. \p FirstMembersOf maps each in-loop value to the first member
4395/// list it was seen in, across all store groups.
4396static bool
4398 DenseMap<VPValue *, SmallVector<VPValue *>> &FirstMembersOf) {
4400 auto *WideMember0 = dyn_cast<VPRecipeWithIRFlags>(Ops[0]);
4401 if (!WideMember0)
4402 return false;
4403 for (VPValue *V : Ops) {
4405 return false;
4406 auto *R = cast<VPRecipeWithIRFlags>(V);
4407 if (vputils::getOpcode(R) != vputils::getOpcode(WideMember0))
4408 return false;
4409 if (R->getScalarType() != WideMember0->getScalarType())
4410 return false;
4411 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
4412 return false;
4413 }
4414
4415 // The first member is narrowed in place using the other members' operands.
4416 // Bail out if a value is the first member of one list and also part of a
4417 // different list.
4418 for (VPValue *V : Ops) {
4419 if (V->isDefinedOutsideLoopRegions())
4420 continue;
4421 auto [It, Inserted] = FirstMembersOf.try_emplace(V, Ops);
4422 if (!Inserted && (It->second.front() == V || V == WideMember0) &&
4423 !equal(It->second, Ops))
4424 return false;
4425 }
4426
4427 for (unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
4429 for (VPValue *Op : Ops)
4430 OpsI.push_back(Op->getDefiningRecipe()->getOperand(Idx));
4431
4432 if (canNarrowOps(OpsI, IsScalable, FirstMembersOf))
4433 continue;
4434
4435 if (any_of(enumerate(OpsI), [WideMember0, Idx, IsScalable](const auto &P) {
4436 const auto &[OpIdx, OpV] = P;
4437 return !canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
4438 }))
4439 return false;
4440 }
4441
4442 return true;
4443}
4444
4445/// Returns VF from \p VFs if \p IR is a full interleave group with factor and
4446/// number of members both equal to VF. The interleave group must also access
4447/// the full vector width.
4448static std::optional<ElementCount>
4451 const TargetTransformInfo &TTI) {
4452 if (!InterleaveR || InterleaveR->getMask())
4453 return std::nullopt;
4454
4455 Type *GroupElementTy = nullptr;
4456 if (InterleaveR->getStoredValues().empty()) {
4457 GroupElementTy = InterleaveR->getVPValue(0)->getScalarType();
4458 if (!all_of(InterleaveR->definedValues(), [GroupElementTy](VPValue *Op) {
4459 return Op->getScalarType() == GroupElementTy;
4460 }))
4461 return std::nullopt;
4462 } else {
4463 GroupElementTy = InterleaveR->getStoredValues()[0]->getScalarType();
4464 if (!all_of(InterleaveR->getStoredValues(), [GroupElementTy](VPValue *Op) {
4465 return Op->getScalarType() == GroupElementTy;
4466 }))
4467 return std::nullopt;
4468 }
4469
4470 auto IG = InterleaveR->getInterleaveGroup();
4471 if (IG->getFactor() != IG->getNumMembers() || IG->isReverse())
4472 return std::nullopt;
4473
4474 auto GetVectorBitWidthForVF = [&TTI](ElementCount VF) {
4475 TypeSize Size = TTI.getRegisterBitWidth(
4478 assert(Size.isScalable() == VF.isScalable() &&
4479 "if Size is scalable, VF must be scalable and vice versa");
4480 return Size.getKnownMinValue();
4481 };
4482
4483 for (ElementCount VF : VFs) {
4484 unsigned MinVal = VF.getKnownMinValue();
4485 unsigned GroupSize = GroupElementTy->getScalarSizeInBits() * MinVal;
4486 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
4487 return {VF};
4488 }
4489 return std::nullopt;
4490}
4491
4492/// Returns true if \p VPValue is a narrow VPValue.
4493static bool isAlreadyNarrow(VPValue *VPV) {
4494 if (isa<VPIRValue>(VPV))
4495 return true;
4496 auto *RepR = dyn_cast<VPReplicateRecipe>(VPV);
4497 return RepR && RepR->isSingleScalar();
4498}
4499
4500// Convert the wide recipes defining the VPValues in \p Members feeding an
4501// interleave group to a single narrow variant. The first member is reused as
4502// the narrowed recipe. BuildVectors for live-in operands are inserted into \p
4503// Preheader.
4505 SmallPtrSetImpl<VPValue *> &NarrowedOps,
4506 VPBasicBlock *Preheader) {
4507 VPValue *V = Members.front();
4508 if (NarrowedOps.contains(V))
4509 return V;
4510
4511 if (V->isDefinedOutsideLoopRegions()) {
4512 assert(all_of(Members,
4513 [V](VPValue *M) {
4514 return M->isDefinedOutsideLoopRegions() &&
4515 M->getScalarType() == V->getScalarType();
4516 }) &&
4517 "expected distinct loop-invariant values of matching scalar type");
4518 auto *BV = new VPInstruction(VPInstruction::BuildVector, Members);
4519 Preheader->appendRecipe(BV);
4520 NarrowedOps.insert(BV);
4521 return BV;
4522 }
4523
4524 if (isAlreadyNarrow(V))
4525 return V;
4526
4527 VPRecipeBase *R = V->getDefiningRecipe();
4529 auto *WideMember0 = cast<VPRecipeWithIRFlags>(R);
4530 for (VPValue *Member : Members.drop_front())
4531 WideMember0->intersectFlags(*cast<VPRecipeWithIRFlags>(Member));
4532 for (unsigned Idx = 0, E = WideMember0->getNumOperands(); Idx != E; ++Idx) {
4534 for (VPValue *Member : Members)
4535 OpsI.push_back(Member->getDefiningRecipe()->getOperand(Idx));
4536 WideMember0->setOperand(
4537 Idx, narrowInterleaveGroupOp(OpsI, NarrowedOps, Preheader));
4538 }
4539 return V;
4540 }
4541
4542 if (auto *LoadGroup = dyn_cast<VPInterleaveRecipe>(R)) {
4543 // Narrow interleave group to wide load, as transformed VPlan will only
4544 // process one original iteration.
4545 auto *LI = cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos());
4546 auto *L = VPBuilder(LoadGroup).createWidenLoad(
4547 *LI, LoadGroup->getAddr(), LoadGroup->getMask(), /*Consecutive=*/true,
4548 *LoadGroup, LoadGroup->getDebugLoc());
4549 NarrowedOps.insert(L);
4550 return L;
4551 }
4552
4553 if (auto *RepR = dyn_cast<VPReplicateRecipe>(R)) {
4554 assert(RepR->isSingleScalar() && RepR->getOpcode() == Instruction::Load &&
4555 "must be a single scalar load");
4556 NarrowedOps.insert(RepR);
4557 return RepR;
4558 }
4559
4560 auto *WideLoad = cast<VPWidenLoadRecipe>(R);
4561 VPValue *PtrOp = WideLoad->getAddr();
4562 if (auto *VecPtr = dyn_cast<VPVectorPointerRecipe>(PtrOp))
4563 PtrOp = VecPtr->getOperand(0);
4564 // Narrow wide load to uniform scalar load, as transformed VPlan will only
4565 // process one original iteration.
4566 auto *N = new VPReplicateRecipe(&WideLoad->getIngredient(), {PtrOp},
4567 /*IsUniform*/ true,
4568 /*Mask*/ nullptr, {}, *WideLoad);
4569 N->insertBefore(WideLoad);
4570 NarrowedOps.insert(N);
4571 return N;
4572}
4573
4574std::unique_ptr<VPlan>
4576 const TargetTransformInfo &TTI) {
4577 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
4578
4579 if (!VectorLoop)
4580 return nullptr;
4581
4582 // Only handle single-block loops for now.
4583 if (VectorLoop->getEntryBasicBlock() != VectorLoop->getExitingBasicBlock())
4584 return nullptr;
4585
4586 // Skip plans when we may not be able to properly narrow.
4587 VPBasicBlock *Exiting = VectorLoop->getExitingBasicBlock();
4588 if (!match(&Exiting->back(), m_BranchOnCount()))
4589 return nullptr;
4590
4591 assert(match(&Exiting->back(),
4593 m_Specific(&Plan.getVectorTripCount()))) &&
4594 "unexpected branch-on-count");
4595
4598 std::optional<ElementCount> VFToOptimize;
4599 for (auto &R : *VectorLoop->getEntryBasicBlock()) {
4602 continue;
4603
4604 // Bail out on recipes not supported at the moment:
4605 // * phi recipes other than the canonical induction
4606 // * recipes writing to memory except interleave groups
4607 // Only support plans with a canonical induction phi.
4608 if (R.isPhi())
4609 return nullptr;
4610
4611 auto *InterleaveR = dyn_cast<VPInterleaveRecipe>(&R);
4612 if (R.mayWriteToMemory() && !InterleaveR)
4613 return nullptr;
4614
4615 // Bail out if any recipe defines a vector value used outside the
4616 // vector loop region.
4617 if (any_of(R.definedValues(), [&](VPValue *V) {
4618 return any_of(V->users(), [&](VPUser *U) {
4619 auto *UR = cast<VPRecipeBase>(U);
4620 return UR->getParent()->getParent() != VectorLoop;
4621 });
4622 }))
4623 return nullptr;
4624
4625 // All other ops are allowed, but we reject uses that cannot be converted
4626 // when checking all allowed consumers (store interleave groups) below.
4627 if (!InterleaveR)
4628 continue;
4629
4630 // Try to find a single VF, where all interleave groups are consecutive and
4631 // saturate the full vector width. If we already have a candidate VF, check
4632 // if it is applicable for the current InterleaveR, otherwise look for a
4633 // suitable VF across the Plan's VFs.
4635 VFToOptimize ? SmallVector<ElementCount>({*VFToOptimize})
4636 : to_vector(Plan.vectorFactors());
4637 std::optional<ElementCount> NarrowedVF =
4638 isConsecutiveInterleaveGroup(InterleaveR, VFs, TTI);
4639 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
4640 return nullptr;
4641 VFToOptimize = NarrowedVF;
4642
4643 // Skip read interleave groups.
4644 if (InterleaveR->getStoredValues().empty())
4645 continue;
4646
4647 // Narrow interleave groups, if all operands are already matching narrow
4648 // ops.
4649 auto *Member0 = InterleaveR->getStoredValues()[0];
4650 if (isAlreadyNarrow(Member0) &&
4651 all_of(InterleaveR->getStoredValues(), equal_to(Member0))) {
4652 StoreGroups.push_back(InterleaveR);
4653 continue;
4654 }
4655
4656 // For now, we only support full interleave groups storing load interleave
4657 // groups.
4658 if (all_of(enumerate(InterleaveR->getStoredValues()), [](auto Op) {
4659 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
4660 if (!DefR)
4661 return false;
4662 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
4663 return IR && IR->getInterleaveGroup()->isFull() &&
4664 IR->getVPValue(Op.index()) == Op.value();
4665 })) {
4666 StoreGroups.push_back(InterleaveR);
4667 continue;
4668 }
4669
4670 // Check if all values feeding InterleaveR are matching wide recipes whose
4671 // operands can be narrowed, without conflicting uses across groups.
4672 if (!canNarrowOps(InterleaveR->getStoredValues(),
4673 VFToOptimize->isScalable(), FirstMembersOf))
4674 return nullptr;
4675 StoreGroups.push_back(InterleaveR);
4676 }
4677
4678 if (StoreGroups.empty())
4679 return nullptr;
4680
4681 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
4682 bool RequiresScalarEpilogue =
4683 MiddleVPBB->getNumSuccessors() == 1 &&
4684 MiddleVPBB->getSingleSuccessor() == Plan.getScalarPreheader();
4685 // Bail out for tail-folding (middle block with a single successor to exit).
4686 if (MiddleVPBB->getNumSuccessors() != 2 && !RequiresScalarEpilogue)
4687 return nullptr;
4688
4689 // All interleave groups in Plan can be narrowed for VFToOptimize. Split the
4690 // original Plan into 2: a) a new clone which contains all VFs of Plan, except
4691 // VFToOptimize, and b) the original Plan with VFToOptimize as single VF.
4692 // TODO: Handle cases where only some interleave groups can be narrowed.
4693 std::unique_ptr<VPlan> NewPlan;
4694 if (size(Plan.vectorFactors()) != 1) {
4695 NewPlan = std::unique_ptr<VPlan>(Plan.duplicate());
4696 Plan.setVF(*VFToOptimize);
4697 NewPlan->removeVF(*VFToOptimize);
4698 }
4699
4700 // Convert InterleaveGroup \p R to a single VPWidenLoadRecipe.
4701 SmallPtrSet<VPValue *, 4> NarrowedOps;
4702 VPBasicBlock *Preheader = Plan.getVectorPreheader();
4703 // Narrow operation tree rooted at store groups.
4704 for (auto *StoreGroup : StoreGroups) {
4705 VPValue *Res = narrowInterleaveGroupOp(StoreGroup->getStoredValues(),
4706 NarrowedOps, Preheader);
4707 auto *SI =
4708 cast<StoreInst>(StoreGroup->getInterleaveGroup()->getInsertPos());
4709 VPBuilder(StoreGroup)
4710 .createWidenStore(*SI, StoreGroup->getAddr(), Res, nullptr,
4711 /*Consecutive=*/true, *StoreGroup,
4712 StoreGroup->getDebugLoc());
4713 StoreGroup->eraseFromParent();
4714 }
4715
4716 // Adjust induction to reflect that the transformed plan only processes one
4717 // original iteration.
4719 Type *CanIVTy = VectorLoop->getCanonicalIVType();
4720 VPBasicBlock *VectorPH = Plan.getVectorPreheader();
4721 VPBuilder PHBuilder(VectorPH, VectorPH->getFirstNonPhi());
4722
4723 VPValue *UF = &Plan.getUF();
4724 VPValue *Step;
4725 if (VFToOptimize->isScalable()) {
4726 VPValue *VScale =
4727 PHBuilder.createElementCount(CanIVTy, ElementCount::getScalable(1));
4728 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale, UF},
4729 {true, false});
4730 Plan.getVF().replaceAllUsesWith(VScale);
4731 } else {
4732 Step = UF;
4733 Plan.getVF().replaceAllUsesWith(Plan.getConstantInt(CanIVTy, 1));
4734 }
4735 // Materialize vector trip count with the narrowed step.
4736 materializeVectorTripCount(Plan, VectorPH, /*TailByMasking=*/false,
4737 RequiresScalarEpilogue, Step);
4738
4739 CanIVInc->setOperand(1, Step);
4740 Plan.getVFxUF().replaceAllUsesWith(Step);
4741
4742 removeDeadRecipes(Plan);
4743 assert(none_of(*VectorLoop->getEntryBasicBlock(),
4745 "All VPVectorPointerRecipes should have been removed");
4746 return NewPlan;
4747}
4748
4750 VFRange &Range) {
4751 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
4752 auto *MiddleVPBB = Plan.getMiddleBlock();
4753 VPBuilder MiddleBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
4754
4755 auto IsScalableOne = [](ElementCount VF) -> bool {
4756 return VF == ElementCount::getScalable(1);
4757 };
4758
4761 VectorRegion->getEntryBasicBlock()->phis())) {
4762 assert(VectorRegion->getSingleSuccessor() == Plan.getMiddleBlock() &&
4763 "Cannot handle loops with uncountable early exits");
4764
4765 // Find the existing splice for this FOR, created in
4766 // createHeaderPhiRecipes. All uses of FOR have already been replaced with
4767 // RecurSplice there; only RecurSplice itself still references FOR.
4768 auto *RecurSplice =
4770 assert(RecurSplice && "expected FirstOrderRecurrenceSplice");
4771
4772 // For VF vscale x 1, if vscale = 1, we are unable to extract the
4773 // penultimate value of the recurrence. Instead we rely on the existing
4774 // extract of the last element from the result of
4775 // VPInstruction::FirstOrderRecurrenceSplice.
4776 // TODO: Consider vscale_range info and UF.
4777 if (any_of(RecurSplice->users(),
4778 [](VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
4780 Range))
4781 return;
4782
4783 // This is the second phase of vectorizing first-order recurrences, creating
4784 // extracts for users outside the loop. An overview of the transformation is
4785 // described below. Suppose we have the following loop with some use after
4786 // the loop of the last a[i-1],
4787 //
4788 // for (int i = 0; i < n; ++i) {
4789 // t = a[i - 1];
4790 // b[i] = a[i] - t;
4791 // }
4792 // use t;
4793 //
4794 // There is a first-order recurrence on "a". For this loop, the shorthand
4795 // scalar IR looks like:
4796 //
4797 // scalar.ph:
4798 // s.init = a[-1]
4799 // br scalar.body
4800 //
4801 // scalar.body:
4802 // i = phi [0, scalar.ph], [i+1, scalar.body]
4803 // s1 = phi [s.init, scalar.ph], [s2, scalar.body]
4804 // s2 = a[i]
4805 // b[i] = s2 - s1
4806 // br cond, scalar.body, exit.block
4807 //
4808 // exit.block:
4809 // use = lcssa.phi [s1, scalar.body]
4810 //
4811 // In this example, s1 is a recurrence because it's value depends on the
4812 // previous iteration. In the first phase of vectorization, we created a
4813 // VPFirstOrderRecurrencePHIRecipe v1 for s1. Now we create the extracts
4814 // for users in the scalar preheader and exit block.
4815 //
4816 // vector.ph:
4817 // v_init = vector(..., ..., ..., a[-1])
4818 // br vector.body
4819 //
4820 // vector.body
4821 // i = phi [0, vector.ph], [i+4, vector.body]
4822 // v1 = phi [v_init, vector.ph], [v2, vector.body]
4823 // v2 = a[i, i+1, i+2, i+3]
4824 // v1' = splice(v1(3), v2(0, 1, 2))
4825 // b[i, i+1, i+2, i+3] = v2 - v1'
4826 // br cond, vector.body, middle.block
4827 //
4828 // middle.block:
4829 // vector.recur.extract.for.phi = v2(2)
4830 // vector.recur.extract = v2(3)
4831 // br cond, scalar.ph, exit.block
4832 //
4833 // scalar.ph:
4834 // scalar.recur.init = phi [vector.recur.extract, middle.block],
4835 // [s.init, otherwise]
4836 // br scalar.body
4837 //
4838 // scalar.body:
4839 // i = phi [0, scalar.ph], [i+1, scalar.body]
4840 // s1 = phi [scalar.recur.init, scalar.ph], [s2, scalar.body]
4841 // s2 = a[i]
4842 // b[i] = s2 - s1
4843 // br cond, scalar.body, exit.block
4844 //
4845 // exit.block:
4846 // lo = lcssa.phi [s1, scalar.body],
4847 // [vector.recur.extract.for.phi, middle.block]
4848 //
4849 // Update extracts of the splice in the middle block: they extract the
4850 // penultimate element of the recurrence.
4852 make_range(MiddleVPBB->getFirstNonPhi(), MiddleVPBB->end()))) {
4853 if (!match(&R, m_ExtractLastLaneOfLastPart(m_Specific(RecurSplice))))
4854 continue;
4855
4856 auto *ExtractR = cast<VPInstruction>(&R);
4857 VPValue *PenultimateElement = MiddleBuilder.createNaryOp(
4858 VPInstruction::ExtractPenultimateElement, RecurSplice->getOperand(1),
4859 {}, "vector.recur.extract.for.phi");
4860 for (VPUser *ExitU : to_vector(ExtractR->users())) {
4861 if (auto *ExitPhi = dyn_cast<VPIRPhi>(ExitU))
4862 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
4863 }
4864 }
4865 }
4866}
4867
4868/// Check if \p V is a binary expression of a widened IV and a loop-invariant
4869/// value. Returns the widened IV if found, nullptr otherwise.
4871 auto *BinOp = dyn_cast<VPWidenRecipe>(V);
4872 if (!BinOp || !Instruction::isBinaryOp(BinOp->getOpcode()) ||
4873 Instruction::isIntDivRem(BinOp->getOpcode()))
4874 return nullptr;
4875
4876 VPValue *WidenIVCandidate = BinOp->getOperand(0);
4877 VPValue *InvariantCandidate = BinOp->getOperand(1);
4878 if (!isa<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate))
4879 std::swap(WidenIVCandidate, InvariantCandidate);
4880
4881 if (!InvariantCandidate->isDefinedOutsideLoopRegions())
4882 return nullptr;
4883
4884 return dyn_cast<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate);
4885}
4886
4887/// Create a scalar version of \p BinOp, with its \p WidenIV operand replaced
4888/// by \p ScalarIV, and place it after \p ScalarIV's defining recipe.
4892 BinOp->getNumOperands() == 2 && "BinOp must have 2 operands");
4893 auto *ClonedOp = BinOp->clone();
4894 if (ClonedOp->getOperand(0) == WidenIV) {
4895 ClonedOp->setOperand(0, ScalarIV);
4896 } else {
4897 assert(ClonedOp->getOperand(1) == WidenIV && "one operand must be WideIV");
4898 ClonedOp->setOperand(1, ScalarIV);
4899 }
4900 ClonedOp->insertAfter(ScalarIV->getDefiningRecipe());
4901 return ClonedOp;
4902}
4903
4904/// If \p S is an affine AddRec, returns true if its step is known to be
4905/// positive and false if it is known to be negative. Returns std::nullopt if
4906/// \p S is not an affine AddRec, or if the sign of its step cannot be
4907/// determined.
4908static std::optional<bool> getStepDirection(const SCEV *S,
4909 ScalarEvolution &SE) {
4910 const SCEV *Step;
4911 if (!match(S, m_scev_AffineAddRec(m_SCEV(), m_SCEV(Step))))
4912 return std::nullopt;
4913 if (SE.isKnownPositive(Step))
4914 return true;
4915 if (SE.isKnownNegative(Step))
4916 return false;
4917 return std::nullopt;
4918}
4919
4922 Loop &L) {
4923 ScalarEvolution &SE = *PSE.getSE();
4924 VPRegionBlock *VectorLoopRegion = Plan.getVectorLoopRegion();
4925
4926 // Helper lambda to check if the IV range excludes the sentinel value. Try
4927 // signed first, then unsigned. Return an excluded sentinel if found,
4928 // otherwise return std::nullopt.
4929 auto CheckSentinel = [&SE](const SCEV *IVSCEV,
4930 bool UseMax) -> std::optional<APSInt> {
4931 unsigned BW = IVSCEV->getType()->getScalarSizeInBits();
4932 for (bool Signed : {true, false}) {
4933 APSInt Sentinel = UseMax ? APSInt::getMinValue(BW, /*Unsigned=*/!Signed)
4934 : APSInt::getMaxValue(BW, /*Unsigned=*/!Signed);
4935
4936 ConstantRange IVRange =
4937 Signed ? SE.getSignedRange(IVSCEV) : SE.getUnsignedRange(IVSCEV);
4938 if (!IVRange.contains(Sentinel))
4939 return Sentinel;
4940 }
4941 return std::nullopt;
4942 };
4943
4944 VPValue *HeaderMask = VectorLoopRegion->getHeaderMask();
4945 for (VPRecipeBase &Phi :
4946 make_early_inc_range(VectorLoopRegion->getEntryBasicBlock()->phis())) {
4947 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&Phi);
4949 PhiR->getRecurrenceKind()))
4950 continue;
4951
4952 Type *PhiTy = PhiR->getScalarType();
4953 if (PhiTy->isPointerTy() || PhiTy->isFloatingPointTy())
4954 continue;
4955
4956 // If there's a header mask, the backedge select will not be the find-last
4957 // select.
4958 VPValue *BackedgeVal = PhiR->getBackedgeValue();
4959 auto *FindLastSelect = cast<VPSingleDefRecipe>(BackedgeVal);
4960 if (HeaderMask &&
4961 !match(BackedgeVal,
4962 m_Select(m_Specific(HeaderMask),
4963 m_VPSingleDefRecipe(FindLastSelect), m_Specific(PhiR))))
4964 continue;
4965
4966 // Get the find-last expression from the find-last select of the reduction
4967 // phi. The find-last select should be a select between the phi and the
4968 // find-last expression.
4969 VPValue *Cond, *FindLastExpression;
4970 if (!match(FindLastSelect, m_SelectLike(m_VPValue(Cond), m_Specific(PhiR),
4971 m_VPValue(FindLastExpression))) &&
4972 !match(FindLastSelect,
4973 m_SelectLike(m_VPValue(Cond), m_VPValue(FindLastExpression),
4974 m_Specific(PhiR))))
4975 continue;
4976
4977 // Check if FindLastExpression is a simple expression of a widened IV. If
4978 // so, we can track the underlying IV instead and sink the expression.
4979 auto *IVOfExpressionToSink = getExpressionIV(FindLastExpression);
4980 const SCEV *IVSCEV = vputils::getSCEVExprForVPValue(
4981 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
4982 &L);
4983 if (!match(IVSCEV, m_scev_AffineAddRec(m_SCEV(), m_SCEV()))) {
4984 assert(!match(vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L),
4986 "IVOfExpressionToSink not being an AddRec must imply "
4987 "FindLastExpression not being an AddRec.");
4988 continue;
4989 }
4990
4991 // Determine direction from the step of IVSCEV, if possible.
4992 std::optional<bool> StepDirection = getStepDirection(IVSCEV, SE);
4993 if (!StepDirection)
4994 continue;
4995
4996 bool UseMax = *StepDirection;
4997 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
4998 bool UseSigned = SentinelVal && SentinelVal->isSigned();
4999
5000 // Sinking an expression will disable epilogue vectorization. Only use it,
5001 // if FindLastExpression cannot be vectorized via a sentinel. Sinking may
5002 // also prevent vectorizing using a sentinel (e.g., if the expression is a
5003 // multiply or divide by large constant, respectively), which also makes
5004 // sinking undesirable.
5005 if (IVOfExpressionToSink) {
5006 const SCEV *FindLastExpressionSCEV =
5007 vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L);
5008 if (std::optional<bool> NewUseMax =
5009 getStepDirection(FindLastExpressionSCEV, SE)) {
5010 if (auto NewSentinel =
5011 CheckSentinel(FindLastExpressionSCEV, *NewUseMax)) {
5012 // The original expression already has a sentinel, so prefer not
5013 // sinking to keep epilogue vectorization possible.
5014 SentinelVal = *NewSentinel;
5015 UseSigned = NewSentinel->isSigned();
5016 UseMax = *NewUseMax;
5017 IVSCEV = FindLastExpressionSCEV;
5018 IVOfExpressionToSink = nullptr;
5019 }
5020 }
5021 }
5022
5023 // If no sentinel was found, fall back to a boolean AnyOf reduction to track
5024 // if the condition was ever true. Requires the IV to not wrap, otherwise we
5025 // cannot use min/max.
5026 if (!SentinelVal) {
5027 auto *AR = cast<SCEVAddRecExpr>(IVSCEV);
5028 if (AR->hasNoSignedWrap())
5029 UseSigned = true;
5030 else if (AR->hasNoUnsignedWrap())
5031 UseSigned = false;
5032 else
5033 continue;
5034 }
5035
5037 BackedgeVal,
5039
5040 VPValue *NewFindLastSelect = BackedgeVal;
5041 VPValue *SelectCond = Cond;
5042 if (!SentinelVal || IVOfExpressionToSink) {
5043 // When we need to create a new select, normalize the condition so that
5044 // PhiR is the last operand and include the header mask if needed.
5045 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
5046 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
5047 if (match(FindLastSelect,
5049 SelectCond = LoopBuilder.createNot(SelectCond);
5050
5051 // When tail folding, mask the condition with the header mask to prevent
5052 // propagating poison from inactive lanes in the last vector iteration.
5053 if (HeaderMask)
5054 SelectCond = LoopBuilder.createLogicalAnd(HeaderMask, SelectCond);
5055
5056 if (SelectCond != Cond || IVOfExpressionToSink) {
5057 NewFindLastSelect = LoopBuilder.createSelect(
5058 SelectCond,
5059 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
5060 PhiR, DL);
5061 }
5062 }
5063
5064 // Create the reduction result in the middle block using sentinel directly.
5065 RecurKind MinMaxKind =
5066 UseMax ? (UseSigned ? RecurKind::SMax : RecurKind::UMax)
5067 : (UseSigned ? RecurKind::SMin : RecurKind::UMin);
5068 VPIRFlags Flags(MinMaxKind, /*IsOrdered=*/false, /*IsInLoop=*/false,
5069 FastMathFlags());
5070 DebugLoc ExitDL = RdxResult->getDebugLoc();
5071 VPBuilder MiddleBuilder(RdxResult);
5072 VPValue *ReducedIV =
5074 NewFindLastSelect, Flags, ExitDL);
5075
5076 // If IVOfExpressionToSink is an expression to sink, sink it now.
5077 VPValue *VectorRegionExitingVal = ReducedIV;
5078 bool SunkExpression = false;
5079 if (IVOfExpressionToSink) {
5080 VectorRegionExitingVal =
5081 cloneBinOpForScalarIV(cast<VPWidenRecipe>(FindLastExpression),
5082 ReducedIV, IVOfExpressionToSink);
5083 SunkExpression = true;
5084 }
5085
5086 VPValue *NewRdxResult;
5087 VPValue *StartVPV = PhiR->getStartValue();
5088 if (SentinelVal) {
5089 // Sentinel-based approach: reduce IVs with min/max, compare against
5090 // sentinel to detect if condition was ever true, select accordingly.
5091 VPValue *Sentinel = Plan.getConstantInt(*SentinelVal);
5092 auto *Cmp = MiddleBuilder.createICmp(CmpInst::ICMP_NE, ReducedIV,
5093 Sentinel, ExitDL);
5094 NewRdxResult = MiddleBuilder.createSelect(Cmp, VectorRegionExitingVal,
5095 StartVPV, ExitDL);
5096 StartVPV = Sentinel;
5097 } else {
5098 // Introduce a boolean AnyOf reduction to track if the condition was ever
5099 // true in the loop. Use it to select the initial start value, if it was
5100 // never true.
5101 auto *AnyOfPhi = new VPReductionPHIRecipe(
5102 /*Phi=*/nullptr, RecurKind::Or, *Plan.getFalse(), *Plan.getFalse(),
5103 RdxUnordered{1}, {}, /*HasUsesOutsideReductionChain=*/false);
5104 AnyOfPhi->insertAfter(PhiR);
5105
5106 VPBuilder LoopBuilder(BackedgeVal->getDefiningRecipe());
5107 VPValue *OrVal = LoopBuilder.createOr(AnyOfPhi, SelectCond);
5108 AnyOfPhi->setOperand(1, OrVal);
5109
5110 NewRdxResult = MiddleBuilder.createAnyOfReduction(
5111 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
5112
5113 // Initialize the IV reduction phi with the neutral element, not the
5114 // original start value, to ensure correct min/max reduction results.
5115 StartVPV = Plan.getOrAddLiveIn(
5116 getRecurrenceIdentity(MinMaxKind, IVSCEV->getType(), {}));
5117 }
5118 RdxResult->replaceAllUsesWith(NewRdxResult);
5119 RdxResult->eraseFromParent();
5120
5121 auto *NewPhiR = new VPReductionPHIRecipe(
5122 cast<PHINode>(PhiR->getUnderlyingInstr()), RecurKind::FindIV, *StartVPV,
5123 *NewFindLastSelect, RdxUnordered{1}, {},
5124 PhiR->hasUsesOutsideReductionChain());
5125 if (SunkExpression)
5126 NewPhiR->setExpressionSunk();
5127 NewPhiR->insertBefore(PhiR);
5128 PhiR->replaceAllUsesWith(NewPhiR);
5129 PhiR->eraseFromParent();
5130 }
5131}
5132
5133namespace {
5134
5135struct ReductionExtend {
5136 Type *SrcType = nullptr;
5137 ExtendKind Kind = ExtendKind::PR_None;
5138};
5139
5140/// Describes the extends used to compute the extended reduction operand.
5141/// ExtendB is optional. If ExtendB is present, ExtendsUser is a binary
5142/// operation.
5143struct ExtendedReductionOperand {
5144 /// The recipe that consumes the extends.
5145 VPWidenRecipe *ExtendsUser = nullptr;
5146 /// Extend descriptions (inputs to getPartialReductionCost).
5147 ReductionExtend ExtendA, ExtendB;
5148};
5149
5150/// A collection of recipes that describe a partial reduction. Matches either
5151/// reduction_bin_op (extended op, accumulator), or
5152/// reduction_bin_op (accumulator, extended op).
5153/// The possible forms of the "extended op" are listed in
5154/// matchExtendedReductionOperand.
5155struct PartialReductionDescriptor {
5156 /// The top-level binary operation that forms the reduction to a scalar
5157 /// after the loop body.
5158 VPWidenRecipe *ReductionBinOp = nullptr;
5159 /// The user of the extends that is then reduced.
5160 ExtendedReductionOperand ExtendedOp;
5161 /// The recurrence kind for the entire partial reduction chain.
5162 /// This allows distinguishing between Sub and AddWithSub recurrences,
5163 /// when the ReductionBinOp is a Instruction::Sub.
5164 RecurKind RK;
5165 /// The index of the accumulator operand of ReductionBinOp. The extended op
5166 /// is `1 - AccumulatorOpIdx`.
5167 unsigned AccumulatorOpIdx;
5168 unsigned ScaleFactor;
5169 /// Optional blend to represent predication for the block that updates the
5170 /// reduction.
5171 VPBlendRecipe *Blend = nullptr;
5172};
5173
5174// Return the incoming index of the single-use value in the blend, which is
5175// expected to be the predicated reduction update.
5176static std::optional<unsigned>
5177getBlendReductionUpdateValueIdx(VPBlendRecipe *Blend) {
5178 assert(Blend && !Blend->isNormalized() &&
5179 Blend->getNumIncomingValues() == 2 &&
5180 "Expected a non-normalized blend with two incoming values");
5181 bool FirstIncomingHasOneUse = Blend->getIncomingValue(0)->hasOneUse();
5182
5183 // Only the update value should have one use (the blend). The previous
5184 // value should always have at least two uses, the blend and the reduction.
5185 if (FirstIncomingHasOneUse == Blend->getIncomingValue(1)->hasOneUse())
5186 return std::nullopt;
5187 return FirstIncomingHasOneUse ? 0 : 1;
5188}
5189
5190static VPSingleDefRecipe *
5191optimizeExtendsForPartialReduction(VPSingleDefRecipe *Op) {
5192 // reduce.add(mul(ext(A), C))
5193 // -> reduce.add(mul(ext(A), ext(trunc(C))))
5194 const APInt *Const;
5195 if (match(Op, m_Mul(m_ZExtOrSExt(m_VPValue()), m_APInt(Const)))) {
5196 auto *ExtA = cast<VPWidenCastRecipe>(Op->getOperand(0));
5197 Instruction::CastOps ExtOpc = ExtA->getOpcode();
5198 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
5199 if (!Op->hasOneUse() ||
5201 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
5202 return Op;
5203
5204 VPBuilder Builder(Op);
5205 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
5206 Op->getOperand(1), NarrowTy);
5207 Type *WideTy = ExtA->getScalarType();
5208 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
5209 return Op;
5210 }
5211
5212 // reduce.add(abs(sub(ext(A), ext(B))))
5213 // -> reduce.add(ext(absolute-difference(A, B)))
5214 VPValue *X, *Y;
5217 auto *Sub = Op->getOperand(0)->getDefiningRecipe();
5218 auto *Ext = cast<VPWidenCastRecipe>(Sub->getOperand(0));
5219 assert(Ext->getOpcode() ==
5220 cast<VPWidenCastRecipe>(Sub->getOperand(1))->getOpcode() &&
5221 "Expected both the LHS and RHS extends to be the same");
5222 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
5223 VPBuilder Builder(Op);
5224 Type *SrcTy = X->getScalarType();
5225 auto *FreezeX = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {X}));
5226 auto *FreezeY = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {Y}));
5227 auto *Max = Builder.insert(
5228 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smax : Intrinsic::umax,
5229 {FreezeX, FreezeY}, SrcTy));
5230 auto *Min = Builder.insert(
5231 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smin : Intrinsic::umin,
5232 {FreezeX, FreezeY}, SrcTy));
5233 auto *AbsDiff = Builder.insert(
5234 new VPWidenRecipe(Instruction::Sub, {Max, Min},
5235 VPIRFlags::getDefaultFlags(Instruction::Sub)));
5236 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
5237 Op->getScalarType());
5238 }
5239
5240 // reduce.add(ext(mul(ext(A), ext(B))))
5241 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
5242 // TODO: Support this optimization for float types.
5244 m_ZExtOrSExt(m_VPValue()))))) {
5245 auto *Ext = cast<VPWidenCastRecipe>(Op);
5246 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
5247 auto *MulLHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5248 auto *MulRHS = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5249 assert(Mul->hasOneUse() && Ext->getOpcode() == MulLHS->getOpcode() &&
5250 MulLHS->getOpcode() == MulRHS->getOpcode() &&
5252 "Expected the outer extend to be foldable");
5253 VPBuilder Builder(Mul);
5254 auto *NewLHS = Builder.createWidenCast(
5255 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
5256 auto *NewRHS = MulLHS == MulRHS
5257 ? NewLHS
5258 : Builder.createWidenCast(MulRHS->getOpcode(),
5259 MulRHS->getOperand(0),
5260 Ext->getScalarType());
5261 auto *NewMul = Mul->cloneWithOperands({NewLHS, NewRHS});
5262 Builder.insert(NewMul);
5263 Op->replaceAllUsesWith(NewMul);
5264 Op->eraseFromParent();
5265 Mul->eraseFromParent();
5266 return NewMul;
5267 }
5268
5269 return Op;
5270}
5271
5272static VPExpressionRecipe *
5273createPartialReductionExpression(VPReductionRecipe *Red) {
5274 VPValue *VecOp = Red->getVecOp();
5275
5276 // reduce.[f]add(ext(op))
5277 // -> VPExpressionRecipe(op, red)
5278 if (match(VecOp, m_WidenAnyExtend(m_VPValue())))
5279 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
5280
5281 // reduce.[f]add(neg(ext(op)))
5282 // -> VPExpressionRecipe(op, sub/neg, red)
5283 if (match(VecOp, m_AnyNeg(m_WidenAnyExtend(m_VPValue())))) {
5284 auto *Neg = cast<VPWidenRecipe>(VecOp);
5285 auto *Ext = cast<VPWidenCastRecipe>(Neg->getLastOperand());
5286 return new VPExpressionRecipe(Ext, Neg, Red);
5287 }
5288
5289 // reduce.[f]add([f]mul(ext(a), ext(b)))
5290 // -> VPExpressionRecipe(a, b, mul, red)
5291 if (match(VecOp, m_FMul(m_FPExt(m_VPValue()), m_FPExt(m_VPValue()))) ||
5292 match(VecOp,
5294 auto *Mul = cast<VPWidenRecipe>(VecOp);
5295 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5296 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5297 return new VPExpressionRecipe(ExtA, ExtB, Mul, Red);
5298 }
5299
5300 // reduce.fadd(fneg(fmul(fpext(a), fpext(b))))
5301 // -> VPExpressionRecipe(a, b, fmul, fsub, red)
5302 if (match(VecOp,
5304 auto *FNeg = cast<VPWidenRecipe>(VecOp);
5305 auto *FMul = cast<VPWidenRecipe>(FNeg->getOperand(0));
5306 auto *ExtA = cast<VPWidenCastRecipe>(FMul->getOperand(0));
5307 auto *ExtB = cast<VPWidenCastRecipe>(FMul->getOperand(1));
5308 return new VPExpressionRecipe(ExtA, ExtB, FMul, FNeg, Red);
5309 }
5310
5311 // reduce.add(neg(mul(ext(a), ext(b))))
5312 // -> VPExpressionRecipe(a, b, mul, sub, red)
5314 m_ZExtOrSExt(m_VPValue()))))) {
5315 auto *Sub = cast<VPWidenRecipe>(VecOp);
5316 auto *Mul = cast<VPWidenRecipe>(Sub->getOperand(1));
5317 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
5318 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
5319 return new VPExpressionRecipe(ExtA, ExtB, Mul, Sub, Red);
5320 }
5321
5322 llvm_unreachable("Unsupported expression");
5323}
5324
5325// Helper to transform a PartialReductionDescriptor into a partial reduction
5326// recipe. Assumes profitability has been checked.
5327static void transformToPartialReduction(const PartialReductionDescriptor &Link,
5328 VPlan &Plan,
5329 VPReductionPHIRecipe *RdxPhi) {
5330 VPWidenRecipe *WidenRecipe = Link.ReductionBinOp;
5331 assert(WidenRecipe->getNumOperands() == 2 && "Expected binary operation");
5332
5333 VPValue *Accumulator = WidenRecipe->getOperand(Link.AccumulatorOpIdx);
5334 auto *ExtendedOp = cast<VPSingleDefRecipe>(
5335 WidenRecipe->getOperand(1 - Link.AccumulatorOpIdx));
5336
5337 // FIXME: Do these transforms before invoking the cost-model.
5338 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
5339
5340 // Sub-reductions can be implemented in two ways:
5341 // (1) negate the operand in the vector loop (the default way).
5342 // (2) subtract the reduced value from the init value in the middle block.
5343 // Both ways keep the reduction itself as an 'add' reduction.
5344 //
5345 // The ISD nodes for partial reductions don't support folding the
5346 // sub/negation into its operands because the following is not a valid
5347 // transformation:
5348 // sub(0, mul(ext(a), ext(b)))
5349 // -> mul(ext(a), ext(sub(0, b)))
5350 //
5351 // It's therefore better to choose option (2) such that the partial
5352 // reduction is always positive (starting at '0') and to do a final
5353 // subtract in the middle block.
5354 if ((WidenRecipe->getOpcode() == Instruction::Sub &&
5355 Link.RK != RecurKind::Sub) ||
5356 (WidenRecipe->getOpcode() == Instruction::FSub &&
5357 Link.RK != RecurKind::FSub)) {
5358 VPBuilder Builder(WidenRecipe);
5359 Type *ElemTy = ExtendedOp->getScalarType();
5360 VPWidenRecipe *NegRecipe;
5361 if (WidenRecipe->getOpcode() == Instruction::FSub) {
5362 NegRecipe =
5363 new VPWidenRecipe(Instruction::FNeg, {ExtendedOp},
5364 VPIRFlags::getDefaultFlags(Instruction::FNeg),
5366 } else {
5367 auto *Zero = Plan.getZero(ElemTy);
5368 NegRecipe =
5369 new VPWidenRecipe(Instruction::Sub, {Zero, ExtendedOp},
5370 VPIRFlags::getDefaultFlags(Instruction::Sub),
5372 }
5373 Builder.insert(NegRecipe);
5374 ExtendedOp = NegRecipe;
5375 }
5376
5377 // Check if WidenRecipe is the final result of the reduction. If so, look
5378 // through the Select recipe introduced by tail-folding, otherwise look
5379 // through any Blend recipe introduced by predication for the block.
5380 VPValue *ExitSearch =
5381 Link.Blend ? cast<VPValue>(Link.Blend) : cast<VPValue>(WidenRecipe);
5382
5383 VPValue *Cond = nullptr;
5385 findUserOf(ExitSearch, m_Select(m_VPValue(Cond), m_Specific(ExitSearch),
5386 m_Specific(RdxPhi))));
5387
5388 if (Link.Blend) {
5389 std::optional<unsigned> BlendReductionIdx =
5390 getBlendReductionUpdateValueIdx(Link.Blend);
5391 assert(BlendReductionIdx &&
5392 Link.Blend->getIncomingValue(*BlendReductionIdx) == WidenRecipe &&
5393 "Expected blend to contain the reduction update");
5394 VPValue *BlendCond = Link.Blend->getMask(*BlendReductionIdx);
5395 Cond = ExitValue ? VPBuilder(WidenRecipe)
5396 .createLogicalAnd(Cond, BlendCond,
5397 WidenRecipe->getDebugLoc())
5398 : BlendCond;
5399 }
5400
5401 // When folding the tail, the inactive lanes of the reduction update are
5402 // computed from values that do not correspond to any scalar iteration
5403 // and must not be accumulated.
5404 if (!Cond)
5406
5407 [[maybe_unused]] bool IsLastInChain =
5408 RdxPhi->getBackedgeValue() == WidenRecipe ||
5409 RdxPhi->getBackedgeValue() == ExitValue ||
5410 RdxPhi->getBackedgeValue() == Link.Blend;
5411 assert((!ExitValue || IsLastInChain) &&
5412 "if we found ExitValue, it must match RdxPhi's backedge value");
5413
5414 Type *PhiType = RdxPhi->getScalarType();
5415 RecurKind RdxKind =
5417 auto *PartialRed = new VPReductionRecipe(
5418 RdxKind,
5419 RdxKind == RecurKind::FAdd ? WidenRecipe->getFastMathFlagsOrNone()
5420 : FastMathFlags(),
5421 WidenRecipe->getUnderlyingInstr(), Accumulator, ExtendedOp, Cond,
5422 RdxUnordered{/*VFScaleFactor=*/Link.ScaleFactor});
5423 PartialRed->insertBefore(WidenRecipe);
5424
5425 if (ExitValue)
5426 ExitValue->replaceAllUsesWith(PartialRed);
5427 if (Link.Blend)
5428 Link.Blend->replaceAllUsesWith(PartialRed);
5429 WidenRecipe->replaceAllUsesWith(PartialRed);
5430
5431 // For cost-model purposes, fold this into a VPExpression.
5432 VPExpressionRecipe *E = createPartialReductionExpression(PartialRed);
5433 E->insertBefore(WidenRecipe);
5434 PartialRed->replaceAllUsesWith(E);
5435}
5436
5437/// Returns the cost of a link in a partial-reduction chain for a given VF.
5438static InstructionCost
5439getPartialReductionLinkCost(VPCostContext &CostCtx,
5440 const PartialReductionDescriptor &Link,
5441 ElementCount VF) {
5442 Type *RdxType = Link.ReductionBinOp->getScalarType();
5443 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5444 std::optional<unsigned> BinOpc = std::nullopt;
5445 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
5446 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5447 BinOpc = ExtendedOp.ExtendsUser->getOpcode();
5448
5449 std::optional<llvm::FastMathFlags> Flags;
5450 if (RdxType->isFloatingPointTy())
5451 Flags = Link.ReductionBinOp->getFastMathFlagsOrNone();
5452
5453 auto GetLinkOpcode = [&Link]() -> unsigned {
5454 switch (Link.RK) {
5455 case RecurKind::Sub:
5456 return Instruction::Add;
5457 case RecurKind::FSub:
5458 return Instruction::FAdd;
5459 default:
5460 return Link.ReductionBinOp->getOpcode();
5461 }
5462 };
5463
5464 return CostCtx.TTI.getPartialReductionCost(
5465 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
5466 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
5467 CostCtx.CostKind, Flags);
5468}
5469
5470/// Checks if \p Op (which is an operand of \p UpdateR) is an extended reduction
5471/// operand. This is an operand where the source of the value (e.g. a load) has
5472/// been extended (sext, zext, or fpext) before it is used in the reduction.
5473///
5474/// Possible forms matched by this function:
5475/// - UpdateR(PrevValue, ext(...))
5476/// - UpdateR(PrevValue, mul(ext(...), ext(...)))
5477/// - UpdateR(PrevValue, mul(ext(...), Constant))
5478/// - UpdateR(PrevValue, ext(mul(ext(...), ext(...))))
5479/// - UpdateR(PrevValue, ext(mul(ext(...), Constant)))
5480/// - UpdateR(PrevValue, abs(sub(ext(...), ext(...)))
5481///
5482/// Note: The second operand of UpdateR corresponds to \p Op in the examples.
5483static std::optional<ExtendedReductionOperand>
5484matchExtendedReductionOperand(VPWidenRecipe *UpdateR, VPValue *Op) {
5485 assert(is_contained(UpdateR->operands(), Op) &&
5486 "Op should be operand of UpdateR");
5487
5488 // Try matching an absolute difference operand of the form
5489 // `abs(sub(ext(A), ext(B)))`. This will be later transformed into
5490 // `ext(absolute-difference(A, B))`. This allows us to perform the absolute
5491 // difference on a wider type and get the extend for "free" from the partial
5492 // reduction.
5493 VPValue *X, *Y;
5494 if (Op->hasOneUse() &&
5498 auto *Abs = cast<VPWidenIntrinsicRecipe>(Op);
5499 auto *Sub = cast<VPWidenRecipe>(Abs->getOperand(0));
5500 auto *LHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(0));
5501 auto *RHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(1));
5502 Type *LHSInputType = X->getScalarType();
5503 Type *RHSInputType = Y->getScalarType();
5504 if (LHSInputType != RHSInputType ||
5505 LHSExt->getOpcode() != RHSExt->getOpcode())
5506 return std::nullopt;
5507 // Note: This is essentially the same as matching ext(...) as we will
5508 // rewrite this operand to ext(absolute-difference(A, B)).
5509 return ExtendedReductionOperand{
5510 Sub,
5511 /*ExtendA=*/{LHSInputType, getPartialReductionExtendKind(LHSExt)},
5512 /*ExtendB=*/{}};
5513 }
5514
5515 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
5517 auto *CastRecipe = cast<VPWidenCastRecipe>(Op);
5518 VPValue *CastSource = CastRecipe->getOperand(0);
5519 OuterExtKind = getPartialReductionExtendKind(CastRecipe);
5520 if (match(CastSource, m_Mul(m_VPValue(), m_VPValue())) ||
5521 match(CastSource, m_FMul(m_VPValue(), m_VPValue()))) {
5522 // Match: ext(mul(...))
5523 // Record the outer extend kind and set `Op` to the mul. We can then match
5524 // this as a binary operation. Note: We can optimize out the outer extend
5525 // by widening the inner extends to match it. See
5526 // optimizeExtendsForPartialReduction.
5527 Op = CastSource;
5528 } else {
5529 return ExtendedReductionOperand{
5530 UpdateR,
5531 /*ExtendA=*/{CastSource->getScalarType(), *OuterExtKind},
5532 /*ExtendB=*/{}};
5533 }
5534 }
5535
5536 if (!Op->hasOneUse())
5537 return std::nullopt;
5538
5540 if (!MulOp ||
5541 !is_contained({Instruction::Mul, Instruction::FMul}, MulOp->getOpcode()))
5542 return std::nullopt;
5543
5544 // The rest of the matching assumes `Op` is a (possibly extended) mul
5545 // operation.
5546
5547 VPValue *LHS = MulOp->getOperand(0);
5548 VPValue *RHS = MulOp->getOperand(1);
5549
5550 // The LHS of the operation must always be an extend.
5552 return std::nullopt;
5553
5554 auto *LHSCast = cast<VPWidenCastRecipe>(LHS);
5555 Type *LHSInputType = LHSCast->getOperand(0)->getScalarType();
5556 ExtendKind LHSExtendKind = getPartialReductionExtendKind(LHSCast);
5557
5558 // The RHS of the operation can be an extend or a constant integer.
5559 const APInt *RHSConst = nullptr;
5560 VPWidenCastRecipe *RHSCast = nullptr;
5562 RHSCast = cast<VPWidenCastRecipe>(RHS);
5563 else if (!match(RHS, m_APInt(RHSConst)) ||
5564 !canConstantBeExtended(RHSConst, LHSInputType, LHSExtendKind))
5565 return std::nullopt;
5566
5567 // The outer extend kind must match the inner extends for folding.
5568 for (VPWidenCastRecipe *Cast : {LHSCast, RHSCast})
5569 if (Cast && OuterExtKind &&
5570 getPartialReductionExtendKind(Cast) != OuterExtKind)
5571 return std::nullopt;
5572
5573 Type *RHSInputType = LHSInputType;
5574 ExtendKind RHSExtendKind = LHSExtendKind;
5575 if (RHSCast) {
5576 RHSInputType = RHSCast->getOperand(0)->getScalarType();
5577 RHSExtendKind = getPartialReductionExtendKind(RHSCast);
5578 }
5579
5580 // The outer extend can only be treated as extending the operands of the mul
5581 // if the narrow mul cannot wrap.
5582 if (OuterExtKind && MulOp->getOpcode() == Instruction::Mul &&
5584 return std::nullopt;
5585
5586 return ExtendedReductionOperand{
5587 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
5588}
5589
5590/// Examines each operation in the reduction chain corresponding to \p RedPhiR,
5591/// and determines if the target can use a cheaper operation with a wider
5592/// per-iteration input VF and narrower PHI VF. If successful, returns the chain
5593/// of partial reduction descriptors (that are links in the reduction chain).
5594static std::optional<SmallVector<PartialReductionDescriptor>>
5595getScaledReductionChain(VPReductionPHIRecipe *RedPhiR) {
5596 // Get the backedge value from the reduction PHI and find the
5597 // ComputeReductionResult that uses it (directly or through a select for
5598 // predicated reductions).
5599 auto *RdxResult = vputils::findComputeReductionResult(RedPhiR);
5600 if (!RdxResult)
5601 return std::nullopt;
5602 VPValue *ExitValue = RdxResult->getOperand(0);
5603 match(ExitValue, m_Select(m_VPValue(), m_VPValue(ExitValue), m_VPValue()));
5604
5606 RecurKind RK = RedPhiR->getRecurrenceKind();
5607 Type *PhiType = RedPhiR->getScalarType();
5608 TypeSize PHISize = PhiType->getPrimitiveSizeInBits();
5609
5610 // Work backwards from the ExitValue examining each reduction operation.
5611 VPValue *CurrentValue = ExitValue;
5612 while (CurrentValue != RedPhiR) {
5613 VPBlendRecipe *Blend = dyn_cast<VPBlendRecipe>(CurrentValue);
5614 std::optional<unsigned> BlendReductionIdx;
5615 if (Blend) {
5616 assert(!Blend->isNormalized() && "Expect Blend not to be normalized.");
5617 if (Blend->getNumIncomingValues() != 2)
5618 return std::nullopt;
5619
5620 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
5621 if (!BlendReductionIdx)
5622 return std::nullopt;
5623
5624 CurrentValue = Blend->getIncomingValue(*BlendReductionIdx);
5625 }
5626
5627 auto *UpdateR = dyn_cast<VPWidenRecipe>(CurrentValue);
5628 if (!UpdateR || !Instruction::isBinaryOp(UpdateR->getOpcode()))
5629 return std::nullopt;
5630
5631 VPValue *Op = UpdateR->getOperand(1);
5632 VPValue *PrevValue = UpdateR->getOperand(0);
5633
5634 // Find the extended operand. The other operand (PrevValue) is the next link
5635 // in the reduction chain.
5636 std::optional<ExtendedReductionOperand> ExtendedOp =
5637 matchExtendedReductionOperand(UpdateR, Op);
5638 if (!ExtendedOp) {
5639 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
5640 if (!ExtendedOp)
5641 return std::nullopt;
5642 std::swap(Op, PrevValue);
5643 }
5644
5645 // Look for VPBlend(reduce(PrevValue, Op), PrevValue), where
5646 // reduce is equal to CurrentValue. This can be lowered as
5647 // a conditional reduction by hoisting the select to the inputs.
5648 if (Blend && Blend->getIncomingValue(1 - *BlendReductionIdx) != PrevValue)
5649 return std::nullopt;
5650
5651 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
5652 TypeSize ExtSrcSize = ExtSrcType->getPrimitiveSizeInBits();
5653 if (!PHISize.hasKnownScalarFactor(ExtSrcSize))
5654 return std::nullopt;
5655
5656 PartialReductionDescriptor Link(
5657 {UpdateR, *ExtendedOp, RK,
5658 PrevValue == UpdateR->getOperand(0) ? 0U : 1U,
5659 static_cast<unsigned>(PHISize.getKnownScalarFactor(ExtSrcSize)),
5660 Blend});
5661 Chain.push_back(Link);
5662 CurrentValue = PrevValue;
5663 }
5664
5665 // The chain links were collected by traversing backwards from the exit value.
5666 // Reverse the chain so the links follow program order.
5667 std::reverse(Chain.begin(), Chain.end());
5668 return Chain;
5669}
5670} // namespace
5671
5672// Scale the PHI and ReductionStartVector by \p Factor and if the recurrence is
5673// a sub-recurrence, negate the reduction result.
5676 unsigned Factor, RecurKind RK) {
5677 assert(Phi->getVFScaleFactor() == 1 && "scale factor must not be set");
5678 Phi->setVFScaleFactor(Factor);
5679
5680 auto *StartInst = cast<VPInstruction>(Phi->getStartValue());
5681 assert(StartInst->getOpcode() == VPInstruction::ReductionStartVector);
5682 auto *NewScaleFactor = Plan.getConstantInt(32, Factor);
5683 StartInst->setOperand(2, NewScaleFactor);
5684
5685 if (RK != RecurKind::Sub && RK != RecurKind::FSub)
5686 return;
5687
5688 // Update the PHI node to start at `0` and update the reduction-result
5689 // to subtract from the PHI's start value.
5690 VPValue *OldStartValue = StartInst->getOperand(0);
5691 StartInst->setOperand(0, StartInst->getOperand(1));
5692
5693 // Replace reduction_result by 'sub (startval, reductionresult)'.
5695 assert(RdxResult && "Could not find reduction result");
5696
5697 VPBuilder Builder = VPBuilder::getToInsertAfter(RdxResult);
5698 unsigned SubOpc = RK == RecurKind::FSub ? Instruction::BinaryOps::FSub
5699 : Instruction::BinaryOps::Sub;
5700 VPInstruction *NewResult = Builder.createNaryOp(
5701 SubOpc, {OldStartValue, RdxResult}, VPIRFlags::getDefaultFlags(SubOpc),
5702 Phi->getDebugLoc());
5703 RdxResult->replaceUsesWithIf(NewResult, not_equal_to(NewResult));
5704}
5705
5707 VPCostContext &CostCtx,
5708 VFRange &Range) {
5709 // Find all possible valid partial reductions, grouping chains by their PHI.
5710 // This grouping allows invalidating the whole chain, if any link is not a
5711 // valid partial reduction.
5713 PhiToChain;
5714 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
5715 SmallVector<VPReductionPHIRecipe *, 4> UnorderedReductions;
5716 for (VPReductionPHIRecipe &RedPhiR :
5718 if (auto Chain = getScaledReductionChain(&RedPhiR))
5719 PhiToChain.try_emplace(&RedPhiR, std::move(*Chain));
5720 else if (CostCtx.Opts.use_partial_reductions_by_default &&
5721 (RedPhiR.getRecurrenceKind() == RecurKind::Add ||
5722 (RedPhiR.getRecurrenceKind() == RecurKind::FAdd &&
5723 !RedPhiR.isOrdered() && !RedPhiR.isInLoop())))
5724 UnorderedReductions.push_back(&RedPhiR);
5725 }
5726
5727 // For general unordered reductions which aren't part of a candidate chain for
5728 // a scaled partial reduction, we can still use the intrinsic to allow for
5729 // more optimization later on.
5730 for (auto *Rdx : UnorderedReductions) {
5731 auto *Backedge = dyn_cast<VPWidenRecipe>(Rdx->getBackedgeValue());
5732 VPValue *OtherOp;
5733 if (!Backedge ||
5734 !match(Backedge,
5735 m_CombineOr(m_c_FAdd(m_Specific(Rdx), m_VPValue(OtherOp)),
5736 m_c_Add(m_Specific(Rdx), m_VPValue(OtherOp)))))
5737 continue;
5738
5739 // If the target indicates that the intrinsic is as cheap as (or cheaper
5740 // than) the add, then prefer the intrinsic.
5742 [&CostCtx, Rdx, Backedge](ElementCount VF) {
5743 InstructionCost CurrentCost = Backedge->computeCost(VF, CostCtx);
5744 Type *ScalarTy = Backedge->getScalarType();
5745 auto FMF = ScalarTy->isFloatingPointTy()
5746 ? std::make_optional(Rdx->getFastMathFlagsOrNone())
5747 : std::nullopt;
5748
5750 Backedge->getOpcode(), ScalarTy, /*InputTypeB=*/nullptr,
5751 ScalarTy, VF, TTI::PR_None, TTI::PR_None,
5752 /*BinOp=*/std::nullopt, CostCtx.CostKind, FMF);
5753 return PRCost <= CurrentCost;
5754 },
5755 Range))
5756 continue;
5757
5758 auto *Partial = new VPReductionRecipe(
5759 Rdx->getRecurrenceKind(), Rdx->getFastMathFlagsOrNone(),
5760 Backedge->getUnderlyingInstr(), Rdx, OtherOp, nullptr,
5761 getReductionStyle(/*InLoop=*/false, /*Ordered=*/false,
5762 /*ScaleFactor=*/1));
5763 Partial->insertBefore(Backedge);
5764 Backedge->replaceAllUsesWith(Partial);
5765 Backedge->eraseFromParent();
5766 }
5767
5768 if (PhiToChain.empty())
5769 return;
5770
5771 // Build set of partial reduction operations and blends for user validation
5772 // and a map of reduction bin ops to their scale factors for scale validation.
5773 SmallPtrSet<VPRecipeBase *, 4> PartialReductionOps;
5774 SmallPtrSet<VPBlendRecipe *, 4> PartialReductionBlends;
5775 DenseMap<VPSingleDefRecipe *, unsigned> ScaledReductionMap;
5776 for (auto &[_, Chain] : PhiToChain)
5777 for (const PartialReductionDescriptor &Link : Chain) {
5778 PartialReductionOps.insert(Link.ExtendedOp.ExtendsUser);
5779 if (Link.Blend)
5780 PartialReductionBlends.insert(Link.Blend);
5781 ScaledReductionMap[Link.ReductionBinOp] = Link.ScaleFactor;
5782 }
5783
5784 // A partial reduction is invalid if any of its extends are used by
5785 // something that isn't another partial reduction. This is because the
5786 // extends are intended to be lowered along with the reduction itself.
5787 auto ExtendUsersValid = [&](VPValue *Ext) {
5788 return !isa<VPWidenCastRecipe>(Ext) || all_of(Ext->users(), [&](VPUser *U) {
5789 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
5790 });
5791 };
5792
5793 auto IsProfitablePartialReductionChainForVF =
5794 [&](ArrayRef<PartialReductionDescriptor> Chain, ElementCount VF) -> bool {
5795 InstructionCost PartialCost = 0, RegularCost = 0;
5796
5797 // The chain is a profitable partial reduction chain if the cost of handling
5798 // the entire chain is cheaper when using partial reductions than when
5799 // handling the entire chain using regular reductions.
5800 for (const PartialReductionDescriptor &Link : Chain) {
5801 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
5802 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
5803 if (!LinkCost.isValid())
5804 return false;
5805
5806 PartialCost += LinkCost;
5807 RegularCost += Link.ReductionBinOp->computeCost(VF, CostCtx);
5808 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
5809 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
5810 RegularCost += ExtendedOp.ExtendsUser->computeCost(VF, CostCtx);
5811 for (VPValue *Op : ExtendedOp.ExtendsUser->operands())
5812 if (auto *Extend = dyn_cast<VPWidenCastRecipe>(Op))
5813 RegularCost += Extend->computeCost(VF, CostCtx);
5814 }
5815 return PartialCost.isValid() && PartialCost < RegularCost;
5816 };
5817
5818 // Validate chains: check that extends are only used by partial reductions,
5819 // and that reduction bin ops are only used by other partial reductions with
5820 // matching scale factors, are outside the loop region or the select
5821 // introduced by tail-folding. Otherwise we would create users of scaled
5822 // reductions where the types of the other operands don't match.
5823 for (auto &[RedPhiR, Chain] : PhiToChain) {
5824 for (const PartialReductionDescriptor &Link : Chain) {
5825 if (!all_of(Link.ExtendedOp.ExtendsUser->operands(), ExtendUsersValid)) {
5826 Chain.clear();
5827 break;
5828 }
5829 auto UseIsValid = [&, RedPhiR = RedPhiR](VPUser *U) {
5830 if (auto *PhiR = dyn_cast<VPReductionPHIRecipe>(U))
5831 return PhiR == RedPhiR;
5832 auto *R = cast<VPSingleDefRecipe>(U);
5833
5834 if (auto *Blend = dyn_cast<VPBlendRecipe>(R))
5835 return Blend == Link.Blend || PartialReductionBlends.contains(Blend);
5836
5837 return Link.ScaleFactor == ScaledReductionMap.lookup_or(R, 0) ||
5839 m_Specific(Link.ReductionBinOp))) ||
5840 match(R, m_Select(m_VPValue(), m_Specific(Link.ReductionBinOp),
5841 m_Specific(RedPhiR)));
5842 };
5843 if (!all_of(Link.ReductionBinOp->users(), UseIsValid)) {
5844 Chain.clear();
5845 break;
5846 }
5847
5848 // Check if the compute-reduction-result is used by a sunk store.
5849 // TODO: Also form partial reductions in those cases.
5850 if (auto *RdxResult = vputils::findComputeReductionResult(RedPhiR)) {
5851 if (any_of(RdxResult->users(), [](VPUser *U) {
5852 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
5853 return RepR && RepR->getOpcode() == Instruction::Store;
5854 })) {
5855 Chain.clear();
5856 break;
5857 }
5858 }
5859 }
5860
5861 // Clear the chain if it is not profitable.
5863 [&, &Chain = Chain](ElementCount VF) {
5864 return IsProfitablePartialReductionChainForVF(Chain, VF);
5865 },
5866 Range))
5867 Chain.clear();
5868 }
5869
5870 for (auto &[Phi, Chain] : PhiToChain) {
5871 if (Chain.empty())
5872 continue;
5873
5874 for (const PartialReductionDescriptor &Link : Chain)
5875 transformToPartialReduction(Link, Plan, Phi);
5876
5877 // After transforming all links in the chain, the PHI node and result need
5878 // updating. Note that we can pick any link in the chain for this, as the
5879 // ScaleFactor and RecurKind must match for all links in the chain.
5880 const PartialReductionDescriptor &Link = Chain[0];
5881 updatePartialReductionPhiAndResult(Plan, Phi, Link.ScaleFactor, Link.RK);
5882 }
5883}
5884
5886 VPRecipeBuilder &RecipeBuilder,
5887 VPCostContext &CostCtx) {
5888 // Collect all loads/stores first. We will start with ones having simpler
5889 // decisions followed by more complex ones that are potentially
5890 // guided/dependent on the simpler ones.
5892 for (VPBasicBlock *VPBB :
5895 for (VPInstruction &VPI : make_isa_range<VPInstruction>(*VPBB)) {
5896 if (VPI.getUnderlyingValue() &&
5897 is_contained({Instruction::Load, Instruction::Store},
5898 VPI.getOpcode()))
5899 MemOps.push_back(&VPI);
5900 }
5901 }
5902
5903 // Few helpers to process different kinds of memory operations.
5904
5905 // To be used as argument to `VPlanTransforms::runPass` which explicitly
5906 // specified pass name, hence `VPlan &` parameter.
5907 auto ProcessSubset = [&](VPlan &, auto ProcessVPInst) {
5908 SmallVector<VPInstruction *> RemainingMemOps;
5909 for (VPInstruction *VPI : MemOps) {
5910 if (!ProcessVPInst(VPI))
5911 RemainingMemOps.push_back(VPI);
5912 }
5913
5914 MemOps.clear();
5915 std::swap(MemOps, RemainingMemOps);
5916 };
5917
5918 auto ReplaceWith = [&](VPInstruction *VPI, VPRecipeBase *New) {
5919 assert(New->getParent() && "New recipe must have been inserted");
5920 if (VPI->getOpcode() == Instruction::Load)
5921 VPI->replaceAllUsesWith(New->getVPSingleValue());
5922 VPI->eraseFromParent();
5923
5924 // VPI has been processed.
5925 return true;
5926 };
5927
5928 auto Scalarize = [&](VPInstruction *VPI) {
5929 return ReplaceWith(VPI, VPBuilder(VPI).insert(
5930 RecipeBuilder.handleReplication(VPI, Range)));
5931 };
5932
5933 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
5934 VPBuilder FinalRedStoresBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
5936 "lowerMemoryIdioms", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5937 if (RecipeBuilder.replaceWithFinalIfReductionStore(
5938 VPI, FinalRedStoresBuilder))
5939 return true;
5940
5941 // Filter out scalar VPlan for the remaining idioms.
5943 [](ElementCount VF) { return VF.isScalar(); }, Range))
5944 return false;
5945
5946 if (VPHistogramRecipe *Histogram = RecipeBuilder.widenIfHistogram(VPI))
5947 return ReplaceWith(VPI, VPBuilder(VPI).insert(Histogram));
5948
5949 return false;
5950 });
5951
5952 // Filter out scalar VPlan for the remaining memory operations.
5954 [](ElementCount VF) { return VF.isScalar(); }, Range))
5955 return;
5956
5957 // If the instruction's allocated size doesn't equal it's type size, it
5958 // requires padding and will be scalarized.
5960 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
5961 [&](VPInstruction *VPI) {
5963 if (hasIrregularType(getLoadStoreType(I), I->getDataLayout()))
5964 return Scalarize(VPI);
5965
5966 return false;
5967 });
5968
5969 if (!RecipeBuilder.prefersVectorizedAddressing()) {
5971 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](VPInstruction *VPI) {
5973 bool IsLoad = VPI->getOpcode() == Instruction::Load;
5974 if (RecipeBuilder.isPredicatedInst(I) || !IsLoad ||
5976 return false;
5977
5978 // Scalarize loads used as addresses, matching the legacy CM. The load
5979 // is single-scalar if the pointer is loop-invariant, otherwise it is
5980 // replicated per-lane. No mask is needed as the load is not
5981 // predicated.
5982 VPValue *Ptr = VPI->getOperand(0);
5983 const SCEV *PtrSCEV =
5984 vputils::getSCEVExprForVPValue(Ptr, CostCtx.PSE, CostCtx.L);
5985 bool IsSingleScalarLoad =
5986 !isa<SCEVCouldNotCompute>(PtrSCEV) &&
5987 CostCtx.PSE.getSE()->isLoopInvariant(PtrSCEV, CostCtx.L);
5988
5989 ReplaceWith(VPI,
5990 VPBuilder(VPI).insert(new VPReplicateRecipe(
5991 I, Ptr, /*IsSingleScalar=*/IsSingleScalarLoad,
5992 /*Mask=*/nullptr, *VPI, *VPI, VPI->getDebugLoc())));
5993 return true;
5994 });
5995 }
5996
5997 // Widen unit-stride consecutive accesses, matching the legacy CM. Both
5998 // forward (stride +1) and reverse (stride -1) accesses are handled.
6000 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](VPInstruction *VPI) {
6002 bool IsLoad = VPI->getOpcode() == Instruction::Load;
6003 VPValue *Ptr = VPI->getOperand(!IsLoad);
6004 Type *ScalarTy =
6005 IsLoad ? VPI->getScalarType() : VPI->getOperand(0)->getScalarType();
6006 std::optional<int64_t> Stride =
6007 vputils::getConstantStride(Ptr, ScalarTy, CostCtx.PSE, CostCtx.L);
6008 if (Stride != 1 && Stride != -1)
6009 return false;
6010 bool Reverse = Stride == -1;
6011
6012 // A predicated access can only be widened (rather than scalarized) if
6013 // the target supports a masked load/store for it.
6014 // TODO: Determine if a load/store needs predication directly in VPlan.
6015 bool IsPredicated = RecipeBuilder.isPredicatedInst(I);
6016 if (IsPredicated && !CostCtx.Config.isLegalMaskedLoadOrStore(
6017 IsLoad, ScalarTy, getLoadStoreAlignment(I),
6019 return false;
6020
6021 VPBuilder Builder(VPI);
6022 VPSingleDefRecipe *VectorPtr = Builder.createConsecutiveVectorPointer(
6023 Ptr, ScalarTy, Reverse, VPI->getDebugLoc());
6024
6025 VPValue *Mask = IsPredicated ? VPI->getMask() : nullptr;
6026 // Reverse the mask so it matches the reversed access order.
6027 if (Reverse && Mask)
6028 Mask = Builder.createNaryOp(VPInstruction::Reverse, Mask,
6029 VPI->getDebugLoc());
6030
6031 if (IsLoad) {
6032 VPSingleDefRecipe *Load = Builder.createWidenLoad(
6033 *cast<LoadInst>(I), VectorPtr, Mask,
6034 /*Consecutive=*/true, *VPI, VPI->getDebugLoc());
6035 // Reverse the loaded values back into program order.
6036 if (Reverse)
6037 Load = Builder.createNaryOp(VPInstruction::Reverse, Load,
6038 VPI->getDebugLoc());
6039 return ReplaceWith(VPI, Load);
6040 }
6041
6042 VPValue *StoredVal = VPI->getOperand(0);
6043 if (Reverse)
6044 // Reverse the stored values so they are written in descending order.
6045 StoredVal = Builder.createNaryOp(VPInstruction::Reverse, StoredVal,
6046 VPI->getDebugLoc());
6047
6048 auto *StoreR = Builder.createWidenStore(
6049 *cast<StoreInst>(I), VectorPtr, StoredVal, Mask,
6050 /*Consecutive=*/true, *VPI, VPI->getDebugLoc());
6051 return ReplaceWith(VPI, StoreR);
6052 });
6053
6054 VPlanTransforms::runPass("delegateMemOpWideningToLegacyCM", ProcessSubset,
6055 Plan, [&](VPInstruction *VPI) {
6056 if (VPRecipeBase *Recipe =
6057 RecipeBuilder.tryToWidenMemory(VPI, Range))
6058 return ReplaceWith(VPI, Recipe);
6059
6060 return Scalarize(VPI);
6061 });
6062}
6063
6066 [&](ElementCount VF) { return VF.isScalar(); }, Range))
6067 return;
6068
6070 Plan.getEntry());
6072 for (VPInstruction &VPI :
6074 auto *I = cast_or_null<Instruction>(VPI.getUnderlyingValue());
6075 // Wouldn't be able to create a `VPReplicateRecipe` anyway.
6076 if (!I)
6077 continue;
6078
6079 // If executing other lanes produces side-effects we can't avoid them.
6080 if (VPI.mayHaveSideEffects())
6081 continue;
6082
6083 // ExtractValue takes the shape of its aggregate, decided in
6084 // tryToCreateWidenNonPhiRecipe.
6085 if (VPI.getOpcode() == Instruction::ExtractValue)
6086 continue;
6087
6088 // We want to drop the mask operand, verify we can safely do that.
6089 if (VPI.isMasked() && !VPI.isSafeToSpeculativelyExecute())
6090 continue;
6091
6092 // Other lanes are needed - can't drop them.
6093 if (!vputils::onlyFirstLaneUsed(&VPI))
6094 continue;
6095
6096 auto *Recipe = VPBuilder::createSingleScalarOp(
6097 VPI.getOpcode(), VPI.operandsWithoutMask(), /*Mask=*/nullptr, VPI,
6098 VPI, VPI.getDebugLoc(), VPI.getScalarType(), I);
6099 Recipe->insertBefore(&VPI);
6100 VPI.replaceAllUsesWith(Recipe);
6101 VPI.eraseFromParent();
6102 }
6103 }
6104}
6105
6106/// Returns true if \p Info's parameter kinds are compatible with \p Args.
6107static bool areVFParamsOk(const VFInfo &Info, ArrayRef<VPValue *> Args,
6108 PredicatedScalarEvolution &PSE, const Loop *L) {
6109 ScalarEvolution *SE = PSE.getSE();
6110 return all_of(Info.Shape.Parameters, [&](VFParameter Param) {
6111 switch (Param.ParamKind) {
6112 case VFParamKind::Vector:
6113 case VFParamKind::GlobalPredicate:
6114 return true;
6115 case VFParamKind::OMP_Uniform:
6116 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
6117 SE->isLoopInvariant(
6118 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6119 L);
6120 case VFParamKind::OMP_Linear:
6121 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
6122 m_scev_AffineAddRec(
6123 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
6124 m_SpecificLoop(L)));
6125 default:
6126 return false;
6127 }
6128 });
6129}
6130
6131/// Find a vector variant of \p CI for \p VF, respecting \p MaskRequired.
6132/// Returns the variant function, or nullptr. Masked variants are assumed to
6133/// take the mask as a trailing parameter.
6135 ElementCount VF, bool MaskRequired,
6137 const Loop *L) {
6138 if (CI->isNoBuiltin())
6139 return nullptr;
6140 auto Mappings = VFDatabase::getMappings(*CI);
6141 const auto *It = find_if(Mappings, [&](const VFInfo &Info) {
6142 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
6143 areVFParamsOk(Info, Args, PSE, L);
6144 });
6145 if (It == Mappings.end())
6146 return nullptr;
6147 return CI->getModule()->getFunction(It->VectorName);
6148}
6149
6150namespace {
6151/// The outcome of choosing how to widen a call at a given VF.
6152struct CallWideningDecision {
6153 enum class KindTy { Scalarize, Intrinsic, VectorVariant };
6154 CallWideningDecision(KindTy Kind, Function *Variant = nullptr)
6155 : Kind(Kind), Variant(Variant) {}
6156 KindTy Kind;
6157
6158 /// Set when Kind == VectorVariant.
6160
6161 bool operator==(const CallWideningDecision &Other) const {
6162 return Kind == Other.Kind && Variant == Other.Variant;
6163 }
6164};
6165} // namespace
6166
6167/// Pick the cheapest widening for the call \p VPI at \p VF among scalarization,
6168/// vector intrinsic, and vector library variant.
6169static CallWideningDecision decideCallWidening(VPInstruction &VPI,
6171 ElementCount VF,
6172 VPCostContext &CostCtx) {
6173 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
6174
6175 // Scalar VFs and calls forced or known to scalarize always replicate.
6176 if (VF.isScalar() || CostCtx.willBeScalarized(CI, VF))
6177 return CallWideningDecision::KindTy::Scalarize;
6178
6179 auto *CalledFn = cast<Function>(
6181 Type *ResultTy = VPI.getScalarType();
6183 bool MaskRequired = CostCtx.isMaskRequired(CI);
6184
6185 // Pseudo intrinsics (assume, lifetime, ...) are always scalarized.
6187 return CallWideningDecision::KindTy::Scalarize;
6188
6189 InstructionCost ScalarCost =
6190 VPReplicateRecipe::computeCallCost(CalledFn, ResultTy, Ops,
6191 /*IsSingleScalar=*/false, VF, CostCtx);
6192
6193 Function *VecFunc =
6194 findVectorVariant(CI, Ops, VF, MaskRequired, CostCtx.PSE, CostCtx.L);
6196 if (VecFunc)
6197 VecCallCost = VPWidenCallRecipe::computeCallCost(VecFunc, CostCtx);
6198
6199 // Prefer the intrinsic if it is at least as cheap as scalarizing and any
6200 // available vector variant.
6201 if (ID) {
6203 VPWidenIntrinsicRecipe::computeCallCost(ID, Ops, VPI, VF, CostCtx);
6204 if (IntrinsicCost.isValid() && ScalarCost >= IntrinsicCost &&
6205 (!VecFunc || VecCallCost >= IntrinsicCost))
6206 return CallWideningDecision::KindTy::Intrinsic;
6207 }
6208
6209 // Otherwise, use a vector library variant when it beats scalarizing.
6210 if (VecFunc && ScalarCost >= VecCallCost)
6211 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
6212
6213 return CallWideningDecision::KindTy::Scalarize;
6214}
6215
6217 VPRecipeBuilder &RecipeBuilder,
6218 VPCostContext &CostCtx) {
6219 bool Widened = false;
6222 for (VPInstruction &VPI :
6224 if (!VPI.getUnderlyingValue() || VPI.getOpcode() != Instruction::Call)
6225 continue;
6226
6227 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
6228 SmallVector<VPValue *, 4> Ops(VPI.op_begin(),
6229 VPI.op_begin() + CI->arg_size());
6230
6231 CallWideningDecision Decision =
6232 decideCallWidening(VPI, Ops, Range.Start, CostCtx);
6234 [&](ElementCount VF) {
6235 return Decision == decideCallWidening(VPI, Ops, VF, CostCtx);
6236 },
6237 Range);
6238
6239 assert((Decision.Kind == CallWideningDecision::KindTy::Scalarize ||
6240 !CI->hasOperandBundles()) &&
6241 "calls with operand bundles must not be widened");
6242 VPSingleDefRecipe *Replacement = nullptr;
6243 switch (Decision.Kind) {
6244 case CallWideningDecision::KindTy::Intrinsic: {
6246 Type *ResultTy = VPI.getScalarType();
6247 Replacement = new VPWidenIntrinsicRecipe(*CI, ID, Ops, ResultTy, VPI,
6248 VPI, VPI.getDebugLoc());
6249 Widened = true;
6250 break;
6251 }
6252 case CallWideningDecision::KindTy::VectorVariant: {
6253 // Masked variants take the mask as a trailing parameter, so they have
6254 // one more parameter than the original call's arguments.
6255 if (Decision.Variant->arg_size() > Ops.size()) {
6256 VPValue *Mask = VPI.isMasked() ? VPI.getMask() : Plan.getTrue();
6257 Ops.push_back(Mask);
6258 }
6259 Ops.push_back(VPI.getOperand(VPI.getNumOperandsWithoutMask() - 1));
6260 VPIRAttributes Attrs(VPI, Decision.Variant->getFunctionType());
6261 Replacement = new VPWidenCallRecipe(CI, Decision.Variant, Ops, VPI, VPI,
6262 Attrs, VPI.getDebugLoc());
6263 Widened = true;
6264 break;
6265 }
6266 case CallWideningDecision::KindTy::Scalarize:
6267 Replacement = RecipeBuilder.handleReplication(&VPI, Range);
6268 break;
6269 }
6270
6271 Replacement->insertBefore(&VPI);
6272 VPI.replaceAllUsesWith(Replacement);
6273 VPI.eraseFromParent();
6274 }
6275 }
6276 return Widened;
6277}
6278
6280 const TargetTransformInfo &TTI,
6282 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
6283 VPBasicBlock *HeaderVPBB = LoopRegion->getEntryBasicBlock();
6285 vp_depth_first_shallow(LoopRegion->getEntry()))) {
6286 for (VPInstruction &VPI :
6288 // Only truncates are handled, as sext/zext may wrap, FP conversions lose
6289 // precision and other casts depend on the pointer size.
6290 if (VPI.getOpcode() != Instruction::Trunc)
6291 continue;
6292
6293 VPValue *Op = VPI.getOperand(0);
6294 auto *WideIV = getOptimizableIVOf(Op, PSE);
6295 if (!WideIV)
6296 continue;
6297
6298 // getOptimizableIVOf also matches an add of the IV and its step, which
6299 // is not handled here.
6300 // TODO: Also narrow truncates of the incremented IV.
6301 if (Op != WideIV)
6302 continue;
6303
6304 // A truncate that is not widened is left to the scalarization decisions
6305 // made earlier.
6307 continue;
6308
6309 // Replacing a free truncate would add an induction update instruction to
6310 // each iteration of the loop. The canonical induction is exempt, as it
6311 // needs an update instruction regardless.
6312 auto IsNarrowingProfitable = [&](ElementCount VF) {
6313 return match(WideIV, m_CanonicalWidenIV()) ||
6314 !TTI.isTruncateFree(
6315 toVectorTy(VPI.getOperand(0)->getScalarType(), VF),
6316 toVectorTy(VPI.getScalarType(), VF));
6317 };
6319 IsNarrowingProfitable, Range))
6320 continue;
6321
6322 // Wrap flags of the original induction do not hold in the truncated
6323 // type, so do not propagate them.
6324 auto *NarrowIV = new VPWidenIntOrFpInductionRecipe(
6325 WideIV->getPHINode(), WideIV->getStartValue(), WideIV->getStepValue(),
6326 WideIV->getVFValue(), WideIV->getInductionDescriptor(),
6327 VPI.getScalarType(), VPIRFlags::WrapFlagsTy(false, false),
6328 VPI.getDebugLoc());
6329 NarrowIV->insertBefore(*HeaderVPBB, HeaderVPBB->getFirstNonPhi());
6330 VPI.replaceAllUsesWith(NarrowIV);
6331 VPI.eraseFromParent();
6332 }
6333 }
6334}
6335
6338 Loop &L, VPCostContext &Ctx,
6339 VFRange &Range) {
6340 if (Plan.hasScalarVFOnly())
6341 return;
6342
6343 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
6344 VPValue *I32VF = nullptr;
6346 vp_depth_first_shallow(VectorLoop->getEntry()))) {
6347 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
6348 auto *MemR = dyn_cast<VPWidenMemoryRecipe>(&R);
6349 // TODO: Transform reverse access into strided access with -1 stride.
6350 // TODO: Transform gather/scatter with uniform address into strided access
6351 // with 0 stride.
6352 // TODO: Transform interleave access into multiple strided accesses.
6353 if (!MemR || MemR->isConsecutive())
6354 continue;
6355
6356 VPValue *Ptr = MemR->getAddr();
6357 // Check if this is a strided access by analyzing the address SCEV for an
6358 // affine addRec.
6359 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, &L);
6360 const SCEV *Start;
6361 const SCEVConstant *Step;
6362 // TODO: Support non-constant loop invariant stride.
6363 if (!match(PtrSCEV,
6365 m_SpecificLoop(&L))))
6366 continue;
6367
6368 VPValue *StoredValue = nullptr;
6369 Type *DataTy;
6370 Intrinsic::ID IntrinID;
6371 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(&R)) {
6372 StoredValue = StoreR->getStoredValue();
6373 DataTy = StoredValue->getScalarType();
6374 IntrinID = Intrinsic::experimental_vp_strided_store;
6375 } else {
6376 auto *LoadR = cast<VPWidenLoadRecipe>(&R);
6377 DataTy = LoadR->getScalarType();
6378 IntrinID = Intrinsic::experimental_vp_strided_load;
6379 }
6380
6381 Align Alignment = MemR->getAlign();
6382 auto IsProfitable = [&](ElementCount VF) {
6383 Type *VectorTy = toVectorTy(DataTy, VF);
6384 if (!Ctx.TTI.isLegalStridedLoadStore(VectorTy, Alignment))
6385 return false;
6386 const InstructionCost CurrentCost = MemR->computeCost(VF, Ctx);
6387 const InstructionCost StridedLoadStoreCost =
6389 IntrinID, VectorTy, MemR->isMasked(), Alignment, Ctx);
6390 return StridedLoadStoreCost < CurrentCost;
6391 };
6392
6394 Range))
6395 continue;
6396
6397 // Invalidate the legacy widening decision so the cost of replaced load is
6398 // not counted during precomputeCosts.
6399 // TODO: Remove once the legacy exit cost computation is retired.
6400 for (ElementCount VF : Range)
6401 Ctx.invalidateWideningDecision(&MemR->getIngredient(), VF);
6402
6403 // Get VF as i32 for the vector length operand.
6404 if (!I32VF) {
6405 VPBuilder Builder(Plan.getVectorPreheader());
6406 I32VF = Builder.createScalarZExtOrTrunc(
6407 &Plan.getVF(), Type::getInt32Ty(Plan.getContext()),
6409 }
6410
6411 VPBuilder Builder(&R);
6412 // Create the base pointer of strided access.
6413 // TODO: reuse VPDerivedIVRecipe for base pointer computation when it
6414 // supports a general VPValue as the start value.
6415 VPValue *StartVPV =
6416 VPSCEVExpander(Builder, *PSE.getSE(), R.getDebugLoc()).expand(Start);
6417 VPValue *StrideInBytes = Plan.getOrAddLiveIn(Step->getValue());
6418 Type *IndexTy = Plan.getDataLayout().getIndexType(Ptr->getScalarType());
6419 assert(IndexTy == StrideInBytes->getScalarType() &&
6420 "Stride type from SCEV must match the index type");
6421 VPValue *CanIV = Builder.createScalarZExtOrTrunc(
6422 VectorLoop->getCanonicalIV(), IndexTy, DebugLoc::getUnknown());
6423 auto *AddRecPtr = cast<SCEVAddRecExpr>(PtrSCEV);
6424 auto *Offset = Builder.createOverflowingOp(
6425 Instruction::Mul, {CanIV, StrideInBytes},
6426 {AddRecPtr->hasNoUnsignedWrap(), /*HasNSW=*/false});
6427 GEPNoWrapFlags NWFlags = AddRecPtr->hasNoUnsignedWrap()
6430 VPValue *BasePtr = Builder.createNoWrapPtrAdd(StartVPV, Offset, NWFlags);
6431
6432 // Create a new vector pointer for strided access.
6433 VPValue *NewPtr = Builder.createVectorPointer(
6434 BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes, NWFlags,
6435 R.getDebugLoc());
6436
6437 VPValue *Mask = MemR->getMask();
6438 if (!Mask)
6439 Mask = Plan.getTrue();
6441 if (StoredValue)
6442 Ops.push_back(StoredValue);
6443 Ops.append({NewPtr, StrideInBytes, Mask, I32VF});
6444
6445 auto *StridedR = Builder.createWidenMemIntrinsic(
6446 IntrinID, Ops,
6447 StoredValue ? Type::getVoidTy(Plan.getContext()) : DataTy, Alignment,
6448 *MemR, R.getDebugLoc());
6449 if (!StoredValue)
6450 cast<VPWidenLoadRecipe>(&R)->replaceAllUsesWith(StridedR);
6451 R.eraseFromParent();
6452 }
6453 }
6454}
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:338
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 bool loopMayHaveSideEffects(VPBasicBlock *HeaderVPBB)
static VPValue * tryToComputeEndValueForInduction(VPWidenInductionRecipe *WideIV, VPBuilder &VectorPHBuilder, VPValue *VectorTC)
Compute the end value for WideIV, unless it is truncated.
static bool replaceMaskWithCompareForScalarPlan(VPlan &Plan, ElementCount BestVF)
static VPValue * simplifyRecipe(VPlan &Plan, VPSingleDefRecipe *Def)
Return an existing value or a live in for VPSingleDefRecipe Def if possible.
static VPValue * optimizeEarlyExitInductionUser(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the early exit block.
static bool canFoldOuterExtendIntoMul(VPWidenRecipe *Mul)
Returns true if the narrow Mul in ext(mul(ext(A), ext(B))) or ext(mul(ext(A), C)) cannot wrap.
static VPValue * narrowInterleaveGroupOp(ArrayRef< VPValue * > Members, SmallPtrSetImpl< VPValue * > &NarrowedOps, VPBasicBlock *Preheader)
static VPValue * optimizeLatchExitInductionUser(VPlan &Plan, VPValue *Op, DenseMap< VPValue *, VPValue * > &EndValues, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the exit block coming from the l...
static void reassociateHeaderMask(VPlan &Plan)
Reassociate (headermask && x) && y -> headermask && (x && y) to allow the header mask to be simplifie...
static void updatePartialReductionPhiAndResult(VPlan &Plan, VPReductionPHIRecipe *Phi, unsigned Factor, RecurKind RK)
static VPSingleDefRecipe * combineRecipe(VPlan &Plan, VPSingleDefRecipe *Def, VPCombineBuilder &Builder)
Combine Def into a simpler recipe.
static VPBasicBlock * getPredicatedThenBlock(VPRegionBlock *R)
If R is a triangle region, return the 'then' block of the triangle.
static bool tryToRemoveDeadCycle(VPRecipeBase *R)
If R is a phi-like recipe starting a dead cycle of recipes, erase all reachable recipes of the dead c...
static bool canHoistOrSinkWithNoAliasCheck(const MemoryLocation &MemLoc, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, std::optional< SinkStoreInfo > SinkInfo={})
Check if a memory operation doesn't alias with memory operations using scoped noalias metadata,...
static VPRegionBlock * createReplicateRegion(VPReplicateRecipe *PredRecipe, VPRegionBlock *ParentRegion, VPlan &Plan)
static void simplifyBlends(VPlan &Plan)
Normalize and simplify VPBlendRecipes.
static bool cannotHoistOrSinkRecipe(VPRecipeBase &R, VPBasicBlock *FirstBB, VPBasicBlock *LastBB, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink a non-memory or memory recipe R out...
static auto m_Uncountable(VPValue *&Cond)
Matches an exit condition formed by comparing a value loaded from memory with a loop-invariant term.
static std::optional< Instruction::BinaryOps > getUnmaskedDivRemOpcode(Intrinsic::ID ID)
static bool isAlreadyNarrow(VPValue *VPV)
Returns true if VPValue is a narrow VPValue.
static bool optimizeVectorInductionWidthForTCAndVFUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF)
Optimize the width of vector induction variables in Plan based on a known constant Trip Count,...
static VPExpressionRecipe * tryToMatchAndCreateMulAccumulateReduction(VPReductionRecipe *Red, VPCostContext &Ctx, VFRange &Range)
This function tries convert extended in-loop reductions to VPExpressionRecipe and clamp the Range if ...
static bool canSinkStoreWithNoAliasCheck(ArrayRef< VPReplicateRecipe * > StoresToSink, PredicatedScalarEvolution &PSE, const Loop &L)
static std::optional< bool > getStepDirection(const SCEV *S, ScalarEvolution &SE)
If S is an affine AddRec, returns true if its step is known to be positive and false if it is known t...
static VPIRMetadata getMetadataOf(VPRecipeBase *R)
Returns the metadata attached to R, or an empty set for a recipe that does not carry any.
static Type * getLoadStoreValueType(VPSingleDefRecipe *R)
Get the value type of a VPInstruction or VPReplicateRecipe load or store.
static void narrowToSingleScalarRecipes(VPlan &Plan)
This file provides utility VPlan to VPlan transformations.
#define RUN_VPLAN_PASS(PASS,...)
This file contains the declarations of the Vectorization Plan base classes:
static const X86InstrFMA3Group Groups[]
Value * RHS
Value * LHS
BinaryOperator * Mul
static const uint32_t IV[8]
Definition blake3_impl.h:83
Helper for extra no-alias checks via known-safe recipe and SCEV.
SinkStoreInfo(ArrayRef< VPReplicateRecipe * > ExcludeRecipes, VPReplicateRecipe &GroupLeader, PredicatedScalarEvolution &PSE, const Loop &L)
SinkStoreInfo(VPReplicateRecipe &GroupLeader)
bool shouldSkip(VPRecipeBase &R) const
Return true if R should be skipped during alias checking, either because it's in the exclude set or b...
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
APInt abs() const
Get the absolute value.
Definition APInt.h:1815
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
int32_t exactLogBase2() const
Definition APInt.h:1803
bool isNonNegative() const
Determine if this APInt Value is non-negative (>= 0)
Definition APInt.h:330
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1030
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:436
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
Definition APInt.h:1225
An arbitrary precision integer that knows its signedness.
Definition APSInt.h:24
static APSInt getMinValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the minimum integer value with the given bit width and signedness.
Definition APSInt.h:310
static APSInt getMaxValue(uint32_t numBits, bool Unsigned)
Return the APSInt representing the maximum integer value with the given bit width and signedness.
Definition APSInt.h:302
@ NoAlias
The two locations do not alias at all.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & back() const
Get the last element.
Definition ArrayRef.h:150
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:194
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
bool isNoBuiltin() const
Return true if the call should not be treated as a call to a builtin.
This class represents a function call, abstracting a target machine's calling convention.
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
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.
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:1610
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
LLVM_ABI MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight, bool IsExpected=false)
Return metadata containing two branch weights.
Definition MDBuilder.cpp:38
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
ValueT lookup(const KeyT &Key) const
Definition MapVector.h:110
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Definition MapVector.h:118
bool empty() const
Definition MapVector.h:79
Representation for a specific memory location.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Definition Module.cpp:235
The optimization diagnostic interface.
Post-order traversal of a graph.
An interface layer with SCEV used to manage how we see SCEV expressions for values in the context of ...
ScalarEvolution * getSE() const
Returns the ScalarEvolution analysis used.
LLVM_ABI const SCEV * getSCEV(Value *V)
Returns the SCEV expression of V, in the context of the current SCEV predicate.
static LLVM_ABI unsigned getOpcode(RecurKind Kind)
Returns the opcode corresponding to the RecurrenceKind.
static bool isFindLastRecurrenceKind(RecurKind Kind)
Returns true if the recurrence kind is of the form select(cmp(),x,y) where one of (x,...
LLVM_ABI bool match(StringRef String, SmallVectorImpl< StringRef > *Matches=nullptr, std::string *Error=nullptr) const
matches - Match the regex against a given String.
Definition Regex.cpp:84
RegionT * getParent() const
Get the parent of the Region.
Definition RegionInfo.h:365
This class represents a constant integer value.
ConstantInt * getValue() const
static const SCEV * rewrite(const SCEV *Scev, ScalarEvolution &SE, ValueToSCEVMapTy &Map)
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
const DataLayout & getDataLayout() const
Return the DataLayout associated with the module this SCEV instance is operating on.
LLVM_ABI const SCEV * getElementCount(Type *Ty, ElementCount EC, SCEVFlags Flags=SCEV::FlagNone)
LLVM_ABI bool isKnownNegative(const SCEV *S)
Test if the given expression is known to be negative.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
ConstantRange getSignedRange(const SCEV *S)
Determine the signed range for a particular SCEV.
LLVM_ABI bool isLoopInvariant(const SCEV *S, const Loop *L)
Return true if the value of the given SCEV is unchanging in the specified loop.
LLVM_ABI bool isKnownPositive(const SCEV *S)
Test if the given expression is known to be positive.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
LLVM_ABI bool isKnownPredicate(CmpPredicate Pred, SCEVUse LHS, SCEVUse RHS)
Test if the given expression is known to satisfy the condition described by Pred, LHS,...
LLVM_ABI bool isGuaranteedNotToCauseUB(const SCEV *Op)
Returns true if Op is guaranteed not to cause immediate UB.
LLVM_ABI const SCEV * getNegativeSCEV(const SCEV *V, SCEVFlags Flags=SCEV::FlagNone)
Return the SCEV object corresponding to -V.
static LLVM_ABI AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A vector that has set insertion semantics.
Definition SetVector.h:57
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
size_type size() const
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
iterator begin() const
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
static LLVM_ABI PartialReductionExtendKind getPartialReductionExtendKind(Instruction *I)
Get the kind of extension that an instruction represents.
TargetCostKind
The kind of cost model.
@ TCK_RecipThroughput
Reciprocal throughput.
LLVM_ABI InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, PartialReductionExtendKind OpAExtend, PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
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:4487
void appendRecipe(VPRecipeBase *Recipe)
Augment the existing recipes of a VPBasicBlock with an additional Recipe as the last recipe.
Definition VPlan.h:4562
RecipeListTy::iterator iterator
Instruction iterators...
Definition VPlan.h:4514
iterator end()
Definition VPlan.h:4524
iterator begin()
Recipe iterator methods.
Definition VPlan.h:4522
iterator_range< iterator > phis()
Returns an iterator range over the PHI-like recipes in the block.
Definition VPlan.h:4575
iterator getFirstNonPhi()
Return the position of the first non-phi node recipe in the block.
Definition VPlan.cpp:228
VPBasicBlock * splitAt(iterator SplitAt)
Split current block at SplitAt by inserting a new block between the current block and its successors ...
Definition VPlan.cpp:528
const VPRecipeBase & front() const
Definition VPlan.h:4534
VPRecipeBase * getTerminator()
If the block has multiple successors, return the branch recipe terminating the block.
Definition VPlan.cpp:607
const VPRecipeBase & back() const
Definition VPlan.h:4536
void insert(VPRecipeBase *Recipe, iterator InsertPt)
Definition VPlan.h:4553
bool empty() const
Definition VPlan.h:4533
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
Definition VPlan.h:3018
VPValue * getIncomingValue(unsigned Idx) const
Return incoming value number Idx.
Definition VPlan.h:3065
VPValue * getMask(unsigned Idx) const
Return mask number Idx.
Definition VPlan.h:3070
unsigned getNumIncomingValues() const
Return the number of incoming values, taking into account when normalized the first incoming value wi...
Definition VPlan.h:3060
void setMask(unsigned Idx, VPValue *V)
Set mask number Idx to V.
Definition VPlan.h:3076
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:3056
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
Definition VPlan.h:99
void setSuccessors(ArrayRef< VPBlockBase * > NewSuccs)
Set each VPBasicBlock in NewSuccss as successor of this VPBlockBase.
Definition VPlan.h:309
VPRegionBlock * getParent()
Definition VPlan.h:197
const VPBasicBlock * getExitingBasicBlock() const
Definition VPlan.cpp:198
size_t getNumSuccessors() const
Definition VPlan.h:247
void setPredecessors(ArrayRef< VPBlockBase * > NewPreds)
Set each VPBasicBlock in NewPreds as predecessor of this VPBlockBase.
Definition VPlan.h:300
const VPBlocksTy & getPredecessors() const
Definition VPlan.h:232
VPBlockBase * getSinglePredecessor() const
Definition VPlan.h:243
void clearPredecessors()
Remove all the predecessor of this block.
Definition VPlan.h:316
const VPBasicBlock * getEntryBasicBlock() const
Definition VPlan.cpp:183
VPBlockBase * getSingleSuccessor() const
Definition VPlan.h:237
const VPBlocksTy & getSuccessors() const
Definition VPlan.h:221
static auto blocksAs(T &&Range)
Return an iterator range over Range with each block cast to BlockTy.
Definition VPlanUtils.h:436
static void insertOnEdge(VPBlockBase *From, VPBlockBase *To, VPBlockBase *BlockPtr)
Inserts BlockPtr on the edge between From and To.
Definition VPlanUtils.h:455
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:345
static void connectBlocks(VPBlockBase *From, VPBlockBase *To, unsigned PredIdx=-1u, unsigned SuccIdx=-1u)
Connect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:363
static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To)
Disconnect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:381
static auto blocksOnly(T &&Range)
Return an iterator range over Range which only includes BlockTy blocks.
Definition VPlanUtils.h:429
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:413
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:3569
VPlan-based builder utility similar to IRBuilder.
VPInstruction * createFreeze(VPValue *Op, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
static VPBuilderBase getToInsertAfter(VPRecipeBase *R)
VPInstruction * createLogicalAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createAnyOfReduction(VPValue *ChainOp, VPValue *TrueVal, VPValue *FalseVal, DebugLoc DL=DebugLoc::getUnknown())
Create an AnyOf reduction pattern: or-reduce ChainOp, freeze the result, then select between TrueVal ...
VPDerivedIVRecipe * createDerivedIV(InductionDescriptor::InductionKind Kind, FPMathOperator *FPBinOp, VPValue *Start, VPValue *Current, VPValue *Step, const VPIRFlags::WrapFlagsTy &Flags={})
Convert Current to Start + Current * Step.
VPWidenCastRecipe * createWidenCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
VPInstruction * createAdd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", VPRecipeWithIRFlags::WrapFlagsTy WrapFlags={false, false})
VPInstruction * createSelect(VPValue *Cond, VPValue *TrueVal, VPValue *FalseVal, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", std::optional< VPIRFlags > Flags=std::nullopt)
Create a select of TrueVal and FalseVal based on Cond, using the default flags for the result type,...
VPValue * createScalarZExtOrTrunc(VPValue *Op, Type *ResultTy, DebugLoc DL)
static VPSingleDefRecipe * createSingleScalarOp(unsigned Opcode, ArrayRef< VPValue * > Operands, VPValue *Mask, const VPIRFlags &Flags, const VPIRMetadata &Metadata, DebugLoc DL, Type *ResultTy, Instruction *UV)
VPInstruction * createLogicalOr(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createScalarCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy, DebugLoc DL, std::optional< VPIRFlags > Flags=std::nullopt, const VPIRMetadata &Metadata={})
VPInstruction * createNot(VPValue *Operand, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPWidenLoadRecipe * createWidenLoad(LoadInst &Load, VPValue *Addr, VPValue *Mask, bool Consecutive, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Load, loading from Addr with Mask (may be null).
void setInsertPoint(const VPInsertPoint &IP)
Set the current insert point.
VPWidenStoreRecipe * createWidenStore(StoreInst &Store, VPValue *Addr, VPValue *StoredVal, VPValue *Mask, bool Consecutive, const VPIRMetadata &Metadata, DebugLoc DL)
Create a recipe widening Store, storing StoredVal to Addr with Mask (may be null).
VPInstruction * createNaryOp(unsigned Opcode, ArrayRef< VPValue * > Operands, Instruction *Inst=nullptr, const VPIRFlags &Flags={}, const VPIRMetadata &MD={}, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", Type *ResultTy=nullptr, 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="")
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:4090
A recipe to combine multiple recipes into a single 'expression' recipe, which should be considered a ...
Definition VPlan.h:3616
A pure virtual base class for all recipes modeling header phis, including phis for first order recurr...
Definition VPlan.h:2509
virtual VPValue * getBackedgeValue()
Returns the incoming value from the loop backedge.
Definition VPlan.h:2552
VPValue * getStartValue()
Returns the start value of the phi, if one is set.
Definition VPlan.h:2541
A recipe representing a sequence of load -> update -> store as part of a histogram operation.
Definition VPlan.h:2220
Manage IR attributes for call recipes.
Definition VPlan.h:1276
A special type of VPBasicBlock that wraps an existing IR basic block.
Definition VPlan.h:4640
Class to record and manage LLVM IR flags.
Definition VPlan.h:690
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:1159
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:1329
unsigned getNumOperandsWithoutMask() const
Returns the number of operands, excluding the mask if the VPInstruction is masked.
Definition VPlan.h:1578
@ ExtractLane
Extracts a single lane (first operand) from a set of vector operands.
Definition VPlan.h:1434
@ ReductionStartVector
Start vector for reductions with 3 operands: the original start value, the identity value for the red...
Definition VPlan.h:1430
@ BuildVector
Creates a fixed-width vector containing all operands.
Definition VPlan.h:1380
@ ComputeReductionResult
Reduce the operands to the final reduction result using the operation specified via the operation's V...
Definition VPlan.h:1388
unsigned getOpcode() const
Definition VPlan.h:1521
VPValue * getMask() const
Returns the mask for the VPInstruction.
Definition VPlan.h:1594
const InterleaveGroup< Instruction > * getInterleaveGroup() const
Definition VPlan.h:3171
VPValue * getMask() const
Return the mask used by this recipe.
Definition VPlan.h:3163
ArrayRef< VPValue * > getStoredValues() const
Return the VPValues stored by this interleave group.
Definition VPlan.h:3192
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
Definition VPlan.h:3202
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
Definition VPlan.h:3777
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition VPlan.h:405
VPRegionBlock * getRegion()
Definition VPlan.h:4886
VPBasicBlock * getParent()
Definition VPlan.h:477
DebugLoc getDebugLoc() const
Returns the debug location of the recipe.
Definition VPlan.h:555
void moveBefore(VPBasicBlock &BB, iplist< VPRecipeBase >::iterator I)
Unlink this recipe and insert into BB before I.
void insertBefore(VPRecipeBase *InsertPos)
Insert an unlinked recipe into a basic block immediately before the specified recipe.
void insertAfter(VPRecipeBase *InsertPos)
Insert an unlinked Recipe into a basic block immediately after the specified Recipe.
iplist< VPRecipeBase >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Helper class to create VPRecipies from IR instructions.
VPHistogramRecipe * widenIfHistogram(VPInstruction *VPI)
If VPI represents a histogram operation (as determined by LoopVectorizationLegality) make that safe f...
bool prefersVectorizedAddressing() const
Returns true if the target prefers vectorized addressing.
VPRecipeBase * tryToWidenMemory(VPInstruction *VPI, VFRange &Range)
Check if the load or store instruction VPI should widened for Range.Start and potentially masked.
bool replaceWithFinalIfReductionStore(VPInstruction *VPI, VPBuilder &FinalRedStoresBuilder)
If VPI is a store of a reduction into an invariant address, delete it.
VPSingleDefRecipe * handleReplication(VPInstruction *VPI, VFRange &Range)
Build a replicating or single-scalar recipe for VPI.
bool isPredicatedInst(Instruction *I) const
Returns true if I needs to be predicated (i.e.
Type * getScalarType() const
Returns the scalar type of this VPRecipeValue.
Definition VPlanValue.h:349
A recipe for handling reduction phis.
Definition VPlan.h:2912
bool isOrdered() const
Returns true, if the phi is part of an ordered reduction.
Definition VPlan.h:2984
bool isInLoop() const
Returns true if the phi is part of an in-loop reduction.
Definition VPlan.h:2987
RecurKind getRecurrenceKind() const
Returns the recurrence kind of the reduction.
Definition VPlan.h:2981
A recipe to represent inloop, ordered or partial reduction operations.
Definition VPlan.h:3295
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition VPlan.h:4712
const VPBlockBase * getEntry() const
Definition VPlan.h:4756
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
Definition VPlan.h:4788
void setExiting(VPBlockBase *ExitingBlock)
Set ExitingBlock as the exiting VPBlockBase of this VPRegionBlock.
Definition VPlan.h:4773
void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override
Print this VPRegionBlock to O (recursively), prefixing all lines with Indent.
Definition VPlan.cpp:799
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
Definition VPlan.h:4840
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
Definition VPlan.h:4832
const VPBlockBase * getExiting() const
Definition VPlan.h:4768
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
Definition VPlan.h:4845
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition VPlan.h:3462
bool isSingleScalar() const
Returns true if the recipe produces a single scalar value.
Definition VPlan.h:3519
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:3547
bool isPredicated() const
Definition VPlan.h:3524
VPValue * getMask()
Return the mask of a predicated VPReplicateRecipe.
Definition VPlan.h:3541
Lightweight SCEV-to-VPlan expander.
Definition VPlanUtils.h:275
VPValue * expand(const SCEV *S)
Expand S into recipes and live-ins using the builder.
A recipe for handling phi nodes of integer and floating-point inductions, producing their scalar valu...
Definition VPlan.h:4319
VPSingleDefRecipe is a base class for recipes that model a sequence of one or more output IR that def...
Definition VPlan.h:613
Instruction * getUnderlyingInstr()
Returns the underlying instruction.
Definition VPlan.h:675
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:1436
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:1445
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:1439
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:2339
A recipe for widening Call instructions using library calls.
Definition VPlan.h:2154
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:1921
Instruction::CastOps getOpcode() const
Definition VPlan.h:1957
A recipe for handling GEP instructions.
Definition VPlan.h:2279
Base class for widened induction (VPWidenIntOrFpInductionRecipe and VPWidenPointerInductionRecipe),...
Definition VPlan.h:2577
PHINode * getPHINode() const
Returns the underlying PHINode if one exists, or null otherwise.
Definition VPlan.h:2631
VPValue * getStepValue()
Returns the step value of the induction.
Definition VPlan.h:2619
const InductionDescriptor & getInductionDescriptor() const
Returns the induction descriptor for the recipe.
Definition VPlan.h:2636
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
Definition VPlan.h:2665
bool isTruncated() const
Returns true if this induction is evaluated in a narrower type than the start value.
Definition VPlan.h:2718
A recipe for widening vector intrinsics.
Definition VPlan.h:1969
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:3813
virtual VPRecipeBase * getAsRecipe()=0
Return a VPRecipeBase* to the current object.
A recipe for widened phis.
Definition VPlan.h:2799
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition VPlan.h:1854
InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const override
Return the cost of this VPWidenRecipe.
VPWidenRecipe * clone() override
Clone the current recipe.
Definition VPlan.h:1880
unsigned getOpcode() const
Definition VPlan.h:1899
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition VPlan.h:4899
VPIRValue * getLiveIn(Value *V) const
Return the live-in VPIRValue for V, if there is one or nullptr otherwise.
Definition VPlan.h:5229
bool hasVF(ElementCount VF) const
Definition VPlan.h:5122
const DataLayout & getDataLayout() const
Definition VPlan.h:5100
LLVMContext & getContext() const
Definition VPlan.h:5096
VPBasicBlock * getEntry()
Definition VPlan.h:4991
bool hasScalableVF() const
Definition VPlan.h:5123
VPValue * getTripCount() const
The trip count of the original loop.
Definition VPlan.h:5063
iterator_range< SmallSetVector< ElementCount, 2 >::iterator > vectorFactors() const
Returns an iterator range over all VFs of the plan.
Definition VPlan.h:5129
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
Definition VPlan.h:5195
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
Definition VPlan.h:5094
VPIRValue * getAllOnesValue(Type *Ty)
Return a VPIRValue wrapping the AllOnes value of type Ty.
Definition VPlan.h:5201
VPRegionBlock * createReplicateRegion(VPBlockBase *Entry, VPBlockBase *Exiting, const std::string &Name="")
Create a new replicate region with Entry, Exiting and Name.
Definition VPlan.h:5282
auto getLiveIns() const
Return the list of live-in VPValues available in the VPlan.
Definition VPlan.h:5232
bool hasUF(unsigned UF) const
Definition VPlan.h:5147
ArrayRef< VPIRBasicBlock * > getExitBlocks() const
Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of the original scalar loop.
Definition VPlan.h:5057
VPSymbolicValue & getVectorTripCount()
The vector trip count.
Definition VPlan.h:5084
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:5172
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
Definition VPlan.h:5198
void setVF(ElementCount VF)
Definition VPlan.h:5110
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
Definition VPlan.h:5163
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition VPlan.cpp:1029
unsigned getConcreteUF() const
Returns the concrete UF of the plan, after unrolling.
Definition VPlan.h:5150
void resetTripCount(VPValue *NewTripCount)
Resets the trip count for the VPlan.
Definition VPlan.h:5077
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
Definition VPlan.h:5033
VPBasicBlock * createVPBasicBlock(const Twine &Name, VPRecipeBase *Recipe=nullptr)
Create a new VPBasicBlock with Name and containing Recipe if present.
Definition VPlan.h:5255
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
Definition VPlan.h:5192
VPBasicBlock * getVectorPreheader() const
Returns the preheader of the vector loop region, if one exists, or null otherwise.
Definition VPlan.h:4996
VPSymbolicValue & getUF()
Returns the UF of the vector loop region.
Definition VPlan.h:5091
bool hasScalarVFOnly() const
Definition VPlan.h:5140
VPBasicBlock * getScalarPreheader() const
Return the VPBasicBlock for the preheader of the scalar loop.
Definition VPlan.h:5047
bool hasTailFolded() const
Returns true if the vector loop region is tail-folded.
Definition VPlan.h:5012
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
Definition VPlan.h:5087
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:1189
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:5206
LLVM Value Representation.
Definition Value.h:75
iterator_range< user_iterator > users()
Definition Value.h:428
bool hasName() const
Definition Value.h:263
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
Base class of all SIMD vector types.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
constexpr bool hasKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns true if there exists a value X where RHS*X will result in a value whose quantity matches our ...
Definition TypeSize.h:266
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:201
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS*X will result in a value whose quantity matches our own.
Definition TypeSize.h:274
static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition TypeSize.h:217
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition TypeSize.h:169
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
Definition TypeSize.h:172
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Definition ilist_node.h:123
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)
BinaryOp_match< LHS, RHS, Instruction::URem > m_URem(const LHS &L, const RHS &R)
OneOps_match< OpTy, Instruction::Freeze > m_Freeze(const OpTy &Op)
Matches FreezeInst.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
LogicalOp_match< LHS, RHS, Instruction::And > m_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R either in the form of L & R or L ?
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
BinaryOp_match< LHS, RHS, Instruction::FMul > m_FMul(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
match_deferred< Value > m_Deferred(Value *const &V)
Like m_Specific(), but works if the specific value to match is determined as part of the same match()...
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
CmpClass_match< LHS, RHS, CmpInst, true > m_c_Cmp(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
auto match_fn(const Pattern &P)
A match functor that can be used as a UnaryPredicate in functional algorithms like all_of.
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
SpecificCmpClass_match< LHS, RHS, CmpInst > m_SpecificCmp(CmpPredicate MatchPred, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
CastInst_match< OpTy, FPExtInst > m_FPExt(const OpTy &Op)
SpecificCmpClass_match< LHS, RHS, ICmpInst > m_SpecificICmp(CmpPredicate MatchPred, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::UDiv > m_UDiv(const LHS &L, const RHS &R)
SelectLike_match< CondTy, LTy, RTy > m_SelectLike(const CondTy &C, const LTy &TrueC, const RTy &FalseC)
Matches a value that behaves like a boolean-controlled select, i.e.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, SExtInst > > m_ZExtOrSExt(const OpTy &Op)
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinaryOp_match< LHS, RHS, Instruction::FAdd, true > m_c_FAdd(const LHS &L, const RHS &R)
Matches FAdd with LHS and RHS in either order.
LogicalOp_match< LHS, RHS, Instruction::And, true > m_c_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
LogicalOp_match< LHS, RHS, Instruction::Or, true > m_c_LogicalOr(const LHS &L, const RHS &R)
Matches L || R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Mul, true > m_c_Mul(const LHS &L, const RHS &R)
Matches a Mul with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
bind_cst_ty m_scev_APInt(const APInt *&C)
Match an SCEV constant and bind it to an APInt.
cst_pred_ty< is_one > m_scev_One()
Match an integer 1.
specificloop_ty m_SpecificLoop(const Loop *L)
bool match(const SCEV *S, const Pattern &P)
SCEVAffineAddRec_match< Op0_t, Op1_t, match_isa< const Loop > > m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastLane, VPInstruction_match< VPInstruction::ExtractLastPart, Op0_t > > m_ExtractLastLaneOfLastPart(const Op0_t &Op0)
AllRecipe_commutative_match< Instruction::And, Op0_t, Op1_t > m_c_BinaryAnd(const Op0_t &Op0, const Op1_t &Op1)
Match a binary AND operation.
AllRecipe_match< Instruction::Or, Op0_t, Op1_t > m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
Match a binary OR operation.
VPInstruction_match< VPInstruction::AnyOf > m_AnyOf()
AllRecipe_commutative_match< Instruction::Or, Op0_t, Op1_t > m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ComputeReductionResult, Op0_t > m_ComputeReductionResult(const Op0_t &Op0)
auto m_WidenAnyExtend(const Op0_t &Op0)
match_bind< VPIRValue > m_VPIRValue(VPIRValue *&V)
Match a VPIRValue.
VPInstruction_match< VPInstruction::WideActiveLaneMask, Op0_t, Op1_t, Op2_t > m_WideActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
auto m_VPPhi(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
VPWidenStoreRecipe_match< Op0_t, Op1_t > m_WidenStore(const Op0_t &Op0, const Op1_t &Op1)
AllRecipe_match< Opcode, Op0_t, Op1_t > m_Binary(const Op0_t &Op0, const Op1_t &Op1)
VPWidenLoadRecipe_match< Op0_t > m_WidenLoad(const Op0_t &Op0)
VPInstruction_match< VPInstruction::LastActiveLane, Op0_t > m_LastActiveLane(const Op0_t &Op0)
auto m_WidenIntrinsic(const T &...Ops)
canonical_widen_iv_match m_CanonicalWidenIV()
VPInstruction_match< VPInstruction::ExitingIVValue, Op0_t > m_ExitingIVValue(const Op0_t &Op0)
VPInstruction_match< Instruction::ExtractElement, Op0_t, Op1_t > m_ExtractElement(const Op0_t &Op0, const Op1_t &Op1)
VectorPointerRecipe_match< Op0_t, Op1_t > m_VecPtr(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastLane, Op0_t > m_ExtractLastLane(const Op0_t &Op0)
int_pred_ty< is_zero_int, 1 > m_False()
match_bind< VPSingleDefRecipe > m_VPSingleDefRecipe(VPSingleDefRecipe *&V)
Match a VPSingleDefRecipe, capturing if we match.
VPInstruction_match< VPInstruction::BranchOnCount > m_BranchOnCount()
auto m_GetElementPtr(const Op0_t &Op0, const Op1_t &Op1)
auto m_VPValue()
Match an arbitrary VPValue and ignore it.
VPInstruction_match< VPInstruction::ExtractVectorForPart, Op0_t, Op1_t > m_ExtractVectorForPart(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::ExtractLastPart, Op0_t > m_ExtractLastPart(const Op0_t &Op0)
VPRecipeBase * findUserOf(VPValue *V, const MatchT &P)
If V is used by a recipe matching pattern P, return it.
VPInstruction_match< VPInstruction::Broadcast, Op0_t > m_Broadcast(const Op0_t &Op0)
bool match(Val *V, const Pattern &P)
header_mask_match m_HeaderMask()
VPInstruction_match< VPInstruction::BuildVector > m_BuildVector()
BuildVector is matches only its opcode, w/o matching its operands as the number of operands is not fi...
VPInstruction_match< VPInstruction::ExtractPenultimateElement, Op0_t > m_ExtractPenultimateElement(const Op0_t &Op0)
match_bind< VPInstruction > m_VPInstruction(VPInstruction *&V)
Match a VPInstruction, capturing if we match.
VPInstruction_match< VPInstruction::FirstActiveLane, Op0_t > m_FirstActiveLane(const Op0_t &Op0)
int_pred_ty< is_one, 1 > m_True()
auto m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
VPInstruction_match< VPInstruction::ExtractLane, Op0_t, Op1_t > m_ExtractLane(const Op0_t &Op0, const Op1_t &Op1)
auto m_AnyNeg(const Op0_t &Op0)
VPInstruction_match< VPInstruction::Reverse, Op0_t > m_Reverse(const Op0_t &Op0)
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
bool isSingleScalar(const VPValue *VPV)
Returns true if VPV is a single scalar, either because it produces the same value for all lanes or on...
VPValue * getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr)
Get or create a VPValue that corresponds to the expansion of Expr.
bool cannotHoistOrSinkRecipe(const VPRecipeBase &R, bool Sinking=false)
Return true if we do not know how to (mechanically) hoist or sink R.
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
std::optional< int64_t > getConstantStride(VPValue *Addr, Type *AccessTy, PredicatedScalarEvolution &PSE, const Loop *L)
If the pointer operand Addr of a memory access is an affine AddRec w.r.t.
VPInstruction * findComputeReductionResult(VPReductionPHIRecipe *PhiR)
Find the ComputeReductionResult recipe for PhiR, looking through selects inserted for predicated redu...
VPInstruction * findCanonicalIVIncrement(VPlan &Plan)
Find the canonical IV increment of Plan's vector loop region.
std::optional< MemoryLocation > getMemoryLocation(const VPRecipeBase &R)
Return a MemoryLocation for R with noalias metadata populated from R, if the recipe is supported and ...
bool onlyFirstLaneUsed(const VPValue *Def)
Returns true if only the first lane of Def is used by all users.
VPIRValue * tryToFoldLiveIns(VPSingleDefRecipe &R, ArrayRef< VPValue * > Operands, const DataLayout &DL)
Try to fold R using InstSimplifyFolder.
SmallVector< std::pair< VPBasicBlock *, VPIRBasicBlock * > > getEarlyExits(const VPlan &Plan, const VPBlockBase *MiddleVPBB)
Returns the (early exiting block, exit block) pairs of Plan, i.e.
VPScalarIVStepsRecipe * createScalarIVSteps(VPlan &Plan, InductionDescriptor::InductionKind Kind, Instruction::BinaryOps InductionOpcode, FPMathOperator *FPBinOp, Type *ResultTy, VPValue *StartV, VPValue *Step, DebugLoc DL, VPBuilder &Builder, const VPIRFlags::WrapFlagsTy &Flags={})
Create a scalar-iv-steps recipe over Plan's canonical IV for an induction of Kind with InductionOpcod...
void recursivelyDeleteDeadRecipes(VPValue *V)
Recursively delete V and any of its operands that become dead.
bool doesGeneratePerAllLanes(const VPRecipeBase *R)
Returns true if R produces scalar values for all VF lanes.
bool isDeadRecipe(VPRecipeBase &R)
Returns true if R is dead, i.e.
VPRecipeBase * findRecipe(VPValue *Start, PredT Pred)
Search Start's users for a recipe satisfying Pred, looking through recipes with definitions.
Definition VPlanUtils.h:150
LLVM_ABI_FOR_TEST bool isUniformAcrossVFsAndUFs(const VPValue *V)
Checks if V is uniform across all VF lanes and UF parts.
bool isUsedByLoadStoreAddress(const VPValue *V)
Returns true if V is used as part of the address of another load or store.
std::optional< std::pair< bool, unsigned > > getOpcodeOrIntrinsicID(const VPValue *V)
Get the instruction opcode or intrinsic ID for the recipe defining V.
VPValue * scalarizeVPWidenPointerInduction(VPWidenPointerInductionRecipe *PtrIV, VPlan &Plan, VPBuilder &Builder)
Scalarize a VPWidenPointerInductionRecipe by replacing it with a PtrAdd (IndStart,...
LLVM_ABI_FOR_TEST const SCEV * getSCEVExprForVPValue(const VPValue *V, PredicatedScalarEvolution &PSE, const Loop *L=nullptr)
Return the SCEV expression for V.
void pullOutPermutations(VPlan &Plan, Match_t Perm, Builder Build)
Removes the permutation pattern Perm from any elementwise operations in the plan, by constructing a n...
Definition VPlanUtils.h:259
SmallVector< VPUser * > collectUsersRecursively(VPValue *V)
Collect all users of V, looking through recipes that define other values.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
SmallVector< VPBasicBlock * > vp_rpo_plain_cfg_loop_body(VPBasicBlock *Header)
Returns the VPBasicBlocks forming the loop body of a plain (pre-region) VPlan in reverse post-order s...
Definition VPlanCFG.h:262
@ Offset
Definition DWP.cpp:577
constexpr auto not_equal_to(T &&Arg)
Functor variant of std::not_equal_to that can be used as a UnaryPredicate in functional algorithms li...
Definition STLExtras.h:2196
void stable_sort(R &&Range)
Definition STLExtras.h:2132
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2094
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
unsigned getLoadStoreAddressSpace(const Value *I)
A helper function that returns the address space of the pointer operand of load or store instruction.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
LLVM_ABI Intrinsic::ID getVectorIntrinsicIDForCall(const CallInst *CI, const TargetLibraryInfo *TLI)
Returns intrinsic ID for call.
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
Definition STLExtras.h:856
ReductionStyle getReductionStyle(bool InLoop, bool Ordered, unsigned ScaleFactor)
Definition VPlan.h:2899
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:69
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:85
@ ReadOnly
No side effects to worry about, so we can process any uncountable exits in the loop and branch either...
Definition VPlan.h:89
@ MaskedHandleExitInScalarLoop
All memory operations other than the load(s) required to determine whether an uncountable exit occurr...
Definition VPlan.h:94
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:1792
T * find_singleton(R &&Range, Predicate P, bool AllowRepeats=false)
Return the single value in Range that satisfies P(<member of Range> *, AllowRepeats)->T * returning n...
Definition STLExtras.h:1853
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
Definition STLExtras.h:323
@ Other
Any other memory.
Definition ModRef.h:68
TargetTransformInfo TTI
RecurKind
These are the kinds of recurrences that we support.
@ UMin
Unsigned integer min implemented in terms of select(cmp()).
@ FindIV
FindIV reduction with select(icmp(),x,y) where one of (x,y) is a loop induction variable (increasing ...
@ Or
Bitwise or logical OR of integers.
@ Mul
Product of integers.
@ FSub
Subtraction of floats.
@ FMul
Product of floats.
@ SMax
Signed integer max implemented in terms of select(cmp()).
@ SMin
Signed integer min implemented in terms of select(cmp()).
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
@ AddChainWithSubs
A chain of adds and subs.
@ FAdd
Sum of floats.
@ UMax
Unsigned integer max implemented in terms of select(cmp()).
LLVM_ABI Value * getRecurrenceIdentity(RecurKind K, Type *Tp, FastMathFlags FMF)
Given information about an recurrence kind, return the identity for the @llvm.vector....
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition STLExtras.h:2028
DWARFExpression::Operation Op
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2104
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI bool extractBranchWeights(const MDNode *ProfileData, SmallVectorImpl< uint32_t > &Weights)
Extract branch weights from MD_prof metadata.
const VectorizeOptions & getVectorizeOptions(const LLVMContext &C)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
Definition STLExtras.h:2182
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Definition STLExtras.h:2162
Type * toVectorTy(Type *Scalar, ElementCount EC)
A helper function for converting Scalar types to vector types.
LLVM_ABI bool isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L, ScalarEvolution &SE, DominatorTree &DT, AssumptionCache *AC=nullptr, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Return true if we can prove that the given load (which is assumed to be within the specified loop) wo...
Definition Loads.cpp:306
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
LLVM_ABI_FOR_TEST bool verifyVPlanIsValid(const VPlan &Plan)
Verify invariants for general VPlans.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:287
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
VPBasicBlock * EarlyExitingVPBB
VPIRBasicBlock * EarlyExitVPBB
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
An information struct used to provide DenseMap with the various necessary components for a given valu...
This reduction is unordered with the partial result scaled down by some factor.
Definition VPlan.h:2894
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:1896
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:2850
WrapFlagsTy withoutNoSignedWrap()
Definition VPlan.h:712
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:3877
A recipe for widening store operations, using the stored value, the address to store to and an option...
Definition VPlan.h:3982
static LLVM_ABI_FOR_TEST void printIfRequested(VPlan &Plan, Function *Fn, StringRef NumberedPassName, bool After)
Print Plan of Fn before or after the pass NumberedPassName if requested.
static void simplifyLiveInsWithSCEV(VPlan &Plan, PredicatedScalarEvolution &PSE)
Check Plan's live-ins and replace them with constants, if they can be simplified via SCEV.
static bool makeCallWideningDecisions(VPlan &Plan, VFRange &Range, VPRecipeBuilder &RecipeBuilder, VPCostContext &CostCtx)
Convert call VPInstructions in Plan into widened call, vector intrinsic or replicate recipes based on...
static decltype(auto) runPass(StringRef PassName, PassTy &&Pass, VPlan &Plan, ArgsTy &&...Args)
Helper to run a VPlan pass Pass on VPlan, forwarding extra arguments to the pass.
static void createInterleaveGroups(VPlan &Plan, const SmallPtrSetImpl< const InterleaveGroup< Instruction > * > &InterleaveGroups, const bool &EpilogueAllowed)
static LLVM_ABI_FOR_TEST bool handleUncountableEarlyExits(VPlan &Plan, OptimizationRemarkEmitter *ORE, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC, UncountableExitStyle Style)
Update Plan to account for uncountable early exits by introducing appropriate branching logic in the ...
static LLVM_ABI_FOR_TEST bool tryToConvertVPInstructionsToVPRecipes(VPlan &Plan, const TargetLibraryInfo &TLI, PredicatedScalarEvolution &PSE, Loop *OuterLoop)
Replaces the VPInstructions in Plan with corresponding widen recipes.
static void createAndOptimizeReplicateRegions(VPlan &Plan)
Wrap predicated VPReplicateRecipes with a mask operand in an if-then region block and remove the mask...
static std::unique_ptr< VPlan > narrowInterleaveGroups(VPlan &Plan, const TargetTransformInfo &TTI)
Try to find a single VF among Plan's VFs for which all interleave groups (with known minimum VF eleme...
static void makeMemOpWideningDecisions(VPlan &Plan, VFRange &Range, VPRecipeBuilder &RecipeBuilder, VPCostContext &CostCtx)
Convert load/store VPInstructions in Plan into widened or replicate recipes.
static void narrowInductionTruncates(VPlan &Plan, VFRange &Range, const TargetTransformInfo &TTI, PredicatedScalarEvolution &PSE)
Replace truncates of a wide induction, or of that induction's increment, by a VPWidenIntOrFpInduction...
static void hoistPredicatedLoads(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
Hoist predicated loads from the same address to the loop entry block, if they are guaranteed to execu...
static bool mergeBlocksIntoPredecessors(VPlan &Plan)
Remove redundant VPBasicBlocks by merging them into their single predecessor if the latter has a sing...
static void optimizeFindIVReductions(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &L)
Optimize FindLast reductions selecting IVs (or expressions of IVs) by converting them to FindIV reduc...
static void convertToAbstractRecipes(VPlan &Plan, VPCostContext &Ctx, VFRange &Range)
This function converts initial recipes to the abstract recipes and clamps Range based on cost model f...
static void makeScalarizationDecisions(VPlan &Plan, VFRange &Range)
Make VPlan-based scalarization decision prior to delegating to the ones made by the legacy CM.
static bool areAllLoadsDereferenceable(VPBasicBlock *HeaderVPBB, Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT, AssumptionCache *AC)
Check if all loads in the loop are dereferenceable.
static LLVM_ABI_FOR_TEST void verifyIfRequested(VPlan &Plan)
Abort if -vplan-verify-each is set and Plan is invalid.
static void optimizeInductionLiveOutUsers(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
If there's a single exit block, optimize its phi recipes that use exiting IV values by feeding them p...
static void simplifyReverses(VPlan &Plan)
Cancel out redundant reverses in Plan, e.g. reverse(reverse(x)) -> x.
static void adjustFirstOrderRecurrenceMiddleUsers(VPlan &Plan, VFRange &Range)
Adjust first-order recurrence users in the middle block: create penultimate element extracts for LCSS...
static void removeDeadRecipes(VPlan &Plan)
Remove dead recipes from Plan.
static void sinkPredicatedStores(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L)
Sink predicated stores to the same address with complementary predicates (P and NOT P) to an uncondit...
static bool removeBranchOnConst(VPlan &Plan, bool OnlyLatches=false)
Remove BranchOnCond recipes with true or false conditions together with removing dead edges to their ...
static void convertToStridedAccesses(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop &L, VPCostContext &Ctx, VFRange &Range)
Transform widen memory recipes into strided access recipes when legal and profitable.
static void clearReductionWrapFlags(VPlan &Plan)
Clear NSW/NUW flags from reduction instructions if necessary.
static LLVM_ABI_FOR_TEST bool isPrintingRequested(const VPlan &Plan)
static void createPartialReductions(VPlan &Plan, VPCostContext &CostCtx, VFRange &Range)
Detect and create partial reduction recipes for scaled or unordered reductions in Plan.
static void cse(VPlan &Plan, const VPDominatorTree &VPDT)
Perform common-subexpression-elimination on Plan.
static void replaceSymbolicStrides(VPlan &Plan, PredicatedScalarEvolution &PSE, const SymbolicStrideMap &StridesMap, const VPDominatorTree &VPDT)
Replace symbolic strides from StridesMap in Plan with constants when possible.
static LLVM_ABI_FOR_TEST void optimize(VPlan &Plan)
Apply VPlan-to-VPlan optimizations to Plan, including induction recipe optimizations,...
static void truncateToMinimalBitwidths(VPlan &Plan, const MapVector< Instruction *, uint64_t > &MinBWs)
Insert truncates and extends for any truncated recipe.
static void dropPoisonGeneratingRecipes(VPlan &Plan)
Drop poison flags from recipes that may generate a poison value that is used after vectorization,...
static void optimizeForVFAndUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Optimize Plan based on BestVF and BestUF.
static void widenMemoryAccessesByUF(VPlan &Plan, ElementCount VF, unsigned UF, const TargetTransformInfo &TTI)
Widens memory operations by a factor of UF based on a target hook.
static bool splitCombinedExits(VPlan &Plan, PredicatedScalarEvolution &PSE, Loop *TheLoop)
If a single exit has multiple conditions combined together, split them and create new exiting blocks.
static void combineRecipes(VPlan &Plan)
Perform instcombine-like simplifications on recipes in Plan.