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 "VPlanVerifier.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"
32#include "llvm/Analysis/Loads.h"
39#include "llvm/IR/Intrinsics.h"
40#include "llvm/IR/MDBuilder.h"
41#include "llvm/IR/Metadata.h"
46
47using namespace llvm;
48using namespace VPlanPatternMatch;
49using namespace SCEVPatternMatch;
50
52 VPlan &Plan, const TargetLibraryInfo &TLI) {
53
55 Plan.getVectorLoopRegion());
57 // Skip blocks outside region
58 if (!VPBB->getParent())
59 break;
60 VPRecipeBase *Term = VPBB->getTerminator();
61 auto EndIter = Term ? Term->getIterator() : VPBB->end();
62 // Introduce each ingredient into VPlan.
63 for (VPRecipeBase &Ingredient :
64 make_early_inc_range(make_range(VPBB->begin(), EndIter))) {
65
66 VPValue *VPV = Ingredient.getVPSingleValue();
67 if (!VPV->getUnderlyingValue())
68 continue;
69
71
72 // Atomic accesses and fences have ordering/atomicity semantics that
73 // cannot be preserved by lane-wise widening.
75 return false;
76
77 VPRecipeBase *NewRecipe = nullptr;
78 if (auto *PhiR = dyn_cast<VPPhi>(&Ingredient)) {
79 auto *Phi = cast<PHINode>(PhiR->getUnderlyingValue());
80 NewRecipe = new VPWidenPHIRecipe(PhiR->operands(), PhiR->getDebugLoc(),
81 Phi->getName());
82 } else if (auto *VPI = dyn_cast<VPInstruction>(&Ingredient)) {
83 assert(!isa<PHINode>(Inst) && "phis should be handled above");
84 // Create VPWidenMemoryRecipe for loads and stores.
85 if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
86 NewRecipe = new VPWidenLoadRecipe(
87 *Load, Ingredient.getOperand(0), nullptr /*Mask*/,
88 false /*Consecutive*/, *VPI, Ingredient.getDebugLoc());
89 } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
90 NewRecipe = new VPWidenStoreRecipe(
91 *Store, Ingredient.getOperand(1), Ingredient.getOperand(0),
92 nullptr /*Mask*/, false /*Consecutive*/, *VPI,
93 Ingredient.getDebugLoc());
95 NewRecipe = new VPWidenGEPRecipe(GEP->getSourceElementType(),
96 Ingredient.operands(), *VPI,
97 Ingredient.getDebugLoc(), GEP);
98 } else if (CallInst *CI = dyn_cast<CallInst>(Inst)) {
99 Intrinsic::ID VectorID = getVectorIntrinsicIDForCall(CI, &TLI);
100 if (VectorID == Intrinsic::not_intrinsic)
101 return false;
102
103 // The noalias.scope.decl intrinsic declares a noalias scope that
104 // is valid for a single iteration. Emitting it as a single-scalar
105 // replicate would incorrectly extend the scope across multiple
106 // original iterations packed into one vector iteration.
107 // FIXME: If we want to vectorize this loop, then we have to drop
108 // all the associated !alias.scope and !noalias.
109 if (VectorID == Intrinsic::experimental_noalias_scope_decl)
110 return false;
111
112 // These intrinsics are recognized by getVectorIntrinsicIDForCall
113 // but are not widenable. Emit them as replicate instead of widening.
114 if (VectorID == Intrinsic::assume ||
115 VectorID == Intrinsic::lifetime_end ||
116 VectorID == Intrinsic::lifetime_start ||
117 VectorID == Intrinsic::sideeffect ||
118 VectorID == Intrinsic::pseudoprobe) {
119 // If the operand of llvm.assume holds before vectorization, it will
120 // also hold per lane.
121 // llvm.pseudoprobe requires to be duplicated per lane for accurate
122 // sample count.
123 const bool IsSingleScalar = VectorID != Intrinsic::assume &&
124 VectorID != Intrinsic::pseudoprobe;
125 NewRecipe = new VPReplicateRecipe(CI, Ingredient.operands(),
126 /*IsSingleScalar=*/IsSingleScalar,
127 /*Mask=*/nullptr, *VPI, *VPI,
128 Ingredient.getDebugLoc());
129 } else {
130 NewRecipe = new VPWidenIntrinsicRecipe(
131 *CI, VectorID, drop_end(Ingredient.operands()), CI->getType(),
132 VPIRFlags(*CI), *VPI, CI->getDebugLoc());
133 }
134 } else if (auto *CI = dyn_cast<CastInst>(Inst)) {
135 NewRecipe = new VPWidenCastRecipe(
136 CI->getOpcode(), Ingredient.getOperand(0), CI->getType(), CI,
137 VPIRFlags(*CI), VPIRMetadata(*CI));
138 } else {
139 NewRecipe = new VPWidenRecipe(*Inst, Ingredient.operands(), *VPI,
140 *VPI, Ingredient.getDebugLoc());
141 }
142 } else {
144 "inductions must be created earlier");
145 continue;
146 }
147
148 NewRecipe->insertBefore(&Ingredient);
149 if (NewRecipe->getNumDefinedValues() == 1)
150 VPV->replaceAllUsesWith(NewRecipe->getVPSingleValue());
151 else
152 assert(NewRecipe->getNumDefinedValues() == 0 &&
153 "Only recpies with zero or one defined values expected");
154 Ingredient.eraseFromParent();
155 }
156 }
157 return true;
158}
159
160/// Helper for extra no-alias checks via known-safe recipe and SCEV.
163 VPReplicateRecipe &GroupLeader;
164 PredicatedScalarEvolution *PSE = nullptr;
165 const Loop *L = nullptr;
166
167 // Return true if \p A and \p B are known to not alias for all VFs in the
168 // plan, checked via the distance between the accesses
169 bool isNoAliasViaDistance(VPReplicateRecipe *A, VPReplicateRecipe *B) const {
170 if (A->getOpcode() != Instruction::Store ||
171 B->getOpcode() != Instruction::Store)
172 return false;
173
174 if (!PSE || !L)
175 return A == B;
176
177 VPValue *AddrA = A->getOperand(1);
178 const SCEV *SCEVA = vputils::getSCEVExprForVPValue(AddrA, *PSE, L);
179 VPValue *AddrB = B->getOperand(1);
180 const SCEV *SCEVB = vputils::getSCEVExprForVPValue(AddrB, *PSE, L);
182 return false;
183
184 const APInt *Distance;
185 ScalarEvolution &SE = *PSE->getSE();
186 if (!match(SE.getMinusSCEV(SCEVA, SCEVB), m_scev_APInt(Distance)))
187 return false;
188
189 const DataLayout &DL = SE.getDataLayout();
190 Type *TyA = A->getOperand(0)->getScalarType();
191 uint64_t SizeA = DL.getTypeStoreSize(TyA);
192 Type *TyB = B->getOperand(0)->getScalarType();
193 uint64_t SizeB = DL.getTypeStoreSize(TyB);
194
195 // Use the maximum store size to ensure no overlap from either direction.
196 // Currently only handles fixed sizes, as it is only used for
197 // replicating VPReplicateRecipes.
198 uint64_t MaxStoreSize = std::max(SizeA, SizeB);
199
200 auto VFs = B->getParent()->getPlan()->vectorFactors();
202 if (MaxVF.isScalable())
203 return false;
204 return Distance->abs().uge(
205 MaxVF.multiplyCoefficientBy(MaxStoreSize).getFixedValue());
206 }
207
208public:
211 const Loop &L)
212 : ExcludeRecipes(ExcludeRecipes.begin(), ExcludeRecipes.end()),
213 GroupLeader(GroupLeader), PSE(&PSE), L(&L) {}
214
215 SinkStoreInfo(VPReplicateRecipe &GroupLeader) : GroupLeader(GroupLeader) {}
216
217 /// Return true if \p R should be skipped during alias checking, either
218 /// because it's in the exclude set or because no-alias can be proven via
219 /// SCEV.
220 bool shouldSkip(VPRecipeBase &R) const {
221 auto *Store = dyn_cast<VPReplicateRecipe>(&R);
222 return ExcludeRecipes.contains(Store) ||
223 (Store && isNoAliasViaDistance(Store, &GroupLeader));
224 }
225};
226
227/// Check if a memory operation doesn't alias with memory operations using
228/// scoped noalias metadata, in blocks in the single-successor chain between \p
229/// FirstBB and \p LastBB. If \p SinkInfo is std::nullopt, only recipes that may
230/// write to memory are checked (for load hoisting). Otherwise recipes that both
231/// read and write memory are checked, and SCEV is used to prove no-alias
232/// between the group leader and other replicate recipes (for store sinking).
233static bool
235 VPBasicBlock *FirstBB, VPBasicBlock *LastBB,
236 std::optional<SinkStoreInfo> SinkInfo = {}) {
237 bool CheckReads = SinkInfo.has_value();
238 for (VPBasicBlock *VPBB :
240 for (VPRecipeBase &R : *VPBB) {
241 if (SinkInfo && SinkInfo->shouldSkip(R))
242 continue;
243
244 // Skip recipes that don't need checking.
245 if (!R.mayWriteToMemory() && !(CheckReads && R.mayReadFromMemory()))
246 continue;
247
249 if (!Loc)
250 // Conservatively assume aliasing for memory operations without
251 // location.
252 return false;
253
255 return false;
256 }
257 }
258 return true;
259}
260
261/// Get the value type of the replicate load or store. \p IsLoad indicates
262/// whether it is a load.
264 return (IsLoad ? R : R->getOperand(0))->getScalarType();
265}
266
267/// Collect either replicated Loads or Stores grouped by their address SCEV and
268/// their load-store type, in a deep-traversal of the vector loop region in \p
269/// Plan.
270template <unsigned Opcode>
273 VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L,
274 function_ref<bool(VPReplicateRecipe *)> FilterFn) {
275 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
276 "Only Load and Store opcodes supported");
277 constexpr bool IsLoad = (Opcode == Instruction::Load);
280 RecipesByAddressAndType;
283 for (VPRecipeBase &R : *VPBB) {
284 auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
285 if (!RepR || RepR->getOpcode() != Opcode || !FilterFn(RepR))
286 continue;
287
288 // For loads, operand 0 is address; for stores, operand 1 is address.
289 VPValue *Addr = RepR->getOperand(IsLoad ? 0 : 1);
290 const Type *LoadStoreTy = getLoadStoreValueType(RepR, IsLoad);
291 const SCEV *AddrSCEV = vputils::getSCEVExprForVPValue(Addr, PSE, L);
292 if (!isa<SCEVCouldNotCompute>(AddrSCEV))
293 RecipesByAddressAndType[{AddrSCEV, LoadStoreTy}].push_back(RepR);
294 }
295 }
296 auto Groups = to_vector(RecipesByAddressAndType.values());
297 VPDominatorTree VPDT(Plan);
298 for (auto &Group : Groups) {
299 // Sort mem ops by dominance order, with earliest (most dominating) first.
301 return VPDT.properlyDominates(A, B);
302 });
303 }
304 return Groups;
305}
306
307static bool sinkScalarOperands(VPlan &Plan) {
308 auto Iter = vp_depth_first_deep(Plan.getEntry());
309 bool ScalarVFOnly = Plan.hasScalarVFOnly();
310 bool Changed = false;
311
313 auto InsertIfValidSinkCandidate = [ScalarVFOnly, &WorkList](
314 VPBasicBlock *SinkTo, VPValue *Op) {
315 auto *Candidate =
316 dyn_cast_or_null<VPSingleDefRecipe>(Op->getDefiningRecipe());
317 if (!Candidate)
318 return;
319
320 // We only know how to sink VPReplicateRecipes and VPScalarIVStepsRecipes
321 // for now.
323 return;
324
325 if (Candidate->getParent() == SinkTo ||
326 vputils::cannotHoistOrSinkRecipe(*Candidate, /*Sinking=*/true))
327 return;
328
329 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Candidate))
330 if (!ScalarVFOnly && RepR->isSingleScalar())
331 return;
332
333 WorkList.insert({SinkTo, Candidate});
334 };
335
336 // First, collect the operands of all recipes in replicate blocks as seeds for
337 // sinking.
339 VPBasicBlock *EntryVPBB = VPR->getEntryBasicBlock();
340 if (!VPR->isReplicator() || EntryVPBB->getSuccessors().size() != 2)
341 continue;
342 VPBasicBlock *VPBB = cast<VPBasicBlock>(EntryVPBB->getSuccessors().front());
343 if (VPBB->getSingleSuccessor() != VPR->getExitingBasicBlock())
344 continue;
345 for (auto &Recipe : *VPBB)
346 for (VPValue *Op : Recipe.operands())
347 InsertIfValidSinkCandidate(VPBB, Op);
348 }
349
350 // Try to sink each replicate or scalar IV steps recipe in the worklist.
351 for (unsigned I = 0; I != WorkList.size(); ++I) {
352 VPBasicBlock *SinkTo;
353 VPSingleDefRecipe *SinkCandidate;
354 std::tie(SinkTo, SinkCandidate) = WorkList[I];
355
356 // All recipe users of SinkCandidate must be in the same block SinkTo or all
357 // users outside of SinkTo must only use the first lane of SinkCandidate. In
358 // the latter case, we need to duplicate SinkCandidate.
359 auto UsersOutsideSinkTo =
360 make_filter_range(SinkCandidate->users(), [SinkTo](VPUser *U) {
361 return cast<VPRecipeBase>(U)->getParent() != SinkTo;
362 });
363 if (any_of(UsersOutsideSinkTo, [SinkCandidate](VPUser *U) {
364 return !U->usesFirstLaneOnly(SinkCandidate);
365 }))
366 continue;
367 bool NeedsDuplicating = !UsersOutsideSinkTo.empty();
368
369 if (NeedsDuplicating) {
370 if (ScalarVFOnly)
371 continue;
372 VPSingleDefRecipe *Clone;
373 if (auto *SinkCandidateRepR =
374 dyn_cast<VPReplicateRecipe>(SinkCandidate)) {
375 // TODO: Handle converting to uniform recipes as separate transform,
376 // then cloning should be sufficient here.
378 SinkCandidateRepR->getOpcode(), SinkCandidate->operands(),
379 /*Mask=*/nullptr, *SinkCandidateRepR, *SinkCandidateRepR,
380 SinkCandidate->getDebugLoc(), SinkCandidate->getUnderlyingInstr());
381 // TODO: add ".cloned" suffix to name of Clone's VPValue.
382 } else {
383 Clone = SinkCandidate->clone();
384 }
385
386 Clone->insertBefore(SinkCandidate);
387 SinkCandidate->replaceUsesWithIf(Clone, [SinkTo](VPUser &U, unsigned) {
388 return cast<VPRecipeBase>(&U)->getParent() != SinkTo;
389 });
390 }
391 SinkCandidate->moveBefore(*SinkTo, SinkTo->getFirstNonPhi());
392 for (VPValue *Op : SinkCandidate->operands())
393 InsertIfValidSinkCandidate(SinkTo, Op);
394 Changed = true;
395 }
396 return Changed;
397}
398
399/// If \p R is a region with a VPBranchOnMaskRecipe in the entry block, return
400/// the mask.
402 auto *EntryBB = dyn_cast<VPBasicBlock>(R->getEntry());
403 if (!EntryBB || EntryBB->size() != 1 ||
404 !isa<VPBranchOnMaskRecipe>(EntryBB->begin()))
405 return nullptr;
406
407 return cast<VPBranchOnMaskRecipe>(&*EntryBB->begin())->getOperand(0);
408}
409
410/// If \p R is a triangle region, return the 'then' block of the triangle.
412 auto *EntryBB = cast<VPBasicBlock>(R->getEntry());
413 if (EntryBB->getNumSuccessors() != 2)
414 return nullptr;
415
416 auto *Succ0 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[0]);
417 auto *Succ1 = dyn_cast<VPBasicBlock>(EntryBB->getSuccessors()[1]);
418 if (!Succ0 || !Succ1)
419 return nullptr;
420
421 if (Succ0->getNumSuccessors() + Succ1->getNumSuccessors() != 1)
422 return nullptr;
423 if (Succ0->getSingleSuccessor() == Succ1)
424 return Succ0;
425 if (Succ1->getSingleSuccessor() == Succ0)
426 return Succ1;
427 return nullptr;
428}
429
430// Merge replicate regions in their successor region, if a replicate region
431// is connected to a successor replicate region with the same predicate by a
432// single, empty VPBasicBlock.
434 SmallPtrSet<VPRegionBlock *, 4> TransformedRegions;
435
436 // Collect replicate regions followed by an empty block, followed by another
437 // replicate region with matching masks to process front. This is to avoid
438 // iterator invalidation issues while merging regions.
441 vp_depth_first_deep(Plan.getEntry()))) {
442 if (!Region1->isReplicator())
443 continue;
444 auto *MiddleBasicBlock =
445 dyn_cast_or_null<VPBasicBlock>(Region1->getSingleSuccessor());
446 if (!MiddleBasicBlock || !MiddleBasicBlock->empty())
447 continue;
448
449 auto *Region2 =
450 dyn_cast_or_null<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
451 if (!Region2 || !Region2->isReplicator())
452 continue;
453
454 VPValue *Mask1 = getPredicatedMask(Region1);
455 VPValue *Mask2 = getPredicatedMask(Region2);
456 if (!Mask1 || Mask1 != Mask2)
457 continue;
458
459 assert(Mask1 && Mask2 && "both region must have conditions");
460 WorkList.push_back(Region1);
461 }
462
463 // Move recipes from Region1 to its successor region, if both are triangles.
464 for (VPRegionBlock *Region1 : WorkList) {
465 if (TransformedRegions.contains(Region1))
466 continue;
467 auto *MiddleBasicBlock = cast<VPBasicBlock>(Region1->getSingleSuccessor());
468 auto *Region2 = cast<VPRegionBlock>(MiddleBasicBlock->getSingleSuccessor());
469
470 VPBasicBlock *Then1 = getPredicatedThenBlock(Region1);
471 VPBasicBlock *Then2 = getPredicatedThenBlock(Region2);
472 if (!Then1 || !Then2)
473 continue;
474
475 // Note: No fusion-preventing memory dependencies are expected in either
476 // region. Such dependencies should be rejected during earlier dependence
477 // checks, which guarantee accesses can be re-ordered for vectorization.
478 //
479 // Move recipes to the successor region.
480 for (VPRecipeBase &ToMove : make_early_inc_range(reverse(*Then1)))
481 ToMove.moveBefore(*Then2, Then2->getFirstNonPhi());
482
483 auto *Merge1 = cast<VPBasicBlock>(Then1->getSingleSuccessor());
484 auto *Merge2 = cast<VPBasicBlock>(Then2->getSingleSuccessor());
485
486 // Move VPPredInstPHIRecipes from the merge block to the successor region's
487 // merge block. Update all users inside the successor region to use the
488 // original values.
489 for (VPRecipeBase &Phi1ToMove : make_early_inc_range(reverse(*Merge1))) {
490 VPValue *PredInst1 =
491 cast<VPPredInstPHIRecipe>(&Phi1ToMove)->getOperand(0);
492 VPValue *Phi1ToMoveV = Phi1ToMove.getVPSingleValue();
493 Phi1ToMoveV->replaceUsesWithIf(PredInst1, [Then2](VPUser &U, unsigned) {
494 return cast<VPRecipeBase>(&U)->getParent() == Then2;
495 });
496
497 // Remove phi recipes that are unused after merging the regions.
498 if (Phi1ToMove.getVPSingleValue()->user_empty()) {
499 Phi1ToMove.eraseFromParent();
500 continue;
501 }
502 Phi1ToMove.moveBefore(*Merge2, Merge2->begin());
503 }
504
505 // Remove the dead recipes in Region1's entry block.
506 for (VPRecipeBase &R :
507 make_early_inc_range(reverse(*Region1->getEntryBasicBlock())))
508 R.eraseFromParent();
509
510 // Finally, remove the first region.
511 for (VPBlockBase *Pred : make_early_inc_range(Region1->getPredecessors())) {
512 VPBlockUtils::disconnectBlocks(Pred, Region1);
513 VPBlockUtils::connectBlocks(Pred, MiddleBasicBlock);
514 }
515 VPBlockUtils::disconnectBlocks(Region1, MiddleBasicBlock);
516 TransformedRegions.insert(Region1);
517 }
518
519 return !TransformedRegions.empty();
520}
521
523 VPRegionBlock *ParentRegion,
524 VPlan &Plan) {
525 Instruction *Instr = PredRecipe->getUnderlyingInstr();
526 // Build the triangular if-then region.
527 std::string RegionName = (Twine("pred.") + Instr->getOpcodeName()).str();
528 assert(Instr->getParent() && "Predicated instruction not in any basic block");
529 auto *BlockInMask = PredRecipe->getMask();
530 auto *MaskDef = BlockInMask->getDefiningRecipe();
531 auto *BOMRecipe = new VPBranchOnMaskRecipe(
532 BlockInMask, MaskDef ? MaskDef->getDebugLoc() : DebugLoc::getUnknown());
533 auto *Entry =
534 Plan.createVPBasicBlock(Twine(RegionName) + ".entry", BOMRecipe);
535
536 // Replace predicated replicate recipe with a replicate recipe without a
537 // mask but in the replicate region.
538 auto *RecipeWithoutMask = new VPReplicateRecipe(
539 PredRecipe->getUnderlyingInstr(), PredRecipe->operandsWithoutMask(),
540 PredRecipe->isSingleScalar(), nullptr /*Mask*/, *PredRecipe, *PredRecipe,
541 PredRecipe->getDebugLoc());
542 auto *Pred =
543 Plan.createVPBasicBlock(Twine(RegionName) + ".if", RecipeWithoutMask);
544 auto *Exiting = Plan.createVPBasicBlock(Twine(RegionName) + ".continue");
546 Plan.createReplicateRegion(Entry, Exiting, RegionName);
547
548 // Note: first set Entry as region entry and then connect successors starting
549 // from it in order, to propagate the "parent" of each VPBasicBlock.
550 Region->setParent(ParentRegion);
551 VPBlockUtils::insertTwoBlocksAfter(Pred, Exiting, Entry);
552 VPBlockUtils::connectBlocks(Pred, Exiting);
553
554 if (!PredRecipe->user_empty()) {
555 auto *PHIRecipe = new VPPredInstPHIRecipe(RecipeWithoutMask,
556 RecipeWithoutMask->getDebugLoc());
557 Exiting->appendRecipe(PHIRecipe);
558 PredRecipe->replaceAllUsesWith(PHIRecipe);
559 }
560 PredRecipe->eraseFromParent();
561 return Region;
562}
563
564static void addReplicateRegions(VPlan &Plan) {
567 vp_depth_first_deep(Plan.getEntry()))) {
568 for (VPRecipeBase &R : *VPBB)
569 if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
570 if (RepR->isPredicated())
571 WorkList.push_back(RepR);
572 }
573 }
574
575 unsigned BBNum = 0;
576 for (VPReplicateRecipe *RepR : WorkList) {
577 VPBasicBlock *CurrentBlock = RepR->getParent();
578 VPBasicBlock *SplitBlock = CurrentBlock->splitAt(RepR->getIterator());
579
580 BasicBlock *OrigBB = RepR->getUnderlyingInstr()->getParent();
581 SplitBlock->setName(
582 OrigBB->hasName() ? OrigBB->getName() + "." + Twine(BBNum++) : "");
583 // Record predicated instructions for above packing optimizations.
585 createReplicateRegion(RepR, CurrentBlock->getParent(), Plan);
587
588 VPRegionBlock *ParentRegion = Region->getParent();
589 if (ParentRegion && ParentRegion->getExiting() == CurrentBlock)
590 ParentRegion->setExiting(SplitBlock);
591 }
592}
593
597 vp_depth_first_deep(Plan.getEntry()))) {
598 // Don't fold the blocks in the skeleton of the Plan into their single
599 // predecessors for now.
600 // TODO: Remove restriction once more of the skeleton is modeled in VPlan.
601 if (!VPBB->getParent())
602 continue;
603 auto *PredVPBB =
604 dyn_cast_or_null<VPBasicBlock>(VPBB->getSinglePredecessor());
605 if (!PredVPBB || PredVPBB->getNumSuccessors() != 1 ||
606 isa<VPIRBasicBlock>(PredVPBB))
607 continue;
608 WorkList.push_back(VPBB);
609 }
610
611 for (VPBasicBlock *VPBB : WorkList) {
612 VPBasicBlock *PredVPBB = cast<VPBasicBlock>(VPBB->getSinglePredecessor());
613 for (VPRecipeBase &R : make_early_inc_range(*VPBB))
614 R.moveBefore(*PredVPBB, PredVPBB->end());
615 VPBlockUtils::disconnectBlocks(PredVPBB, VPBB);
616 auto *ParentRegion = VPBB->getParent();
617 if (ParentRegion && ParentRegion->getExiting() == VPBB)
618 ParentRegion->setExiting(PredVPBB);
619 VPBlockUtils::transferSuccessors(VPBB, PredVPBB);
620 // VPBB is now dead and will be cleaned up when the plan gets destroyed.
621 }
622 return !WorkList.empty();
623}
624
626 // Convert masked VPReplicateRecipes to if-then region blocks.
628
629 bool ShouldSimplify = true;
630 while (ShouldSimplify) {
631 ShouldSimplify = sinkScalarOperands(Plan);
632 ShouldSimplify |= mergeReplicateRegionsIntoSuccessors(Plan);
633 ShouldSimplify |= mergeBlocksIntoPredecessors(Plan);
634 }
635}
636
637/// Remove redundant casts of inductions.
638///
639/// Such redundant casts are casts of induction variables that can be ignored,
640/// because we already proved that the casted phi is equal to the uncasted phi
641/// in the vectorized loop. There is no need to vectorize the cast - the same
642/// value can be used for both the phi and casts in the vector loop.
644 for (auto &Phi : Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
646 if (!IV || IV->getTruncInst())
647 continue;
648
649 // A sequence of IR Casts has potentially been recorded for IV, which
650 // *must be bypassed* when the IV is vectorized, because the vectorized IV
651 // will produce the desired casted value. This sequence forms a def-use
652 // chain and is provided in reverse order, ending with the cast that uses
653 // the IV phi. Search for the recipe of the last cast in the chain and
654 // replace it with the original IV. Note that only the final cast is
655 // expected to have users outside the cast-chain and the dead casts left
656 // over will be cleaned up later.
657 ArrayRef<Instruction *> Casts = IV->getInductionDescriptor().getCastInsts();
658 VPValue *FindMyCast = IV;
659 for (Instruction *IRCast : reverse(Casts)) {
660 VPSingleDefRecipe *FoundUserCast = nullptr;
661 for (auto *U : FindMyCast->users()) {
662 auto *UserCast = dyn_cast<VPSingleDefRecipe>(U);
663 if (UserCast && UserCast->getUnderlyingValue() == IRCast) {
664 FoundUserCast = UserCast;
665 break;
666 }
667 }
668 // A cast recipe in the chain may have been removed by earlier DCE.
669 if (!FoundUserCast)
670 break;
671 FindMyCast = FoundUserCast;
672 }
673 if (FindMyCast != IV)
674 FindMyCast->replaceAllUsesWith(IV);
675 }
676}
677
680 Instruction::BinaryOps InductionOpcode,
681 FPMathOperator *FPBinOp, Instruction *TruncI,
682 VPIRValue *StartV, VPValue *Step, DebugLoc DL,
683 VPBuilder &Builder) {
684 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
685 VPBasicBlock *HeaderVPBB = LoopRegion->getEntryBasicBlock();
686 VPValue *CanonicalIV = LoopRegion->getCanonicalIV();
687 VPSingleDefRecipe *BaseIV =
688 Builder.createDerivedIV(Kind, FPBinOp, StartV, CanonicalIV, Step);
689
690 // Truncate base induction if needed.
691 Type *ResultTy = BaseIV->getScalarType();
692 if (TruncI) {
693 Type *TruncTy = TruncI->getType();
694 assert(ResultTy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits() &&
695 "Not truncating.");
696 assert(ResultTy->isIntegerTy() && "Truncation requires an integer type");
697 BaseIV = Builder.createScalarCast(Instruction::Trunc, BaseIV, TruncTy, DL);
698 ResultTy = TruncTy;
699 }
700
701 // Truncate step if needed.
702 Type *StepTy = Step->getScalarType();
703 if (ResultTy != StepTy) {
704 assert(StepTy->getScalarSizeInBits() > ResultTy->getScalarSizeInBits() &&
705 "Not truncating.");
706 assert(StepTy->isIntegerTy() && "Truncation requires an integer type");
707 auto *VecPreheader =
709 VPBuilder::InsertPointGuard Guard(Builder);
710 Builder.setInsertPoint(VecPreheader);
711 Step = Builder.createScalarCast(Instruction::Trunc, Step, ResultTy, DL);
712 }
713 return Builder.createScalarIVSteps(InductionOpcode, FPBinOp, BaseIV, Step,
714 &Plan.getVF(), DL);
715}
716
718 VPlan &Plan, ScalarEvolution &SE, const TargetTransformInfo &TTI,
720 const SmallPtrSetImpl<const Value *> &ValuesToIgnore) {
721 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
722 if (!LoopRegion)
723 return;
724
725 auto *WideCanIV =
727 if (!WideCanIV)
728 return;
729
730 Type *CanIVTy = LoopRegion->getCanonicalIVType();
731
732 // Replace the wide canonical IV with a scalar-iv-steps over the canonical
733 // IV.
734 if (Plan.hasScalarVFOnly() || vputils::onlyFirstLaneUsed(WideCanIV)) {
735 VPBuilder Builder(WideCanIV);
736 WideCanIV->replaceAllUsesWith(createScalarIVSteps(
737 Plan, InductionDescriptor::IK_IntInduction, Instruction::Add, nullptr,
738 nullptr, Plan.getZero(CanIVTy), Plan.getConstantInt(CanIVTy, 1),
739 WideCanIV->getDebugLoc(), Builder));
740 WideCanIV->eraseFromParent();
741 return;
742 }
743
744 if (vputils::onlyScalarValuesUsed(WideCanIV))
745 return;
746
747 // If a canonical VPWidenIntOrFpInductionRecipe already produces vector lanes
748 // in the header, reuse it instead of introducing another wide induction phi.
749 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
750 for (VPRecipeBase &Phi : Header->phis()) {
752 if (!match(&Phi, m_CanonicalWidenIV(WidenIV)))
753 continue;
754 // The reused wide IV feeds the header mask, whose lanes may extend past
755 // the trip count; drop flags that only hold inside the scalar loop.
756 WidenIV->dropPoisonGeneratingFlags();
757 WideCanIV->replaceAllUsesWith(WidenIV);
758 WideCanIV->eraseFromParent();
759 return;
760 }
761
762 // Introduce a new VPWidenIntOrFpInductionRecipe if profitable.
763 auto *VecTy = VectorType::get(CanIVTy, VF);
764 InstructionCost BroadcastCost = TTI.getShuffleCost(
766 InstructionCost PHICost = TTI.getCFInstrCost(Instruction::PHI, CostKind);
767 if (PHICost > BroadcastCost)
768 return;
769
770 // Bail out if the additional wide induction phi increase the expected spill
771 // cost.
772 VPRegisterUsage UnrolledBase =
773 calculateRegisterUsageForPlan(Plan, VF, TTI, ValuesToIgnore)[0];
774 for (unsigned &NumUsers : make_second_range(UnrolledBase.MaxLocalUsers))
775 NumUsers *= UF;
776 unsigned RegClass = TTI.getRegisterClassForType(/*Vector=*/true, VecTy);
777 VPRegisterUsage Projected = UnrolledBase;
778 Projected.MaxLocalUsers[RegClass] += TTI.getRegUsageForType(VecTy);
779 if (Projected.spillCost(TTI, CostKind) >
780 UnrolledBase.spillCost(TTI, CostKind))
781 return;
782
785 VPValue *StepV = Plan.getConstantInt(CanIVTy, 1);
786 auto *NewWideIV = new VPWidenIntOrFpInductionRecipe(
787 /*IV=*/nullptr, Plan.getZero(CanIVTy), StepV, &Plan.getVF(), ID,
788 WideCanIV->getNoWrapFlags(), WideCanIV->getDebugLoc());
789 NewWideIV->insertBefore(&*Header->getFirstNonPhi());
790 WideCanIV->replaceAllUsesWith(NewWideIV);
791 WideCanIV->eraseFromParent();
792}
793
794/// Returns true if \p R is dead and can be removed.
795static bool isDeadRecipe(VPRecipeBase &R) {
796 // Do remove conditional assume instructions as their conditions may be
797 // flattened.
798 auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
799 bool IsConditionalAssume = RepR && RepR->isPredicated() &&
801 if (IsConditionalAssume)
802 return true;
803
804 if (R.mayHaveSideEffects())
805 return false;
806
807 // Recipe is dead if no user keeps the recipe alive.
808 return all_of(R.definedValues(), [](VPValue *V) { return V->user_empty(); });
809}
810
813 Plan.getEntry());
815 // The recipes in the block are processed in reverse order, to catch chains
816 // of dead recipes.
817 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
818 if (isDeadRecipe(R)) {
819 R.eraseFromParent();
820 continue;
821 }
822
823 // Check if R is a dead VPPhi <-> update cycle and remove it.
824 VPValue *Start, *Incoming;
825 if (!match(&R, m_VPPhi(m_VPValue(Start), m_VPValue(Incoming))))
826 continue;
827 auto *PhiR = cast<VPPhi>(&R);
828 VPUser *PhiUser = PhiR->getSingleUser();
829 if (!PhiUser)
830 continue;
831 if (PhiUser != Incoming->getDefiningRecipe() ||
832 Incoming->getNumUsers() != 1)
833 continue;
834 PhiR->replaceAllUsesWith(Start);
835 PhiR->eraseFromParent();
836 Incoming->getDefiningRecipe()->eraseFromParent();
837 }
838 }
839}
840
843 for (unsigned I = 0; I != Users.size(); ++I) {
845 for (VPValue *V : Cur->definedValues())
846 Users.insert_range(V->users());
847 }
848 return Users.takeVector();
849}
850
851/// Scalarize a VPWidenPointerInductionRecipe by replacing it with a PtrAdd
852/// (IndStart, ScalarIVSteps (0, Step)). This is used when the recipe only
853/// generates scalar values.
854static VPValue *
856 VPlan &Plan, VPBuilder &Builder) {
858 VPIRValue *StartV = Plan.getZero(ID.getStep()->getType());
859 VPValue *StepV = PtrIV->getOperand(1);
861 Plan, InductionDescriptor::IK_IntInduction, Instruction::Add, nullptr,
862 nullptr, StartV, StepV, PtrIV->getDebugLoc(), Builder);
863
864 return Builder.createPtrAdd(PtrIV->getStartValue(), Steps,
865 PtrIV->getDebugLoc(), "next.gep");
866}
867
868/// Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd
869/// (IndStart, ScalarIVSteps (0, Step)) if only its scalar values are used, as
870/// VPWidenPointerInductionRecipe will generate vectors only. If some users
871/// require vectors while other require scalars, the scalar uses need to extract
872/// the scalars from the generated vectors (Note that this is different to how
873/// int/fp inductions are handled). Legalize extract-from-ends using uniform
874/// VPReplicateRecipe of wide inductions to use regular VPReplicateRecipe, so
875/// the correct end value is available. Also optimize
876/// VPWidenIntOrFpInductionRecipe, if any of its users needs scalar values, by
877/// providing them scalar steps built on the canonical scalar IV and update the
878/// original IV's users. This is an optional optimization to reduce the needs of
879/// vector extracts.
882 bool HasOnlyVectorVFs = !Plan.hasScalarVFOnly();
883 VPBuilder Builder(HeaderVPBB, HeaderVPBB->getFirstNonPhi());
884 for (VPRecipeBase &Phi : HeaderVPBB->phis()) {
885 auto *PhiR = dyn_cast<VPWidenInductionRecipe>(&Phi);
886 if (!PhiR)
887 continue;
888
889 // Try to narrow wide and replicating recipes to uniform recipes, based on
890 // VPlan analysis.
891 // TODO: Apply to all recipes in the future, to replace legacy uniformity
892 // analysis.
893 auto Users = collectUsersRecursively(PhiR);
894 for (VPUser *U : reverse(Users)) {
895 auto *Def = dyn_cast<VPRecipeWithIRFlags>(U);
896 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
897 // Skip recipes that shouldn't be narrowed.
898 if (!Def || !isa<VPReplicateRecipe, VPWidenRecipe>(Def) ||
899 Def->user_empty() || !Def->getUnderlyingValue() ||
900 (RepR && (RepR->isSingleScalar() || RepR->isPredicated())))
901 continue;
902
903 // Skip recipes that may have other lanes than their first used.
905 continue;
906
907 // TODO: Support scalarizing ExtractValue.
908 if (match(Def,
910 continue;
911
913 Def->getUnderlyingInstr()->getOpcode(), Def->operands(),
914 /*Mask=*/nullptr, *Def, {}, DebugLoc::getUnknown(),
915 Def->getUnderlyingInstr());
916 Clone->insertAfter(Def);
917 Def->replaceAllUsesWith(Clone);
918 }
919
920 // Replace wide pointer inductions which have only their scalars used by
921 // PtrAdd(IndStart, ScalarIVSteps (0, Step)).
922 if (auto *PtrIV = dyn_cast<VPWidenPointerInductionRecipe>(&Phi)) {
923 if (!Plan.hasScalarVFOnly() &&
924 !PtrIV->onlyScalarsGenerated(Plan.hasScalableVF()))
925 continue;
926
927 VPValue *PtrAdd = scalarizeVPWidenPointerInduction(PtrIV, Plan, Builder);
928 PtrIV->replaceAllUsesWith(PtrAdd);
929 continue;
930 }
931
932 // Replace widened induction with scalar steps for users that only use
933 // scalars.
934 auto *WideIV = cast<VPWidenIntOrFpInductionRecipe>(&Phi);
935 if (HasOnlyVectorVFs && none_of(WideIV->users(), [WideIV](VPUser *U) {
936 return U->usesScalars(WideIV);
937 }))
938 continue;
939
940 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
942 Plan, ID.getKind(), ID.getInductionOpcode(),
943 dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
944 WideIV->getTruncInst(), WideIV->getStartValue(), WideIV->getStepValue(),
945 WideIV->getDebugLoc(), Builder);
946
947 // Update scalar users of IV to use Step instead.
948 if (!HasOnlyVectorVFs) {
949 assert(!Plan.hasScalableVF() &&
950 "plans containing a scalar VF cannot also include scalable VFs");
951 WideIV->replaceAllUsesWith(Steps);
952 } else {
953 bool HasScalableVF = Plan.hasScalableVF();
954 WideIV->replaceUsesWithIf(Steps,
955 [WideIV, HasScalableVF](VPUser &U, unsigned) {
956 if (HasScalableVF)
957 return U.usesFirstLaneOnly(WideIV);
958 return U.usesScalars(WideIV);
959 });
960 }
961 }
962}
963
964/// Check if \p VPV is an untruncated wide induction, either before or after the
965/// increment. If so return the header IV (before the increment), otherwise
966/// return null.
969 auto *WideIV = dyn_cast<VPWidenInductionRecipe>(VPV);
970 if (WideIV) {
971 // VPV itself is a wide induction, separately compute the end value for exit
972 // users if it is not a truncated IV.
973 auto *IntOrFpIV = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
974 return (IntOrFpIV && IntOrFpIV->getTruncInst()) ? nullptr : WideIV;
975 }
976
977 // Check if VPV is an optimizable induction increment.
978 VPRecipeBase *Def = VPV->getDefiningRecipe();
979 if (!Def || Def->getNumOperands() != 2)
980 return nullptr;
981 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(0));
982 if (!WideIV)
983 WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(1));
984 if (!WideIV)
985 return nullptr;
986
987 auto IsWideIVInc = [&]() {
988 auto &ID = WideIV->getInductionDescriptor();
989
990 // Check if VPV increments the induction by the induction step.
991 VPValue *IVStep = WideIV->getStepValue();
992 switch (ID.getInductionOpcode()) {
993 case Instruction::Add:
994 return match(VPV, m_c_Add(m_Specific(WideIV), m_Specific(IVStep)));
995 case Instruction::FAdd:
996 return match(VPV, m_c_FAdd(m_Specific(WideIV), m_Specific(IVStep)));
997 case Instruction::FSub:
998 return match(VPV, m_Binary<Instruction::FSub>(m_Specific(WideIV),
999 m_Specific(IVStep)));
1000 case Instruction::Sub: {
1001 // IVStep will be the negated step of the subtraction. Check if Step == -1
1002 // * IVStep.
1003 VPValue *Step;
1004 if (!match(VPV, m_Sub(m_VPValue(), m_VPValue(Step))))
1005 return false;
1006 const SCEV *IVStepSCEV = vputils::getSCEVExprForVPValue(IVStep, PSE);
1007 const SCEV *StepSCEV = vputils::getSCEVExprForVPValue(Step, PSE);
1008 ScalarEvolution &SE = *PSE.getSE();
1009 return !isa<SCEVCouldNotCompute>(IVStepSCEV) &&
1010 !isa<SCEVCouldNotCompute>(StepSCEV) &&
1011 IVStepSCEV == SE.getNegativeSCEV(StepSCEV);
1012 }
1013 default:
1014 return ID.getKind() == InductionDescriptor::IK_PtrInduction &&
1015 match(VPV, m_GetElementPtr(m_Specific(WideIV),
1016 m_Specific(WideIV->getStepValue())));
1017 }
1018 llvm_unreachable("should have been covered by switch above");
1019 };
1020 return IsWideIVInc() ? WideIV : nullptr;
1021}
1022
1023/// Attempts to optimize the induction variable exit values for users in the
1024/// early exit block.
1027 VPValue *Incoming, *Mask;
1029 m_VPValue(Incoming))))
1030 return nullptr;
1031
1032 auto *WideIV = getOptimizableIVOf(Incoming, PSE);
1033 if (!WideIV)
1034 return nullptr;
1035
1036 auto *WideIntOrFp = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
1037 if (WideIntOrFp && WideIntOrFp->getTruncInst())
1038 return nullptr;
1039
1040 // Calculate the final index.
1041 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
1042 auto *CanonicalIV = LoopRegion->getCanonicalIV();
1043 Type *CanonicalIVType = LoopRegion->getCanonicalIVType();
1044 auto *ExtractR = cast<VPInstruction>(Op);
1045 VPBuilder B(ExtractR);
1046
1047 DebugLoc DL = ExtractR->getDebugLoc();
1048 VPValue *FirstActiveLane = B.createFirstActiveLane(Mask, DL);
1049 FirstActiveLane = B.createScalarZExtOrTrunc(
1050 FirstActiveLane, CanonicalIVType, FirstActiveLane->getScalarType(), DL);
1051 VPValue *EndValue = B.createAdd(CanonicalIV, FirstActiveLane, DL);
1052
1053 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
1054 // changed it means the exit is using the incremented value, so we need to
1055 // add the step.
1056 if (Incoming != WideIV) {
1057 VPValue *One = Plan.getConstantInt(CanonicalIVType, 1);
1058 EndValue = B.createAdd(EndValue, One, DL);
1059 }
1060
1061 if (!match(WideIV, m_CanonicalWidenIV())) {
1062 const InductionDescriptor &ID = WideIV->getInductionDescriptor();
1063 VPIRValue *Start = WideIV->getStartValue();
1064 VPValue *Step = WideIV->getStepValue();
1065 EndValue = B.createDerivedIV(
1066 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1067 Start, EndValue, Step);
1068 }
1069
1070 return EndValue;
1071}
1072
1073/// Compute the end value for \p WideIV, unless it is truncated. Creates a
1074/// VPDerivedIVRecipe for non-canonical inductions.
1076 VPBuilder &VectorPHBuilder,
1077 VPValue *VectorTC) {
1078 auto *WideIntOrFp = dyn_cast<VPWidenIntOrFpInductionRecipe>(WideIV);
1079 // Truncated wide inductions resume from the last lane of their vector value
1080 // in the last vector iteration which is handled elsewhere.
1081 if (WideIntOrFp && WideIntOrFp->getTruncInst())
1082 return nullptr;
1083
1084 VPIRValue *Start = WideIV->getStartValue();
1085 VPValue *Step = WideIV->getStepValue();
1087 VPValue *EndValue = VectorTC;
1088 if (!match(WideIV, m_CanonicalWidenIV())) {
1089 EndValue = VectorPHBuilder.createDerivedIV(
1090 ID.getKind(), dyn_cast_or_null<FPMathOperator>(ID.getInductionBinOp()),
1091 Start, VectorTC, Step);
1092 }
1093
1094 // EndValue is derived from the vector trip count (which has the same type as
1095 // the widest induction) and thus may be wider than the induction here.
1096 Type *ScalarTypeOfWideIV = WideIV->getScalarType();
1097 if (ScalarTypeOfWideIV != EndValue->getScalarType()) {
1098 EndValue = VectorPHBuilder.createScalarCast(Instruction::Trunc, EndValue,
1099 ScalarTypeOfWideIV,
1100 WideIV->getDebugLoc());
1101 }
1102
1103 return EndValue;
1104}
1105
1106/// Attempts to optimize the induction variable exit values for users in the
1107/// exit block coming from the latch in the original scalar loop.
1108static VPValue *
1112 VPValue *Incoming;
1113 if (!match(Op,
1115 VPValue *Mask;
1117 m_VPValue(Incoming))) ||
1118 !match(Mask, m_HeaderMask()))
1119 return nullptr;
1120 }
1121
1122 VPWidenInductionRecipe *WideIV = getOptimizableIVOf(Incoming, PSE);
1123 if (!WideIV)
1124 return nullptr;
1125
1126 VPValue *EndValue = EndValues.lookup(WideIV);
1127 assert(EndValue && "Must have computed the end value up front");
1128
1129 // `getOptimizableIVOf()` always returns the pre-incremented IV, so if it
1130 // changed it means the exit is using the incremented value, so we don't
1131 // need to subtract the step.
1132 if (Incoming != WideIV)
1133 return EndValue;
1134
1135 // Otherwise, subtract the step from the EndValue.
1136 auto *ExtractR = cast<VPInstruction>(Op);
1137 VPBuilder B(ExtractR);
1138 VPValue *Step = WideIV->getStepValue();
1139 Type *ScalarTy = WideIV->getScalarType();
1140 if (ScalarTy->isIntegerTy())
1141 return B.createSub(EndValue, Step, DebugLoc::getUnknown(), "ind.escape");
1142 if (ScalarTy->isPointerTy()) {
1143 Type *StepTy = Step->getScalarType();
1144 auto *Zero = Plan.getZero(StepTy);
1145 return B.createPtrAdd(EndValue, B.createSub(Zero, Step),
1146 DebugLoc::getUnknown(), "ind.escape");
1147 }
1148 if (ScalarTy->isFloatingPointTy()) {
1149 const auto &ID = WideIV->getInductionDescriptor();
1150 return B.createNaryOp(
1151 ID.getInductionBinOp()->getOpcode() == Instruction::FAdd
1152 ? Instruction::FSub
1153 : Instruction::FAdd,
1154 {EndValue, Step}, {ID.getInductionBinOp()->getFastMathFlags()});
1155 }
1156 llvm_unreachable("all possible induction types must be handled");
1157 return nullptr;
1158}
1159
1161 VPlan &Plan, PredicatedScalarEvolution &PSE) {
1162 // Compute end values for all inductions.
1163 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
1164 auto *VectorPH = cast<VPBasicBlock>(VectorRegion->getSinglePredecessor());
1165 VPBuilder VectorPHBuilder(VectorPH, VectorPH->begin());
1167 VPValue *ResumeTC =
1168 Plan.hasTailFolded() ? Plan.getTripCount() : &Plan.getVectorTripCount();
1169 for (auto &Phi : VectorRegion->getEntryBasicBlock()->phis()) {
1170 auto *WideIV = dyn_cast<VPWidenInductionRecipe>(&Phi);
1171 if (!WideIV)
1172 continue;
1173 if (VPValue *EndValue =
1174 tryToComputeEndValueForInduction(WideIV, VectorPHBuilder, ResumeTC))
1175 EndValues[WideIV] = EndValue;
1176 }
1177
1178 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
1179 for (VPRecipeBase &R : make_early_inc_range(*MiddleVPBB)) {
1180 VPValue *Op;
1181 if (!match(&R, m_ExitingIVValue(m_VPValue(Op))))
1182 continue;
1183 auto *WideIV = cast<VPWidenInductionRecipe>(Op);
1184 if (VPValue *EndValue = EndValues.lookup(WideIV)) {
1185 R.getVPSingleValue()->replaceAllUsesWith(EndValue);
1186 R.eraseFromParent();
1187 }
1188 }
1189
1190 // Then, optimize exit block users.
1191 for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
1192 for (VPRecipeBase &R : ExitVPBB->phis()) {
1193 auto *ExitIRI = cast<VPIRPhi>(&R);
1194
1195 for (auto [Idx, PredVPBB] : enumerate(ExitVPBB->getPredecessors())) {
1196 VPValue *Escape = nullptr;
1197 if (PredVPBB == MiddleVPBB)
1199 Plan, ExitIRI->getOperand(Idx), EndValues, PSE);
1200 else
1202 Plan, ExitIRI->getOperand(Idx), PSE);
1203 if (Escape)
1204 ExitIRI->setOperand(Idx, Escape);
1205 }
1206 }
1207 }
1208}
1209
1210/// Remove redundant ExpandSCEVRecipes in \p Plan's entry block by replacing
1211/// them with already existing recipes expanding the same SCEV expression.
1214
1215 for (VPRecipeBase &R :
1217 auto *ExpR = dyn_cast<VPExpandSCEVRecipe>(&R);
1218 if (!ExpR)
1219 continue;
1220
1221 const auto &[V, Inserted] = SCEV2VPV.try_emplace(ExpR->getSCEV(), ExpR);
1222 if (Inserted)
1223 continue;
1224
1225 ExpR->replaceAllUsesWith(V->second);
1226 if (ExpR == Plan.getTripCount())
1227 Plan.resetTripCount(V->second);
1228
1229 ExpR->eraseFromParent();
1230 }
1231}
1232
1234 SmallVector<VPValue *> WorkList;
1236 WorkList.push_back(V);
1237
1238 while (!WorkList.empty()) {
1239 VPValue *Cur = WorkList.pop_back_val();
1240 if (!Seen.insert(Cur).second)
1241 continue;
1242 VPRecipeBase *R = Cur->getDefiningRecipe();
1243 if (!R)
1244 continue;
1245 if (!isDeadRecipe(*R))
1246 continue;
1247 append_range(WorkList, R->operands());
1248 R->eraseFromParent();
1249 }
1250}
1251
1252/// Get any instruction opcode or intrinsic ID data embedded in recipe \p R.
1253/// Returns an optional pair, where the first element indicates whether it is
1254/// an intrinsic ID.
1255static std::optional<std::pair<bool, unsigned>>
1258 return std::make_pair(true, IID);
1259 return TypeSwitch<const VPSingleDefRecipe *,
1260 std::optional<std::pair<bool, unsigned>>>(R)
1263 [](auto *I) { return std::make_pair(false, I->getOpcode()); })
1264 .Case([](const VPWidenPHIRecipe *I) {
1265 return std::make_pair(false, Instruction::PHI);
1266 })
1267 .Case<VPVectorPointerRecipe, VPPredInstPHIRecipe, VPScalarIVStepsRecipe>(
1268 [](auto *I) {
1269 // For recipes that do not directly map to LLVM IR instructions,
1270 // assign opcodes after the last VPInstruction opcode (which is also
1271 // after the last IR Instruction opcode), based on the VPRecipeID.
1272 return std::make_pair(false, VPInstruction::OpsEnd + 1 +
1273 I->getVPRecipeID());
1274 })
1275 .Default([](auto *) { return std::nullopt; });
1276}
1277
1278/// Try to fold \p R using InstSimplifyFolder. Will succeed and return a
1279/// non-nullptr VPValue for a handled opcode or intrinsic ID if corresponding \p
1280/// Operands are foldable live-ins.
1282 ArrayRef<VPValue *> Operands,
1283 const DataLayout &DL) {
1284 auto OpcodeOrIID = getOpcodeOrIntrinsicID(&R);
1285 if (!OpcodeOrIID)
1286 return nullptr;
1287
1289 for (VPValue *Op : Operands) {
1290 VPValue *Candidate = Op;
1291 match(Op, m_Broadcast(m_VPValue(Candidate)));
1292 if (!match(Candidate, m_LiveIn()))
1293 return nullptr;
1294 Value *V = Candidate->getUnderlyingValue();
1295 if (!V)
1296 return nullptr;
1297 Ops.push_back(V);
1298 }
1299
1300 VPlan &Plan = *R.getParent()->getPlan();
1301 auto FoldToIRValue = [&]() -> Value * {
1302 InstSimplifyFolder Folder(DL);
1303 if (OpcodeOrIID->first) {
1304 // VPInstructions store the called intrinsic as last operand.
1305 if (isa<VPInstruction>(R))
1306 Ops.pop_back();
1307
1308 auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(&R);
1309 return Folder.FoldIntrinsic(OpcodeOrIID->second, Ops, R.getScalarType(),
1310 RFlags ? RFlags->getFastMathFlagsOrNone()
1311 : FastMathFlags());
1312 }
1313 unsigned Opcode = OpcodeOrIID->second;
1314 if (Instruction::isBinaryOp(Opcode))
1315 return Folder.FoldBinOp(static_cast<Instruction::BinaryOps>(Opcode),
1316 Ops[0], Ops[1]);
1317 if (Instruction::isCast(Opcode))
1318 return Folder.FoldCast(static_cast<Instruction::CastOps>(Opcode), Ops[0],
1319 R.getVPSingleValue()->getScalarType());
1320 switch (Opcode) {
1321 case VPInstruction::Not:
1322 return Folder.FoldBinOp(Instruction::BinaryOps::Xor, Ops[0],
1324 case Instruction::Select:
1325 return Folder.FoldSelect(Ops[0], Ops[1], Ops[2]);
1326 case Instruction::ICmp:
1327 case Instruction::FCmp:
1328 return Folder.FoldCmp(cast<VPRecipeWithIRFlags>(R).getPredicate(), Ops[0],
1329 Ops[1]);
1330 case Instruction::GetElementPtr: {
1331 auto &RFlags = cast<VPRecipeWithIRFlags>(R);
1332 auto *GEP = cast<GetElementPtrInst>(RFlags.getUnderlyingInstr());
1333 return Folder.FoldGEP(GEP->getSourceElementType(), Ops[0],
1334 drop_begin(Ops), RFlags.getGEPNoWrapFlags());
1335 }
1338 return Folder.FoldGEP(IntegerType::getInt8Ty(Plan.getContext()), Ops[0],
1339 Ops[1],
1340 cast<VPRecipeWithIRFlags>(R).getGEPNoWrapFlags());
1341 // An extract of a live-in is an extract of a broadcast, so return the
1342 // broadcasted element.
1343 case Instruction::ExtractElement:
1344 assert(!Ops[0]->getType()->isVectorTy() && "Live-ins should be scalar");
1345 return Ops[0];
1346 }
1347 return nullptr;
1348 };
1349
1350 if (Value *V = FoldToIRValue())
1351 return Plan.getOrAddLiveIn(V);
1352 return nullptr;
1353}
1354
1355/// Try to simplify logical and bitwise recipes in \p Def.
1357 bool CanCreateNewRecipe) {
1358 VPlan *Plan = Def->getParent()->getPlan();
1359
1360 // Simplify (X && Y) | (X && !Y) -> X.
1361 // TODO: Split up into simpler, modular combines: (X && Y) | (X && Z) into X
1362 // && (Y | Z) and (X | !X) into true. This requires queuing newly created
1363 // recipes to be visited during simplification.
1364 VPValue *X, *Y, *Z;
1365 if (match(Def,
1368 Def->replaceAllUsesWith(X);
1369 Def->eraseFromParent();
1370 return true;
1371 }
1372
1373 // x | AllOnes -> AllOnes
1374 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_AllOnes()))) {
1375 Def->replaceAllUsesWith(Plan->getAllOnesValue(Def->getScalarType()));
1376 return true;
1377 }
1378
1379 // x | 0 -> x
1380 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_ZeroInt()))) {
1381 Def->replaceAllUsesWith(X);
1382 return true;
1383 }
1384
1385 // x | !x -> AllOnes
1386 if (match(Def, m_c_BinaryOr(m_VPValue(X), m_Not(m_Deferred(X))))) {
1387 Def->replaceAllUsesWith(Plan->getAllOnesValue(Def->getScalarType()));
1388 return true;
1389 }
1390
1391 // x & 0 -> 0
1392 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_ZeroInt()))) {
1393 Def->replaceAllUsesWith(Plan->getZero(Def->getScalarType()));
1394 return true;
1395 }
1396
1397 // x & AllOnes -> x
1398 if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_AllOnes()))) {
1399 Def->replaceAllUsesWith(X);
1400 return true;
1401 }
1402
1403 // x && false -> false
1404 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False()))) {
1405 Def->replaceAllUsesWith(Plan->getFalse());
1406 return true;
1407 }
1408
1409 // x && true -> x
1410 if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True()))) {
1411 Def->replaceAllUsesWith(X);
1412 return true;
1413 }
1414
1415 // (x && y) | (x && z) -> x && (y | z)
1416 if (CanCreateNewRecipe &&
1419 // Simplify only if one of the operands has one use to avoid creating an
1420 // extra recipe.
1421 (!Def->getOperand(0)->hasMoreThanOneUniqueUser() ||
1422 !Def->getOperand(1)->hasMoreThanOneUniqueUser())) {
1423 Def->replaceAllUsesWith(
1424 Builder.createLogicalAnd(X, Builder.createOr(Y, Z)));
1425 return true;
1426 }
1427
1428 // x && (x && y) -> x && y
1429 if (match(Def, m_LogicalAnd(m_VPValue(X),
1431 Def->replaceAllUsesWith(Def->getOperand(1));
1432 return true;
1433 }
1434
1435 // x && (y && x) -> x && y
1436 if (match(Def, m_LogicalAnd(m_VPValue(X),
1438 Def->replaceAllUsesWith(Builder.createLogicalAnd(X, Y));
1439 return true;
1440 }
1441
1442 // x && !x -> 0
1443 if (match(Def, m_LogicalAnd(m_VPValue(X), m_Not(m_Deferred(X))))) {
1444 Def->replaceAllUsesWith(Plan->getFalse());
1445 return true;
1446 }
1447
1448 if (match(Def, m_Select(m_VPValue(), m_VPValue(X), m_Deferred(X)))) {
1449 Def->replaceAllUsesWith(X);
1450 return true;
1451 }
1452
1453 // select c, false, true -> not c
1454 VPValue *C;
1455 if (CanCreateNewRecipe &&
1456 match(Def, m_Select(m_VPValue(C), m_False(), m_True()))) {
1457 Def->replaceAllUsesWith(Builder.createNot(C));
1458 return true;
1459 }
1460
1461 // select !c, x, y -> select c, y, x
1462 if (match(Def, m_Select(m_Not(m_VPValue(C)), m_VPValue(X), m_VPValue(Y)))) {
1463 Def->setOperand(0, C);
1464 Def->setOperand(1, Y);
1465 Def->setOperand(2, X);
1466 return true;
1467 }
1468
1469 // select x, (i1 y | z), y -> y | (x && z)
1470 if (CanCreateNewRecipe &&
1471 match(Def, m_Select(m_VPValue(X),
1473 m_Deferred(Y))) &&
1474 Y->getScalarType()->isIntegerTy(1)) {
1475 Def->replaceAllUsesWith(
1476 Builder.createOr(Y, Builder.createLogicalAnd(X, Z)));
1477 return true;
1478 }
1479
1480 return false;
1481}
1482
1483/// Try to simplify VPSingleDefRecipe \p Def.
1485 VPlan *Plan = Def->getParent()->getPlan();
1486
1487 // Simplification of live-in IR values for SingleDef recipes using
1488 // InstSimplifyFolder.
1489 const DataLayout &DL = Plan->getDataLayout();
1490 if (VPValue *V = tryToFoldLiveIns(*Def, Def->operands(), DL))
1491 return Def->replaceAllUsesWith(V);
1492
1493 // Fold PredPHI LiveIn -> LiveIn.
1494 if (auto *PredPHI = dyn_cast<VPPredInstPHIRecipe>(Def)) {
1495 VPValue *Op = PredPHI->getOperand(0);
1496 if (isa<VPIRValue>(Op))
1497 PredPHI->replaceAllUsesWith(Op);
1498 }
1499
1500 // Drop the mask of a predicated store masked by the header mask (which is
1501 // guaranteed to be true at least for the first lane) and both the stored
1502 // value and the address are uniform across VF and UF. The header mask is
1503 // still the abstract region value here.
1504 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Def);
1505 RepR && RepR->isPredicated() && RepR->getOpcode() == Instruction::Store &&
1506 all_of(RepR->operandsWithoutMask(), vputils::isUniformAcrossVFsAndUFs) &&
1507 match(RepR->getMask(), m_HeaderMask())) {
1508 auto *Unmasked = new VPReplicateRecipe(
1509 RepR->getUnderlyingInstr(), RepR->operandsWithoutMask(),
1510 RepR->isSingleScalar(), /*Mask=*/nullptr, *RepR, *RepR,
1511 RepR->getDebugLoc());
1512 Unmasked->insertBefore(RepR);
1513 RepR->replaceAllUsesWith(Unmasked);
1514 RepR->eraseFromParent();
1515 return;
1516 }
1517
1518 VPBuilder Builder(Def);
1519
1520 // Avoid replacing VPInstructions with underlying values with new
1521 // VPInstructions, as we would fail to create widen/replicate recpes from the
1522 // new VPInstructions without an underlying value, and miss out on some
1523 // transformations that only apply to widened/replicated recipes later, by
1524 // doing so.
1525 // TODO: We should also not replace non-VPInstructions like VPWidenRecipe with
1526 // VPInstructions without underlying values, as those will get skipped during
1527 // cost computation.
1528 bool CanCreateNewRecipe =
1529 !isa<VPInstruction>(Def) || !Def->getUnderlyingValue();
1530
1531 VPValue *A;
1532 if (match(Def, m_Trunc(m_ZExtOrSExt(m_VPValue(A))))) {
1533 Type *TruncTy = Def->getScalarType();
1534 Type *ATy = A->getScalarType();
1535 if (TruncTy == ATy) {
1536 Def->replaceAllUsesWith(A);
1537 } else {
1538 // Don't replace a non-widened cast recipe with a widened cast.
1539 if (!isa<VPWidenCastRecipe>(Def))
1540 return;
1541 if (ATy->getScalarSizeInBits() < TruncTy->getScalarSizeInBits()) {
1542
1543 unsigned ExtOpcode = match(Def->getOperand(0), m_SExt(m_VPValue()))
1544 ? Instruction::SExt
1545 : Instruction::ZExt;
1546 auto *Ext = Builder.createWidenCast(Instruction::CastOps(ExtOpcode), A,
1547 TruncTy);
1548 if (auto *UnderlyingExt = Def->getOperand(0)->getUnderlyingValue()) {
1549 // UnderlyingExt has distinct return type, used to retain legacy cost.
1550 Ext->setUnderlyingValue(UnderlyingExt);
1551 }
1552 Def->replaceAllUsesWith(Ext);
1553 } else if (ATy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits()) {
1554 auto *Trunc = Builder.createWidenCast(Instruction::Trunc, A, TruncTy);
1555 Def->replaceAllUsesWith(Trunc);
1556 }
1557 }
1558 }
1559
1560 if (simplifyLogicalRecipe(Def, Builder, CanCreateNewRecipe))
1561 return;
1562
1563 VPValue *X, *Y, *C;
1564 if (match(Def, m_c_Add(m_VPValue(A), m_ZeroInt())))
1565 return Def->replaceAllUsesWith(A);
1566
1567 if (match(Def, m_c_Mul(m_VPValue(A), m_One())))
1568 return Def->replaceAllUsesWith(A);
1569
1570 if (match(Def, m_c_Mul(m_VPValue(A), m_ZeroInt())))
1571 return Def->replaceAllUsesWith(Plan->getZero(Def->getScalarType()));
1572
1573 if (CanCreateNewRecipe && match(Def, m_c_Mul(m_VPValue(A), m_AllOnes()))) {
1574 // Preserve nsw from the Mul on the new Sub.
1576 false, cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap()};
1577 return Def->replaceAllUsesWith(Builder.createSub(
1578 Plan->getZero(A->getScalarType()), A, Def->getDebugLoc(), "", NW));
1579 }
1580
1581 if (CanCreateNewRecipe &&
1583 // Preserve nsw from the Add and the Sub, if it's present on both, on the
1584 // new Sub.
1586 false,
1587 cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap() &&
1588 cast<VPRecipeWithIRFlags>(Def->getOperand(Def->getOperand(0) == X))
1589 ->hasNoSignedWrap()};
1590 return Def->replaceAllUsesWith(
1591 Builder.createSub(X, Y, Def->getDebugLoc(), "", NW));
1592 }
1593
1594 const APInt *APC;
1595 if (CanCreateNewRecipe && match(Def, m_c_Mul(m_VPValue(A), m_APInt(APC))) &&
1596 APC->isPowerOf2()) {
1597 auto *MulR = cast<VPRecipeWithIRFlags>(Def);
1598 unsigned ShiftAmt = APC->exactLogBase2();
1599 VPIRFlags::WrapFlagsTy NW(MulR->hasNoUnsignedWrap(),
1600 MulR->hasNoSignedWrap() &&
1601 ShiftAmt != APC->getBitWidth() - 1);
1602 return Def->replaceAllUsesWith(Builder.createNaryOp(
1603 Instruction::Shl,
1604 {A, Plan->getConstantInt(APC->getBitWidth(), ShiftAmt)}, NW,
1605 Def->getDebugLoc()));
1606 }
1607
1608 if (CanCreateNewRecipe && match(Def, m_UDiv(m_VPValue(A), m_APInt(APC))) &&
1609 APC->isPowerOf2())
1610 return Def->replaceAllUsesWith(Builder.createNaryOp(
1611 Instruction::LShr,
1612 {A, Plan->getConstantInt(APC->getBitWidth(), APC->exactLogBase2())},
1613 *cast<VPRecipeWithIRFlags>(Def), Def->getDebugLoc()));
1614
1615 if (match(Def, m_Not(m_VPValue(A)))) {
1616 if (match(A, m_Not(m_VPValue(A))))
1617 return Def->replaceAllUsesWith(A);
1618
1619 // Try to fold Not into compares by adjusting the predicate in-place.
1620 CmpPredicate Pred;
1621 if (match(A, m_Cmp(Pred, m_VPValue(), m_VPValue()))) {
1622 auto *Cmp = cast<VPRecipeWithIRFlags>(A);
1623 if (all_of(Cmp->users(),
1625 m_Not(m_Specific(Cmp)),
1626 m_Select(m_Specific(Cmp), m_VPValue(), m_VPValue()))))) {
1627 Cmp->setPredicate(CmpInst::getInversePredicate(Pred));
1628 for (VPUser *U : to_vector(Cmp->users())) {
1629 auto *R = cast<VPSingleDefRecipe>(U);
1630 if (match(R, m_Select(m_Specific(Cmp), m_VPValue(X), m_VPValue(Y)))) {
1631 // select (cmp pred), x, y -> select (cmp inv_pred), y, x
1632 R->setOperand(1, Y);
1633 R->setOperand(2, X);
1634 } else {
1635 // not (cmp pred) -> cmp inv_pred
1636 assert(match(R, m_Not(m_Specific(Cmp))) && "Unexpected user");
1637 R->replaceAllUsesWith(Cmp);
1638 }
1639 }
1640 // If Cmp doesn't have a debug location, use the one from the negation,
1641 // to preserve the location.
1642 if (!Cmp->getDebugLoc() && Def->getDebugLoc())
1643 Cmp->setDebugLoc(Def->getDebugLoc());
1644 }
1645 }
1646 }
1647
1648 // Fold any-of (fcmp uno %A, %A), (fcmp uno %B, %B), ... ->
1649 // any-of (fcmp uno %A, %B), ...
1650 if (match(Def, m_AnyOf())) {
1652 VPRecipeBase *UnpairedCmp = nullptr;
1653 for (VPValue *Op : Def->operands()) {
1654 VPValue *X;
1655 if (Op->getNumUsers() > 1 ||
1657 m_Deferred(X)))) {
1658 NewOps.push_back(Op);
1659 } else if (!UnpairedCmp) {
1660 UnpairedCmp = Op->getDefiningRecipe();
1661 } else {
1662 NewOps.push_back(Builder.createFCmp(CmpInst::FCMP_UNO,
1663 UnpairedCmp->getOperand(0), X));
1664 UnpairedCmp = nullptr;
1665 }
1666 }
1667
1668 if (UnpairedCmp)
1669 NewOps.push_back(UnpairedCmp->getVPSingleValue());
1670
1671 if (NewOps.size() < Def->getNumOperands()) {
1672 VPValue *NewAnyOf = Builder.createNaryOp(VPInstruction::AnyOf, NewOps);
1673 return Def->replaceAllUsesWith(NewAnyOf);
1674 }
1675 }
1676
1677 // Fold (fcmp uno %X, %X) or (fcmp uno %Y, %Y) -> fcmp uno %X, %Y
1678 // This is useful for fmax/fmin without fast-math flags, where we need to
1679 // check if any operand is NaN.
1680 if (CanCreateNewRecipe &&
1682 m_Deferred(X)),
1684 m_Deferred(Y))))) {
1685 VPValue *NewCmp = Builder.createFCmp(CmpInst::FCMP_UNO, X, Y);
1686 return Def->replaceAllUsesWith(NewCmp);
1687 }
1688
1689 // Remove redundant DerviedIVs, that is 0 + A * 1 -> A and 0 + 0 * x -> 0.
1690 if ((match(Def, m_DerivedIV(m_ZeroInt(), m_VPValue(A), m_One())) ||
1691 match(Def, m_DerivedIV(m_ZeroInt(), m_ZeroInt(), m_VPValue()))) &&
1692 Def->getOperand(1)->getScalarType() == Def->getScalarType())
1693 return Def->replaceAllUsesWith(Def->getOperand(1));
1694
1696 m_One()))) {
1697 Type *WideStepTy = Def->getScalarType();
1698 if (X->getScalarType() != WideStepTy)
1699 X = Builder.createWidenCast(Instruction::Trunc, X, WideStepTy);
1700 Def->replaceAllUsesWith(X);
1701 return;
1702 }
1703
1704 // For i1 vp.merges produced by AnyOf reductions:
1705 // vp.merge true, (or x, y), x, evl -> vp.merge y, true, x, evl
1707 m_VPValue(X), m_VPValue())) &&
1709 Def->getScalarType()->isIntegerTy(1)) {
1710 Def->setOperand(1, Def->getOperand(0));
1711 Def->setOperand(0, Y);
1712 return;
1713 }
1714
1715 // Simplify MaskedCond with no block mask to its single operand.
1717 !cast<VPInstruction>(Def)->isMasked())
1718 return Def->replaceAllUsesWith(Def->getOperand(0));
1719
1720 // Look through ExtractLastLane.
1721 if (match(Def, m_ExtractLastLane(m_VPValue(A)))) {
1722 if (match(A, m_BuildVector())) {
1723 auto *BuildVector = cast<VPInstruction>(A);
1724 Def->replaceAllUsesWith(
1725 BuildVector->getOperand(BuildVector->getNumOperands() - 1));
1726 return;
1727 }
1728
1729 if (match(A, m_Broadcast(m_VPValue(X))))
1730 return Def->replaceAllUsesWith(X);
1731
1733 return Def->replaceAllUsesWith(A);
1734
1735 if (Plan->hasScalarVFOnly())
1736 return Def->replaceAllUsesWith(A);
1737 }
1738
1739 // Look through ExtractPenultimateElement (BuildVector ....).
1741 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1742 Def->replaceAllUsesWith(
1743 BuildVector->getOperand(BuildVector->getNumOperands() - 2));
1744 return;
1745 }
1746
1747 uint64_t Idx;
1749 auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
1750 Def->replaceAllUsesWith(BuildVector->getOperand(Idx));
1751 return;
1752 }
1753
1754 if (match(Def, m_BuildVector()) && all_equal(Def->operands())) {
1755 Def->replaceAllUsesWith(
1756 Builder.createNaryOp(VPInstruction::Broadcast, Def->getOperand(0)));
1757 return;
1758 }
1759
1760 // Replace uses of a BuildVector by users that only use its first lane with
1761 // its first operand directly.
1762 if (match(Def, m_BuildVector())) {
1763 Def->replaceUsesWithIf(Def->getOperand(0), [Def](VPUser &U, unsigned) {
1764 return U.usesFirstLaneOnly(Def);
1765 });
1766 }
1767
1768 // Look through broadcast of single-scalar when used as select conditions; in
1769 // that case the scalar condition can be used directly.
1770 if (match(Def,
1773 "broadcast operand must be single-scalar");
1774 Def->setOperand(0, C);
1775 return;
1776 }
1777
1778 if (match(Def, m_Broadcast(m_VPValue(X))))
1779 return Def->replaceUsesWithIf(
1780 X, [Def](const VPUser &U, unsigned) { return U.usesScalars(Def); });
1781
1783 if (Def->getNumOperands() == 1) {
1784 Def->replaceAllUsesWith(Def->getOperand(0));
1785 return;
1786 }
1787 if (auto *Phi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(Def)) {
1788 if (all_equal(Phi->incoming_values()))
1789 Phi->replaceAllUsesWith(Phi->getOperand(0));
1790 }
1791 return;
1792 }
1793
1794 VPIRValue *IRV;
1795 if (Def->getNumOperands() == 1 &&
1797 return Def->replaceAllUsesWith(IRV);
1798
1799 // Some simplifications can only be applied after unrolling. Perform them
1800 // below.
1801 if (!Plan->isUnrolled())
1802 return;
1803
1804 // After unrolling, extract-lane may be used to extract values from multiple
1805 // scalar sources. Only simplify when extracting from a single scalar source.
1806 VPValue *LaneToExtract;
1807 if (match(Def, m_ExtractLane(m_VPValue(LaneToExtract), m_VPValue(A)))) {
1808 // Simplify extract-lane(%lane_num, %scalar_val) -> %scalar_val.
1810 return Def->replaceAllUsesWith(A);
1811
1812 // Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
1813 // scalar canonical IV.
1815 if (match(LaneToExtract, m_ZeroInt()) &&
1816 match(A, m_CanonicalWidenIV(WidenIV)))
1817 return Def->replaceAllUsesWith(WidenIV->getRegion()->getCanonicalIV());
1818
1819 // Simplify extract-lane with single source to extract-element.
1820 Def->replaceAllUsesWith(Builder.createNaryOp(
1821 Instruction::ExtractElement, {A, LaneToExtract}, Def->getDebugLoc()));
1822 return;
1823 }
1824
1825 // Look for cycles where Def is of the form:
1826 // X = phi(0, IVInc) ; used only by IVInc, or by IVInc and Inc = X + Y
1827 // IVInc = X + Step ; used by X and Def
1828 // Def = IVInc + Y
1829 // Fold the increment Y into the phi's start value, replace Def with IVInc,
1830 // and if Inc exists, replace it with X.
1831 if (match(Def, m_Add(m_Add(m_VPValue(X), m_VPValue()), m_VPValue(Y))) &&
1832 isa<VPIRValue>(Y) &&
1833 match(X, m_VPPhi(m_ZeroInt(), m_Specific(Def->getOperand(0))))) {
1834 auto *Phi = cast<VPPhi>(X);
1835 auto *IVInc = Def->getOperand(0);
1836 if (IVInc->getNumUsers() == 2) {
1837 // If Phi has a second user (besides IVInc's defining recipe), it must
1838 // be Inc = Phi + Y for the fold to apply.
1840 findUserOf(Phi, m_Add(m_Specific(Phi), m_Specific(Y))));
1841 if (Phi->getNumUsers() == 1 || (Phi->getNumUsers() == 2 && Inc)) {
1842 Def->replaceAllUsesWith(IVInc);
1843 if (Inc)
1844 Inc->replaceAllUsesWith(Phi);
1845 Phi->setOperand(0, Y);
1846 return;
1847 }
1848 }
1849 }
1850
1851 // Simplify unrolled VectorPointer without offset, or with zero offset, to
1852 // just the pointer operand.
1853 if (auto *VPR = dyn_cast<VPVectorPointerRecipe>(Def))
1854 if (!VPR->getVFxPart() || match(VPR->getVFxPart(), m_ZeroInt()))
1855 return VPR->replaceAllUsesWith(VPR->getOperand(0));
1856
1857 // VPScalarIVSteps after unrolling can be replaced by their start value, if
1858 // the start index is zero and only the first lane 0 is demanded.
1859 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Def)) {
1860 if (!Steps->getStartIndex() && vputils::onlyFirstLaneUsed(Steps)) {
1861 Steps->replaceAllUsesWith(Steps->getOperand(0));
1862 return;
1863 }
1864 }
1865 // Simplify redundant ReductionStartVector recipes after unrolling.
1866 VPValue *StartV;
1868 m_VPValue(StartV), m_VPValue(), m_VPValue()))) {
1869 Def->replaceUsesWithIf(StartV, [](const VPUser &U, unsigned Idx) {
1870 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&U);
1871 return PhiR && PhiR->isInLoop();
1872 });
1873 return;
1874 }
1875
1876 if (Plan->getConcreteUF() == 1 && match(Def, m_ExtractLastPart(m_VPValue(A))))
1877 return Def->replaceAllUsesWith(A);
1878}
1879
1889
1890/// Removes the permutation pattern \p Perm from any elementwise operations
1891/// in the plan, by constructing a new permutation via \p Build.
1892/// e.g. binop(perm(x), perm(y)) -> perm(binop(x,y)).
1893template <typename Match_t, typename Builder>
1894static void pullOutPermutations(VPlan &Plan, Match_t Perm, Builder Build) {
1896 vp_depth_first_deep(Plan.getEntry()))) {
1897 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
1898 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
1899 if (!Def || !vputils::isElementwise(Def))
1900 continue;
1901
1902 // At least one of the ops must be a permutation.
1903 if (!any_of(Def->operands(), match_fn(Perm(m_VPValue()))))
1904 continue;
1905
1906 // All operands must be permuted or a live in (splat).
1907 if (!all_of(
1908 Def->operands(),
1910 continue;
1911
1912 VPValue *X;
1913 // Remove the inner permutations.
1914 for (unsigned I = 0; I < Def->getNumOperands(); I++)
1915 if (match(Def->getOperand(I), Perm(m_VPValue(X))))
1916 Def->setOperand(I, X);
1917
1918 VPSingleDefRecipe *Res = Build(Def);
1919 Res->insertAfter(Def);
1920 Def->replaceUsesWithIf(
1921 Res, [&Res](VPUser &U, unsigned _) { return &U != Res; });
1922 }
1923 }
1924}
1925
1927 // Pull out reverses from any elementwise op.
1928 // binop(reverse(x), reverse(y)) -> reverse(binop(x,y))
1930 Plan, [](const auto &X) { return m_Reverse(X); },
1931 [](auto *X) { return new VPInstruction(VPInstruction::Reverse, X); });
1932
1933 // reverse(reverse(x)) -> x
1934 VPValue *X;
1937 for (VPRecipeBase &R : make_early_inc_range(*VPBB))
1938 if (match(&R, m_Reverse(m_Reverse(m_VPValue(X)))))
1939 R.getVPSingleValue()->replaceAllUsesWith(X);
1940}
1941
1942/// Reassociate (headermask && x) && y -> headermask && (x && y) to allow the
1943/// header mask to be simplified further when tail folding, e.g. in
1944/// optimizeEVLMasks.
1945static void reassociateHeaderMask(VPlan &Plan) {
1946 VPValue *HeaderMask = Plan.getVectorLoopRegion()->getHeaderMask();
1947 if (!HeaderMask)
1948 return;
1949
1950 SmallVector<VPUser *> Worklist;
1951 for (VPUser *U : HeaderMask->users())
1952 if (match(U, m_LogicalAnd(m_Specific(HeaderMask), m_VPValue())))
1954
1955 while (!Worklist.empty()) {
1956 auto *R = dyn_cast<VPSingleDefRecipe>(Worklist.pop_back_val());
1957 VPValue *X, *Y;
1958 if (!R || !match(R, m_LogicalAnd(
1959 m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(X)),
1960 m_VPValue(Y))))
1961 continue;
1962 append_range(Worklist, R->users());
1963 VPBuilder Builder(R);
1964 R->replaceAllUsesWith(
1965 Builder.createLogicalAnd(HeaderMask, Builder.createLogicalAnd(X, Y)));
1966 }
1967}
1968
1969static std::optional<Instruction::BinaryOps>
1971 switch (ID) {
1972 case Intrinsic::masked_udiv:
1973 return Instruction::UDiv;
1974 case Intrinsic::masked_sdiv:
1975 return Instruction::SDiv;
1976 case Intrinsic::masked_urem:
1977 return Instruction::URem;
1978 case Intrinsic::masked_srem:
1979 return Instruction::SRem;
1980 default:
1981 return {};
1982 }
1983}
1984
1986 if (Plan.hasScalarVFOnly())
1987 return;
1988
1990 vp_depth_first_deep(Plan.getEntry()))) {
1991 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
1994 continue;
1995 auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
1996 if (RepR && (RepR->isSingleScalar() || RepR->isPredicated()))
1997 continue;
1998
1999 auto *RepOrWidenR = cast<VPRecipeWithIRFlags>(&R);
2000 if (RepR && RepR->getOpcode() == Instruction::Store &&
2001 vputils::isSingleScalar(RepR->getOperand(1))) {
2002 auto *Clone = new VPReplicateRecipe(
2003 RepOrWidenR->getUnderlyingInstr(), RepOrWidenR->operands(),
2004 true /*IsSingleScalar*/, nullptr /*Mask*/, *RepR /*Flags*/,
2005 *RepR /*Metadata*/, RepR->getDebugLoc());
2006 Clone->insertBefore(RepOrWidenR);
2007 VPBuilder Builder(Clone);
2008 VPValue *ExtractOp = Clone->getOperand(0);
2009 if (vputils::isUniformAcrossVFsAndUFs(RepR->getOperand(1)))
2010 ExtractOp =
2011 Builder.createNaryOp(VPInstruction::ExtractLastPart, ExtractOp);
2012 ExtractOp =
2013 Builder.createNaryOp(VPInstruction::ExtractLastLane, ExtractOp);
2014 Clone->setOperand(0, ExtractOp);
2015 RepR->eraseFromParent();
2016 continue;
2017 }
2018
2019 // Narrow llvm.masked.{u,s}{div,rem} intrinsics with a safe divisor.
2020 if (auto *IntrR = dyn_cast<VPWidenIntrinsicRecipe>(RepOrWidenR)) {
2021 if (!vputils::onlyFirstLaneUsed(IntrR))
2022 continue;
2023 auto Opc = getUnmaskedDivRemOpcode(IntrR->getVectorIntrinsicID());
2024 if (!Opc)
2025 continue;
2026 VPBuilder Builder(IntrR);
2027 VPValue *SafeDivisor = Builder.createSelect(
2028 IntrR->getOperand(2), IntrR->getOperand(1),
2029 Plan.getConstantInt(IntrR->getScalarType(), 1));
2030 VPValue *Clone = Builder.createNaryOp(
2031 *Opc, {IntrR->getOperand(0), SafeDivisor},
2032 VPIRFlags::getDefaultFlags(*Opc), IntrR->getDebugLoc());
2033 IntrR->replaceAllUsesWith(Clone);
2034 IntrR->eraseFromParent();
2035 continue;
2036 }
2037
2038 // Skip recipes that aren't single scalars.
2039 if (!vputils::isSingleScalar(RepOrWidenR))
2040 continue;
2041
2042 // Predicate to check if a user of Op introduces extra broadcasts.
2043 auto IntroducesBCastOf = [](const VPValue *Op) {
2044 return [Op](const VPUser *U) {
2045 if (auto *VPI = dyn_cast<VPInstruction>(U)) {
2049 VPI->getOpcode()))
2050 return false;
2051 }
2052 return !U->usesScalars(Op);
2053 };
2054 };
2055
2056 if (any_of(RepOrWidenR->users(), IntroducesBCastOf(RepOrWidenR)) &&
2057 none_of(RepOrWidenR->operands(), [&](VPValue *Op) {
2058 if (any_of(
2059 make_filter_range(Op->users(), not_equal_to(RepOrWidenR)),
2060 IntroducesBCastOf(Op)))
2061 return false;
2062 // Non-constant live-ins require broadcasts, while constants do not
2063 // need explicit broadcasts.
2064 bool LiveInNeedsBroadcast =
2065 isa<VPIRValue>(Op) && !isa<VPConstant>(Op);
2066 auto *OpR = dyn_cast<VPReplicateRecipe>(Op);
2067 return LiveInNeedsBroadcast || (OpR && OpR->isSingleScalar());
2068 }))
2069 continue;
2070
2071 auto *Clone = VPBuilder::createSingleScalarOp(
2072 getOpcodeOrIntrinsicID(RepOrWidenR)->second, RepOrWidenR->operands(),
2073 /*Mask=*/nullptr, *RepOrWidenR, {}, DebugLoc::getUnknown(),
2074 RepOrWidenR->getUnderlyingInstr());
2075 Clone->insertBefore(RepOrWidenR);
2076 RepOrWidenR->replaceAllUsesWith(Clone);
2077 if (isDeadRecipe(*RepOrWidenR))
2078 RepOrWidenR->eraseFromParent();
2079 }
2080 }
2081}
2082
2083/// Try to see if all of \p Blend's masks share a common value logically and'ed
2084/// and remove it from the masks.
2086 if (Blend->isNormalized())
2087 return;
2088 VPValue *CommonEdgeMask;
2089 if (!match(Blend->getMask(0),
2090 m_LogicalAnd(m_VPValue(CommonEdgeMask), m_VPValue())))
2091 return;
2092 for (unsigned I = 0; I < Blend->getNumIncomingValues(); I++)
2093 if (!match(Blend->getMask(I),
2094 m_LogicalAnd(m_Specific(CommonEdgeMask), m_VPValue())))
2095 return;
2096 for (unsigned I = 0; I < Blend->getNumIncomingValues(); I++)
2097 Blend->setMask(I, Blend->getMask(I)->getDefiningRecipe()->getOperand(1));
2098}
2099
2100/// Normalize and simplify VPBlendRecipes. Should be run after simplifyRecipes
2101/// to make sure the masks are simplified.
2102static void simplifyBlends(VPlan &Plan) {
2105 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2106 auto *Blend = dyn_cast<VPBlendRecipe>(&R);
2107 if (!Blend)
2108 continue;
2109
2110 removeCommonBlendMask(Blend);
2111
2112 // Try to remove redundant blend recipes.
2113 SmallPtrSet<VPValue *, 4> UniqueValues;
2114 if (Blend->isNormalized() || !match(Blend->getMask(0), m_False()))
2115 UniqueValues.insert(Blend->getIncomingValue(0));
2116 for (unsigned I = 1; I != Blend->getNumIncomingValues(); ++I)
2117 if (!match(Blend->getMask(I), m_False()))
2118 UniqueValues.insert(Blend->getIncomingValue(I));
2119
2120 if (UniqueValues.size() == 1) {
2121 Blend->replaceAllUsesWith(*UniqueValues.begin());
2122 Blend->eraseFromParent();
2123 continue;
2124 }
2125
2126 if (Blend->isNormalized())
2127 continue;
2128
2129 // Normalize the blend so its first incoming value is used as the initial
2130 // value with the others blended into it.
2131
2132 unsigned StartIndex = 0;
2133 for (unsigned I = 0; I != Blend->getNumIncomingValues(); ++I) {
2134 // If a value's mask is used only by the blend then is can be deadcoded.
2135 // TODO: Find the most expensive mask that can be deadcoded, or a mask
2136 // that's used by multiple blends where it can be removed from them all.
2137 VPValue *Mask = Blend->getMask(I);
2138 if (Mask->hasOneUse() && !match(Mask, m_False())) {
2139 StartIndex = I;
2140 break;
2141 }
2142 }
2143
2144 SmallVector<VPValue *, 4> OperandsWithMask;
2145 OperandsWithMask.push_back(Blend->getIncomingValue(StartIndex));
2146
2147 for (unsigned I = 0; I != Blend->getNumIncomingValues(); ++I) {
2148 if (I == StartIndex)
2149 continue;
2150 OperandsWithMask.push_back(Blend->getIncomingValue(I));
2151 OperandsWithMask.push_back(Blend->getMask(I));
2152 }
2153
2154 auto *NewBlend =
2155 new VPBlendRecipe(cast_or_null<PHINode>(Blend->getUnderlyingValue()),
2156 OperandsWithMask, *Blend, Blend->getDebugLoc());
2157 NewBlend->insertBefore(&R);
2158
2159 VPValue *DeadMask = Blend->getMask(StartIndex);
2160 Blend->replaceAllUsesWith(NewBlend);
2161 Blend->eraseFromParent();
2163
2164 /// Simplify BLEND %a, %b, Not(%mask) -> BLEND %b, %a, %mask.
2165 VPValue *NewMask;
2166 if (NewBlend->getNumOperands() == 3 &&
2167 match(NewBlend->getMask(1), m_Not(m_VPValue(NewMask)))) {
2168 VPValue *Inc0 = NewBlend->getOperand(0);
2169 VPValue *Inc1 = NewBlend->getOperand(1);
2170 VPValue *OldMask = NewBlend->getOperand(2);
2171 NewBlend->setOperand(0, Inc1);
2172 NewBlend->setOperand(1, Inc0);
2173 NewBlend->setOperand(2, NewMask);
2174 if (OldMask->user_empty())
2175 cast<VPInstruction>(OldMask)->eraseFromParent();
2176 }
2177 }
2178 }
2179}
2180
2181/// Optimize the width of vector induction variables in \p Plan based on a known
2182/// constant Trip Count, \p BestVF and \p BestUF.
2184 ElementCount BestVF,
2185 unsigned BestUF) {
2186 // Only proceed if we have not completely removed the vector region.
2187 if (!Plan.getVectorLoopRegion())
2188 return false;
2189
2190 const APInt *TC;
2191 if (!BestVF.isFixed() || !match(Plan.getTripCount(), m_APInt(TC)))
2192 return false;
2193
2194 // Calculate the minimum power-of-2 bit width that can fit the known TC, VF
2195 // and UF. Returns at least 8.
2196 auto ComputeBitWidth = [](APInt TC, uint64_t Align) {
2197 APInt AlignedTC =
2200 APInt MaxVal = AlignedTC - 1;
2201 return std::max<unsigned>(PowerOf2Ceil(MaxVal.getActiveBits()), 8);
2202 };
2203 unsigned NewBitWidth =
2204 ComputeBitWidth(*TC, BestVF.getKnownMinValue() * BestUF);
2205
2206 LLVMContext &Ctx = Plan.getContext();
2207 auto *NewIVTy = IntegerType::get(Ctx, NewBitWidth);
2208
2209 bool MadeChange = false;
2210
2211 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
2212 for (VPRecipeBase &Phi : HeaderVPBB->phis()) {
2213 // Currently only handle canonical IVs as it is trivial to replace the start
2214 // and stop values, and we currently only perform the optimization when the
2215 // IV has a single use.
2217 if (!match(&Phi, m_CanonicalWidenIV(WideIV)))
2218 continue;
2219 if (WideIV->hasMoreThanOneUniqueUser() ||
2220 NewIVTy == WideIV->getScalarType())
2221 continue;
2222
2223 // Currently only handle cases where the single user is a header-mask
2224 // comparison with the backedge-taken-count.
2225 VPUser *SingleUser = WideIV->getSingleUser();
2226 if (!SingleUser ||
2227 !match(SingleUser,
2228 m_ICmp(m_Specific(WideIV),
2230 continue;
2231
2232 // Update IV operands and comparison bound to use new narrower type.
2233 assert(!WideIV->getTruncInst() &&
2234 "canonical IV is not expected to have a truncation");
2235 auto *NewWideIV = new VPWidenIntOrFpInductionRecipe(
2236 WideIV->getPHINode(), Plan.getZero(NewIVTy),
2237 Plan.getConstantInt(NewIVTy, 1), WideIV->getVFValue(),
2238 WideIV->getInductionDescriptor(), *WideIV, WideIV->getDebugLoc());
2239 NewWideIV->insertBefore(WideIV);
2240
2241 auto *NewBTC = new VPWidenCastRecipe(
2242 Instruction::Trunc, Plan.getOrCreateBackedgeTakenCount(), NewIVTy,
2243 nullptr, VPIRFlags::getDefaultFlags(Instruction::Trunc));
2244 Plan.getVectorPreheader()->appendRecipe(NewBTC);
2245 auto *Cmp = cast<VPInstruction>(WideIV->getSingleUser());
2246 Cmp->replaceAllUsesWith(
2247 VPBuilder(Cmp).createICmp(Cmp->getPredicate(), NewWideIV, NewBTC));
2248
2249 MadeChange = true;
2250 }
2251
2252 return MadeChange;
2253}
2254
2255/// Return true if \p Cond is known to be true for given \p BestVF and \p
2256/// BestUF.
2258 ElementCount BestVF, unsigned BestUF,
2261 return any_of(Cond->getDefiningRecipe()->operands(), [&Plan, BestVF, BestUF,
2262 &PSE](VPValue *C) {
2263 return isConditionTrueViaVFAndUF(C, Plan, BestVF, BestUF, PSE);
2264 });
2265
2266 auto *CanIV = Plan.getVectorLoopRegion()->getCanonicalIV();
2269 m_c_Add(m_Specific(CanIV), m_Specific(&Plan.getVFxUF())),
2270 m_Specific(&Plan.getVectorTripCount()))))
2271 return false;
2272
2273 // The compare checks CanIV + VFxUF == vector trip count. The vector trip
2274 // count is not conveniently available as SCEV so far, so we compare directly
2275 // against the original trip count. This is stricter than necessary, as we
2276 // will only return true if the trip count == vector trip count.
2277 const SCEV *VectorTripCount =
2279 if (isa<SCEVCouldNotCompute>(VectorTripCount))
2280 VectorTripCount = vputils::getSCEVExprForVPValue(Plan.getTripCount(), PSE);
2281 assert(!isa<SCEVCouldNotCompute>(VectorTripCount) &&
2282 "Trip count SCEV must be computable");
2283 ScalarEvolution &SE = *PSE.getSE();
2284 ElementCount NumElements = BestVF.multiplyCoefficientBy(BestUF);
2285 const SCEV *C = SE.getElementCount(VectorTripCount->getType(), NumElements);
2286 return SE.isKnownPredicate(CmpInst::ICMP_EQ, VectorTripCount, C);
2287}
2288
2289/// Try to replace multiple active lane masks used for control flow with
2290/// a single, wide active lane mask instruction followed by multiple
2291/// extract subvector intrinsics. This applies to the active lane mask
2292/// instructions both in the loop and in the preheader.
2293/// Incoming values of all ActiveLaneMaskPHIs are updated to use the
2294/// new extracts from the first active lane mask, which has it's last
2295/// operand (multiplier) set to UF.
2297 unsigned UF) {
2298 if (!EnableWideActiveLaneMask || !VF.isVector() || UF == 1)
2299 return false;
2300
2301 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2302 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2303 auto *Term = &ExitingVPBB->back();
2304
2305 using namespace llvm::VPlanPatternMatch;
2307 m_VPValue(), m_VPValue(), m_VPValue())))))
2308 return false;
2309
2310 auto *Header = cast<VPBasicBlock>(VectorRegion->getEntry());
2311 LLVMContext &Ctx = Plan.getContext();
2312
2313 auto ExtractFromALM = [&](VPInstruction *ALM,
2314 SmallVectorImpl<VPValue *> &Extracts) {
2315 DebugLoc DL = ALM->getDebugLoc();
2316 for (unsigned Part = 0; Part < UF; ++Part) {
2318 Ops.append({ALM, Plan.getConstantInt(64, VF.getKnownMinValue() * Part)});
2319 auto *Ext =
2320 new VPWidenIntrinsicRecipe(Intrinsic::vector_extract, Ops,
2321 IntegerType::getInt1Ty(Ctx), {}, {}, DL);
2322 Extracts[Part] = Ext;
2323 Ext->insertAfter(ALM);
2324 }
2325 };
2326
2327 // Create a list of each active lane mask phi, ordered by unroll part.
2329 for (VPRecipeBase &R : Header->phis()) {
2331 if (!Phi)
2332 continue;
2333 VPValue *Index = nullptr;
2334 match(Phi->getBackedgeValue(),
2336 assert(Index && "Expected index from ActiveLaneMask instruction");
2337
2338 uint64_t Part;
2339 if (match(Index,
2341 m_VPValue(), m_Mul(m_VPValue(), m_ConstantInt(Part)))))
2342 Phis[Part] = Phi;
2343 else {
2344 // Anything other than a CanonicalIVIncrementForPart is part 0
2345 assert(!match(
2346 Index,
2348 Phis[0] = Phi;
2349 }
2350 }
2351
2352 assert(all_of(Phis, not_equal_to(nullptr)) &&
2353 "Expected one VPActiveLaneMaskPHIRecipe for each unroll part");
2354
2355 auto *EntryALM = cast<VPInstruction>(Phis[0]->getStartValue());
2356 auto *LoopALM = cast<VPInstruction>(Phis[0]->getBackedgeValue());
2357
2358 assert((EntryALM->getOpcode() == VPInstruction::ActiveLaneMask &&
2359 LoopALM->getOpcode() == VPInstruction::ActiveLaneMask) &&
2360 "Expected incoming values of Phi to be ActiveLaneMasks");
2361
2362 // When using wide lane masks, the return type of the get.active.lane.mask
2363 // intrinsic is VF x UF (last operand).
2364 VPValue *ALMMultiplier = Plan.getConstantInt(64, UF);
2365 EntryALM->setOperand(2, ALMMultiplier);
2366 LoopALM->setOperand(2, ALMMultiplier);
2367
2368 // Create UF x extract vectors and insert into preheader.
2369 SmallVector<VPValue *> EntryExtracts(UF);
2370 ExtractFromALM(EntryALM, EntryExtracts);
2371
2372 // Create UF x extract vectors and insert before the loop compare & branch,
2373 // updating the compare to use the first extract.
2374 SmallVector<VPValue *> LoopExtracts(UF);
2375 ExtractFromALM(LoopALM, LoopExtracts);
2376 VPInstruction *Not = cast<VPInstruction>(Term->getOperand(0));
2377 Not->setOperand(0, LoopExtracts[0]);
2378
2379 // Update the incoming values of active lane mask phis.
2380 for (unsigned Part = 0; Part < UF; ++Part) {
2381 Phis[Part]->setStartValue(EntryExtracts[Part]);
2382 Phis[Part]->setBackedgeValue(LoopExtracts[Part]);
2383 }
2384
2385 return true;
2386}
2387
2388/// Try to simplify the branch condition of \p Plan. This may restrict the
2389/// resulting plan to \p BestVF and \p BestUF.
2391 unsigned BestUF,
2393 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
2394 VPBasicBlock *ExitingVPBB = VectorRegion->getExitingBasicBlock();
2395 auto *Term = &ExitingVPBB->back();
2396 VPValue *Cond;
2397 auto m_CanIVInc = m_Add(m_VPValue(), m_Specific(&Plan.getVFxUF()));
2398 // Check if the branch condition compares the canonical IV increment (for main
2399 // loop), or the canonical IV increment plus an offset (for epilog loop).
2400 if (match(Term, m_BranchOnCount(
2401 m_CombineOr(m_CanIVInc, m_c_Add(m_CanIVInc, m_LiveIn())),
2402 m_VPValue())) ||
2404 m_VPValue(), m_VPValue(), m_VPValue()))))) {
2405 // Try to simplify the branch condition if VectorTC <= VF * UF when the
2406 // latch terminator is BranchOnCount or BranchOnCond(Not(ActiveLaneMask)).
2407 const SCEV *VectorTripCount =
2409 if (isa<SCEVCouldNotCompute>(VectorTripCount))
2410 VectorTripCount =
2412 assert(!isa<SCEVCouldNotCompute>(VectorTripCount) &&
2413 "Trip count SCEV must be computable");
2414 ScalarEvolution &SE = *PSE.getSE();
2415 ElementCount NumElements = BestVF.multiplyCoefficientBy(BestUF);
2416 const SCEV *C = SE.getElementCount(VectorTripCount->getType(), NumElements);
2417 if (!SE.isKnownPredicate(CmpInst::ICMP_ULE, VectorTripCount, C))
2418 return false;
2419 } else if (match(Term, m_BranchOnCond(m_VPValue(Cond))) ||
2421 // For BranchOnCond, check if we can prove the condition to be true using VF
2422 // and UF.
2423 if (!isConditionTrueViaVFAndUF(Cond, Plan, BestVF, BestUF, PSE))
2424 return false;
2425 } else {
2426 return false;
2427 }
2428
2429 // The vector loop region only executes once. Convert terminator of the
2430 // exiting block to exit in the first iteration.
2431 if (match(Term, m_BranchOnTwoConds())) {
2432 Term->setOperand(1, Plan.getTrue());
2433 return true;
2434 }
2435
2436 auto *BOC = new VPInstruction(VPInstruction::BranchOnCond, Plan.getTrue(), {},
2437 {}, Term->getDebugLoc());
2438 ExitingVPBB->appendRecipe(BOC);
2439 Term->eraseFromParent();
2440
2441 return true;
2442}
2443
2444/// From the definition of llvm.experimental.get.vector.length,
2445/// VPInstruction::ExplicitVectorLength(%AVL) = %AVL when %AVL <= VF.
2449 vp_depth_first_deep(Plan.getEntry()))) {
2450 for (VPRecipeBase &R : *VPBB) {
2451 VPValue *AVL;
2452 if (!match(&R, m_EVL(m_VPValue(AVL))))
2453 continue;
2454
2455 const SCEV *AVLSCEV = vputils::getSCEVExprForVPValue(AVL, PSE);
2456 if (isa<SCEVCouldNotCompute>(AVLSCEV))
2457 continue;
2458 ScalarEvolution &SE = *PSE.getSE();
2459 const SCEV *VFSCEV = SE.getElementCount(AVLSCEV->getType(), VF);
2460 if (!SE.isKnownPredicate(CmpInst::ICMP_ULE, AVLSCEV, VFSCEV))
2461 continue;
2462
2464 AVL, Type::getInt32Ty(Plan.getContext()), AVLSCEV->getType(),
2465 R.getDebugLoc());
2466 if (Trunc != AVL) {
2467 auto *TruncR = cast<VPSingleDefRecipe>(Trunc);
2468 const DataLayout &DL = Plan.getDataLayout();
2469 if (VPValue *Folded = tryToFoldLiveIns(*TruncR, TruncR->operands(), DL))
2470 Trunc = Folded;
2471 }
2472 R.getVPSingleValue()->replaceAllUsesWith(Trunc);
2473 return true;
2474 }
2475 }
2476 return false;
2477}
2478
2480 unsigned BestUF,
2482 assert(Plan.hasVF(BestVF) && "BestVF is not available in Plan");
2483 assert(Plan.hasUF(BestUF) && "BestUF is not available in Plan");
2484
2485 bool MadeChange = tryToReplaceALMWithWideALM(Plan, BestVF, BestUF);
2486 MadeChange |= simplifyBranchConditionForVFAndUF(Plan, BestVF, BestUF, PSE);
2487 MadeChange |= optimizeVectorInductionWidthForTCAndVFUF(Plan, BestVF, BestUF);
2488
2489 if (MadeChange) {
2490 Plan.setVF(BestVF);
2491 assert(Plan.getConcreteUF() == BestUF && "BestUF must match the Plan's UF");
2492 }
2493}
2494
2496 for (VPRecipeBase &R :
2498 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&R);
2499 if (!PhiR)
2500 continue;
2501 RecurKind RK = PhiR->getRecurrenceKind();
2502 if (RK != RecurKind::Add && RK != RecurKind::Mul && RK != RecurKind::Sub &&
2504 continue;
2505
2506 for (VPUser *U : collectUsersRecursively(PhiR))
2507 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(U)) {
2508 RecWithFlags->dropPoisonGeneratingFlags();
2509 }
2510 }
2511}
2512
2513namespace {
2514struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
2515 /// If recipe \p R will lower to a GEP with a non-i8 source element type,
2516 /// return that source element type.
2517 static Type *getGEPSourceElementType(const VPSingleDefRecipe *R) {
2518 // All VPInstructions that lower to GEPs must have the i8 source element
2519 // type (as they are PtrAdds), so we omit it.
2521 .Case([](const VPReplicateRecipe *I) -> Type * {
2522 if (auto *GEP = dyn_cast<GetElementPtrInst>(I->getUnderlyingValue()))
2523 return GEP->getSourceElementType();
2524 return nullptr;
2525 })
2526 .Case<VPVectorPointerRecipe, VPWidenGEPRecipe>(
2527 [](auto *I) { return I->getSourceElementType(); })
2528 .Default([](auto *) { return nullptr; });
2529 }
2530
2531 /// Returns true if recipe \p Def can be safely handed for CSE.
2532 static bool canHandle(const VPSingleDefRecipe *Def) {
2533 // We can extend the list of handled recipes in the future,
2534 // provided we account for the data embedded in them while checking for
2535 // equality or hashing.
2536 auto C = getOpcodeOrIntrinsicID(Def);
2537
2538 // The issue with (Insert|Extract)Value is that the index of the
2539 // insert/extract is not a proper operand in LLVM IR, and hence also not in
2540 // VPlan.
2541 if (!C || (!C->first && (C->second == Instruction::InsertValue ||
2542 C->second == Instruction::ExtractValue)))
2543 return false;
2544
2545 // During CSE, we can only handle non-memory recipes, as memory can alias.
2546 return !Def->mayReadOrWriteMemory();
2547 }
2548
2549 /// Hash the underlying data of \p Def.
2550 static unsigned getHashValue(const VPSingleDefRecipe *Def) {
2551 hash_code Result = hash_combine(
2552 Def->getVPRecipeID(), getOpcodeOrIntrinsicID(Def),
2553 getGEPSourceElementType(Def), Def->getScalarType(),
2555 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
2556 if (RFlags->hasPredicate())
2557 return hash_combine(Result, RFlags->getPredicate());
2558 if (auto *SIVSteps = dyn_cast<VPScalarIVStepsRecipe>(Def))
2559 return hash_combine(Result, SIVSteps->getInductionOpcode());
2560 return Result;
2561 }
2562
2563 /// Check equality of underlying data of \p L and \p R.
2564 static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
2565 if (L->getVPRecipeID() != R->getVPRecipeID() ||
2567 getGEPSourceElementType(L) != getGEPSourceElementType(R) ||
2569 !equal(L->operands(), R->operands()))
2570 return false;
2572 "must have valid opcode info for both recipes");
2573 if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
2574 if (LFlags->hasPredicate() &&
2575 LFlags->getPredicate() !=
2576 cast<VPRecipeWithIRFlags>(R)->getPredicate())
2577 return false;
2578 if (auto *LSIV = dyn_cast<VPScalarIVStepsRecipe>(L))
2579 if (LSIV->getInductionOpcode() !=
2580 cast<VPScalarIVStepsRecipe>(R)->getInductionOpcode())
2581 return false;
2582 // Phi recipes can only be equal if they are in the same VPBB, as they
2583 // implicitly depend on their predecessors.
2584 if (isa<VPWidenPHIRecipe>(L) && L->getParent() != R->getParent())
2585 return false;
2586 // Recipes in replicate regions implicitly depend on predicate. If either
2587 // recipe is in a replicate region, only consider them equal if both have
2588 // the same parent.
2589 const VPRegionBlock *RegionL = L->getRegion();
2590 const VPRegionBlock *RegionR = R->getRegion();
2591 if (((RegionL && RegionL->isReplicator()) ||
2592 (RegionR && RegionR->isReplicator())) &&
2593 L->getParent() != R->getParent())
2594 return false;
2595 return L->getScalarType() == R->getScalarType();
2596 }
2597};
2598} // end anonymous namespace
2599
2600/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
2601/// Plan.
2603 VPDominatorTree VPDT(Plan);
2605
2607 Plan.getEntry());
2609 for (VPRecipeBase &R : *VPBB) {
2610 auto *Def = dyn_cast<VPSingleDefRecipe>(&R);
2611 if (!Def || !VPCSEDenseMapInfo::canHandle(Def))
2612 continue;
2613 if (VPSingleDefRecipe *V = CSEMap.lookup(Def)) {
2614 // V must dominate Def for a valid replacement.
2615 if (!VPDT.dominates(V->getParent(), VPBB))
2616 continue;
2617 // Only keep flags present on both V and Def.
2618 if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(V))
2619 RFlags->intersectFlags(*cast<VPRecipeWithIRFlags>(Def));
2620 Def->replaceAllUsesWith(V);
2621 continue;
2622 }
2623 CSEMap[Def] = Def;
2624 }
2625 }
2626}
2627
2628/// Return true if we do not know how to (mechanically) hoist or sink a
2629/// non-memory or memory recipe \p R out of a loop region. When sinking, passing
2630/// \p Sinking = true ensures that assumes aren't sunk.
2632 VPBasicBlock *LastBB,
2633 bool Sinking = false) {
2634 if (!isa<VPReplicateRecipe>(R) || !R.mayReadOrWriteMemory() ||
2636 return vputils::cannotHoistOrSinkRecipe(R, Sinking);
2637
2638 // Check that the memory operation doesn't alias between FirstBB and LastBB.
2639 auto MemLoc = vputils::getMemoryLocation(R);
2640
2641 // TODO: Could make use of SinkStoreInfo::isNoAliasViaDistance by collecting
2642 // stores upfront, and constructing a full SinkStoreInfo.
2643 auto SinkInfo =
2644 Sinking ? std::make_optional(SinkStoreInfo(cast<VPReplicateRecipe>(R)))
2645 : std::nullopt;
2646
2647 return !MemLoc ||
2648 !canHoistOrSinkWithNoAliasCheck(*MemLoc, FirstBB, LastBB, SinkInfo);
2649}
2650
2651/// Move loop-invariant recipes out of the vector loop region in \p Plan.
2652static void licm(VPlan &Plan) {
2653 VPBasicBlock *Preheader = Plan.getVectorPreheader();
2654
2655 // Hoist any loop invariant recipes from the vector loop region to the
2656 // preheader. Preform a shallow traversal of the vector loop region, to
2657 // exclude recipes in replicate regions. Since the top-level blocks in the
2658 // vector loop region are guaranteed to execute if the vector pre-header is,
2659 // we don't need to check speculation safety.
2660 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
2661 assert(Preheader->getSingleSuccessor() == LoopRegion &&
2662 "Expected vector prehader's successor to be the vector loop region");
2664 vp_depth_first_shallow(LoopRegion->getEntry()))) {
2665 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2666 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2667 LoopRegion->getExitingBasicBlock()))
2668 continue;
2669 if (any_of(R.operands(), [](VPValue *Op) {
2670 return !Op->isDefinedOutsideLoopRegions();
2671 }))
2672 continue;
2673 R.moveBefore(*Preheader, Preheader->end());
2674 }
2675 }
2676
2677#ifndef NDEBUG
2678 VPDominatorTree VPDT(Plan);
2679#endif
2680 // Sink recipes with no users inside the vector loop region if all users are
2681 // in the same exit block of the region.
2682 // TODO: Extend to sink recipes from inner loops.
2684 LoopRegion->getEntry());
2686 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
2687 if (cannotHoistOrSinkRecipe(R, LoopRegion->getEntryBasicBlock(),
2688 LoopRegion->getExitingBasicBlock(),
2689 /*Sinking=*/true))
2690 continue;
2691
2692 if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
2693 assert(!RepR->isPredicated() &&
2694 "Expected prior transformation of predicated replicates to "
2695 "replicate regions");
2696 // narrowToSingleScalarRecipes should have already maximally narrowed
2697 // replicates to single-scalar replicates.
2698 // TODO: When unrolling, replicateByVF doesn't handle sunk
2699 // non-single-scalar replicates correctly.
2700 if (!RepR->isSingleScalar())
2701 continue;
2702
2703 // The pointer operand of stores must be loop-invariant.
2704 if (RepR->getOpcode() == Instruction::Store &&
2705 !RepR->getOperand(1)->isDefinedOutsideLoopRegions())
2706 continue;
2707 }
2708
2709 [[maybe_unused]] auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
2710 assert((!R.mayWriteToMemory() ||
2711 (RepR && RepR->getOpcode() == Instruction::Store &&
2712 RepR->getOperand(1)->isDefinedOutsideLoopRegions())) &&
2713 "The only recipes that may write to memory are expected to be "
2714 "stores with invariant pointer-operand");
2715
2716 // TODO: Use R.definedValues() instead of casting to VPSingleDefRecipe to
2717 // support recipes with multiple defined values (e.g., interleaved loads).
2718 auto *Def = cast<VPSingleDefRecipe>(&R);
2719
2720 // Cannot sink the recipe if the user is defined in a loop region or a
2721 // non-successor of the vector loop region. Cannot sink if user is a phi
2722 // either.
2723 VPBasicBlock *SinkBB = nullptr;
2724 if (any_of(Def->users(), [&SinkBB, &LoopRegion](VPUser *U) {
2725 auto *UserR = cast<VPRecipeBase>(U);
2726 VPBasicBlock *Parent = UserR->getParent();
2727 // TODO: Support sinking when users are in multiple blocks.
2728 if (SinkBB && SinkBB != Parent)
2729 return true;
2730 SinkBB = Parent;
2731 // TODO: If the user is a PHI node, we should check the block of
2732 // incoming value. Support PHI node users if needed.
2733 return UserR->isPhi() || Parent->getEnclosingLoopRegion() ||
2734 Parent->getSinglePredecessor() != LoopRegion;
2735 }))
2736 continue;
2737
2738 if (!SinkBB)
2739 SinkBB = cast<VPBasicBlock>(LoopRegion->getSingleSuccessor());
2740
2741 // TODO: This will need to be a check instead of a assert after
2742 // conditional branches in vectorized loops are supported.
2743 assert(VPDT.properlyDominates(VPBB, SinkBB) &&
2744 "Defining block must dominate sink block");
2745 // TODO: Clone the recipe if users are on multiple exit paths, instead of
2746 // just moving.
2747 Def->moveBefore(*SinkBB, SinkBB->getFirstNonPhi());
2748 }
2749 }
2750}
2751
2753 VPlan &Plan, const MapVector<Instruction *, uint64_t> &MinBWs) {
2754 if (Plan.hasScalarVFOnly())
2755 return;
2756 // Keep track of created truncates, so they can be re-used. Note that we
2757 // cannot use RAUW after creating a new truncate, as this would could make
2758 // other uses have different types for their operands, making them invalidly
2759 // typed.
2761 VPBasicBlock *PH = Plan.getVectorPreheader();
2764 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
2767 continue;
2768
2769 VPValue *ResultVPV = R.getVPSingleValue();
2770 auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
2771 unsigned NewResSizeInBits = MinBWs.lookup(UI);
2772 if (!NewResSizeInBits)
2773 continue;
2774
2775 // If the value wasn't vectorized, we must maintain the original scalar
2776 // type. Skip those here, after incrementing NumProcessedRecipes. Also
2777 // skip casts which do not need to be handled explicitly here, as
2778 // redundant casts will be removed during recipe simplification.
2780 continue;
2781
2782 Type *OldResTy = ResultVPV->getScalarType();
2783 unsigned OldResSizeInBits = OldResTy->getScalarSizeInBits();
2784 assert(OldResTy->isIntegerTy() && "only integer types supported");
2785 (void)OldResSizeInBits;
2786
2787 auto *NewResTy = IntegerType::get(Plan.getContext(), NewResSizeInBits);
2788
2789 // Any wrapping introduced by shrinking this operation shouldn't be
2790 // considered undefined behavior. So, we can't unconditionally copy
2791 // arithmetic wrapping flags to VPW.
2792 if (auto *VPW = dyn_cast<VPRecipeWithIRFlags>(&R))
2793 VPW->dropPoisonGeneratingFlags();
2794
2795 assert((OldResSizeInBits != NewResSizeInBits ||
2796 match(&R, m_ICmp(m_VPValue(), m_VPValue()))) &&
2797 "Only ICmps should not need extending the result.");
2798 assert(!isa<VPWidenStoreRecipe>(&R) && "stores cannot be narrowed");
2799
2800 // For loads/intrinsics we don't recreate the recipe; just wrap the
2801 // original wide result in a ZExt to OldResTy.
2803 if (OldResSizeInBits != NewResSizeInBits) {
2805 Instruction::ZExt, ResultVPV, OldResTy);
2806 ResultVPV->replaceAllUsesWith(Ext);
2807 Ext->setOperand(0, ResultVPV);
2808 }
2809 continue;
2810 }
2811
2812 // Shrink operands by introducing truncates as needed.
2813 unsigned StartIdx =
2814 match(&R, m_Select(m_VPValue(), m_VPValue(), m_VPValue())) ? 1 : 0;
2815 SmallVector<VPValue *> NewOperands(R.operands());
2816 for (VPValue *&Op : drop_begin(NewOperands, StartIdx)) {
2817 unsigned OpSizeInBits = Op->getScalarType()->getScalarSizeInBits();
2818 if (OpSizeInBits == NewResSizeInBits)
2819 continue;
2820 assert(OpSizeInBits > NewResSizeInBits && "nothing to truncate");
2821 auto [ProcessedIter, Inserted] = ProcessedTruncs.try_emplace(Op);
2822 if (Inserted) {
2823 VPBuilder Builder;
2824 if (isa<VPIRValue>(Op))
2825 Builder.setInsertPoint(PH);
2826 else
2827 Builder.setInsertPoint(&R);
2828 ProcessedIter->second =
2829 Builder.createWidenCast(Instruction::Trunc, Op, NewResTy);
2830 }
2831 Op = ProcessedIter->second;
2832 }
2833
2834 auto *NWR = cast<VPWidenRecipe>(&R)->cloneWithOperands(NewOperands);
2835 NWR->insertBefore(&R);
2836
2837 // Wrap NWR in a ZExt to preserve the original wide type for downstream
2838 // users (unless this is an ICmp, which produces i1 regardless).
2839 VPValue *Replacement = NWR->getVPSingleValue();
2840 if (OldResSizeInBits != NewResSizeInBits)
2841 Replacement =
2843 .createWidenCast(Instruction::ZExt, Replacement, OldResTy)
2844 ->getVPSingleValue();
2845 ResultVPV->replaceAllUsesWith(Replacement);
2846 R.eraseFromParent();
2847 }
2848 }
2849}
2850
2851bool VPlanTransforms::removeBranchOnConst(VPlan &Plan, bool OnlyLatches) {
2852 std::optional<VPDominatorTree> VPDT;
2853 if (OnlyLatches)
2854 VPDT.emplace(Plan);
2855
2856 // Collect all blocks before modifying the CFG so we can identify unreachable
2857 // ones after constant branch removal.
2859
2860 bool SimplifiedPhi = false;
2861 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(AllBlocks)) {
2862 VPValue *Cond;
2863 // Skip blocks that are not terminated by BranchOnCond.
2864 if (VPBB->empty() || !match(&VPBB->back(), m_BranchOnCond(m_VPValue(Cond))))
2865 continue;
2866
2867 if (OnlyLatches && !VPBlockUtils::isLatch(VPBB, *VPDT))
2868 continue;
2869
2870 assert(VPBB->getNumSuccessors() == 2 &&
2871 "Two successors expected for BranchOnCond");
2872 unsigned RemovedIdx;
2873 if (match(Cond, m_True()))
2874 RemovedIdx = 1;
2875 else if (match(Cond, m_False()))
2876 RemovedIdx = 0;
2877 else
2878 continue;
2879
2880 VPBasicBlock *RemovedSucc =
2881 cast<VPBasicBlock>(VPBB->getSuccessors()[RemovedIdx]);
2882 assert(count(RemovedSucc->getPredecessors(), VPBB) == 1 &&
2883 "There must be a single edge between VPBB and its successor");
2884 // Values coming from VPBB into phi recipes of RemovedSucc are removed from
2885 // these recipes.
2886 auto Phis = RemovedSucc->phis();
2887 for (VPRecipeBase &R : Phis)
2888 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(VPBB);
2889 SimplifiedPhi |= !std::empty(Phis);
2890
2891 // Disconnect blocks and remove the terminator.
2892 VPBlockUtils::disconnectBlocks(VPBB, RemovedSucc);
2893 VPBB->back().eraseFromParent();
2894 }
2895
2896 // Compute which blocks are still reachable from the entry after constant
2897 // branch removal.
2900
2901 // Detach all unreachable blocks from their successors, removing their recipes
2902 // and incoming values from phi recipes.
2903 VPSymbolicValue Tmp(nullptr);
2904 for (VPBlockBase *B : AllBlocks) {
2905 if (Reachable.contains(B))
2906 continue;
2907 for (VPBlockBase *Succ : to_vector(B->successors())) {
2908 if (auto *SuccBB = dyn_cast<VPBasicBlock>(Succ))
2909 for (VPRecipeBase &R : SuccBB->phis())
2910 cast<VPPhiAccessors>(&R)->removeIncomingValueFor(B);
2912 }
2913 for (VPBasicBlock *DeadBB :
2915 for (VPRecipeBase &R : make_early_inc_range(*DeadBB)) {
2916 for (VPValue *Def : R.definedValues())
2917 Def->replaceAllUsesWith(&Tmp);
2918 R.eraseFromParent();
2919 }
2920 }
2921 }
2922 return SimplifiedPhi;
2923}
2924
2945
2946// Add a VPActiveLaneMaskPHIRecipe and related recipes to \p Plan and replace
2947// the loop terminator with a branch-on-cond recipe with the negated
2948// active-lane-mask as operand. Note that this turns the loop into an
2949// uncountable one. Only the existing terminator is replaced, all other existing
2950// recipes/users remain unchanged, except for poison-generating flags being
2951// dropped from the canonical IV increment. Return the created
2952// VPActiveLaneMaskPHIRecipe.
2953//
2954// The function adds the following recipes:
2955//
2956// vector.ph:
2957// %EntryInc = canonical-iv-increment-for-part CanonicalIVStart
2958// %EntryALM = active-lane-mask %EntryInc, TC
2959//
2960// vector.body:
2961// ...
2962// %P = active-lane-mask-phi [ %EntryALM, %vector.ph ], [ %ALM, %vector.body ]
2963// ...
2964// %InLoopInc = canonical-iv-increment-for-part CanonicalIVIncrement
2965// %ALM = active-lane-mask %InLoopInc, TC
2966// %Negated = Not %ALM
2967// branch-on-cond %Negated
2968//
2971 VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
2972 VPBasicBlock *EB = TopRegion->getExitingBasicBlock();
2973 VPValue *StartV = Plan.getZero(TopRegion->getCanonicalIVType());
2974 auto *CanonicalIVIncrement = TopRegion->getOrCreateCanonicalIVIncrement();
2975 // TODO: Check if dropping the flags is needed.
2976 TopRegion->clearCanonicalIVNUW(CanonicalIVIncrement);
2977 DebugLoc DL = CanonicalIVIncrement->getDebugLoc();
2978 // We can't use StartV directly in the ActiveLaneMask VPInstruction, since
2979 // we have to take unrolling into account. Each part needs to start at
2980 // Part * VF
2981 auto *VecPreheader = Plan.getVectorPreheader();
2982 VPBuilder Builder(VecPreheader);
2983
2984 // Create the ActiveLaneMask instruction using the correct start values.
2985 VPValue *TC = Plan.getTripCount();
2986 VPValue *VF = &Plan.getVF();
2987
2988 auto *EntryIncrement =
2989 Builder.createOverflowingOp(VPInstruction::CanonicalIVIncrementForPart,
2990 {StartV, VF}, {}, DL, "index.part.next");
2991
2992 // Create the active lane mask instruction in the VPlan preheader.
2993 VPValue *ALMMultiplier =
2994 Plan.getConstantInt(TopRegion->getCanonicalIVType(), 1);
2995 auto *EntryALM = Builder.createNaryOp(VPInstruction::ActiveLaneMask,
2996 {EntryIncrement, TC, ALMMultiplier}, DL,
2997 "active.lane.mask.entry");
2998
2999 // Now create the ActiveLaneMaskPhi recipe in the main loop using the
3000 // preheader ActiveLaneMask instruction.
3001 auto *LaneMaskPhi =
3003 auto *HeaderVPBB = TopRegion->getEntryBasicBlock();
3004 LaneMaskPhi->insertBefore(*HeaderVPBB, HeaderVPBB->begin());
3005
3006 // Create the active lane mask for the next iteration of the loop before the
3007 // original terminator.
3008 VPRecipeBase *OriginalTerminator = EB->getTerminator();
3009 Builder.setInsertPoint(OriginalTerminator);
3010 auto *InLoopIncrement = Builder.createOverflowingOp(
3012 {CanonicalIVIncrement, &Plan.getVF()}, {}, DL);
3013 auto *ALM = Builder.createNaryOp(VPInstruction::ActiveLaneMask,
3014 {InLoopIncrement, TC, ALMMultiplier}, DL,
3015 "active.lane.mask.next");
3016 LaneMaskPhi->addBackedgeValue(ALM);
3017
3018 // Replace the original terminator with BranchOnCond. We have to invert the
3019 // mask here because a true condition means jumping to the exit block.
3020 auto *NotMask = Builder.createNot(ALM, DL);
3021 Builder.createNaryOp(VPInstruction::BranchOnCond, {NotMask}, DL);
3022 OriginalTerminator->eraseFromParent();
3023 return LaneMaskPhi;
3024}
3025
3027 VPlan &Plan, bool UseActiveLaneMask, bool UseActiveLaneMaskForControlFlow) {
3028 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
3029 VPValue *HeaderMask = LoopRegion->getUsedHeaderMask();
3030 if (!HeaderMask)
3031 return;
3032
3033 if (UseActiveLaneMaskForControlFlow) {
3035 return;
3036 }
3037
3038 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
3039 VPBuilder Builder(Header, Header->getFirstNonPhi());
3040 auto *WideCanonicalIV = Builder.insert(new VPWidenCanonicalIVRecipe(
3041 LoopRegion->getCanonicalIV(),
3042 VPIRFlags::WrapFlagsTy(/*HasNUW=*/true, /*HasNSW=*/false)));
3043 VPValue *Mask;
3044 if (UseActiveLaneMask) {
3045 VPValue *ALMMultiplier =
3046 Plan.getConstantInt(LoopRegion->getCanonicalIVType(), 1);
3047 Mask = Builder.createNaryOp(
3049 {WideCanonicalIV, Plan.getTripCount(), ALMMultiplier}, nullptr,
3050 "active.lane.mask");
3051 } else {
3052 Mask = Builder.createICmp(CmpInst::ICMP_ULE, WideCanonicalIV,
3054 }
3055 HeaderMask->replaceAllUsesWith(Mask);
3056}
3057
3058template <typename Op0_t, typename Op1_t> struct RemoveMask_match {
3059 Op0_t In;
3061
3062 RemoveMask_match(const Op0_t &In, Op1_t &Out) : In(In), Out(Out) {}
3063
3064 template <typename OpTy> bool match(OpTy *V) const {
3065 if (m_Specific(In).match(V)) {
3066 Out = nullptr;
3067 return true;
3068 }
3069 return m_LogicalAnd(m_Specific(In), m_VPValue(Out)).match(V);
3070 }
3071};
3072
3073/// Match a specific mask \p In, or a combination of it (logical-and In, Out).
3074/// Returns the remaining part \p Out if so, or nullptr otherwise.
3075template <typename Op0_t, typename Op1_t>
3076static inline RemoveMask_match<Op0_t, Op1_t> m_RemoveMask(const Op0_t &In,
3077 Op1_t &Out) {
3078 return RemoveMask_match<Op0_t, Op1_t>(In, Out);
3079}
3080
3081static std::optional<Intrinsic::ID> getVPDivRemIntrinsic(Intrinsic::ID IntrID) {
3082 switch (IntrID) {
3083 case Intrinsic::masked_udiv:
3084 return Intrinsic::vp_udiv;
3085 case Intrinsic::masked_sdiv:
3086 return Intrinsic::vp_sdiv;
3087 case Intrinsic::masked_urem:
3088 return Intrinsic::vp_urem;
3089 case Intrinsic::masked_srem:
3090 return Intrinsic::vp_srem;
3091 default:
3092 return std::nullopt;
3093 }
3094}
3095
3096/// Try to optimize a \p CurRecipe masked by \p HeaderMask to a corresponding
3097/// EVL-based recipe without the header mask. Returns nullptr if no EVL-based
3098/// recipe could be created.
3099/// \p HeaderMask Header Mask.
3100/// \p CurRecipe Recipe to be transform.
3101/// \p EVL The explicit vector length parameter of vector-predication
3102/// intrinsics.
3104 VPRecipeBase &CurRecipe, VPValue &EVL) {
3105 VPlan *Plan = CurRecipe.getParent()->getPlan();
3106 DebugLoc DL = CurRecipe.getDebugLoc();
3107 VPValue *Addr, *Mask, *EndPtr;
3108
3109 /// Adjust any end pointers so that they point to the end of EVL lanes not VF.
3110 auto AdjustEndPtr = [&CurRecipe, &EVL](VPValue *EndPtr) {
3111 auto *EVLEndPtr = cast<VPVectorEndPointerRecipe>(EndPtr)->clone();
3112 EVLEndPtr->insertBefore(&CurRecipe);
3113 // Cast EVL (i32) to match the VF operand's type.
3114 VPValue *EVLAsVF = VPBuilder(EVLEndPtr).createScalarZExtOrTrunc(
3115 &EVL, EVLEndPtr->getOperand(1)->getScalarType(), EVL.getScalarType(),
3117 EVLEndPtr->setOperand(1, EVLAsVF);
3118 return EVLEndPtr;
3119 };
3120
3121 auto GetVPReverse = [&CurRecipe, &EVL, Plan,
3123 if (!V)
3124 return nullptr;
3125 auto *Reverse = new VPWidenIntrinsicRecipe(
3126 Intrinsic::experimental_vp_reverse, {V, Plan->getTrue(), &EVL},
3127 V->getScalarType(), {}, {}, DL);
3128 Reverse->insertBefore(&CurRecipe);
3129 return Reverse;
3130 };
3131
3132 if (match(&CurRecipe,
3133 m_MaskedLoad(m_VPValue(Addr), m_RemoveMask(HeaderMask, Mask))))
3134 return new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe), Addr,
3135 EVL, Mask);
3136
3137 if (match(&CurRecipe,
3138 m_MaskedLoad(m_VPValue(EndPtr),
3139 m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
3140 match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
3141 Mask = GetVPReverse(Mask);
3142 Addr = AdjustEndPtr(EndPtr);
3143 auto *LoadR = new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe),
3144 Addr, EVL, Mask);
3145 LoadR->insertBefore(&CurRecipe);
3146 VPValue *Poison = Plan->getPoison(LoadR->getScalarType());
3147 return new VPWidenIntrinsicRecipe(Intrinsic::vector_splice_left,
3148 {Poison, LoadR, &EVL},
3149 LoadR->getScalarType(), {}, {}, DL);
3150 }
3151
3152 VPValue *Stride;
3154 m_VPValue(Addr), m_VPValue(Stride),
3155 m_RemoveMask(HeaderMask, Mask),
3156 m_TruncOrSelf(m_Specific(&Plan->getVF()))))) {
3157 if (!Mask)
3158 Mask = Plan->getTrue();
3159 auto *NewLoad = cast<VPWidenMemIntrinsicRecipe>(&CurRecipe)->clone();
3160 NewLoad->setOperand(2, Mask);
3161 NewLoad->setOperand(3, &EVL);
3162 return NewLoad;
3163 }
3164
3165 VPValue *StoredVal;
3166 if (match(&CurRecipe, m_MaskedStore(m_VPValue(Addr), m_VPValue(StoredVal),
3167 m_RemoveMask(HeaderMask, Mask))))
3168 return new VPWidenStoreEVLRecipe(cast<VPWidenStoreRecipe>(CurRecipe), Addr,
3169 StoredVal, EVL, Mask);
3170
3171 if (match(&CurRecipe,
3172 m_MaskedStore(m_VPValue(EndPtr), m_VPValue(StoredVal),
3173 m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
3174 match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
3175 Mask = GetVPReverse(Mask);
3176 Addr = AdjustEndPtr(EndPtr);
3177 VPValue *Poison = Plan->getPoison(StoredVal->getScalarType());
3178 auto *SpliceR = new VPWidenIntrinsicRecipe(
3179 Intrinsic::vector_splice_right, {StoredVal, Poison, &EVL},
3180 StoredVal->getScalarType(), {}, {}, DL);
3181 SpliceR->insertBefore(&CurRecipe);
3182 return new VPWidenStoreEVLRecipe(cast<VPWidenStoreRecipe>(CurRecipe), Addr,
3183 SpliceR, EVL, Mask);
3184 }
3185
3186 if (auto *Rdx = dyn_cast<VPReductionRecipe>(&CurRecipe))
3187 if (Rdx->isConditional() &&
3188 match(Rdx->getCondOp(), m_RemoveMask(HeaderMask, Mask)))
3189 return new VPReductionEVLRecipe(*Rdx, EVL, Mask);
3190
3191 if (auto *Interleave = dyn_cast<VPInterleaveRecipe>(&CurRecipe))
3192 if (Interleave->getMask() &&
3193 match(Interleave->getMask(), m_RemoveMask(HeaderMask, Mask)))
3194 return new VPInterleaveEVLRecipe(*Interleave, EVL, Mask);
3195
3196 VPValue *LHS, *RHS;
3197 if (match(&CurRecipe, m_SelectLike(m_RemoveMask(HeaderMask, Mask),
3199 return new VPWidenIntrinsicRecipe(
3200 Intrinsic::vp_merge, {Mask ? Mask : Plan->getTrue(), LHS, RHS, &EVL},
3201 LHS->getScalarType(), {}, {}, DL);
3202
3203 if (match(&CurRecipe, m_LastActiveLane(m_Specific(HeaderMask)))) {
3204 Type *Ty = CurRecipe.getVPSingleValue()->getScalarType();
3205 VPValue *ZExt =
3206 VPBuilder(&CurRecipe)
3207 .createScalarZExtOrTrunc(&EVL, Ty, EVL.getScalarType(), DL);
3208 return new VPInstruction(
3209 Instruction::Sub, {ZExt, Plan->getConstantInt(Ty, 1)},
3210 VPIRFlags::getDefaultFlags(Instruction::Sub), {}, DL);
3211 }
3212
3213 // lhs | (headermask && rhs) -> vp.merge rhs, true, lhs, evl
3214 if (match(&CurRecipe,
3216 m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(RHS)))))
3217 return new VPWidenIntrinsicRecipe(Intrinsic::vp_merge,
3218 {RHS, Plan->getTrue(), LHS, &EVL},
3219 LHS->getScalarType(), {}, {}, DL);
3220
3221 if (auto *IntrR = dyn_cast<VPWidenIntrinsicRecipe>(&CurRecipe))
3222 if (auto VPID = getVPDivRemIntrinsic(IntrR->getVectorIntrinsicID()))
3223 if (match(IntrR->getOperand(2), m_RemoveMask(HeaderMask, Mask)))
3224 return new VPWidenIntrinsicRecipe(*VPID,
3225 {IntrR->getOperand(0),
3226 IntrR->getOperand(1),
3227 Mask ? Mask : Plan->getTrue(), &EVL},
3228 IntrR->getScalarType(), {}, {}, DL);
3229
3230 return nullptr;
3231}
3232
3233/// Optimize away any EVL-based header masks to VP intrinsic based recipes.
3234/// The transforms here need to preserve the original semantics.
3236 // Find the EVL-based header mask if it exists: icmp ult step-vector, EVL
3237 VPValue *HeaderMask = nullptr, *EVL = nullptr;
3240 m_VPValue(EVL))) &&
3241 match(EVL, m_EVL(m_VPValue()))) {
3242 HeaderMask = R.getVPSingleValue();
3243 break;
3244 }
3245 }
3246 if (!HeaderMask)
3247 return;
3248
3249 SmallVector<VPRecipeBase *> OldRecipes;
3250 for (VPUser *U : collectUsersRecursively(HeaderMask)) {
3252 if (auto *NewR = optimizeMaskToEVL(HeaderMask, *R, *EVL)) {
3253 NewR->insertBefore(R);
3254 for (auto [Old, New] :
3255 zip_equal(R->definedValues(), NewR->definedValues()))
3256 Old->replaceAllUsesWith(New);
3257 OldRecipes.push_back(R);
3258 }
3259 }
3260
3261 // Replace remaining (HeaderMask && Mask) with vp.merge (True, Mask,
3262 // False, EVL)
3263 for (VPUser *U : collectUsersRecursively(HeaderMask)) {
3264 VPValue *Mask;
3265 if (match(U, m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(Mask)))) {
3266 auto *LogicalAnd = cast<VPInstruction>(U);
3267 auto *Merge = new VPWidenIntrinsicRecipe(
3268 Intrinsic::vp_merge, {Plan.getTrue(), Mask, Plan.getFalse(), EVL},
3269 Mask->getScalarType(), {}, {}, LogicalAnd->getDebugLoc());
3270 Merge->insertBefore(LogicalAnd);
3271 LogicalAnd->replaceAllUsesWith(Merge);
3272 OldRecipes.push_back(LogicalAnd);
3273 }
3274 }
3275
3276 // Pull out left splices from any elementwise op.
3277 // binop(splice.left(poison, x, evl), live-in)
3278 // -> splice.left(poison, binop(x,live-in), evl)
3280 Plan,
3281 [&EVL](const auto &X) {
3283 m_Specific(EVL));
3284 },
3285 [&Plan, &EVL](auto *X) {
3286 return new VPWidenIntrinsicRecipe(
3287 Intrinsic::vector_splice_left,
3288 {Plan.getPoison(X->getScalarType()), X, EVL}, X->getScalarType(),
3289 {}, {}, X->getDebugLoc());
3290 });
3291
3292 // Fold the following splice patterns:
3293 // splice.right(splice.left(poison, x, evl), poison, evl) -> x
3294 // vector.reverse(splice.left(poison, x, evl)) -> vp.reverse(x, true, evl)
3295 // splice.right(vector.reverse(x), poison, evl) -> vp.reverse(x, true, evl)
3296 for (VPUser *U : collectUsersRecursively(EVL)) {
3297 auto *R = cast<VPRecipeBase>(U);
3298 // Remove potentially dead left splices from the transform above.
3300 R->getVPSingleValue()->getNumUsers() == 0) {
3301 OldRecipes.push_back(R);
3302 continue;
3303 }
3304
3305 VPValue *X;
3308 m_Poison(), m_VPValue(X), m_Specific(EVL)),
3309 m_Poison(), m_Specific(EVL)))) {
3310 R->getVPSingleValue()->replaceAllUsesWith(X);
3311 OldRecipes.push_back(R);
3312 continue;
3313 }
3314
3315 if (!match(U,
3318 m_Poison(), m_VPValue(X), m_Specific(EVL))),
3320 m_Reverse(m_VPValue(X)), m_Poison(), m_Specific(EVL)))))
3321 continue;
3322
3323 auto *VPReverse = new VPWidenIntrinsicRecipe(
3324 Intrinsic::experimental_vp_reverse, {X, Plan.getTrue(), EVL},
3325 X->getScalarType(), {}, {}, R->getDebugLoc());
3326 VPReverse->insertBefore(R);
3327 R->getVPSingleValue()->replaceAllUsesWith(VPReverse);
3328 OldRecipes.push_back(R);
3329 }
3330
3331 for (VPRecipeBase *R : reverse(OldRecipes)) {
3332 SmallVector<VPValue *> PossiblyDead(R->operands());
3333 R->eraseFromParent();
3334 for (VPValue *Op : PossiblyDead)
3336 }
3337}
3338
3339/// After replacing the canonical IV with a EVL-based IV, fixup recipes that use
3340/// VF to use the EVL instead to avoid incorrect updates on the penultimate
3341/// iteration.
3342static void fixupVFUsersForEVL(VPlan &Plan, VPValue &EVL) {
3343 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
3344 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
3345
3346 // EVL is i32 but VF/VFxUF are IdxTy. Convert as needed.
3347 VPValue *EVLAsIdx =
3351
3352 assert(all_of(Plan.getVF().users(),
3353 [&Plan](VPUser *U) {
3354 auto IsAllowedUser =
3355 IsaPred<VPVectorEndPointerRecipe, VPScalarIVStepsRecipe,
3356 VPWidenIntOrFpInductionRecipe,
3357 VPWidenMemIntrinsicRecipe>;
3358 if (match(U, m_Trunc(m_Specific(&Plan.getVF()))))
3359 return all_of(cast<VPSingleDefRecipe>(U)->users(),
3360 IsAllowedUser);
3361 return IsAllowedUser(U);
3362 }) &&
3363 "User of VF that we can't transform to EVL.");
3364 Plan.getVF().replaceUsesWithIf(EVLAsIdx, [](VPUser &U, unsigned Idx) {
3366 });
3367
3368 assert(all_of(Plan.getVFxUF().users(),
3370 m_c_Add(m_Specific(LoopRegion->getCanonicalIV()),
3371 m_Specific(&Plan.getVFxUF())),
3373 "Only users of VFxUF should be VPWidenPointerInductionRecipe and the "
3374 "increment of the canonical induction.");
3375 Plan.getVFxUF().replaceUsesWithIf(EVLAsIdx, [](VPUser &U, unsigned Idx) {
3376 // Only replace uses in VPWidenPointerInductionRecipe; The increment of the
3377 // canonical induction must not be updated.
3379 });
3380
3381 // Create a scalar phi to track the previous EVL if fixed-order recurrence is
3382 // contained.
3383 bool ContainsFORs =
3385 if (ContainsFORs) {
3386 // TODO: Use VPInstruction::ExplicitVectorLength to get maximum EVL.
3387 VPValue *MaxEVL = &Plan.getVF();
3388 // Emit VPScalarCastRecipe in preheader if VF is not a 32 bits integer.
3389 VPBuilder Builder(LoopRegion->getPreheaderVPBB());
3390 MaxEVL = Builder.createScalarZExtOrTrunc(
3391 MaxEVL, Type::getInt32Ty(Plan.getContext()), MaxEVL->getScalarType(),
3393
3394 Builder.setInsertPoint(Header, Header->getFirstNonPhi());
3395 VPValue *PrevEVL = Builder.createScalarPhi(
3396 {MaxEVL, &EVL}, DebugLoc::getUnknown(), "prev.evl");
3397
3400 for (VPRecipeBase &R : *VPBB) {
3401 VPValue *V1, *V2;
3402 if (!match(&R,
3404 m_VPValue(V1), m_VPValue(V2))))
3405 continue;
3406 VPValue *Imm = Plan.getOrAddLiveIn(
3409 Intrinsic::experimental_vp_splice,
3410 {V1, V2, Imm, Plan.getTrue(), PrevEVL, &EVL},
3411 R.getVPSingleValue()->getScalarType(), {}, {}, R.getDebugLoc());
3412 VPSplice->insertBefore(&R);
3413 R.getVPSingleValue()->replaceAllUsesWith(VPSplice);
3414 }
3415 }
3416 }
3417
3418 VPValue *HeaderMask = LoopRegion->getHeaderMask();
3419 if (!HeaderMask)
3420 return;
3421
3422 // Ensure that any reduction that uses a select to mask off tail lanes does so
3423 // in the vector loop, not the middle block, since EVL tail folding can have
3424 // tail elements in the penultimate iteration.
3425 assert(all_of(*Plan.getMiddleBlock(), [&Plan, HeaderMask](VPRecipeBase &R) {
3426 if (match(&R, m_ComputeReductionResult(m_Select(m_Specific(HeaderMask),
3427 m_VPValue(), m_VPValue()))))
3428 return R.getOperand(0)->getDefiningRecipe()->getRegion() ==
3429 Plan.getVectorLoopRegion();
3430 return true;
3431 }));
3432
3433 // Replace the abstract header mask with a mask equivalent to predicating by
3434 // EVL: icmp ult step-vector, EVL
3435 VPRecipeBase *EVLR = EVL.getDefiningRecipe();
3436 VPBuilder Builder(EVLR->getParent(), std::next(EVLR->getIterator()));
3437 Type *EVLType = EVL.getScalarType();
3438 VPValue *EVLMask = Builder.createICmp(
3440 Builder.createNaryOp(VPInstruction::StepVector, {}, EVLType), &EVL);
3441 HeaderMask->replaceAllUsesWith(EVLMask);
3442}
3443
3444/// Converts a tail folded vector loop region to step by
3445/// VPInstruction::ExplicitVectorLength elements instead of VF elements each
3446/// iteration.
3447///
3448/// - Add a VPCurrentIterationPHIRecipe and related recipes to \p Plan and
3449/// replaces all uses of the canonical IV except for the canonical IV
3450/// increment with a VPCurrentIterationPHIRecipe. The canonical IV is used
3451/// only for loop iterations counting after this transformation.
3452///
3453/// - The header mask is replaced with a header mask based on the EVL.
3454///
3455/// - Plans with FORs have a new phi added to keep track of the EVL of the
3456/// previous iteration, and VPFirstOrderRecurrencePHIRecipes are replaced with
3457/// @llvm.vp.splice.
3458///
3459/// The function uses the following definitions:
3460/// %StartV is the canonical induction start value.
3461///
3462/// The function adds the following recipes:
3463///
3464/// vector.ph:
3465/// ...
3466///
3467/// vector.body:
3468/// ...
3469/// %CurrentIter = CURRENT-ITERATION-PHI [ %StartV, %vector.ph ],
3470/// [ %NextIter, %vector.body ]
3471/// %AVL = phi [ trip-count, %vector.ph ], [ %NextAVL, %vector.body ]
3472/// %VPEVL = EXPLICIT-VECTOR-LENGTH %AVL
3473/// ...
3474/// %OpEVL = cast i32 %VPEVL to IVSize
3475/// %NextIter = add IVSize %OpEVL, %CurrentIter
3476/// %NextAVL = sub IVSize nuw %AVL, %OpEVL
3477/// ...
3478///
3479/// If MaxSafeElements is provided, the function adds the following recipes:
3480/// vector.ph:
3481/// ...
3482///
3483/// vector.body:
3484/// ...
3485/// %CurrentIter = CURRENT-ITERATION-PHI [ %StartV, %vector.ph ],
3486/// [ %NextIter, %vector.body ]
3487/// %AVL = phi [ trip-count, %vector.ph ], [ %NextAVL, %vector.body ]
3488/// %cmp = cmp ult %AVL, MaxSafeElements
3489/// %SAFE_AVL = select %cmp, %AVL, MaxSafeElements
3490/// %VPEVL = EXPLICIT-VECTOR-LENGTH %SAFE_AVL
3491/// ...
3492/// %OpEVL = cast i32 %VPEVL to IVSize
3493/// %NextIter = add IVSize %OpEVL, %CurrentIter
3494/// %NextAVL = sub IVSize nuw %AVL, %OpEVL
3495/// ...
3496///
3498 VPlan &Plan, const std::optional<unsigned> &MaxSafeElements) {
3499 if (Plan.hasScalarVFOnly())
3500 return;
3501 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
3502 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
3503
3504 auto *CanonicalIV = LoopRegion->getCanonicalIV();
3505 auto *CanIVTy = LoopRegion->getCanonicalIVType();
3506 VPValue *StartV = Plan.getZero(CanIVTy);
3507 auto *CanonicalIVIncrement = LoopRegion->getOrCreateCanonicalIVIncrement();
3508
3509 // Create the CurrentIteration recipe in the vector loop.
3510 auto *CurrentIteration =
3512 CurrentIteration->insertBefore(*Header, Header->begin());
3513 VPBuilder Builder(Header, Header->getFirstNonPhi());
3514 // Create the AVL (application vector length), starting from TC -> 0 in steps
3515 // of EVL.
3516 VPPhi *AVLPhi = Builder.createScalarPhi(
3517 {Plan.getTripCount()}, DebugLoc::getCompilerGenerated(), "avl");
3518 VPValue *AVL = AVLPhi;
3519
3520 if (MaxSafeElements) {
3521 // Support for MaxSafeDist for correct loop emission.
3522 VPValue *AVLSafe = Plan.getConstantInt(CanIVTy, *MaxSafeElements);
3523 VPValue *Cmp = Builder.createICmp(ICmpInst::ICMP_ULT, AVL, AVLSafe);
3524 AVL = Builder.createSelect(Cmp, AVL, AVLSafe, DebugLoc::getUnknown(),
3525 "safe_avl");
3526 }
3527 auto *VPEVL = Builder.createNaryOp(VPInstruction::ExplicitVectorLength, AVL,
3528 DebugLoc::getUnknown(), "evl");
3529
3530 Builder.setInsertPoint(CanonicalIVIncrement);
3531 VPValue *OpVPEVL = VPEVL;
3532
3533 auto *I32Ty = Type::getInt32Ty(Plan.getContext());
3534 OpVPEVL = Builder.createScalarZExtOrTrunc(
3535 OpVPEVL, CanIVTy, I32Ty, CanonicalIVIncrement->getDebugLoc());
3536
3537 auto *NextIter = Builder.createAdd(
3538 OpVPEVL, CurrentIteration, CanonicalIVIncrement->getDebugLoc(),
3539 "current.iteration.next", CanonicalIVIncrement->getNoWrapFlags());
3540 CurrentIteration->addBackedgeValue(NextIter);
3541
3542 VPValue *NextAVL =
3543 Builder.createSub(AVLPhi, OpVPEVL, DebugLoc::getCompilerGenerated(),
3544 "avl.next", {/*NUW=*/true, /*NSW=*/false});
3545 AVLPhi->addIncoming(NextAVL);
3546
3547 fixupVFUsersForEVL(Plan, *VPEVL);
3548 removeDeadRecipes(Plan);
3549
3550 // Replace all uses of the canonical IV with VPCurrentIterationPHIRecipe
3551 // except for the canonical IV increment.
3552 CanonicalIV->replaceUsesWithIf(CurrentIteration,
3553 [CanonicalIVIncrement](VPUser &U, unsigned) {
3554 return &U != CanonicalIVIncrement;
3555 });
3556 // TODO: support unroll factor > 1.
3557 Plan.setUF(1);
3558}
3559
3561 // Find the vector loop entry by locating VPCurrentIterationPHIRecipe.
3562 // There should be only one VPCurrentIteration in the entire plan.
3563 VPCurrentIterationPHIRecipe *CurrentIteration = nullptr;
3564
3567 for (VPRecipeBase &R : VPBB->phis())
3568 if (auto *PhiR = dyn_cast<VPCurrentIterationPHIRecipe>(&R)) {
3569 assert(!CurrentIteration &&
3570 "Found multiple CurrentIteration. Only one expected");
3571 CurrentIteration = PhiR;
3572 }
3573
3574 // Early return if it is not variable-length stepping.
3575 if (!CurrentIteration)
3576 return;
3577
3578 VPBasicBlock *HeaderVPBB = CurrentIteration->getParent();
3579 VPValue *CurrentIterationIncr = CurrentIteration->getBackedgeValue();
3580
3581 // Convert CurrentIteration to concrete recipe.
3582 auto *ScalarR =
3583 VPBuilder(CurrentIteration)
3585 {CurrentIteration->getStartValue(), CurrentIterationIncr},
3586 CurrentIteration->getDebugLoc(), "current.iteration.iv");
3587 CurrentIteration->replaceAllUsesWith(ScalarR);
3588 CurrentIteration->eraseFromParent();
3589
3590 // Replace CanonicalIVInc with CurrentIteration increment if it exists.
3591 auto *CanonicalIV = cast<VPPhi>(&*HeaderVPBB->begin());
3592 if (auto *CanIVInc = findUserOf(
3593 CanonicalIV, m_c_Add(m_VPValue(), m_Specific(&Plan.getVFxUF())))) {
3594 cast<VPInstruction>(CanIVInc)->replaceAllUsesWith(CurrentIterationIncr);
3595 CanIVInc->eraseFromParent();
3596 }
3597}
3598
3600 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
3601 if (!LoopRegion)
3602 return;
3603 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
3604 if (Header->empty())
3605 return;
3606 // The EVL IV is always at the beginning.
3607 auto *EVLPhi = dyn_cast<VPCurrentIterationPHIRecipe>(&Header->front());
3608 if (!EVLPhi)
3609 return;
3610
3611 // Bail if not an EVL tail folded loop.
3612 VPValue *AVL;
3613 if (!match(EVLPhi->getBackedgeValue(),
3614 m_c_Add(m_ZExtOrSelf(m_EVL(m_VPValue(AVL))), m_Specific(EVLPhi))))
3615 return;
3616
3617 // The AVL may be capped to a safe distance.
3618 VPValue *SafeAVL, *UnsafeAVL;
3619 if (match(AVL,
3621 m_VPValue(SafeAVL)),
3622 m_Deferred(UnsafeAVL), m_Deferred(SafeAVL))))
3623 AVL = UnsafeAVL;
3624
3625 VPValue *AVLNext;
3626 [[maybe_unused]] bool FoundAVLNext =
3628 m_Specific(Plan.getTripCount()), m_VPValue(AVLNext)));
3629 assert(FoundAVLNext && "Didn't find AVL backedge?");
3630
3631 VPBasicBlock *Latch = LoopRegion->getExitingBasicBlock();
3632 auto *LatchBr = cast<VPInstruction>(Latch->getTerminator());
3633 if (match(LatchBr, m_BranchOnCond(m_True())))
3634 return;
3635
3636 VPValue *CanIVInc;
3637 [[maybe_unused]] bool FoundIncrement = match(
3638 LatchBr,
3640 m_Specific(&Plan.getVectorTripCount()))));
3641 assert(FoundIncrement &&
3642 match(CanIVInc, m_Add(m_Specific(LoopRegion->getCanonicalIV()),
3643 m_Specific(&Plan.getVFxUF()))) &&
3644 "Expected BranchOnCond with ICmp comparing CanIV + VFxUF with vector "
3645 "trip count");
3646
3647 Type *AVLTy = AVLNext->getScalarType();
3648 VPBuilder Builder(LatchBr);
3649 LatchBr->setOperand(
3650 0, Builder.createICmp(CmpInst::ICMP_EQ, AVLNext, Plan.getZero(AVLTy)));
3651}
3652
3654 VPlan &Plan, PredicatedScalarEvolution &PSE,
3655 const DenseMap<Value *, const SCEV *> &StridesMap,
3656 const VPDominatorTree &VPDT) {
3657 // Replace VPValues for known constant strides guaranteed by predicated scalar
3658 // evolution that are guaranteed to be guarded by the runtime checks; that is,
3659 // blocks dominated by the vector preheader.
3660 assert(!Plan.getVectorLoopRegion() &&
3661 "expected to run before loop regions are created");
3662 VPBlockBase *Preheader = Plan.getEntry()->getSuccessors()[1];
3663 auto CanUseVersionedStride = [&VPDT, Preheader](VPUser &U, unsigned) {
3664 auto *R = cast<VPRecipeBase>(&U);
3665 VPBlockBase *Parent = R->getParent();
3666 return VPDT.dominates(Preheader, Parent);
3667 };
3668 ValueToSCEVMapTy RewriteMap;
3669 for (const SCEV *Stride : StridesMap.values()) {
3670 using namespace SCEVPatternMatch;
3671 auto *StrideV = cast<SCEVUnknown>(Stride)->getValue();
3672 const APInt *StrideConst;
3673 if (!match(PSE.getSCEV(StrideV), m_scev_APInt(StrideConst)))
3674 // Only handle constant strides for now.
3675 continue;
3676
3677 auto *CI = Plan.getConstantInt(*StrideConst);
3678 if (VPValue *StrideVPV = Plan.getLiveIn(StrideV))
3679 StrideVPV->replaceUsesWithIf(CI, CanUseVersionedStride);
3680
3681 // The versioned value may not be used in the loop directly but through a
3682 // sext/zext. Add new live-ins in those cases.
3683 for (Value *U : StrideV->users()) {
3685 continue;
3686 VPValue *StrideVPV = Plan.getLiveIn(U);
3687 if (!StrideVPV)
3688 continue;
3689 unsigned BW = U->getType()->getScalarSizeInBits();
3690 APInt C =
3691 isa<SExtInst>(U) ? StrideConst->sext(BW) : StrideConst->zext(BW);
3692 VPValue *CI = Plan.getConstantInt(C);
3693 StrideVPV->replaceUsesWithIf(CI, CanUseVersionedStride);
3694 }
3695 RewriteMap[StrideV] = PSE.getSCEV(StrideV);
3696 }
3697
3698 for (VPRecipeBase &R : *Plan.getEntry()) {
3699 auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(&R);
3700 if (!ExpSCEV)
3701 continue;
3702 const SCEV *ScevExpr = ExpSCEV->getSCEV();
3703 auto *NewSCEV =
3704 SCEVParameterRewriter::rewrite(ScevExpr, *PSE.getSE(), RewriteMap);
3705 if (NewSCEV != ScevExpr) {
3706 VPValue *NewExp = vputils::getOrCreateVPValueForSCEVExpr(Plan, NewSCEV);
3707 ExpSCEV->replaceAllUsesWith(NewExp);
3708 if (Plan.getTripCount() == ExpSCEV)
3709 Plan.resetTripCount(NewExp);
3710 }
3711 }
3712}
3713
3715 // Collect recipes in the backward slice of `Root` that may generate a poison
3716 // value that is used after vectorization.
3718 auto CollectPoisonGeneratingInstrsInBackwardSlice([&](VPRecipeBase *Root) {
3720 Worklist.push_back(Root);
3721
3722 // Traverse the backward slice of Root through its use-def chain.
3723 while (!Worklist.empty()) {
3724 VPRecipeBase *CurRec = Worklist.pop_back_val();
3725
3726 if (!Visited.insert(CurRec).second)
3727 continue;
3728
3729 // Prune search if we find another recipe generating a widen memory
3730 // instruction. Widen memory instructions involved in address computation
3731 // will lead to gather/scatter instructions, which don't need to be
3732 // handled.
3734 VPHeaderPHIRecipe>(CurRec))
3735 continue;
3736
3737 // This recipe contributes to the address computation of a widen
3738 // load/store. If the underlying instruction has poison-generating flags,
3739 // drop them directly.
3740 if (auto *RecWithFlags = dyn_cast<VPRecipeWithIRFlags>(CurRec)) {
3741 VPValue *A, *B;
3742 // Dropping disjoint from an OR may yield incorrect results, as some
3743 // analysis may have converted it to an Add implicitly (e.g. SCEV used
3744 // for dependence analysis). Instead, replace it with an equivalent Add.
3745 // This is possible as all users of the disjoint OR only access lanes
3746 // where the operands are disjoint or poison otherwise.
3747 if (match(RecWithFlags, m_BinaryOr(m_VPValue(A), m_VPValue(B))) &&
3748 RecWithFlags->isDisjoint()) {
3749 VPBuilder Builder(RecWithFlags);
3750 VPInstruction *New =
3751 Builder.createAdd(A, B, RecWithFlags->getDebugLoc());
3752 New->setUnderlyingValue(RecWithFlags->getUnderlyingValue());
3753 RecWithFlags->replaceAllUsesWith(New);
3754 RecWithFlags->eraseFromParent();
3755 CurRec = New;
3756 } else
3757 RecWithFlags->dropPoisonGeneratingFlags();
3758 } else {
3761 (void)Instr;
3762 assert((!Instr || !Instr->hasPoisonGeneratingFlags()) &&
3763 "found instruction with poison generating flags not covered by "
3764 "VPRecipeWithIRFlags");
3765 }
3766
3767 // Add new definitions to the worklist.
3768 for (VPValue *Operand : CurRec->operands())
3769 if (VPRecipeBase *OpDef = Operand->getDefiningRecipe())
3770 Worklist.push_back(OpDef);
3771 }
3772 });
3773
3774 // We want to exclude the tail folding case, as we don't need to drop flags
3775 // for operations computing the first lane in this case: the first lane of the
3776 // header mask must always be true. For reverse memory accesses, the mask is
3777 // wrapped in a Reverse, which is just a permutation of the header mask, so
3778 // peel it off before checking. The header mask is still the abstract region
3779 // value at this point (materialization happens later).
3780 auto IsNotHeaderMask = [](VPValue *Mask) {
3781 return Mask &&
3783 };
3784
3785 // Traverse all the recipes in the VPlan and collect the poison-generating
3786 // recipes in the backward slice starting at the address of a VPWidenRecipe or
3787 // VPInterleaveRecipe.
3788 auto Iter =
3791 for (VPRecipeBase &Recipe : *VPBB) {
3792 if (auto *WidenRec = dyn_cast<VPWidenMemoryRecipe>(&Recipe)) {
3793 VPRecipeBase *AddrDef = WidenRec->getAddr()->getDefiningRecipe();
3794 if (AddrDef && WidenRec->isConsecutive() &&
3795 IsNotHeaderMask(WidenRec->getMask()))
3796 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
3797 } else if (auto *InterleaveRec = dyn_cast<VPInterleaveRecipe>(&Recipe)) {
3798 VPRecipeBase *AddrDef = InterleaveRec->getAddr()->getDefiningRecipe();
3799 if (AddrDef && IsNotHeaderMask(InterleaveRec->getMask()))
3800 CollectPoisonGeneratingInstrsInBackwardSlice(AddrDef);
3801 }
3802 }
3803 }
3804}
3805
3807 VPlan &Plan,
3809 &InterleaveGroups,
3810 const bool &EpilogueAllowed) {
3811 if (InterleaveGroups.empty())
3812 return;
3813
3815 for (VPBasicBlock *VPBB :
3818 for (VPRecipeBase &R : make_filter_range(*VPBB, [](VPRecipeBase &R) {
3819 return isa<VPWidenMemoryRecipe>(&R);
3820 })) {
3821 auto *MemR = cast<VPWidenMemoryRecipe>(&R);
3822 IRMemberToRecipe[&MemR->getIngredient()] = MemR;
3823 }
3824
3825 // Interleave memory: for each Interleave Group we marked earlier as relevant
3826 // for this VPlan, replace the Recipes widening its memory instructions with a
3827 // single VPInterleaveRecipe at its insertion point.
3828 VPDominatorTree VPDT(Plan);
3829 for (const auto *IG : InterleaveGroups) {
3830 VPWidenMemoryRecipe *Start = nullptr;
3831 Instruction *StartMember = nullptr;
3832 for (auto *Member : IG->members())
3833 if (VPWidenMemoryRecipe *R = IRMemberToRecipe.lookup(Member)) {
3834 StartMember = Member;
3835 Start = R;
3836 break;
3837 }
3838 if (!StartMember) // All member recipes are dead, so the group is dead.
3839 continue;
3840 VPIRMetadata InterleaveMD(*Start);
3841 SmallVector<VPValue *, 4> StoredValues;
3842 for (unsigned I = 0; I < IG->getFactor(); ++I) {
3843 Instruction *MemberI = IG->getMember(I);
3844 if (!MemberI)
3845 continue;
3846 if (VPWidenMemoryRecipe *MemoryR = IRMemberToRecipe.lookup(MemberI)) {
3847 if (auto *StoreR = dyn_cast<VPWidenStoreRecipe>(MemoryR->getAsRecipe()))
3848 StoredValues.push_back(StoreR->getStoredValue());
3849 InterleaveMD.intersect(*MemoryR);
3850 } else {
3851 InterleaveMD.intersect(VPIRMetadata(*MemberI));
3852 }
3853 }
3854
3855 bool NeedsMaskForGaps =
3856 (IG->requiresScalarEpilogue() && !EpilogueAllowed) ||
3857 (!StoredValues.empty() && !IG->isFull());
3858
3859 Instruction *IRInsertPos = IG->getInsertPos();
3860 auto *InsertPos = IRMemberToRecipe.lookup(IRInsertPos);
3861 if (!InsertPos) {
3862 // InsertPos member is dead: find a new member that is alive.
3863 assert(isa<VPWidenLoadRecipe>(Start->getAsRecipe()) &&
3864 "Dead member in non-load group?");
3865 InsertPos = Start;
3866 for (Instruction *Member : IG->members())
3867 if (VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member))
3868 if (VPDT.properlyDominates(MemberR->getAsRecipe(),
3869 InsertPos->getAsRecipe()))
3870 InsertPos = MemberR;
3871 IRInsertPos = &InsertPos->getIngredient();
3872 }
3873 VPRecipeBase *InsertPosR = InsertPos->getAsRecipe();
3874
3876 if (auto *Gep = dyn_cast<GetElementPtrInst>(
3877 getLoadStorePointerOperand(IRInsertPos)->stripPointerCasts()))
3878 NW = Gep->getNoWrapFlags().withoutNoUnsignedWrap();
3879
3880 // Get or create the start address for the interleave group.
3881 VPValue *Addr = Start->getAddr();
3882 VPRecipeBase *AddrDef = Addr->getDefiningRecipe();
3883 if (IG->getIndex(StartMember) != 0 ||
3884 (AddrDef && !VPDT.properlyDominates(AddrDef, InsertPosR))) {
3885 // Either member zero's recipe is dead, or we cannot re-use the address of
3886 // member zero because it does not dominate the insert position. Instead,
3887 // use the address of the insert position and create a PtrAdd adjusting it
3888 // to the address of member zero.
3889 // TODO: Hoist Addr's defining recipe (and any operands as needed) to
3890 // InsertPos or sink loads above zero members to join it.
3891 assert(IG->getIndex(IRInsertPos) != 0 &&
3892 "index of insert position shouldn't be zero");
3893 auto &DL = IRInsertPos->getDataLayout();
3894 APInt Offset(32,
3895 DL.getTypeAllocSize(getLoadStoreType(IRInsertPos)) *
3896 IG->getIndex(IRInsertPos),
3897 /*IsSigned=*/true);
3898 VPValue *OffsetVPV = Plan.getConstantInt(-Offset);
3899 VPBuilder B(InsertPosR);
3900 Addr = B.createNoWrapPtrAdd(InsertPos->getAddr(), OffsetVPV, NW);
3901 }
3902 // If the group is reverse, adjust the index to refer to the last vector
3903 // lane instead of the first. We adjust the index from the first vector
3904 // lane, rather than directly getting the pointer for lane VF - 1, because
3905 // the pointer operand of the interleaved access is supposed to be uniform.
3906 if (IG->isReverse()) {
3907 auto *ReversePtr = new VPVectorEndPointerRecipe(
3908 Addr, &Plan.getVF(), getLoadStoreType(IRInsertPos),
3909 -(int64_t)IG->getFactor(), NW, InsertPosR->getDebugLoc());
3910 ReversePtr->insertBefore(InsertPosR);
3911 Addr = ReversePtr;
3912 }
3913 auto *VPIG = new VPInterleaveRecipe(
3914 IG, Addr, StoredValues, InsertPos->getMask(), NeedsMaskForGaps,
3915 InterleaveMD, InsertPosR->getDebugLoc());
3916 VPIG->insertBefore(InsertPosR);
3917
3918 unsigned J = 0;
3919 for (unsigned i = 0; i < IG->getFactor(); ++i)
3920 if (Instruction *Member = IG->getMember(i)) {
3921 VPWidenMemoryRecipe *MemberR = IRMemberToRecipe.lookup(Member);
3922 if (!Member->getType()->isVoidTy()) {
3923 if (MemberR) {
3924 VPValue *OriginalV = MemberR->getAsRecipe()->getVPSingleValue();
3925 OriginalV->replaceAllUsesWith(VPIG->getVPValue(J));
3926 }
3927 J++;
3928 }
3929 if (MemberR)
3930 MemberR->getAsRecipe()->eraseFromParent();
3931 }
3932 }
3933}
3934
3935/// Expand a VPWidenIntOrFpInduction into executable recipes, for the initial
3936/// value, phi and backedge value. In the following example:
3937///
3938/// vector.ph:
3939/// Successor(s): vector loop
3940///
3941/// <x1> vector loop: {
3942/// vector.body:
3943/// WIDEN-INDUCTION %i = phi %start, %step, %vf
3944/// ...
3945/// EMIT branch-on-count ...
3946/// No successors
3947/// }
3948///
3949/// WIDEN-INDUCTION will get expanded to:
3950///
3951/// vector.ph:
3952/// ...
3953/// vp<%induction.start> = ...
3954/// vp<%induction.increment> = ...
3955///
3956/// Successor(s): vector loop
3957///
3958/// <x1> vector loop: {
3959/// vector.body:
3960/// ir<%i> = WIDEN-PHI vp<%induction.start>, vp<%vec.ind.next>
3961/// ...
3962/// vp<%vec.ind.next> = add ir<%i>, vp<%induction.increment>
3963/// EMIT branch-on-count ...
3964/// No successors
3965/// }
3966static void
3968 VPlan *Plan = WidenIVR->getParent()->getPlan();
3969 VPValue *Start = WidenIVR->getStartValue();
3970 VPValue *Step = WidenIVR->getStepValue();
3971 VPValue *VF = WidenIVR->getVFValue();
3972 DebugLoc DL = WidenIVR->getDebugLoc();
3973
3974 // The value from the original loop to which we are mapping the new induction
3975 // variable.
3976 Type *Ty = WidenIVR->getScalarType();
3977
3978 const InductionDescriptor &ID = WidenIVR->getInductionDescriptor();
3981 VPIRFlags Flags = *WidenIVR;
3982 if (ID.getKind() == InductionDescriptor::IK_IntInduction) {
3983 AddOp = Instruction::Add;
3984 MulOp = Instruction::Mul;
3985 } else {
3986 AddOp = ID.getInductionOpcode();
3987 MulOp = Instruction::FMul;
3988 }
3989
3990 // If the phi is truncated, truncate the start and step values.
3991 VPBuilder Builder(Plan->getVectorPreheader());
3992 Type *StepTy = Step->getScalarType();
3993 if (Ty->getScalarSizeInBits() < StepTy->getScalarSizeInBits()) {
3994 assert(StepTy->isIntegerTy() && "Truncation requires an integer type");
3995 Step = Builder.createScalarCast(Instruction::Trunc, Step, Ty, DL);
3996 Start = Builder.createScalarCast(Instruction::Trunc, Start, Ty, DL);
3997 StepTy = Ty;
3998 }
3999
4000 // Construct the initial value of the vector IV in the vector loop preheader.
4001 Type *IVIntTy =
4003 VPValue *Init = Builder.createNaryOp(VPInstruction::StepVector, {}, IVIntTy);
4004 if (StepTy->isFloatingPointTy())
4005 Init = Builder.createWidenCast(Instruction::UIToFP, Init, StepTy);
4006
4007 VPValue *SplatStart = Builder.createNaryOp(VPInstruction::Broadcast, Start);
4008 VPValue *SplatStep = Builder.createNaryOp(VPInstruction::Broadcast, Step);
4009
4010 Init = Builder.createNaryOp(MulOp, {Init, SplatStep}, Flags);
4011 Init = Builder.createNaryOp(AddOp, {SplatStart, Init}, Flags,
4012 DebugLoc::getUnknown(), "induction");
4013
4014 // Create the widened phi of the vector IV.
4015 auto *WidePHI = VPBuilder(WidenIVR).createWidenPhi(
4016 Init, WidenIVR->getDebugLoc(), "vec.ind");
4017
4018 // Create the backedge value for the vector IV.
4019 VPValue *Inc;
4020 VPValue *Prev;
4021 // If unrolled, use the increment and prev value from the operands.
4022 if (auto *SplatVF = WidenIVR->getSplatVFValue()) {
4023 Inc = SplatVF;
4024 Prev = WidenIVR->getLastUnrolledPartOperand();
4025 } else {
4026 // Move the insertion point after the VF definition when the VF is defined
4027 // inside a loop, such as for EVL tail-folding.
4028 if (VPRecipeBase *R = VF->getDefiningRecipe())
4029 if (R->getParent()->getEnclosingLoopRegion())
4030 Builder.setInsertPoint(R->getParent(), std::next(R->getIterator()));
4031
4032 // Multiply the vectorization factor by the step using integer or
4033 // floating-point arithmetic as appropriate.
4034 if (StepTy->isFloatingPointTy())
4035 VF = Builder.createScalarCast(Instruction::CastOps::UIToFP, VF, StepTy,
4036 DL);
4037 else
4038 VF = Builder.createScalarZExtOrTrunc(VF, StepTy, VF->getScalarType(), DL);
4039
4040 Inc = Builder.createNaryOp(MulOp, {Step, VF}, Flags);
4041 Inc = Builder.createNaryOp(VPInstruction::Broadcast, Inc);
4042 Prev = WidePHI;
4043 }
4044
4046 Builder.setInsertPoint(ExitingBB, ExitingBB->getTerminator()->getIterator());
4047 auto *Next = Builder.createNaryOp(AddOp, {Prev, Inc}, Flags,
4048 WidenIVR->getDebugLoc(), "vec.ind.next");
4049
4050 WidePHI->addIncoming(Next);
4051
4052 WidenIVR->replaceAllUsesWith(WidePHI);
4053}
4054
4055/// Expand a VPWidenPointerInductionRecipe into executable recipes, for the
4056/// initial value, phi and backedge value. In the following example:
4057///
4058/// <x1> vector loop: {
4059/// vector.body:
4060/// EMIT ir<%ptr.iv> = WIDEN-POINTER-INDUCTION %start, %step, %vf
4061/// ...
4062/// EMIT branch-on-count ...
4063/// }
4064///
4065/// WIDEN-POINTER-INDUCTION will get expanded to:
4066///
4067/// <x1> vector loop: {
4068/// vector.body:
4069/// EMIT-SCALAR %pointer.phi = phi %start, %ptr.ind
4070/// EMIT %mul = mul %stepvector, %step
4071/// EMIT %vector.gep = wide-ptradd %pointer.phi, %mul
4072/// ...
4073/// EMIT %ptr.ind = ptradd %pointer.phi, %vf
4074/// EMIT branch-on-count ...
4075/// }
4077 VPlan *Plan = R->getParent()->getPlan();
4078 VPValue *Start = R->getStartValue();
4079 VPValue *Step = R->getStepValue();
4080 VPValue *VF = R->getVFValue();
4081
4082 assert(R->getInductionDescriptor().getKind() ==
4084 "Not a pointer induction according to InductionDescriptor!");
4085 assert(R->getScalarType()->isPointerTy() && "Unexpected type.");
4086 assert(!R->onlyScalarsGenerated(Plan->hasScalableVF()) &&
4087 "Recipe should have been replaced");
4088
4089 VPBuilder Builder(R);
4090 DebugLoc DL = R->getDebugLoc();
4091
4092 // Build a scalar pointer phi.
4093 VPPhi *ScalarPtrPhi = Builder.createScalarPhi(Start, DL, "pointer.phi");
4094
4095 // Create actual address geps that use the pointer phi as base and a
4096 // vectorized version of the step value (<step*0, ..., step*N>) as offset.
4097 Builder.setInsertPoint(R->getParent(), R->getParent()->getFirstNonPhi());
4098 Type *StepTy = Step->getScalarType();
4099 VPValue *Offset = Builder.createNaryOp(VPInstruction::StepVector, {}, StepTy);
4100 Offset = Builder.createOverflowingOp(Instruction::Mul, {Offset, Step});
4101 VPValue *PtrAdd =
4102 Builder.createWidePtrAdd(ScalarPtrPhi, Offset, DL, "vector.gep");
4103 R->replaceAllUsesWith(PtrAdd);
4104
4105 // Create the backedge value for the scalar pointer phi.
4107 Builder.setInsertPoint(ExitingBB, ExitingBB->getTerminator()->getIterator());
4108 VF = Builder.createScalarZExtOrTrunc(VF, StepTy, VF->getScalarType(), DL);
4109 VPValue *Inc = Builder.createOverflowingOp(Instruction::Mul, {Step, VF});
4110
4111 VPValue *InductionGEP =
4112 Builder.createPtrAdd(ScalarPtrPhi, Inc, DL, "ptr.ind");
4113 ScalarPtrPhi->addIncoming(InductionGEP);
4114}
4115
4116/// Expand a VPDerivedIVRecipe into executable recipes.
4118 VPBuilder Builder(R);
4119 VPValue *Start = R->getStartValue();
4120 VPValue *Step = R->getStepValue();
4121 VPValue *Index = R->getIndex();
4122 Type *StepTy = Step->getScalarType();
4123 Type *IndexTy = Index->getScalarType();
4124 Index = StepTy->isIntegerTy()
4125 ? Builder.createScalarSExtOrTrunc(
4126 Index, StepTy, IndexTy, DebugLoc::getCompilerGenerated())
4127 : Builder.createScalarCast(Instruction::SIToFP, Index, StepTy,
4129 switch (R->getInductionKind()) {
4131 assert(Index->getScalarType() == Start->getScalarType() &&
4132 "Index type does not match StartValue type");
4133 return R->replaceAllUsesWith(Builder.createAdd(
4134 Start, Builder.createOverflowingOp(Instruction::Mul, {Index, Step})));
4135 }
4137 return R->replaceAllUsesWith(Builder.createPtrAdd(
4138 Start, Builder.createOverflowingOp(Instruction::Mul, {Index, Step})));
4140 assert(StepTy->isFloatingPointTy() && "Expected FP Step value");
4141 const FPMathOperator *FPBinOp = R->getFPBinOp();
4142 assert(FPBinOp &&
4143 (FPBinOp->getOpcode() == Instruction::FAdd ||
4144 FPBinOp->getOpcode() == Instruction::FSub) &&
4145 "Original BinOp should be defined for FP induction");
4146 FastMathFlags FMF = FPBinOp->getFastMathFlags();
4147 VPValue *FMul = Builder.createNaryOp(Instruction::FMul, {Step, Index}, FMF);
4148 return R->replaceAllUsesWith(
4149 Builder.createNaryOp(FPBinOp->getOpcode(), {Start, FMul}, FMF));
4150 }
4152 return;
4153 }
4154 llvm_unreachable("Unhandled induction kind");
4155}
4156
4158 // Replace loop regions with explicity CFG.
4159 SmallVector<VPRegionBlock *> LoopRegions;
4161 vp_depth_first_deep(Plan.getEntry()))) {
4162 if (!R->isReplicator())
4163 LoopRegions.push_back(R);
4164 }
4165 for (VPRegionBlock *R : LoopRegions)
4166 R->dissolveToCFGLoop();
4167}
4168
4171 // The transform runs after dissolving loop regions, so all VPBasicBlocks
4172 // terminated with BranchOnTwoConds are reached via a shallow traversal.
4175 if (!VPBB->empty() && match(&VPBB->back(), m_BranchOnTwoConds()))
4176 WorkList.push_back(cast<VPInstruction>(&VPBB->back()));
4177 }
4178
4179 // Expand BranchOnTwoConds instructions into explicit CFG with two new
4180 // single-condition branches:
4181 // 1. A branch that replaces BranchOnTwoConds, jumps to the first successor if
4182 // the first condition is true, and otherwise jumps to a new interim block.
4183 // 2. A branch that ends the interim block, jumps to the second successor if
4184 // the second condition is true, and otherwise jumps to the third
4185 // successor.
4186 for (VPInstruction *Br : WorkList) {
4187 assert(Br->getNumOperands() == 2 &&
4188 "BranchOnTwoConds must have exactly 2 conditions");
4189 DebugLoc DL = Br->getDebugLoc();
4190 VPBasicBlock *BrOnTwoCondsBB = Br->getParent();
4191 const auto Successors = to_vector(BrOnTwoCondsBB->getSuccessors());
4192 assert(Successors.size() == 3 &&
4193 "BranchOnTwoConds must have exactly 3 successors");
4194
4195 for (VPBlockBase *Succ : Successors)
4196 VPBlockUtils::disconnectBlocks(BrOnTwoCondsBB, Succ);
4197
4198 VPValue *Cond0 = Br->getOperand(0);
4199 VPValue *Cond1 = Br->getOperand(1);
4200 VPBlockBase *Succ0 = Successors[0];
4201 VPBlockBase *Succ1 = Successors[1];
4202 VPBlockBase *Succ2 = Successors[2];
4203
4204 // If the successor block for both conditions is the same, then combine the
4205 // two conditions and plant a single conditional branch.
4206 if (Succ0 == Succ1) {
4207 VPBuilder Builder(Br);
4208 VPValue *Combined = Builder.createOr(Cond0, Cond1, DL);
4209 Builder.createNaryOp(VPInstruction::BranchOnCond, {Combined}, DL);
4210 VPBlockUtils::connectBlocks(BrOnTwoCondsBB, Succ0);
4211 VPBlockUtils::connectBlocks(BrOnTwoCondsBB, Succ2);
4212 Br->eraseFromParent();
4213 continue;
4214 }
4215
4216 assert(!Succ0->getParent() && !Succ1->getParent() && !Succ2->getParent() &&
4217 !BrOnTwoCondsBB->getParent() && "regions must already be dissolved");
4218
4219 VPBasicBlock *InterimBB =
4220 Plan.createVPBasicBlock(BrOnTwoCondsBB->getName() + ".interim");
4221
4222 VPBuilder(BrOnTwoCondsBB)
4224 VPBlockUtils::connectBlocks(BrOnTwoCondsBB, Succ0);
4225 VPBlockUtils::connectBlocks(BrOnTwoCondsBB, InterimBB);
4226
4228 VPBlockUtils::connectBlocks(InterimBB, Succ1);
4229 VPBlockUtils::connectBlocks(InterimBB, Succ2);
4230 Br->eraseFromParent();
4231 }
4232}
4233
4236 vp_depth_first_deep(Plan.getEntry()))) {
4237 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
4238 VPBuilder Builder(&R);
4239 if (auto *WidenIVR = dyn_cast<VPWidenIntOrFpInductionRecipe>(&R)) {
4241 WidenIVR->eraseFromParent();
4242 continue;
4243 }
4244
4245 if (auto *WidenIVR = dyn_cast<VPWidenPointerInductionRecipe>(&R)) {
4246 // If the recipe only generates scalars, scalarize it instead of
4247 // expanding it.
4248 if (WidenIVR->onlyScalarsGenerated(Plan.hasScalableVF())) {
4249 VPValue *PtrAdd =
4250 scalarizeVPWidenPointerInduction(WidenIVR, Plan, Builder);
4251 WidenIVR->replaceAllUsesWith(PtrAdd);
4252 WidenIVR->eraseFromParent();
4253 continue;
4254 }
4256 WidenIVR->eraseFromParent();
4257 continue;
4258 }
4259
4260 if (auto *DerivedIVR = dyn_cast<VPDerivedIVRecipe>(&R)) {
4261 expandVPDerivedIV(DerivedIVR);
4262 DerivedIVR->eraseFromParent();
4263 continue;
4264 }
4265
4266 if (auto *WideCanIV = dyn_cast<VPWidenCanonicalIVRecipe>(&R)) {
4267 VPValue *CanIV = WideCanIV->getCanonicalIV();
4268 Type *CanIVTy = CanIV->getScalarType();
4269 VPValue *Step = WideCanIV->getStepValue();
4270 if (!Step) {
4271 assert(Plan.getConcreteUF() == 1 &&
4272 "Expected unroller to have materialized step for UF != 1");
4273 Step = Plan.getZero(CanIVTy);
4274 }
4275 CanIV = Builder.createNaryOp(VPInstruction::Broadcast, CanIV);
4276 Step = Builder.createNaryOp(VPInstruction::Broadcast, Step);
4277 Step = Builder.createAdd(
4278 Step, Builder.createNaryOp(VPInstruction::StepVector, {}, CanIVTy));
4279 VPValue *CanVecIV =
4280 Builder.createAdd(CanIV, Step, WideCanIV->getDebugLoc(), "vec.iv",
4281 WideCanIV->getNoWrapFlags());
4282 WideCanIV->replaceAllUsesWith(CanVecIV);
4283 WideCanIV->eraseFromParent();
4284 continue;
4285 }
4286
4287 // Expand VPBlendRecipe into VPInstruction::Select.
4288 if (auto *Blend = dyn_cast<VPBlendRecipe>(&R)) {
4289 VPValue *Select = Blend->getIncomingValue(0);
4290 for (unsigned I = 1; I != Blend->getNumIncomingValues(); ++I)
4291 Select = Builder.createSelect(Blend->getMask(I),
4292 Blend->getIncomingValue(I), Select,
4293 R.getDebugLoc(), "predphi", *Blend);
4294 Blend->replaceAllUsesWith(Select);
4295 Blend->eraseFromParent();
4296 continue;
4297 }
4298
4299 if (auto *VEPR = dyn_cast<VPVectorEndPointerRecipe>(&R)) {
4300 if (!VEPR->getOffset()) {
4301 assert(Plan.getConcreteUF() == 1 &&
4302 "Expected unroller to have materialized offset for UF != 1");
4303 VEPR->materializeOffset();
4304 }
4305 continue;
4306 }
4307
4308 if (auto *Expr = dyn_cast<VPExpressionRecipe>(&R)) {
4309 Expr->decompose();
4310 Expr->eraseFromParent();
4311 continue;
4312 }
4313
4314 // Expand LastActiveLane into Not + FirstActiveLane + Sub.
4315 auto *LastActiveL = dyn_cast<VPInstruction>(&R);
4316 if (LastActiveL &&
4317 LastActiveL->getOpcode() == VPInstruction::LastActiveLane) {
4318 // Create Not(Mask) for all operands.
4320 for (VPValue *Op : LastActiveL->operands()) {
4321 VPValue *NotMask = Builder.createNot(Op, LastActiveL->getDebugLoc());
4322 NotMasks.push_back(NotMask);
4323 }
4324
4325 // Create FirstActiveLane on the inverted masks.
4326 VPValue *FirstInactiveLane = Builder.createFirstActiveLane(
4327 NotMasks, LastActiveL->getDebugLoc(), "first.inactive.lane");
4328
4329 // Subtract 1 to get the last active lane.
4330 VPValue *One =
4331 Plan.getConstantInt(FirstInactiveLane->getScalarType(), 1);
4332 VPValue *LastLane =
4333 Builder.createSub(FirstInactiveLane, One,
4334 LastActiveL->getDebugLoc(), "last.active.lane");
4335
4336 LastActiveL->replaceAllUsesWith(LastLane);
4337 LastActiveL->eraseFromParent();
4338 continue;
4339 }
4340
4341 // Lower MaskedCond with block mask to LogicalAnd.
4343 auto *VPI = cast<VPInstruction>(&R);
4344 assert(VPI->isMasked() &&
4345 "Unmasked MaskedCond should be simplified earlier");
4346 VPI->replaceAllUsesWith(Builder.createNaryOp(
4347 VPInstruction::LogicalAnd, {VPI->getMask(), VPI->getOperand(0)}));
4348 VPI->eraseFromParent();
4349 continue;
4350 }
4351
4352 // Lower CanonicalIVIncrementForPart to plain Add.
4353 if (match(
4354 &R,
4356 auto *VPI = cast<VPInstruction>(&R);
4357 VPValue *Add = Builder.createOverflowingOp(
4358 Instruction::Add, VPI->operands(), VPI->getNoWrapFlags(),
4359 VPI->getDebugLoc());
4360 VPI->replaceAllUsesWith(Add);
4361 VPI->eraseFromParent();
4362 continue;
4363 }
4364
4365 // Lower BranchOnCount to ICmp + BranchOnCond.
4366 VPValue *IV, *TC;
4367 if (match(&R, m_BranchOnCount(m_VPValue(IV), m_VPValue(TC)))) {
4368 auto *BranchOnCountInst = cast<VPInstruction>(&R);
4369 DebugLoc DL = BranchOnCountInst->getDebugLoc();
4370 VPValue *Cond = Builder.createICmp(CmpInst::ICMP_EQ, IV, TC, DL);
4371 Builder.createNaryOp(VPInstruction::BranchOnCond, Cond, DL);
4372 BranchOnCountInst->eraseFromParent();
4373 continue;
4374 }
4375
4376 VPValue *VectorStep;
4377 VPValue *ScalarStep;
4379 m_VPValue(VectorStep), m_VPValue(ScalarStep))))
4380 continue;
4381
4382 // Expand WideIVStep.
4383 auto *VPI = cast<VPInstruction>(&R);
4384 Type *IVTy = VPI->getScalarType();
4385 if (VectorStep->getScalarType() != IVTy) {
4387 ? Instruction::UIToFP
4388 : Instruction::Trunc;
4389 VectorStep = Builder.createWidenCast(CastOp, VectorStep, IVTy);
4390 }
4391
4392 assert(!match(ScalarStep, m_One()) && "Expected non-unit scalar-step");
4393 if (ScalarStep->getScalarType() != IVTy) {
4394 ScalarStep =
4395 Builder.createWidenCast(Instruction::Trunc, ScalarStep, IVTy);
4396 }
4397
4398 VPIRFlags Flags;
4399 unsigned MulOpc;
4400 if (IVTy->isFloatingPointTy()) {
4401 MulOpc = Instruction::FMul;
4402 Flags = VPI->getFastMathFlagsOrNone();
4403 } else {
4404 MulOpc = Instruction::Mul;
4405 Flags = VPIRFlags::getDefaultFlags(MulOpc);
4406 }
4407
4408 VPInstruction *Mul = Builder.createNaryOp(
4409 MulOpc, {VectorStep, ScalarStep}, Flags, R.getDebugLoc());
4410 VectorStep = Mul;
4411 VPI->replaceAllUsesWith(VectorStep);
4412 VPI->eraseFromParent();
4413 }
4414 }
4415}
4416
4417/// Returns the VPValue representing the uncountable exit comparison used by
4418/// AnyOf if the recipes it depends on can be traced back to live-ins and
4419/// the addresses (in GEP/PtrAdd form) of any (non-masked) load used in
4420/// generating the values for the comparison. The recipes are stored in
4421/// \p Recipes.
4422static std::optional<VPValue *>
4424 VPBasicBlock *LatchVPBB) {
4425 // Given a plain CFG VPlan loop with countable latch exiting block
4426 // \p LatchVPBB, we're looking to match the recipes contributing to the
4427 // uncountable exit condition comparison (here, vp<%4>) back to either
4428 // live-ins or the address nodes for the load used as part of the uncountable
4429 // exit comparison so that we can either move them within the loop, or copy
4430 // them to the preheader depending on the chosen method for dealing with
4431 // stores in uncountable exit loops.
4432 //
4433 // Currently, the address of the load is restricted to a GEP with 2 operands
4434 // and a live-in base address. This constraint may be relaxed later.
4435 //
4436 // VPlan ' for UF>=1' {
4437 // Live-in vp<%0> = VF * UF
4438 // Live-in vp<%1> = vector-trip-count
4439 // Live-in ir<20> = original trip-count
4440 //
4441 // ir-bb<entry>:
4442 // Successor(s): scalar.ph, vector.ph
4443 //
4444 // vector.ph:
4445 // Successor(s): for.body
4446 //
4447 // for.body:
4448 // EMIT vp<%2> = phi ir<0>, vp<%index.next>
4449 // EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, for.inc ]
4450 // EMIT ir<%uncountable.addr> = getelementptr inbounds nuw ir<%pred>,ir<%iv>
4451 // EMIT ir<%uncountable.val> = load ir<%uncountable.addr>
4452 // EMIT ir<%uncountable.cond> = icmp sgt ir<%uncountable.val>, ir<500>
4453 // EMIT vp<%3> = masked-cond ir<%uncountable.cond>
4454 // Successor(s): for.inc
4455 //
4456 // for.inc:
4457 // EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1>
4458 // EMIT ir<%countable.cond> = icmp eq ir<%iv.next>, ir<20>
4459 // EMIT vp<%index.next> = add nuw vp<%2>, vp<%0>
4460 // EMIT vp<%4> = any-of ir<%3>
4461 // EMIT vp<%5> = icmp eq vp<%index.next>, vp<%1>
4462 // EMIT branch-on-two-conds vp<%4>, vp<%5>
4463 // Successor(s): middle.block, middle.block, for.body
4464 //
4465 // middle.block:
4466 // Successor(s): ir-bb<exit>, scalar.ph
4467 //
4468 // ir-bb<exit>:
4469 // No successors
4470 //
4471 // scalar.ph:
4472 // }
4473
4474 // Find the uncountable loop exit condition.
4475 VPValue *UncountableCondition = nullptr;
4476 if (!match(LatchVPBB->getTerminator(),
4477 m_BranchOnTwoConds(m_AnyOf(m_VPValue(UncountableCondition)),
4478 m_VPValue())))
4479 return std::nullopt;
4480
4482 Worklist.push_back(UncountableCondition);
4483 while (!Worklist.empty()) {
4484 VPValue *V = Worklist.pop_back_val();
4485
4486 // Any value defined outside the loop does not need to be copied.
4487 if (V->isDefinedOutsideLoopRegions())
4488 continue;
4489
4490 // FIXME: Remove the single user restriction; it's here because we're
4491 // starting with the simplest set of loops we can, and multiple
4492 // users means needing to add PHI nodes in the transform.
4493 if (V->getNumUsers() > 1)
4494 return std::nullopt;
4495
4496 VPValue *Op1, *Op2;
4497 // Walk back through recipes until we find at least one load from memory.
4498 if (match(V, m_ICmp(m_VPValue(Op1), m_VPValue(Op2)))) {
4499 Worklist.push_back(Op1);
4500 Worklist.push_back(Op2);
4501 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
4502 } else if (match(V, m_VPInstruction<Instruction::Load>(m_VPValue(Op1)))) {
4503 VPRecipeBase *GepR = Op1->getDefiningRecipe();
4504 // Only matching base + single offset term for now.
4505 if (GepR->getNumOperands() != 2)
4506 return std::nullopt;
4507 // Matching a GEP with a loop-invariant base ptr.
4509 m_LiveIn(), m_VPValue())))
4510 return std::nullopt;
4511 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
4512 Recipes.push_back(cast<VPInstruction>(GepR));
4514 m_VPValue(Op1)))) {
4515 Worklist.push_back(Op1);
4516 Recipes.push_back(cast<VPInstruction>(V->getDefiningRecipe()));
4517 } else
4518 return std::nullopt;
4519 }
4520
4521 // If we couldn't match anything, don't return the condition. It may be
4522 // defined outside the loop.
4523 if (Recipes.empty() || none_of(Recipes, [](VPInstruction *I) {
4525 }))
4526 return std::nullopt;
4527
4528 return UncountableCondition;
4529}
4530
4536
4537/// Update \p Plan to mask memory operations in the loop based on whether the
4538/// early exit is taken or not.
4539///
4540/// We're currently expecting to find a loop with properties similar to the
4541/// following:
4542///
4543/// for.body:
4544/// ir<%indvars.iv> = WIDEN-INDUCTION nuw nsw ir<0>, ir<1>, vp<%0>
4545/// EMIT ir<%arrayidx> = getelementptr inbounds nuw ir<@c>, ir<%indvars.iv>
4546/// EMIT-SCALAR ir<%0> = load ir<%arrayidx>
4547/// EMIT ir<%cmp1> = icmp sgt ir<%0>, ir<5>
4548/// EMIT vp<%1> = masked-cond ir<%cmp1>
4549/// Successor(s): if.end
4550///
4551/// if.end:
4552/// EMIT ir<%arrayidx3> = getelementptr inbounds nuw ir<@src>, ir<%indvars.iv>
4553/// EMIT-SCALAR ir<%2> = load ir<%arrayidx3>
4554/// EMIT ir<%add> = add nsw ir<%2>, ir<42>
4555/// EMIT ir<%arrayidx5> = getelementptr inbounds nuw ir<@dst>, ir<%indvars.iv>
4556/// EMIT store ir<%add>, ir<%arrayidx5>
4557/// EMIT ir<%indvars.iv.next> = add nuw nsw ir<%indvars.iv>, ir<1>
4558/// EMIT vp<%3> = any-of ir<%1>
4559/// EMIT ir<%exitcond.not> = icmp eq ir<%indvars.iv.next>, ir<10000>
4560/// EMIT branch-on-two-conds vp<%3>, ir<%exitcond.not>
4561/// Successor(s): middle.block, middle.block, for.body
4562///
4563/// We currently expect LoopVectorizationLegality to ensure that:
4564/// * There must also be a counted exit. We will need to support speculative
4565/// or first-faulting loads before we can remove this restriction.
4566/// * Any stores within the loop must not alias with the load used for the
4567/// uncountable exit. We can relax this a bit with runtime aliasing checks.
4568/// * Other memory operations in the loop can take place before or after the
4569/// uncountable exit, but must also be unconditional. We need to support
4570/// combining the conditions in VPlanPredicator.
4571/// * The loop must have a single unconditional load contributing to the
4572/// uncountable exit comparison, and the other term must be loop-invariant.
4573/// Improving upon this requires work in getRecipesForUncountableExit to
4574/// handle more complex recipe graphs.
4577 VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB,
4578 Loop *TheLoop, PredicatedScalarEvolution &PSE, DominatorTree &DT,
4579 AssumptionCache *AC) {
4580
4581 // Disconnect early exiting blocks from successors, remove branches. We
4582 // currently don't support multiple uses for recipes involved in creating
4583 // the uncountable exit condition.
4584 for (auto &Exit : Exits) {
4585 if (Exit.EarlyExitingVPBB == LatchVPBB)
4586 continue;
4587
4588 for (VPRecipeBase &R : Exit.EarlyExitVPBB->phis())
4589 cast<VPIRPhi>(&R)->removeIncomingValueFor(Exit.EarlyExitingVPBB);
4590 Exit.EarlyExitingVPBB->getTerminator()->eraseFromParent();
4591 VPBlockUtils::disconnectBlocks(Exit.EarlyExitingVPBB, Exit.EarlyExitVPBB);
4592 }
4593
4594 VPDominatorTree VPDT(Plan);
4595
4596 // We can abandon a VPlan entirely if we return false here, so we shouldn't
4597 // crash if some earlier assumptions on scalar IR don't hold for the vplan
4598 // version of the loop.
4599 SmallVector<VPInstruction *, 8> ConditionRecipes;
4600
4601 std::optional<VPValue *> Cond =
4602 getRecipesForUncountableExit(ConditionRecipes, LatchVPBB);
4603 if (!Cond)
4604 return false;
4605
4606 // Find load contributing to condition.
4607 // At the moment LoopVectorizationLegality only supports a single
4608 // early-exit expression with a compare and a single load that must
4609 // be unconditional.
4610 // TODO: Support more than one load.
4611 auto *Load =
4612 find_singleton<VPInstruction>(ConditionRecipes, [](auto *I, bool _) {
4614 ? I
4615 : nullptr;
4616 });
4617 assert(Load && "Couldn't find exactly one load");
4618 // TODO: Support conditional loads for uncountable exits.
4619 assert(VPDT.dominates(Load->getParent(), LatchVPBB) &&
4620 "Uncountable exit condition load is conditional.");
4621 VPInstruction *Ptr = cast<VPInstruction>(Load->getOperand(0));
4622
4623 // Ensure that we are guaranteed to be able to dereference the memory used
4624 // for determining the uncountable exit for the maximum possible number of
4625 // scalar iterations of the loop.
4626 //
4627 // TODO: Support first-faulting loads in cases where we don't know whether
4628 // all possible addresses are dereferenceable.
4629 {
4631 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, TheLoop);
4632 const DataLayout &DL = Plan.getDataLayout();
4633 APInt EltSize(DL.getIndexTypeSizeInBits(Ptr->getScalarType()),
4634 DL.getTypeStoreSize(Load->getScalarType()).getFixedValue());
4636 PtrSCEV, cast<LoadInst>(Load->getUnderlyingInstr())->getAlign(),
4637 PSE.getSE()->getConstant(EltSize), TheLoop, *PSE.getSE(), DT, AC,
4638 &Predicates))
4639 return false;
4640 }
4641
4642 // Check for a single GEP for the condition load to see if we can link it to
4643 // a widen IV recipe with a step of 1; we're only interested in contiguous
4644 // accesses for the condition load right now.
4645 auto *IV = cast<VPWidenInductionRecipe>(&HeaderVPBB->front());
4646 if (!match(IV->getStartValue(), m_SpecificInt(0)) ||
4647 !match(IV->getStepValue(), m_SpecificInt(1)))
4648 return false;
4650 m_Specific(IV))))
4651 return false;
4652
4653 // We want to guarantee that the uncountable exit condition (and the mask
4654 // we will generate from it) are available for all operations in the loop
4655 // that need to be masked. If the condition recipes are not already the first
4656 // recipes in the header after the last phi, move them there.
4657 auto InsertIt = HeaderVPBB->getFirstNonPhi();
4658 while (InsertIt != HeaderVPBB->end() &&
4659 is_contained(ConditionRecipes, &*InsertIt)) {
4660 erase(ConditionRecipes, &*InsertIt);
4661 InsertIt++;
4662 }
4663 for (auto *Recipe : reverse(ConditionRecipes))
4664 Recipe->moveBefore(*HeaderVPBB, InsertIt);
4665
4666 // Create a mask to represent all lanes that fully execute in the vector loop,
4667 // stopping short of any early exit.
4668 VPBuilder MaskBuilder(HeaderVPBB, InsertIt);
4669 VPValue *FirstActive = MaskBuilder.createFirstActiveLane(*Cond);
4670 Type *IVScalarTy = IV->getScalarType();
4671 Type *FirstActiveTy = FirstActive->getScalarType();
4672 VPValue *ALMMultiplier = Plan.getConstantInt(IVScalarTy, 1);
4673 VPValue *Zero = Plan.getZero(IVScalarTy);
4674 FirstActive = MaskBuilder.createScalarZExtOrTrunc(FirstActive, IVScalarTy,
4675 FirstActiveTy, DebugLoc());
4677 {Zero, FirstActive, ALMMultiplier},
4678 DebugLoc(), "uncountable.exit.mask");
4679
4680 // Convert all other memory operations to use the mask.
4681 for (VPBasicBlock *VPBB : vp_rpo_plain_cfg_loop_body(HeaderVPBB))
4682 for (VPRecipeBase &R : *VPBB)
4683 if (R.mayReadOrWriteMemory() && &R != Load) {
4684 // TODO: Handle conditional memory operations in the loop.
4685 if (!VPDT.dominates(R.getParent(), LatchVPBB))
4686 return false;
4687 cast<VPInstruction>(&R)->addMask(Mask);
4688 }
4689
4690 // Update middle block branch to compare (IV + however many lanes were active)
4691 // against the full trip count, since we may be exiting the vector loop early.
4692 // If we didn't take an early exit, we should get the equivalent of VF from
4693 // the FirstActiveLane.
4694 assert(match(MiddleVPBB->getTerminator(), m_BranchOnCond()) &&
4695 "Expected BranchOnCond terminator for MiddleVPBB");
4696 VPBuilder MiddleBuilder(MiddleVPBB->getTerminator());
4697 VPValue *ScalarIV = MiddleBuilder.createNaryOp(VPInstruction::ExtractLane,
4698 {Zero, IV}, DebugLoc());
4699 VPValue *ExitIV = MiddleBuilder.createAdd(ScalarIV, FirstActive);
4700 VPValue *FullTC =
4701 MiddleBuilder.createICmp(CmpInst::ICMP_EQ, ExitIV, Plan.getTripCount());
4702 MiddleVPBB->getTerminator()->setOperand(0, FullTC);
4703
4704 // Update resume phi in scalar.ph.
4705 VPBasicBlock *ScalarPH = Plan.getScalarPreheader();
4706 auto Phis = ScalarPH->phis();
4707 // TODO: Handle more than one Phi; re-derive from IV.
4708 // TODO: Handle reductions.
4709 if (range_size(Phis) != 1)
4710 return false;
4711 VPPhi *ContinueIV = cast<VPPhi>(Phis.begin());
4712 // Make sure we're referring to the same IV.
4713 assert(
4714 match(ContinueIV->getOperand(0),
4716 "Continuing from different IV");
4717 ContinueIV->setOperand(0, ExitIV);
4718 return true;
4719}
4720
4722 VPlan &Plan, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB,
4723 VPBasicBlock *MiddleVPBB, Loop *TheLoop, PredicatedScalarEvolution &PSE,
4725#ifndef NDEBUG
4726 VPDominatorTree VPDT(Plan);
4727#endif
4728 VPBuilder LatchBuilder(LatchVPBB->getTerminator());
4730 for (VPIRBasicBlock *ExitBlock : Plan.getExitBlocks()) {
4731 for (VPBlockBase *Pred : to_vector(ExitBlock->getPredecessors())) {
4732 if (Pred == MiddleVPBB)
4733 continue;
4734 // Collect condition for this early exit.
4735 auto *EarlyExitingVPBB = cast<VPBasicBlock>(Pred);
4736 VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors()[0];
4737 VPValue *CondOfEarlyExitingVPBB;
4738 [[maybe_unused]] bool Matched =
4739 match(EarlyExitingVPBB->getTerminator(),
4740 m_BranchOnCond(m_VPValue(CondOfEarlyExitingVPBB)));
4741 assert(Matched && "Terminator must be BranchOnCond");
4742
4743 // Insert the MaskedCond in the EarlyExitingVPBB so the predicator adds
4744 // the correct block mask.
4745 VPBuilder EarlyExitingBuilder(EarlyExitingVPBB->getTerminator());
4746 auto *CondToEarlyExit = EarlyExitingBuilder.createNaryOp(
4748 TrueSucc == ExitBlock
4749 ? CondOfEarlyExitingVPBB
4750 : EarlyExitingBuilder.createNot(CondOfEarlyExitingVPBB));
4751 assert((isa<VPIRValue>(CondOfEarlyExitingVPBB) ||
4752 !VPDT.properlyDominates(EarlyExitingVPBB, LatchVPBB) ||
4753 VPDT.properlyDominates(
4754 CondOfEarlyExitingVPBB->getDefiningRecipe()->getParent(),
4755 LatchVPBB)) &&
4756 "exit condition must dominate the latch");
4757 Exits.push_back({
4758 EarlyExitingVPBB,
4759 ExitBlock,
4760 CondToEarlyExit,
4761 });
4762 }
4763 }
4764
4765 assert(!Exits.empty() && "must have at least one early exit");
4766 // Sort exits by RPO order to get correct program order. RPO gives a
4767 // topological ordering of the CFG, ensuring upstream exits are checked
4768 // before downstream exits in the dispatch chain.
4770 HeaderVPBB);
4772 for (const auto &[Num, VPB] : enumerate(RPOT))
4773 RPOIdx[VPB] = Num;
4774 llvm::sort(Exits, [&RPOIdx](const EarlyExitInfo &A, const EarlyExitInfo &B) {
4775 return RPOIdx[A.EarlyExitingVPBB] < RPOIdx[B.EarlyExitingVPBB];
4776 });
4777#ifndef NDEBUG
4778 // After RPO sorting, verify that for any pair where one exit dominates
4779 // another, the dominating exit comes first. This is guaranteed by RPO
4780 // (topological order) and is required for the dispatch chain correctness.
4781 for (unsigned I = 0; I + 1 < Exits.size(); ++I)
4782 for (unsigned J = I + 1; J < Exits.size(); ++J)
4783 assert(!VPDT.properlyDominates(Exits[J].EarlyExitingVPBB,
4784 Exits[I].EarlyExitingVPBB) &&
4785 "RPO sort must place dominating exits before dominated ones");
4786#endif
4787
4788 // Build the AnyOf condition for the latch terminator using logical OR
4789 // to avoid poison propagation from later exit conditions when an earlier
4790 // exit is taken.
4791 VPValue *Combined = Exits[0].CondToExit;
4792 for (const EarlyExitInfo &Info : drop_begin(Exits))
4793 Combined = LatchBuilder.createLogicalOr(Combined, Info.CondToExit);
4794
4795 VPValue *IsAnyExitTaken =
4796 LatchBuilder.createNaryOp(VPInstruction::AnyOf, {Combined});
4797
4798 // Create a comparison for the latch exit condition and replace the
4799 // BranchOnCond with a BranchOnTwoConds. The original BranchOnCond's condition
4800 // is used as the latch-exit condition; canonical IV recipes have not been
4801 // introduced yet, so there is no BranchOnCount to derive the condition from.
4802 auto *LatchExitingBranch = cast<VPInstruction>(LatchVPBB->getTerminator());
4803 assert(LatchExitingBranch->getOpcode() == VPInstruction::BranchOnCond &&
4804 "Unexpected terminator");
4805 VPValue *IsLatchExitTaken = LatchExitingBranch->getOperand(0);
4806 DebugLoc LatchDL = LatchExitingBranch->getDebugLoc();
4807 LatchExitingBranch->eraseFromParent();
4808 LatchBuilder.setInsertPoint(LatchVPBB);
4810 {IsAnyExitTaken, IsLatchExitTaken}, LatchDL);
4811 LatchVPBB->clearSuccessors();
4812
4814 // If handling the exiting lane in the scalar loop, combine the exit
4815 // conditions into a single BranchOnCond.
4816 LatchVPBB->setSuccessors({MiddleVPBB, MiddleVPBB, HeaderVPBB});
4817 MiddleVPBB->clearPredecessors();
4818 MiddleVPBB->setPredecessors({LatchVPBB, LatchVPBB});
4820 Plan, Exits, HeaderVPBB, LatchVPBB, MiddleVPBB, TheLoop, PSE, DT, AC);
4821 }
4822
4823 // Create the vector.early.exit blocks.
4824 SmallVector<VPBasicBlock *> VectorEarlyExitVPBBs(Exits.size());
4825 for (unsigned Idx = 0; Idx != Exits.size(); ++Idx) {
4826 Twine BlockSuffix = Exits.size() == 1 ? "" : Twine(".") + Twine(Idx);
4827 VPBasicBlock *VectorEarlyExitVPBB =
4828 Plan.createVPBasicBlock("vector.early.exit" + BlockSuffix);
4829 VectorEarlyExitVPBBs[Idx] = VectorEarlyExitVPBB;
4830 }
4831
4832 // Create the dispatch block (or reuse the single exit block if only one
4833 // exit). The dispatch block computes the first active lane of the combined
4834 // condition and, for multiple exits, chains through conditions to determine
4835 // which exit to take.
4836 VPBasicBlock *DispatchVPBB =
4837 Exits.size() == 1 ? VectorEarlyExitVPBBs[0]
4838 : Plan.createVPBasicBlock("vector.early.exit.check");
4839 DispatchVPBB->setPredecessors({LatchVPBB});
4840 LatchVPBB->setSuccessors({DispatchVPBB, MiddleVPBB, HeaderVPBB});
4841 VPBuilder DispatchBuilder(DispatchVPBB, DispatchVPBB->begin());
4842 VPValue *FirstActiveLane = DispatchBuilder.createFirstActiveLane(
4843 {Combined}, DebugLoc::getUnknown(), "first.active.lane");
4844
4845 // For each early exit, disconnect the original exiting block
4846 // (early.exiting.I) from the exit block (ir-bb<exit.I>) and route through a
4847 // new vector.early.exit block. Update ir-bb<exit.I>'s phis to extract their
4848 // values at the first active lane:
4849 //
4850 // Input:
4851 // early.exiting.I:
4852 // ...
4853 // EMIT branch-on-cond vp<%cond.I>
4854 // Successor(s): in.loop.succ, ir-bb<exit.I>
4855 //
4856 // ir-bb<exit.I>:
4857 // IR %phi = phi [ vp<%incoming.I>, early.exiting.I ], ...
4858 //
4859 // Output:
4860 // early.exiting.I:
4861 // ...
4862 // Successor(s): in.loop.succ
4863 //
4864 // vector.early.exit.I:
4865 // EMIT vp<%exit.val> = extract-lane vp<%first.lane>, vp<%incoming.I>
4866 // Successor(s): ir-bb<exit.I>
4867 //
4868 // ir-bb<exit.I>:
4869 // IR %phi = phi ... (extra operand: vp<%exit.val> from
4870 // vector.early.exit.I)
4871 //
4872 for (auto [Exit, VectorEarlyExitVPBB] :
4873 zip_equal(Exits, VectorEarlyExitVPBBs)) {
4874 auto &[EarlyExitingVPBB, EarlyExitVPBB, _] = Exit;
4875 // Adjust the phi nodes in EarlyExitVPBB.
4876 // 1. remove incoming values from EarlyExitingVPBB,
4877 // 2. extract the incoming value at FirstActiveLane
4878 // 3. add back the extracts as last operands for the phis
4879 // Then adjust the CFG, removing the edge between EarlyExitingVPBB and
4880 // EarlyExitVPBB and adding a new edge between VectorEarlyExitVPBB and
4881 // EarlyExitVPBB. The extracts at FirstActiveLane are now the incoming
4882 // values from VectorEarlyExitVPBB.
4883 for (VPRecipeBase &R : EarlyExitVPBB->phis()) {
4884 auto *ExitIRI = cast<VPIRPhi>(&R);
4885 VPValue *IncomingVal =
4886 ExitIRI->getIncomingValueForBlock(EarlyExitingVPBB);
4887 VPValue *NewIncoming = IncomingVal;
4888 if (!isa<VPIRValue>(IncomingVal)) {
4889 VPBuilder EarlyExitBuilder(VectorEarlyExitVPBB);
4890 NewIncoming = EarlyExitBuilder.createNaryOp(
4891 VPInstruction::ExtractLane, {FirstActiveLane, IncomingVal},
4892 DebugLoc::getUnknown(), "early.exit.value");
4893 }
4894 ExitIRI->removeIncomingValueFor(EarlyExitingVPBB);
4895 ExitIRI->addIncoming(NewIncoming);
4896 }
4897
4898 EarlyExitingVPBB->getTerminator()->eraseFromParent();
4899 VPBlockUtils::disconnectBlocks(EarlyExitingVPBB, EarlyExitVPBB);
4900 VPBlockUtils::connectBlocks(VectorEarlyExitVPBB, EarlyExitVPBB);
4901 }
4902
4903 // Chain through exits: for each exit, check if its condition is true at
4904 // the first active lane. If so, take that exit; otherwise, try the next.
4905 // The last exit needs no check since it must be taken if all others fail.
4906 //
4907 // For 3 exits (cond.0, cond.1, cond.2), this creates:
4908 //
4909 // latch:
4910 // ...
4911 // EMIT vp<%combined> = logical-or vp<%cond.0>, vp<%cond.1>, vp<%cond.2>
4912 // ...
4913 //
4914 // vector.early.exit.check:
4915 // EMIT vp<%first.lane> = first-active-lane vp<%combined>
4916 // EMIT vp<%at.cond.0> = extract-lane vp<%first.lane>, vp<%cond.0>
4917 // EMIT branch-on-cond vp<%at.cond.0>
4918 // Successor(s): vector.early.exit.0, vector.early.exit.check.0
4919 //
4920 // vector.early.exit.check.0:
4921 // EMIT vp<%at.cond.1> = extract-lane vp<%first.lane>, vp<%cond.1>
4922 // EMIT branch-on-cond vp<%at.cond.1>
4923 // Successor(s): vector.early.exit.1, vector.early.exit.2
4924 VPBasicBlock *CurrentBB = DispatchVPBB;
4925 for (auto [I, Exit] : enumerate(ArrayRef(Exits).drop_back())) {
4926 VPValue *LaneVal = DispatchBuilder.createNaryOp(
4927 VPInstruction::ExtractLane, {FirstActiveLane, Exit.CondToExit},
4928 DebugLoc::getUnknown(), "exit.cond.at.lane");
4929
4930 // For the last dispatch, branch directly to the last exit on false;
4931 // otherwise, create a new check block.
4932 bool IsLastDispatch = (I + 2 == Exits.size());
4933 VPBasicBlock *FalseBB =
4934 IsLastDispatch ? VectorEarlyExitVPBBs.back()
4935 : Plan.createVPBasicBlock(
4936 Twine("vector.early.exit.check.") + Twine(I));
4937
4938 DispatchBuilder.createNaryOp(VPInstruction::BranchOnCond, {LaneVal});
4939 CurrentBB->setSuccessors({VectorEarlyExitVPBBs[I], FalseBB});
4940 VectorEarlyExitVPBBs[I]->setPredecessors({CurrentBB});
4941 FalseBB->setPredecessors({CurrentBB});
4942
4943 CurrentBB = FalseBB;
4944 DispatchBuilder.setInsertPoint(CurrentBB);
4945 }
4946
4947 return true;
4948}
4949
4950/// This function tries convert extended in-loop reductions to
4951/// VPExpressionRecipe and clamp the \p Range if it is beneficial and
4952/// valid. The created recipe must be decomposed to its constituent
4953/// recipes before execution.
4954static VPExpressionRecipe *
4956 VFRange &Range) {
4957 Type *RedTy = Red->getScalarType();
4958 VPValue *VecOp = Red->getVecOp();
4959
4960 assert(!Red->isPartialReduction() &&
4961 "This path does not support partial reductions");
4962
4963 // Clamp the range if using extended-reduction is profitable.
4964 auto IsExtendedRedValidAndClampRange =
4965 [&](unsigned Opcode, Instruction::CastOps ExtOpc, Type *SrcTy) -> bool {
4967 [&](ElementCount VF) {
4968 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
4970
4972 InstructionCost ExtCost =
4973 cast<VPWidenCastRecipe>(VecOp)->computeCost(VF, Ctx);
4974 InstructionCost RedCost = Red->computeCost(VF, Ctx);
4975
4976 assert(!RedTy->isFloatingPointTy() &&
4977 "getExtendedReductionCost only supports integer types");
4978 ExtRedCost = Ctx.TTI.getExtendedReductionCost(
4979 Opcode, ExtOpc == Instruction::CastOps::ZExt, RedTy, SrcVecTy,
4980 Red->getFastMathFlagsOrNone(), CostKind);
4981 return ExtRedCost.isValid() && ExtRedCost < ExtCost + RedCost;
4982 },
4983 Range);
4984 };
4985
4986 VPValue *A;
4987 // Match reduce(ext)).
4989 IsExtendedRedValidAndClampRange(
4990 RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind()),
4991 cast<VPWidenCastRecipe>(VecOp)->getOpcode(), A->getScalarType()))
4992 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
4993
4994 return nullptr;
4995}
4996
4997/// This function tries convert extended in-loop reductions to
4998/// VPExpressionRecipe and clamp the \p Range if it is beneficial
4999/// and valid. The created VPExpressionRecipe must be decomposed to its
5000/// constituent recipes before execution. Patterns of the
5001/// VPExpressionRecipe:
5002/// reduce.add(mul(...)),
5003/// reduce.add(mul(ext(A), ext(B))),
5004/// reduce.add(ext(mul(ext(A), ext(B)))).
5005/// reduce.fadd(fmul(ext(A), ext(B)))
5006static VPExpressionRecipe *
5008 VPCostContext &Ctx, VFRange &Range) {
5009 unsigned Opcode = RecurrenceDescriptor::getOpcode(Red->getRecurrenceKind());
5010 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
5011 Opcode != Instruction::FAdd)
5012 return nullptr;
5013
5014 assert(!Red->isPartialReduction() &&
5015 "This path does not support partial reductions");
5016 Type *RedTy = Red->getScalarType();
5017
5018 // Clamp the range if using multiply-accumulate-reduction is profitable.
5019 auto IsMulAccValidAndClampRange =
5021 VPWidenCastRecipe *OuterExt) -> bool {
5023 [&](ElementCount VF) {
5025 Type *SrcTy = Ext0 ? Ext0->getOperand(0)->getScalarType() : RedTy;
5026 InstructionCost MulAccCost;
5027
5028 // getMulAccReductionCost for in-loop reductions does not support
5029 // mixed or floating-point extends.
5030 if (Ext0 && Ext1 &&
5031 (Ext0->getOpcode() != Ext1->getOpcode() ||
5032 Ext0->getOpcode() == Instruction::CastOps::FPExt))
5033 return false;
5034
5035 bool IsZExt =
5036 !Ext0 || Ext0->getOpcode() == Instruction::CastOps::ZExt;
5037 auto *SrcVecTy = cast<VectorType>(toVectorTy(SrcTy, VF));
5038 MulAccCost = Ctx.TTI.getMulAccReductionCost(IsZExt, Opcode, RedTy,
5039 SrcVecTy, CostKind);
5040
5041 InstructionCost MulCost = Mul->computeCost(VF, Ctx);
5042 InstructionCost RedCost = Red->computeCost(VF, Ctx);
5043 InstructionCost ExtCost = 0;
5044 if (Ext0)
5045 ExtCost += Ext0->computeCost(VF, Ctx);
5046 if (Ext1)
5047 ExtCost += Ext1->computeCost(VF, Ctx);
5048 if (OuterExt)
5049 ExtCost += OuterExt->computeCost(VF, Ctx);
5050
5051 return MulAccCost.isValid() &&
5052 MulAccCost < ExtCost + MulCost + RedCost;
5053 },
5054 Range);
5055 };
5056
5057 VPValue *VecOp = Red->getVecOp();
5058 VPRecipeBase *Sub = nullptr;
5059 VPValue *A, *B;
5060 VPValue *Tmp = nullptr;
5061
5062 if (RedTy->isFloatingPointTy())
5063 return nullptr;
5064
5065 // Sub reductions could have a sub between the add reduction and vec op.
5066 if (match(VecOp, m_Sub(m_ZeroInt(), m_VPValue(Tmp)))) {
5067 Sub = VecOp->getDefiningRecipe();
5068 VecOp = Tmp;
5069 }
5070
5071 // If ValB is a constant and can be safely extended, truncate it to the same
5072 // type as ExtA's operand, then extend it to the same type as ExtA. This
5073 // creates two uniform extends that can more easily be matched by the rest of
5074 // the bundling code. The ExtB reference, ValB and operand 1 of Mul are all
5075 // replaced with the new extend of the constant.
5076 auto ExtendAndReplaceConstantOp = [](VPWidenCastRecipe *ExtA,
5077 VPWidenCastRecipe *&ExtB, VPValue *&ValB,
5078 VPWidenRecipe *Mul) {
5079 if (!ExtA || ExtB || !isa<VPIRValue>(ValB))
5080 return;
5081 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
5082 Instruction::CastOps ExtOpc = ExtA->getOpcode();
5083 const APInt *Const;
5084 if (!match(ValB, m_APInt(Const)) ||
5086 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
5087 return;
5088 // The truncate ensures that the type of each extended operand is the
5089 // same, and it's been proven that the constant can be extended from
5090 // NarrowTy safely. Necessary since ExtA's extended operand would be
5091 // e.g. an i8, while the const will likely be an i32. This will be
5092 // elided by later optimisations.
5093 VPBuilder Builder(Mul);
5094 auto *Trunc =
5095 Builder.createWidenCast(Instruction::CastOps::Trunc, ValB, NarrowTy);
5096 Type *WideTy = ExtA->getScalarType();
5097 ValB = ExtB = Builder.createWidenCast(ExtOpc, Trunc, WideTy);
5098 Mul->setOperand(1, ExtB);
5099 };
5100
5101 // Try to match reduce.add(mul(...)).
5102 if (match(VecOp, m_Mul(m_VPValue(A), m_VPValue(B)))) {
5103 auto *RecipeA = dyn_cast<VPWidenCastRecipe>(A);
5104 auto *RecipeB = dyn_cast<VPWidenCastRecipe>(B);
5105 auto *Mul = cast<VPWidenRecipe>(VecOp);
5106
5107 // Convert reduce.add(mul(ext, const)) to reduce.add(mul(ext, ext(const)))
5108 ExtendAndReplaceConstantOp(RecipeA, RecipeB, B, Mul);
5109
5110 // Match reduce.add/sub(mul(ext, ext)).
5111 if (RecipeA && RecipeB && match(RecipeA, m_ZExtOrSExt(m_VPValue())) &&
5112 match(RecipeB, m_ZExtOrSExt(m_VPValue())) &&
5113 IsMulAccValidAndClampRange(Mul, RecipeA, RecipeB, nullptr)) {
5114 if (Sub)
5115 return new VPExpressionRecipe(RecipeA, RecipeB, Mul,
5116 cast<VPWidenRecipe>(Sub), Red);
5117 return new VPExpressionRecipe(RecipeA, RecipeB, Mul, Red);
5118 }
5119 // TODO: Add an expression type for this variant with a negated mul
5120 if (!Sub && IsMulAccValidAndClampRange(Mul, nullptr, nullptr, nullptr))
5121 return new VPExpressionRecipe(Mul, Red);
5122 }
5123 // TODO: Add an expression type for negated versions of other expression
5124 // variants.
5125 if (Sub)
5126 return nullptr;
5127
5128 // Match reduce.add(ext(mul(A, B))).
5129 if (match(VecOp, m_ZExtOrSExt(m_Mul(m_VPValue(A), m_VPValue(B))))) {
5130 auto *Ext = cast<VPWidenCastRecipe>(VecOp);
5131 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
5132 auto *Ext0 = dyn_cast<VPWidenCastRecipe>(A);
5133 auto *Ext1 = dyn_cast<VPWidenCastRecipe>(B);
5134
5135 // reduce.add(ext(mul(ext, const)))
5136 // -> reduce.add(ext(mul(ext, ext(const))))
5137 ExtendAndReplaceConstantOp(Ext0, Ext1, B, Mul);
5138
5139 // reduce.add(ext(mul(ext(A), ext(B))))
5140 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
5141 // The inner extends must either have the same opcode as the outer extend or
5142 // be the same, in which case the multiply can never result in a negative
5143 // value and the outer extend can be folded away by doing wider
5144 // extends for the operands of the mul.
5145 if (Ext0 && Ext1 &&
5146 (Ext->getOpcode() == Ext0->getOpcode() || Ext0 == Ext1) &&
5147 Ext0->getOpcode() == Ext1->getOpcode() &&
5148 IsMulAccValidAndClampRange(Mul, Ext0, Ext1, Ext) && Mul->hasOneUse()) {
5149 auto *NewExt0 = new VPWidenCastRecipe(
5150 Ext0->getOpcode(), Ext0->getOperand(0), Ext->getScalarType(), nullptr,
5151 *Ext0, *Ext0, Ext0->getDebugLoc());
5152 NewExt0->insertBefore(Ext0);
5153
5154 VPWidenCastRecipe *NewExt1 = NewExt0;
5155 if (Ext0 != Ext1) {
5156 NewExt1 = new VPWidenCastRecipe(Ext1->getOpcode(), Ext1->getOperand(0),
5157 Ext->getScalarType(), nullptr, *Ext1,
5158 *Ext1, Ext1->getDebugLoc());
5159 NewExt1->insertBefore(Ext1);
5160 }
5161 auto *NewMul = Mul->cloneWithOperands({NewExt0, NewExt1});
5162 NewMul->insertBefore(Mul);
5163 Ext->replaceAllUsesWith(NewMul);
5164 Ext->eraseFromParent();
5165 Mul->eraseFromParent();
5166 return new VPExpressionRecipe(NewExt0, NewExt1, NewMul, Red);
5167 }
5168 }
5169 return nullptr;
5170}
5171
5172/// This function tries to create abstract recipes from the reduction recipe for
5173/// following optimizations and cost estimation.
5175 VPCostContext &Ctx,
5176 VFRange &Range) {
5177 // Creation of VPExpressions for partial reductions is entirely handled in
5178 // transformToPartialReduction.
5179 assert(!Red->isPartialReduction() &&
5180 "This path does not support partial reductions");
5181
5182 VPExpressionRecipe *AbstractR = nullptr;
5183 auto IP = std::next(Red->getIterator());
5184 auto *VPBB = Red->getParent();
5185 if (auto *MulAcc = tryToMatchAndCreateMulAccumulateReduction(Red, Ctx, Range))
5186 AbstractR = MulAcc;
5187 else if (auto *ExtRed = tryToMatchAndCreateExtendedReduction(Red, Ctx, Range))
5188 AbstractR = ExtRed;
5189 // Cannot create abstract inloop reduction recipes.
5190 if (!AbstractR)
5191 return;
5192
5193 AbstractR->insertBefore(*VPBB, IP);
5194 Red->replaceAllUsesWith(AbstractR);
5195}
5196
5207
5209 if (Plan.hasScalarVFOnly())
5210 return;
5211
5212#ifndef NDEBUG
5213 VPDominatorTree VPDT(Plan);
5214#endif
5215
5216 SmallVector<VPValue *> VPValues;
5217 if (VPValue *BTC = Plan.getBackedgeTakenCount())
5218 VPValues.push_back(BTC);
5219 append_range(VPValues, Plan.getLiveIns());
5220 for (VPRecipeBase &R : *Plan.getEntry())
5221 append_range(VPValues, R.definedValues());
5222
5223 auto *VectorPreheader = Plan.getVectorPreheader();
5224 for (VPValue *VPV : VPValues) {
5226 continue;
5227
5228 // Add explicit broadcast at the insert point that dominates all users.
5229 VPBasicBlock *HoistBlock = VectorPreheader;
5230 VPBasicBlock::iterator HoistPoint = VectorPreheader->end();
5231 for (VPUser *User : VPV->users()) {
5232 if (User->usesScalars(VPV))
5233 continue;
5234 if (cast<VPRecipeBase>(User)->getParent() == VectorPreheader)
5235 HoistPoint = HoistBlock->begin();
5236 else
5237 assert(VPDT.dominates(VectorPreheader,
5238 cast<VPRecipeBase>(User)->getParent()) &&
5239 "All users must be in the vector preheader or dominated by it");
5240 }
5241
5242 VPBuilder Builder(cast<VPBasicBlock>(HoistBlock), HoistPoint);
5243 auto *Broadcast = Builder.createNaryOp(VPInstruction::Broadcast, {VPV});
5244 VPV->replaceUsesWithIf(Broadcast,
5245 [VPV, Broadcast](VPUser &U, unsigned Idx) {
5246 return Broadcast != &U && !U.usesScalars(VPV);
5247 });
5248 }
5249}
5250
5251// Collect common metadata from a group of replicate recipes by intersecting
5252// metadata from all recipes in the group.
5254 VPIRMetadata CommonMetadata = *Recipes.front();
5255 for (VPReplicateRecipe *Recipe : drop_begin(Recipes))
5256 CommonMetadata.intersect(*Recipe);
5257 return CommonMetadata;
5258}
5259
5260template <unsigned Opcode>
5264 const Loop *L) {
5265 static_assert(Opcode == Instruction::Load || Opcode == Instruction::Store,
5266 "Only Load and Store opcodes supported");
5267 [[maybe_unused]] constexpr bool IsLoad = (Opcode == Instruction::Load);
5268
5269 // For each address, collect operations with the same or complementary masks.
5272 Plan, PSE, L,
5273 [](VPReplicateRecipe *RepR) { return RepR->isPredicated(); });
5274 for (auto Recipes : Groups) {
5275 if (Recipes.size() < 2)
5276 continue;
5277
5279 map_range(Recipes, bind_back<getLoadStoreValueType>(IsLoad))) &&
5280 "Expected all recipes in group to have the same load-store type");
5281
5282 // Collect groups with the same or complementary masks.
5283 for (VPReplicateRecipe *&RecipeI : Recipes) {
5284 if (!RecipeI)
5285 continue;
5286
5287 VPValue *MaskI = RecipeI->getMask();
5289 Group.push_back(RecipeI);
5290 RecipeI = nullptr;
5291
5292 // Find all operations with the same or complementary masks.
5293 bool HasComplementaryMask = false;
5294 for (VPReplicateRecipe *&RecipeJ : Recipes) {
5295 if (!RecipeJ)
5296 continue;
5297
5298 VPValue *MaskJ = RecipeJ->getMask();
5299 // Check if any operation in the group has a complementary mask with
5300 // another, that is M1 == NOT(M2) or M2 == NOT(M1).
5301 HasComplementaryMask |= match(MaskI, m_Not(m_Specific(MaskJ))) ||
5302 match(MaskJ, m_Not(m_Specific(MaskI)));
5303 Group.push_back(RecipeJ);
5304 RecipeJ = nullptr;
5305 }
5306
5307 if (HasComplementaryMask) {
5308 assert(Group.size() >= 2 && "must have at least 2 entries");
5309 AllGroups.push_back(std::move(Group));
5310 }
5311 }
5312 }
5313
5314 return AllGroups;
5315}
5316
5317// Find the recipe with minimum alignment in the group.
5318template <typename InstType>
5319static VPReplicateRecipe *
5321 return *min_element(Group, [](VPReplicateRecipe *A, VPReplicateRecipe *B) {
5322 return cast<InstType>(A->getUnderlyingInstr())->getAlign() <
5323 cast<InstType>(B->getUnderlyingInstr())->getAlign();
5324 });
5325}
5326
5329 const Loop *L) {
5330 auto Groups =
5332 if (Groups.empty())
5333 return;
5334
5335 // Process each group of loads.
5336 for (auto &Group : Groups) {
5337 // Try to use the earliest (most dominating) load to replace all others.
5338 VPReplicateRecipe *EarliestLoad = Group[0];
5339 VPBasicBlock *FirstBB = EarliestLoad->getParent();
5340 VPBasicBlock *LastBB = Group.back()->getParent();
5341
5342 // Check that the load doesn't alias with stores between first and last.
5343 auto LoadLoc = vputils::getMemoryLocation(*EarliestLoad);
5344 if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck(*LoadLoc, FirstBB, LastBB))
5345 continue;
5346
5347 // Collect common metadata from all loads in the group.
5348 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
5349
5350 // Find the load with minimum alignment to use.
5351 auto *LoadWithMinAlign = findRecipeWithMinAlign<LoadInst>(Group);
5352
5353 bool IsSingleScalar = EarliestLoad->isSingleScalar();
5354 assert(all_of(Group,
5355 [IsSingleScalar](VPReplicateRecipe *R) {
5356 return R->isSingleScalar() == IsSingleScalar;
5357 }) &&
5358 "all members in group must agree on IsSingleScalar");
5359
5360 // Create an unpredicated version of the earliest load with common
5361 // metadata.
5362 auto *UnpredicatedLoad = new VPReplicateRecipe(
5363 LoadWithMinAlign->getUnderlyingInstr(), {EarliestLoad->getOperand(0)},
5364 IsSingleScalar, /*Mask=*/nullptr, *EarliestLoad, CommonMetadata);
5365
5366 UnpredicatedLoad->insertBefore(EarliestLoad);
5367
5368 // Replace all loads in the group with the unpredicated load.
5369 for (VPReplicateRecipe *Load : Group) {
5370 Load->replaceAllUsesWith(UnpredicatedLoad);
5371 Load->eraseFromParent();
5372 }
5373 }
5374}
5375
5376static bool
5378 PredicatedScalarEvolution &PSE, const Loop &L) {
5379 auto StoreLoc = vputils::getMemoryLocation(*StoresToSink.front());
5380 if (!StoreLoc || !StoreLoc->AATags.Scope)
5381 return false;
5382
5383 // When sinking a group of stores, all members of the group alias each other.
5384 // Skip them during the alias checks.
5385 VPBasicBlock *FirstBB = StoresToSink.front()->getParent();
5386 VPBasicBlock *LastBB = StoresToSink.back()->getParent();
5387 SinkStoreInfo SinkInfo(StoresToSink, *StoresToSink[0], PSE, L);
5388 return canHoistOrSinkWithNoAliasCheck(*StoreLoc, FirstBB, LastBB, SinkInfo);
5389}
5390
5393 const Loop *L) {
5394 auto Groups =
5396 if (Groups.empty())
5397 return;
5398
5399 for (auto &Group : Groups) {
5400 if (!canSinkStoreWithNoAliasCheck(Group, PSE, *L))
5401 continue;
5402
5403 // Use the last (most dominated) store's location for the unconditional
5404 // store.
5405 VPReplicateRecipe *LastStore = Group.back();
5406 VPBasicBlock *InsertBB = LastStore->getParent();
5407
5408 // Collect common alias metadata from all stores in the group.
5409 VPIRMetadata CommonMetadata = getCommonMetadata(Group);
5410
5411 // Build select chain for stored values.
5412 VPValue *SelectedValue = Group[0]->getOperand(0);
5413 VPBuilder Builder(InsertBB, LastStore->getIterator());
5414
5415 bool IsSingleScalar = Group[0]->isSingleScalar();
5416 for (unsigned I = 1; I < Group.size(); ++I) {
5417 assert(IsSingleScalar == Group[I]->isSingleScalar() &&
5418 "all members in group must agree on IsSingleScalar");
5419 VPValue *Mask = Group[I]->getMask();
5420 VPValue *Value = Group[I]->getOperand(0);
5421 SelectedValue = Builder.createSelect(Mask, Value, SelectedValue,
5422 Group[I]->getDebugLoc());
5423 }
5424
5425 // Find the store with minimum alignment to use.
5426 auto *StoreWithMinAlign = findRecipeWithMinAlign<StoreInst>(Group);
5427
5428 // Create unconditional store with selected value and common metadata.
5429 auto *UnpredicatedStore = new VPReplicateRecipe(
5430 StoreWithMinAlign->getUnderlyingInstr(),
5431 {SelectedValue, LastStore->getOperand(1)}, IsSingleScalar,
5432 /*Mask=*/nullptr, *LastStore, CommonMetadata);
5433 UnpredicatedStore->insertBefore(*InsertBB, LastStore->getIterator());
5434
5435 // Remove all predicated stores from the group.
5436 for (VPReplicateRecipe *Store : Group)
5437 Store->eraseFromParent();
5438 }
5439}
5440
5442 VPlan &Plan, ElementCount BestVF, unsigned BestUF,
5444 assert(Plan.hasVF(BestVF) && "BestVF is not available in Plan");
5445 assert(Plan.hasUF(BestUF) && "BestUF is not available in Plan");
5446
5447 VPValue *TC = Plan.getTripCount();
5448 if (TC->user_empty())
5449 return;
5450
5451 // Skip cases for which the trip count may be non-trivial to materialize.
5452 // I.e., when a scalar tail is absent - due to tail folding, or when a scalar
5453 // tail is required.
5454 if (Plan.hasTailFolded() || !Plan.hasScalarTail() ||
5456 Plan.getScalarPreheader() ||
5457 !isa<VPIRValue>(TC))
5458 return;
5459
5460 // Materialize vector trip counts for constants early if it can simply
5461 // be computed as (Original TC / VF * UF) * VF * UF.
5462 // TODO: Compute vector trip counts for loops requiring a scalar epilogue and
5463 // tail-folded loops.
5464 ScalarEvolution &SE = *PSE.getSE();
5465 auto *TCScev = SE.getSCEV(TC->getLiveInIRValue());
5466 if (!isa<SCEVConstant>(TCScev))
5467 return;
5468 const SCEV *VFxUF = SE.getElementCount(TCScev->getType(), BestVF * BestUF);
5469 auto VecTCScev = SE.getMulExpr(SE.getUDivExpr(TCScev, VFxUF), VFxUF);
5470 if (auto *ConstVecTC = dyn_cast<SCEVConstant>(VecTCScev))
5471 Plan.getVectorTripCount().setUnderlyingValue(ConstVecTC->getValue());
5472}
5473
5475 VPBasicBlock *VectorPH) {
5477 if (BTC->user_empty())
5478 return;
5479
5480 VPBuilder Builder(VectorPH, VectorPH->begin());
5481 auto *TCTy = Plan.getTripCount()->getScalarType();
5482 auto *TCMO =
5483 Builder.createSub(Plan.getTripCount(), Plan.getConstantInt(TCTy, 1),
5484 DebugLoc::getCompilerGenerated(), "trip.count.minus.1");
5485 BTC->replaceAllUsesWith(TCMO);
5486}
5487
5489 if (Plan.hasScalarVFOnly())
5490 return;
5491
5492 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
5493 auto VPBBsOutsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
5495 auto VPBBsInsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
5496 vp_depth_first_shallow(LoopRegion->getEntry()));
5497 // Materialize Build(Struct)Vector for all replicating VPReplicateRecipes,
5498 // VPScalarIVStepsRecipe and VPInstructions, excluding ones in replicate
5499 // regions. Those are not materialized explicitly yet.
5500 // TODO: materialize build vectors for replicating recipes in replicating
5501 // regions.
5502 for (VPBasicBlock *VPBB :
5503 concat<VPBasicBlock *>(VPBBsOutsideLoopRegion, VPBBsInsideLoopRegion)) {
5504 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
5506 continue;
5507 auto *DefR = cast<VPSingleDefRecipe>(&R);
5508 auto UsesVectorOrInsideReplicateRegion = [DefR, LoopRegion](VPUser *U) {
5509 VPRegionBlock *ParentRegion = cast<VPRecipeBase>(U)->getRegion();
5510 return !U->usesScalars(DefR) || ParentRegion != LoopRegion;
5511 };
5512 if ((isa<VPReplicateRecipe>(DefR) &&
5513 cast<VPReplicateRecipe>(DefR)->isSingleScalar()) ||
5514 (isa<VPInstruction>(DefR) &&
5516 !cast<VPInstruction>(DefR)->doesGeneratePerAllLanes())) ||
5517 none_of(DefR->users(), UsesVectorOrInsideReplicateRegion))
5518 continue;
5519
5520 Type *ScalarTy = DefR->getScalarType();
5521 unsigned Opcode = ScalarTy->isStructTy()
5524 auto *BuildVector = new VPInstruction(Opcode, {DefR});
5525 BuildVector->insertAfter(DefR);
5526
5527 DefR->replaceUsesWithIf(
5528 BuildVector, [BuildVector, &UsesVectorOrInsideReplicateRegion](
5529 VPUser &U, unsigned) {
5530 return &U != BuildVector && UsesVectorOrInsideReplicateRegion(&U);
5531 });
5532 }
5533 }
5534
5535 // Create explicit VPInstructions to convert vectors to scalars. The current
5536 // implementation is conservative - it may miss some cases that may or may not
5537 // be vector values. TODO: introduce Unpacks speculatively - remove them later
5538 // if they are known to operate on scalar values.
5539 for (VPBasicBlock *VPBB : VPBBsInsideLoopRegion) {
5540 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
5542 VPDerivedIVRecipe>(&R))
5543 continue;
5544 for (VPValue *Def : R.definedValues()) {
5545 // Skip recipes that are single-scalar.
5546 // TODO: The Defs skipped here may or may not be vector values.
5547 // Introduce Unpacks, and remove them later, if they are guaranteed to
5548 // produce scalar values.
5549 if (vputils::isSingleScalar(Def))
5550 continue;
5551
5552 // Only introduce an Unpack if some, but not all, users use the first
5553 // lane only.
5554 unsigned NumFirstLaneUsers = count_if(Def->users(), [&Def](VPUser *U) {
5555 return U->usesFirstLaneOnly(Def);
5556 });
5557 if (!NumFirstLaneUsers || NumFirstLaneUsers == Def->getNumUsers())
5558 continue;
5559
5560 auto *Unpack = new VPInstruction(VPInstruction::Unpack, {Def});
5561 if (R.isPhi())
5562 Unpack->insertBefore(*VPBB, VPBB->getFirstNonPhi());
5563 else
5564 Unpack->insertAfter(&R);
5565 Def->replaceUsesWithIf(Unpack, [&Def](VPUser &U, unsigned) {
5566 return U.usesFirstLaneOnly(Def);
5567 });
5568 }
5569 }
5570 }
5571}
5572
5574 VPlan &Plan, VPBasicBlock *VectorPHVPBB, bool TailByMasking,
5575 bool RequiresScalarEpilogue, VPValue *Step,
5576 std::optional<uint64_t> MaxRuntimeStep) {
5577 VPSymbolicValue &VectorTC = Plan.getVectorTripCount();
5578 // There's nothing to do if there are no users of the vector trip count or its
5579 // IR value has already been set.
5580 if (VectorTC.user_empty() || VectorTC.getUnderlyingValue())
5581 return;
5582
5583 VPValue *TC = Plan.getTripCount();
5584 Type *TCTy = TC->getScalarType();
5585 VPBasicBlock::iterator InsertPt = VectorPHVPBB->begin();
5586 if (auto *StepR = Step->getDefiningRecipe()) {
5587 assert(VPDominatorTree(Plan).dominates(StepR->getParent(), VectorPHVPBB) &&
5588 "Step VPBB must dominate VectorPHVPBB");
5589 // Insert after Step's definition to maintain valid def-use ordering.
5590 InsertPt = std::next(StepR->getIterator());
5591 }
5592 VPBuilder Builder(VectorPHVPBB, InsertPt);
5593
5594 // For scalable steps, if TC is a constant and is divisible by the maximum
5595 // possible runtime step, then TC % Step == 0 for all valid vscale values
5596 // and the vector trip count equals TC directly.
5597 const APInt *TCVal;
5598 if (!RequiresScalarEpilogue && match(TC, m_APInt(TCVal)) && MaxRuntimeStep &&
5599 TCVal->urem(*MaxRuntimeStep) == 0) {
5600 VectorTC.replaceAllUsesWith(TC);
5601 return;
5602 }
5603
5604 // If the tail is to be folded by masking, round the number of iterations N
5605 // up to a multiple of Step instead of rounding down. This is done by first
5606 // adding Step-1 and then rounding down. Note that it's ok if this addition
5607 // overflows: the vector induction variable will eventually wrap to zero given
5608 // that it starts at zero and its Step is a power of two; the loop will then
5609 // exit, with the last early-exit vector comparison also producing all-true.
5610 if (TailByMasking) {
5611 TC = Builder.createAdd(
5612 TC, Builder.createSub(Step, Plan.getConstantInt(TCTy, 1)),
5613 DebugLoc::getCompilerGenerated(), "n.rnd.up");
5614 }
5615
5616 // Now we need to generate the expression for the part of the loop that the
5617 // vectorized body will execute. This is equal to N - (N % Step) if scalar
5618 // iterations are not required for correctness, or N - Step, otherwise. Step
5619 // is equal to the vectorization factor (number of SIMD elements) times the
5620 // unroll factor (number of SIMD instructions).
5621 VPValue *R =
5622 Builder.createNaryOp(Instruction::URem, {TC, Step},
5623 DebugLoc::getCompilerGenerated(), "n.mod.vf");
5624
5625 // There are cases where we *must* run at least one iteration in the remainder
5626 // loop. See the cost model for when this can happen. If the step evenly
5627 // divides the trip count, we set the remainder to be equal to the step. If
5628 // the step does not evenly divide the trip count, no adjustment is necessary
5629 // since there will already be scalar iterations. Note that the minimum
5630 // iterations check ensures that N >= Step.
5631 if (RequiresScalarEpilogue) {
5632 assert(!TailByMasking &&
5633 "requiring scalar epilogue is not supported with fail folding");
5634 VPValue *IsZero =
5635 Builder.createICmp(CmpInst::ICMP_EQ, R, Plan.getZero(TCTy));
5636 R = Builder.createSelect(IsZero, Step, R);
5637 }
5638
5639 VPValue *Res =
5640 Builder.createSub(TC, R, DebugLoc::getCompilerGenerated(), "n.vec");
5641 VectorTC.replaceAllUsesWith(Res);
5642}
5643
5645 ElementCount VFEC) {
5646 // If VF and VFxUF have already been materialized (no remaining users),
5647 // there's nothing more to do.
5648 if (Plan.getVF().isMaterialized()) {
5649 assert(Plan.getVFxUF().isMaterialized() &&
5650 "VF and VFxUF must be materialized together");
5651 return;
5652 }
5653
5654 VPBuilder Builder(VectorPH, VectorPH->begin());
5655 Type *TCTy = Plan.getTripCount()->getScalarType();
5656 VPValue &VF = Plan.getVF();
5657 VPValue &VFxUF = Plan.getVFxUF();
5658 // If there are no users of the runtime VF, compute VFxUF by constant folding
5659 // the multiplication of VF and UF.
5660 if (VF.user_empty()) {
5661 VPValue *RuntimeVFxUF =
5662 Builder.createElementCount(TCTy, VFEC * Plan.getConcreteUF());
5663 VFxUF.replaceAllUsesWith(RuntimeVFxUF);
5664 return;
5665 }
5666
5667 // For users of the runtime VF, compute it as VF * vscale, and VFxUF as (VF *
5668 // vscale) * UF.
5669 VPValue *RuntimeVF = Builder.createElementCount(TCTy, VFEC);
5671 VPValue *BC = Builder.createNaryOp(VPInstruction::Broadcast, RuntimeVF);
5673 BC, [&VF](VPUser &U, unsigned) { return !U.usesScalars(&VF); });
5674 }
5675 VF.replaceAllUsesWith(RuntimeVF);
5676
5677 VPValue *MulByUF = Builder.createOverflowingOp(
5678 Instruction::Mul,
5679 {RuntimeVF, Plan.getConstantInt(TCTy, Plan.getConcreteUF())},
5680 {true, false});
5681 VFxUF.replaceAllUsesWith(MulByUF);
5682}
5683
5685 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
5686 VPValue *HeaderMask = LoopRegion->getHeaderMask();
5687 Type *I1Ty = IntegerType::getInt1Ty(Plan.getContext());
5688
5689 VPBuilder Builder(Plan.getVectorPreheader());
5690 auto *AliasMask = Builder.createNaryOp(
5691 VPInstruction::IncomingAliasMask, {}, nullptr, {}, {},
5692 DebugLoc::getUnknown(), "incoming.alias.mask", I1Ty);
5693
5694 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
5695 Builder = VPBuilder(Header, Header->getFirstNonPhi());
5696
5697 // Update all existing users of the header mask to "HeaderMask & AliasMask".
5698 auto *ClampedHeaderMask = Builder.createAnd(HeaderMask, AliasMask);
5699 HeaderMask->replaceUsesWithIf(ClampedHeaderMask, [&](VPUser &U, unsigned) {
5700 return &U != ClampedHeaderMask;
5701 });
5702}
5703
5704VPValue *
5706 ArrayRef<PointerDiffInfo> DiffChecks) {
5707 VPBuilder Builder(AliasCheckVPBB);
5708 Type *I1Ty = IntegerType::getInt1Ty(Plan.getContext());
5709
5710 VPValue *IncomingAliasMask = vputils::findIncomingAliasMask(Plan);
5711 assert(IncomingAliasMask && "Expected an alias mask!");
5712
5713 VPValue *AliasMask = nullptr;
5714 for (const PointerDiffInfo &Check : DiffChecks) {
5716 VPValue *Sink =
5718 Type *AddrType = Src->getScalarType();
5719
5720 // TODO: Only freeze the required pointer (not both src and sink).
5721 if (Check.NeedsFreeze) {
5722 Src = Builder.createScalarFreeze(Src, AddrType, DebugLoc::getUnknown());
5723 Sink = Builder.createScalarFreeze(Sink, AddrType, DebugLoc::getUnknown());
5724 }
5725
5726 // TODO: Generate loop_dependence_raw_mask when there's a read-after-write
5727 // dependency between the source and the sink. This is not necessary for
5728 // correctness of the mask, but using the "raw" variant prevents loads
5729 // depending on the completion of stores.
5730 VPWidenIntrinsicRecipe *WARMask = Builder.insert(new VPWidenIntrinsicRecipe(
5731 Intrinsic::loop_dependence_war_mask,
5732 {Src, Sink, Plan.getConstantInt(AddrType, Check.AccessSize)}, I1Ty));
5733
5734 if (AliasMask)
5735 AliasMask = Builder.createAnd(AliasMask, WARMask);
5736 else
5737 AliasMask = WARMask;
5738 }
5739
5741 Type *IndexTy = Plan.getDataLayout().getIndexType(Plan.getContext(), 0);
5742 VPValue *NumActive = Builder.createNaryOp(
5743 VPInstruction::NumActiveLanes, {AliasMask}, nullptr, {}, {},
5744 DebugLoc::getUnknown(), "num.active.lanes", IndexTy);
5745 VPValue *ClampedVF = Builder.createScalarZExtOrTrunc(
5746 NumActive, IVTy, IndexTy, DebugLoc::getCompilerGenerated());
5747
5748 IncomingAliasMask->replaceAllUsesWith(AliasMask);
5749
5750 return ClampedVF;
5751}
5752
5754 VPlan &Plan, ArrayRef<PointerDiffInfo> DiffChecks, bool HasBranchWeights) {
5755 VPBasicBlock *ClampedVFCheck =
5756 Plan.createVPBasicBlock("vector.clamped.vf.check");
5757
5758 VPValue *ClampedVF = materializeAliasMask(Plan, ClampedVFCheck, DiffChecks);
5759 VPBuilder Builder(ClampedVFCheck);
5761 Type *TCTy = Plan.getTripCount()->getScalarType();
5762
5763 // Check the "ClampedVF" from the alias mask is larger than one.
5764 VPValue *IsScalar =
5765 Builder.createICmp(CmpInst::ICMP_ULE, ClampedVF,
5766 Plan.getConstantInt(TCTy, 1), DL, "vf.is.scalar");
5767
5768 VPValue *TripCount = Plan.getTripCount();
5769 VPValue *MaxUIntTripCount =
5771 VPValue *DistanceToMax = Builder.createSub(MaxUIntTripCount, TripCount);
5772
5773 // For tail-folding: Don't execute the vector loop if (UMax - n) < ClampedVF.
5774 // Note: The ClampedVF may not be a power-of-two. This means the loop exit
5775 // condition (index.next == n.vec) may not be correct in the case of an
5776 // overflow. The issue is `n.vec` could be zero due to an overflow, but
5777 // index.next is not guaranteed to overflow to zero as the ClampedVF is not a
5778 // power-of-two).
5779 VPValue *TripCountCheck = Builder.createICmp(
5780 ICmpInst::ICMP_ULT, DistanceToMax, ClampedVF, DL, "vf.step.overflow");
5781
5782 VPValue *Cond = Builder.createOr(IsScalar, TripCountCheck, DL);
5783 attachVPCheckBlock(Plan, Cond, ClampedVFCheck, HasBranchWeights);
5784
5785 // Materialize the trip count early as this will add a use of (VFxUF) that
5786 // needs to be replaced with the ClampedVF.
5788 /*TailByMasking=*/true,
5789 /*RequiresScalarEpilogue=*/false,
5790 &Plan.getVFxUF());
5791
5792 assert(Plan.getConcreteUF() == 1 &&
5793 "Clamped VF not supported with interleaving");
5794 Plan.getVF().replaceAllUsesWith(ClampedVF);
5795 Plan.getVFxUF().replaceAllUsesWith(ClampedVF);
5796}
5797
5799 ScalarEvolution &SE) {
5800 auto *Entry = Plan.getEntry();
5801 VPBuilder Builder(Entry, Entry->begin());
5803 ->getIRBasicBlock()
5804 ->getTerminator()
5805 ->getDebugLoc();
5806 VPSCEVExpander Expander(Builder, SE, DL);
5807
5808 // Expand VPExpandSCEVRecipes to VPInstructions using VPSCEVExpander. During
5809 // the transition, unsupported VPExpandSCEVRecipes are skipped and left for
5810 // late expansion.
5811 for (VPRecipeBase &R : make_early_inc_range(*Entry)) {
5812 auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(&R);
5813 if (!ExpSCEV || ExpSCEV->user_empty())
5814 continue;
5815 Builder.setInsertPoint(ExpSCEV);
5816 VPValue *Expanded = Expander.tryToExpand(ExpSCEV->getSCEV());
5817 if (!Expanded)
5818 continue;
5819 ExpSCEV->replaceAllUsesWith(Expanded);
5820 // TripCount should not be used after expansion to VPInstructions. Reset to
5821 // poison to avoid dangling references.
5822 if (Plan.getTripCount() == ExpSCEV)
5823 Plan.resetTripCount(Plan.getPoison(ExpSCEV->getScalarType()));
5824 ExpSCEV->eraseFromParent();
5825 }
5826}
5827
5830 SCEVExpander Expander(SE, "induction", /*PreserveLCSSA=*/false);
5831
5832 auto *Entry = cast<VPIRBasicBlock>(Plan.getEntry());
5833 BasicBlock *EntryBB = Entry->getIRBasicBlock();
5834 DenseMap<const SCEV *, Value *> ExpandedSCEVs;
5835 // Expand remaining VPExpandSCEVRecipes to IR instructions using SCEVExpander.
5836 for (VPRecipeBase &R : make_early_inc_range(*Entry)) {
5837 auto *ExpSCEV = dyn_cast<VPExpandSCEVRecipe>(&R);
5838 if (!ExpSCEV)
5839 continue;
5840 const SCEV *Expr = ExpSCEV->getSCEV();
5841 Value *Res =
5842 Expander.expandCodeFor(Expr, Expr->getType(), EntryBB->getTerminator());
5843 ExpandedSCEVs[Expr] = Res;
5844 VPValue *Exp = Plan.getOrAddLiveIn(Res);
5845 ExpSCEV->replaceAllUsesWith(Exp);
5846 if (Plan.getTripCount() == ExpSCEV)
5847 Plan.resetTripCount(Exp);
5848 ExpSCEV->eraseFromParent();
5849 }
5851 "all VPExpandSCEVRecipes must have been expanded");
5852 // Add IR instructions in the entry basic block but not in the VPIRBasicBlock
5853 // to the VPIRBasicBlock.
5854 auto EI = Entry->begin();
5855 for (Instruction &I : drop_end(*EntryBB)) {
5856 if (EI != Entry->end() && isa<VPIRInstruction>(*EI) &&
5857 &cast<VPIRInstruction>(&*EI)->getInstruction() == &I) {
5858 EI++;
5859 continue;
5860 }
5862 }
5863
5864 return ExpandedSCEVs;
5865}
5866
5867/// Returns true if \p V is VPWidenLoadRecipe or VPInterleaveRecipe that can be
5868/// converted to a narrower recipe. \p V is used by a wide recipe that feeds a
5869/// store interleave group at index \p Idx, \p WideMember0 is the recipe feeding
5870/// the same interleave group at index 0. A VPWidenLoadRecipe can be narrowed to
5871/// an index-independent load if it feeds all wide ops at all indices (\p OpV
5872/// must be the operand at index \p OpIdx for both the recipe at lane 0, \p
5873/// WideMember0). A VPInterleaveRecipe can be narrowed to a wide load, if \p V
5874/// is defined at \p Idx of a load interleave group.
5875/// A live-in or recipe defined outside the loop region can be converted, if it
5876/// is the same across all lanes, or we can create a BuildVector for it.
5877static bool canNarrowLoad(VPSingleDefRecipe *WideMember0, unsigned OpIdx,
5878 VPValue *OpV, unsigned Idx, bool IsScalable) {
5879 VPValue *Member0Op = WideMember0->getOperand(OpIdx);
5880 if (Member0Op->isDefinedOutsideLoopRegions()) {
5881 // Operand matches Member0, broadcast across all fields for both live-ins
5882 // and recipes.
5883 if (Member0Op == OpV)
5884 return true;
5885 // Otherwise distinct per-field VPValues are assembled into a BuildVector.
5886 return !IsScalable && OpV->isDefinedOutsideLoopRegions() &&
5887 OpV->getScalarType() == Member0Op->getScalarType();
5888 }
5889 VPRecipeBase *Member0OpR = Member0Op->getDefiningRecipe();
5890 if (auto *W = dyn_cast<VPWidenLoadRecipe>(Member0OpR))
5891 // For scalable VFs, the narrowed plan processes vscale iterations at once,
5892 // so a shared wide load cannot be narrowed to a uniform scalar; bail out.
5893 return !IsScalable && !W->getMask() && W->isConsecutive() &&
5894 Member0Op == OpV;
5895 if (auto *IR = dyn_cast<VPInterleaveRecipe>(Member0OpR))
5896 return IR->getInterleaveGroup()->isFull() && IR->getVPValue(Idx) == OpV;
5897 return false;
5898}
5899
5900static bool canNarrowOps(ArrayRef<VPValue *> Ops, bool IsScalable) {
5902 auto *WideMember0 = dyn_cast<VPRecipeWithIRFlags>(Ops[0]);
5903 if (!WideMember0)
5904 return false;
5905 for (VPValue *V : Ops) {
5907 return false;
5908 auto *R = cast<VPRecipeWithIRFlags>(V);
5909 if (getOpcodeOrIntrinsicID(R) != getOpcodeOrIntrinsicID(WideMember0))
5910 return false;
5911 if (R->getScalarType() != WideMember0->getScalarType())
5912 return false;
5913 if (R->hasPredicate() && R->getPredicate() != WideMember0->getPredicate())
5914 return false;
5915 }
5916
5917 for (unsigned Idx = 0; Idx != WideMember0->getNumOperands(); ++Idx) {
5919 for (VPValue *Op : Ops)
5920 OpsI.push_back(Op->getDefiningRecipe()->getOperand(Idx));
5921
5922 if (canNarrowOps(OpsI, IsScalable))
5923 continue;
5924
5925 if (any_of(enumerate(OpsI), [WideMember0, Idx, IsScalable](const auto &P) {
5926 const auto &[OpIdx, OpV] = P;
5927 return !canNarrowLoad(WideMember0, Idx, OpV, OpIdx, IsScalable);
5928 }))
5929 return false;
5930 }
5931
5932 return true;
5933}
5934
5935/// Returns VF from \p VFs if \p IR is a full interleave group with factor and
5936/// number of members both equal to VF. The interleave group must also access
5937/// the full vector width.
5938static std::optional<ElementCount>
5941 const TargetTransformInfo &TTI) {
5942 if (!InterleaveR || InterleaveR->getMask())
5943 return std::nullopt;
5944
5945 Type *GroupElementTy = nullptr;
5946 if (InterleaveR->getStoredValues().empty()) {
5947 GroupElementTy = InterleaveR->getVPValue(0)->getScalarType();
5948 if (!all_of(InterleaveR->definedValues(), [GroupElementTy](VPValue *Op) {
5949 return Op->getScalarType() == GroupElementTy;
5950 }))
5951 return std::nullopt;
5952 } else {
5953 GroupElementTy = InterleaveR->getStoredValues()[0]->getScalarType();
5954 if (!all_of(InterleaveR->getStoredValues(), [GroupElementTy](VPValue *Op) {
5955 return Op->getScalarType() == GroupElementTy;
5956 }))
5957 return std::nullopt;
5958 }
5959
5960 auto IG = InterleaveR->getInterleaveGroup();
5961 if (IG->getFactor() != IG->getNumMembers())
5962 return std::nullopt;
5963
5964 auto GetVectorBitWidthForVF = [&TTI](ElementCount VF) {
5965 TypeSize Size = TTI.getRegisterBitWidth(
5968 assert(Size.isScalable() == VF.isScalable() &&
5969 "if Size is scalable, VF must be scalable and vice versa");
5970 return Size.getKnownMinValue();
5971 };
5972
5973 for (ElementCount VF : VFs) {
5974 unsigned MinVal = VF.getKnownMinValue();
5975 unsigned GroupSize = GroupElementTy->getScalarSizeInBits() * MinVal;
5976 if (IG->getFactor() == MinVal && GroupSize == GetVectorBitWidthForVF(VF))
5977 return {VF};
5978 }
5979 return std::nullopt;
5980}
5981
5982/// Returns true if \p VPValue is a narrow VPValue.
5983static bool isAlreadyNarrow(VPValue *VPV) {
5984 if (isa<VPIRValue>(VPV))
5985 return true;
5986 auto *RepR = dyn_cast<VPReplicateRecipe>(VPV);
5987 return RepR && RepR->isSingleScalar();
5988}
5989
5990// Convert the wide recipes defining the VPValues in \p Members feeding an
5991// interleave group to a single narrow variant. The first member is reused as
5992// the narrowed recipe. BuildVectors for live-in operands are inserted into \p
5993// Preheader.
5995 SmallPtrSetImpl<VPValue *> &NarrowedOps,
5996 VPBasicBlock *Preheader) {
5997 VPValue *V = Members.front();
5998 if (NarrowedOps.contains(V))
5999 return V;
6000
6001 if (V->isDefinedOutsideLoopRegions()) {
6002 assert(all_of(Members,
6003 [V](VPValue *M) {
6004 return M->isDefinedOutsideLoopRegions() &&
6005 M->getScalarType() == V->getScalarType();
6006 }) &&
6007 "expected distinct loop-invariant values of matching scalar type");
6008 auto *BV = new VPInstruction(VPInstruction::BuildVector, Members);
6009 Preheader->appendRecipe(BV);
6010 NarrowedOps.insert(BV);
6011 return BV;
6012 }
6013
6014 if (isAlreadyNarrow(V))
6015 return V;
6016
6017 VPRecipeBase *R = V->getDefiningRecipe();
6019 auto *WideMember0 = cast<VPRecipeWithIRFlags>(R);
6020 for (VPValue *Member : Members.drop_front())
6021 WideMember0->intersectFlags(*cast<VPRecipeWithIRFlags>(Member));
6022 for (unsigned Idx = 0, E = WideMember0->getNumOperands(); Idx != E; ++Idx) {
6024 for (VPValue *Member : Members)
6025 OpsI.push_back(Member->getDefiningRecipe()->getOperand(Idx));
6026 WideMember0->setOperand(
6027 Idx, narrowInterleaveGroupOp(OpsI, NarrowedOps, Preheader));
6028 }
6029 return V;
6030 }
6031
6032 if (auto *LoadGroup = dyn_cast<VPInterleaveRecipe>(R)) {
6033 // Narrow interleave group to wide load, as transformed VPlan will only
6034 // process one original iteration.
6035 auto *LI = cast<LoadInst>(LoadGroup->getInterleaveGroup()->getInsertPos());
6036 auto *L = new VPWidenLoadRecipe(*LI, LoadGroup->getAddr(),
6037 LoadGroup->getMask(), /*Consecutive=*/true,
6038 *LoadGroup, LoadGroup->getDebugLoc());
6039 L->insertBefore(LoadGroup);
6040 NarrowedOps.insert(L);
6041 return L;
6042 }
6043
6044 if (auto *RepR = dyn_cast<VPReplicateRecipe>(R)) {
6045 assert(RepR->isSingleScalar() && RepR->getOpcode() == Instruction::Load &&
6046 "must be a single scalar load");
6047 NarrowedOps.insert(RepR);
6048 return RepR;
6049 }
6050
6051 auto *WideLoad = cast<VPWidenLoadRecipe>(R);
6052 VPValue *PtrOp = WideLoad->getAddr();
6053 if (auto *VecPtr = dyn_cast<VPVectorPointerRecipe>(PtrOp))
6054 PtrOp = VecPtr->getOperand(0);
6055 // Narrow wide load to uniform scalar load, as transformed VPlan will only
6056 // process one original iteration.
6057 auto *N = new VPReplicateRecipe(&WideLoad->getIngredient(), {PtrOp},
6058 /*IsUniform*/ true,
6059 /*Mask*/ nullptr, {}, *WideLoad);
6060 N->insertBefore(WideLoad);
6061 NarrowedOps.insert(N);
6062 return N;
6063}
6064
6065std::unique_ptr<VPlan>
6067 const TargetTransformInfo &TTI) {
6068 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
6069
6070 if (!VectorLoop)
6071 return nullptr;
6072
6073 // Only handle single-block loops for now.
6074 if (VectorLoop->getEntryBasicBlock() != VectorLoop->getExitingBasicBlock())
6075 return nullptr;
6076
6077 // Skip plans when we may not be able to properly narrow.
6078 VPBasicBlock *Exiting = VectorLoop->getExitingBasicBlock();
6079 if (!match(&Exiting->back(), m_BranchOnCount()))
6080 return nullptr;
6081
6082 assert(match(&Exiting->back(),
6084 m_Specific(&Plan.getVectorTripCount()))) &&
6085 "unexpected branch-on-count");
6086
6088 std::optional<ElementCount> VFToOptimize;
6089 for (auto &R : *VectorLoop->getEntryBasicBlock()) {
6092 continue;
6093
6094 // Bail out on recipes not supported at the moment:
6095 // * phi recipes other than the canonical induction
6096 // * recipes writing to memory except interleave groups
6097 // Only support plans with a canonical induction phi.
6098 if (R.isPhi())
6099 return nullptr;
6100
6101 auto *InterleaveR = dyn_cast<VPInterleaveRecipe>(&R);
6102 if (R.mayWriteToMemory() && !InterleaveR)
6103 return nullptr;
6104
6105 // Bail out if any recipe defines a vector value used outside the
6106 // vector loop region.
6107 if (any_of(R.definedValues(), [&](VPValue *V) {
6108 return any_of(V->users(), [&](VPUser *U) {
6109 auto *UR = cast<VPRecipeBase>(U);
6110 return UR->getParent()->getParent() != VectorLoop;
6111 });
6112 }))
6113 return nullptr;
6114
6115 // All other ops are allowed, but we reject uses that cannot be converted
6116 // when checking all allowed consumers (store interleave groups) below.
6117 if (!InterleaveR)
6118 continue;
6119
6120 // Try to find a single VF, where all interleave groups are consecutive and
6121 // saturate the full vector width. If we already have a candidate VF, check
6122 // if it is applicable for the current InterleaveR, otherwise look for a
6123 // suitable VF across the Plan's VFs.
6125 VFToOptimize ? SmallVector<ElementCount>({*VFToOptimize})
6126 : to_vector(Plan.vectorFactors());
6127 std::optional<ElementCount> NarrowedVF =
6128 isConsecutiveInterleaveGroup(InterleaveR, VFs, TTI);
6129 if (!NarrowedVF || (VFToOptimize && NarrowedVF != VFToOptimize))
6130 return nullptr;
6131 VFToOptimize = NarrowedVF;
6132
6133 // Skip read interleave groups.
6134 if (InterleaveR->getStoredValues().empty())
6135 continue;
6136
6137 // Narrow interleave groups, if all operands are already matching narrow
6138 // ops.
6139 auto *Member0 = InterleaveR->getStoredValues()[0];
6140 if (isAlreadyNarrow(Member0) &&
6141 all_of(InterleaveR->getStoredValues(), equal_to(Member0))) {
6142 StoreGroups.push_back(InterleaveR);
6143 continue;
6144 }
6145
6146 // For now, we only support full interleave groups storing load interleave
6147 // groups.
6148 if (all_of(enumerate(InterleaveR->getStoredValues()), [](auto Op) {
6149 VPRecipeBase *DefR = Op.value()->getDefiningRecipe();
6150 if (!DefR)
6151 return false;
6152 auto *IR = dyn_cast<VPInterleaveRecipe>(DefR);
6153 return IR && IR->getInterleaveGroup()->isFull() &&
6154 IR->getVPValue(Op.index()) == Op.value();
6155 })) {
6156 StoreGroups.push_back(InterleaveR);
6157 continue;
6158 }
6159
6160 // Check if all values feeding InterleaveR are matching wide recipes, which
6161 // operands that can be narrowed.
6162 if (!canNarrowOps(InterleaveR->getStoredValues(),
6163 VFToOptimize->isScalable()))
6164 return nullptr;
6165 StoreGroups.push_back(InterleaveR);
6166 }
6167
6168 if (StoreGroups.empty())
6169 return nullptr;
6170
6171 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
6172 bool RequiresScalarEpilogue =
6173 MiddleVPBB->getNumSuccessors() == 1 &&
6174 MiddleVPBB->getSingleSuccessor() == Plan.getScalarPreheader();
6175 // Bail out for tail-folding (middle block with a single successor to exit).
6176 if (MiddleVPBB->getNumSuccessors() != 2 && !RequiresScalarEpilogue)
6177 return nullptr;
6178
6179 // All interleave groups in Plan can be narrowed for VFToOptimize. Split the
6180 // original Plan into 2: a) a new clone which contains all VFs of Plan, except
6181 // VFToOptimize, and b) the original Plan with VFToOptimize as single VF.
6182 // TODO: Handle cases where only some interleave groups can be narrowed.
6183 std::unique_ptr<VPlan> NewPlan;
6184 if (size(Plan.vectorFactors()) != 1) {
6185 NewPlan = std::unique_ptr<VPlan>(Plan.duplicate());
6186 Plan.setVF(*VFToOptimize);
6187 NewPlan->removeVF(*VFToOptimize);
6188 }
6189
6190 // Convert InterleaveGroup \p R to a single VPWidenLoadRecipe.
6191 SmallPtrSet<VPValue *, 4> NarrowedOps;
6192 VPBasicBlock *Preheader = Plan.getVectorPreheader();
6193 // Narrow operation tree rooted at store groups.
6194 for (auto *StoreGroup : StoreGroups) {
6195 VPValue *Res = narrowInterleaveGroupOp(StoreGroup->getStoredValues(),
6196 NarrowedOps, Preheader);
6197 auto *SI =
6198 cast<StoreInst>(StoreGroup->getInterleaveGroup()->getInsertPos());
6199 auto *S = new VPWidenStoreRecipe(*SI, StoreGroup->getAddr(), Res, nullptr,
6200 /*Consecutive=*/true, *StoreGroup,
6201 StoreGroup->getDebugLoc());
6202 S->insertBefore(StoreGroup);
6203 StoreGroup->eraseFromParent();
6204 }
6205
6206 // Adjust induction to reflect that the transformed plan only processes one
6207 // original iteration.
6209 Type *CanIVTy = VectorLoop->getCanonicalIVType();
6210 VPBasicBlock *VectorPH = Plan.getVectorPreheader();
6211 VPBuilder PHBuilder(VectorPH, VectorPH->begin());
6212
6213 VPValue *UF = &Plan.getUF();
6214 VPValue *Step;
6215 if (VFToOptimize->isScalable()) {
6216 VPValue *VScale =
6217 PHBuilder.createElementCount(CanIVTy, ElementCount::getScalable(1));
6218 Step = PHBuilder.createOverflowingOp(Instruction::Mul, {VScale, UF},
6219 {true, false});
6220 Plan.getVF().replaceAllUsesWith(VScale);
6221 } else {
6222 Step = UF;
6223 Plan.getVF().replaceAllUsesWith(Plan.getConstantInt(CanIVTy, 1));
6224 }
6225 // Materialize vector trip count with the narrowed step.
6226 materializeVectorTripCount(Plan, VectorPH, /*TailByMasking=*/false,
6227 RequiresScalarEpilogue, Step);
6228
6229 CanIVInc->setOperand(1, Step);
6230 Plan.getVFxUF().replaceAllUsesWith(Step);
6231
6232 removeDeadRecipes(Plan);
6233 assert(none_of(*VectorLoop->getEntryBasicBlock(),
6235 "All VPVectorPointerRecipes should have been removed");
6236 return NewPlan;
6237}
6238
6239/// Add branch weight metadata, if the \p Plan's middle block is terminated by a
6240/// BranchOnCond recipe.
6242 VPlan &Plan, ElementCount VF, std::optional<unsigned> VScaleForTuning) {
6243 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
6244 auto *MiddleTerm =
6246 // Only add branch metadata if there is a (conditional) terminator.
6247 if (!MiddleTerm)
6248 return;
6249
6250 assert(MiddleTerm->getOpcode() == VPInstruction::BranchOnCond &&
6251 "must have a BranchOnCond");
6252 // Assume that `TripCount % VectorStep ` is equally distributed.
6253 unsigned VectorStep = Plan.getConcreteUF() * VF.getKnownMinValue();
6254 if (VF.isScalable() && VScaleForTuning.has_value())
6255 VectorStep *= *VScaleForTuning;
6256 assert(VectorStep > 0 && "trip count should not be zero");
6257 MDBuilder MDB(Plan.getContext());
6258 MDNode *BranchWeights =
6259 MDB.createBranchWeights({1, VectorStep - 1}, /*IsExpected=*/false);
6260 MiddleTerm->setMetadata(LLVMContext::MD_prof, BranchWeights);
6261}
6262
6264 VFRange &Range) {
6265 VPRegionBlock *VectorRegion = Plan.getVectorLoopRegion();
6266 auto *MiddleVPBB = Plan.getMiddleBlock();
6267 VPBuilder MiddleBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
6268
6269 auto IsScalableOne = [](ElementCount VF) -> bool {
6270 return VF == ElementCount::getScalable(1);
6271 };
6272
6273 for (auto &HeaderPhi : VectorRegion->getEntryBasicBlock()->phis()) {
6274 auto *FOR = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&HeaderPhi);
6275 if (!FOR)
6276 continue;
6277
6278 assert(VectorRegion->getSingleSuccessor() == Plan.getMiddleBlock() &&
6279 "Cannot handle loops with uncountable early exits");
6280
6281 // Find the existing splice for this FOR, created in
6282 // createHeaderPhiRecipes. All uses of FOR have already been replaced with
6283 // RecurSplice there; only RecurSplice itself still references FOR.
6284 auto *RecurSplice =
6286 assert(RecurSplice && "expected FirstOrderRecurrenceSplice");
6287
6288 // For VF vscale x 1, if vscale = 1, we are unable to extract the
6289 // penultimate value of the recurrence. Instead we rely on the existing
6290 // extract of the last element from the result of
6291 // VPInstruction::FirstOrderRecurrenceSplice.
6292 // TODO: Consider vscale_range info and UF.
6293 if (any_of(RecurSplice->users(),
6294 [](VPUser *U) { return !cast<VPRecipeBase>(U)->getRegion(); }) &&
6296 Range))
6297 return;
6298
6299 // This is the second phase of vectorizing first-order recurrences, creating
6300 // extracts for users outside the loop. An overview of the transformation is
6301 // described below. Suppose we have the following loop with some use after
6302 // the loop of the last a[i-1],
6303 //
6304 // for (int i = 0; i < n; ++i) {
6305 // t = a[i - 1];
6306 // b[i] = a[i] - t;
6307 // }
6308 // use t;
6309 //
6310 // There is a first-order recurrence on "a". For this loop, the shorthand
6311 // scalar IR looks like:
6312 //
6313 // scalar.ph:
6314 // s.init = a[-1]
6315 // br scalar.body
6316 //
6317 // scalar.body:
6318 // i = phi [0, scalar.ph], [i+1, scalar.body]
6319 // s1 = phi [s.init, scalar.ph], [s2, scalar.body]
6320 // s2 = a[i]
6321 // b[i] = s2 - s1
6322 // br cond, scalar.body, exit.block
6323 //
6324 // exit.block:
6325 // use = lcssa.phi [s1, scalar.body]
6326 //
6327 // In this example, s1 is a recurrence because it's value depends on the
6328 // previous iteration. In the first phase of vectorization, we created a
6329 // VPFirstOrderRecurrencePHIRecipe v1 for s1. Now we create the extracts
6330 // for users in the scalar preheader and exit block.
6331 //
6332 // vector.ph:
6333 // v_init = vector(..., ..., ..., a[-1])
6334 // br vector.body
6335 //
6336 // vector.body
6337 // i = phi [0, vector.ph], [i+4, vector.body]
6338 // v1 = phi [v_init, vector.ph], [v2, vector.body]
6339 // v2 = a[i, i+1, i+2, i+3]
6340 // v1' = splice(v1(3), v2(0, 1, 2))
6341 // b[i, i+1, i+2, i+3] = v2 - v1'
6342 // br cond, vector.body, middle.block
6343 //
6344 // middle.block:
6345 // vector.recur.extract.for.phi = v2(2)
6346 // vector.recur.extract = v2(3)
6347 // br cond, scalar.ph, exit.block
6348 //
6349 // scalar.ph:
6350 // scalar.recur.init = phi [vector.recur.extract, middle.block],
6351 // [s.init, otherwise]
6352 // br scalar.body
6353 //
6354 // scalar.body:
6355 // i = phi [0, scalar.ph], [i+1, scalar.body]
6356 // s1 = phi [scalar.recur.init, scalar.ph], [s2, scalar.body]
6357 // s2 = a[i]
6358 // b[i] = s2 - s1
6359 // br cond, scalar.body, exit.block
6360 //
6361 // exit.block:
6362 // lo = lcssa.phi [s1, scalar.body],
6363 // [vector.recur.extract.for.phi, middle.block]
6364 //
6365 // Update extracts of the splice in the middle block: they extract the
6366 // penultimate element of the recurrence.
6368 make_range(MiddleVPBB->getFirstNonPhi(), MiddleVPBB->end()))) {
6369 if (!match(&R, m_ExtractLastLaneOfLastPart(m_Specific(RecurSplice))))
6370 continue;
6371
6372 auto *ExtractR = cast<VPInstruction>(&R);
6373 VPValue *PenultimateElement = MiddleBuilder.createNaryOp(
6374 VPInstruction::ExtractPenultimateElement, RecurSplice->getOperand(1),
6375 {}, "vector.recur.extract.for.phi");
6376 for (VPUser *ExitU : to_vector(ExtractR->users())) {
6377 if (auto *ExitPhi = dyn_cast<VPIRPhi>(ExitU))
6378 ExitPhi->replaceUsesOfWith(ExtractR, PenultimateElement);
6379 }
6380 }
6381 }
6382}
6383
6384/// Check if \p V is a binary expression of a widened IV and a loop-invariant
6385/// value. Returns the widened IV if found, nullptr otherwise.
6387 auto *BinOp = dyn_cast<VPWidenRecipe>(V);
6388 if (!BinOp || !Instruction::isBinaryOp(BinOp->getOpcode()) ||
6389 Instruction::isIntDivRem(BinOp->getOpcode()))
6390 return nullptr;
6391
6392 VPValue *WidenIVCandidate = BinOp->getOperand(0);
6393 VPValue *InvariantCandidate = BinOp->getOperand(1);
6394 if (!isa<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate))
6395 std::swap(WidenIVCandidate, InvariantCandidate);
6396
6397 if (!InvariantCandidate->isDefinedOutsideLoopRegions())
6398 return nullptr;
6399
6400 return dyn_cast<VPWidenIntOrFpInductionRecipe>(WidenIVCandidate);
6401}
6402
6403/// Create a scalar version of \p BinOp, with its \p WidenIV operand replaced
6404/// by \p ScalarIV, and place it after \p ScalarIV's defining recipe.
6408 BinOp->getNumOperands() == 2 && "BinOp must have 2 operands");
6409 auto *ClonedOp = BinOp->clone();
6410 if (ClonedOp->getOperand(0) == WidenIV) {
6411 ClonedOp->setOperand(0, ScalarIV);
6412 } else {
6413 assert(ClonedOp->getOperand(1) == WidenIV && "one operand must be WideIV");
6414 ClonedOp->setOperand(1, ScalarIV);
6415 }
6416 ClonedOp->insertAfter(ScalarIV->getDefiningRecipe());
6417 return ClonedOp;
6418}
6419
6422 Loop &L) {
6423 ScalarEvolution &SE = *PSE.getSE();
6424 VPRegionBlock *VectorLoopRegion = Plan.getVectorLoopRegion();
6425
6426 // Helper lambda to check if the IV range excludes the sentinel value. Try
6427 // signed first, then unsigned. Return an excluded sentinel if found,
6428 // otherwise return std::nullopt.
6429 auto CheckSentinel = [&SE](const SCEV *IVSCEV,
6430 bool UseMax) -> std::optional<APSInt> {
6431 unsigned BW = IVSCEV->getType()->getScalarSizeInBits();
6432 for (bool Signed : {true, false}) {
6433 APSInt Sentinel = UseMax ? APSInt::getMinValue(BW, /*Unsigned=*/!Signed)
6434 : APSInt::getMaxValue(BW, /*Unsigned=*/!Signed);
6435
6436 ConstantRange IVRange =
6437 Signed ? SE.getSignedRange(IVSCEV) : SE.getUnsignedRange(IVSCEV);
6438 if (!IVRange.contains(Sentinel))
6439 return Sentinel;
6440 }
6441 return std::nullopt;
6442 };
6443
6444 VPValue *HeaderMask = VectorLoopRegion->getHeaderMask();
6445 for (VPRecipeBase &Phi :
6446 make_early_inc_range(VectorLoopRegion->getEntryBasicBlock()->phis())) {
6447 auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&Phi);
6449 PhiR->getRecurrenceKind()))
6450 continue;
6451
6452 Type *PhiTy = PhiR->getScalarType();
6453 if (PhiTy->isPointerTy() || PhiTy->isFloatingPointTy())
6454 continue;
6455
6456 // If there's a header mask, the backedge select will not be the find-last
6457 // select.
6458 VPValue *BackedgeVal = PhiR->getBackedgeValue();
6459 auto *FindLastSelect = cast<VPSingleDefRecipe>(BackedgeVal);
6460 if (HeaderMask &&
6461 !match(BackedgeVal,
6462 m_Select(m_Specific(HeaderMask),
6463 m_VPSingleDefRecipe(FindLastSelect), m_Specific(PhiR))))
6464 continue;
6465
6466 // Get the find-last expression from the find-last select of the reduction
6467 // phi. The find-last select should be a select between the phi and the
6468 // find-last expression.
6469 VPValue *Cond, *FindLastExpression;
6470 if (!match(FindLastSelect, m_SelectLike(m_VPValue(Cond), m_Specific(PhiR),
6471 m_VPValue(FindLastExpression))) &&
6472 !match(FindLastSelect,
6473 m_SelectLike(m_VPValue(Cond), m_VPValue(FindLastExpression),
6474 m_Specific(PhiR))))
6475 continue;
6476
6477 // Check if FindLastExpression is a simple expression of a widened IV. If
6478 // so, we can track the underlying IV instead and sink the expression.
6479 auto *IVOfExpressionToSink = getExpressionIV(FindLastExpression);
6480 const SCEV *IVSCEV = vputils::getSCEVExprForVPValue(
6481 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression, PSE,
6482 &L);
6483 const SCEV *Step;
6484 if (!match(IVSCEV, m_scev_AffineAddRec(m_SCEV(), m_SCEV(Step)))) {
6485 assert(!match(vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L),
6487 "IVOfExpressionToSink not being an AddRec must imply "
6488 "FindLastExpression not being an AddRec.");
6489 continue;
6490 }
6491
6492 // Determine direction from SCEV step.
6493 if (!SE.isKnownNonZero(Step))
6494 continue;
6495
6496 // Positive step means we need UMax/SMax to find the last IV value, and
6497 // UMin/SMin otherwise.
6498 bool UseMax = SE.isKnownPositive(Step);
6499 std::optional<APSInt> SentinelVal = CheckSentinel(IVSCEV, UseMax);
6500 bool UseSigned = SentinelVal && SentinelVal->isSigned();
6501
6502 // Sinking an expression will disable epilogue vectorization. Only use it,
6503 // if FindLastExpression cannot be vectorized via a sentinel. Sinking may
6504 // also prevent vectorizing using a sentinel (e.g., if the expression is a
6505 // multiply or divide by large constant, respectively), which also makes
6506 // sinking undesirable.
6507 if (IVOfExpressionToSink) {
6508 const SCEV *FindLastExpressionSCEV =
6509 vputils::getSCEVExprForVPValue(FindLastExpression, PSE, &L);
6510 if (match(FindLastExpressionSCEV,
6511 m_scev_AffineAddRec(m_SCEV(), m_SCEV(Step)))) {
6512 bool NewUseMax = SE.isKnownPositive(Step);
6513 if (auto NewSentinel =
6514 CheckSentinel(FindLastExpressionSCEV, NewUseMax)) {
6515 // The original expression already has a sentinel, so prefer not
6516 // sinking to keep epilogue vectorization possible.
6517 SentinelVal = *NewSentinel;
6518 UseSigned = NewSentinel->isSigned();
6519 UseMax = NewUseMax;
6520 IVSCEV = FindLastExpressionSCEV;
6521 IVOfExpressionToSink = nullptr;
6522 }
6523 }
6524 }
6525
6526 // If no sentinel was found, fall back to a boolean AnyOf reduction to track
6527 // if the condition was ever true. Requires the IV to not wrap, otherwise we
6528 // cannot use min/max.
6529 if (!SentinelVal) {
6530 auto *AR = cast<SCEVAddRecExpr>(IVSCEV);
6531 if (AR->hasNoSignedWrap())
6532 UseSigned = true;
6533 else if (AR->hasNoUnsignedWrap())
6534 UseSigned = false;
6535 else
6536 continue;
6537 }
6538
6540 BackedgeVal,
6542
6543 VPValue *NewFindLastSelect = BackedgeVal;
6544 VPValue *SelectCond = Cond;
6545 if (!SentinelVal || IVOfExpressionToSink) {
6546 // When we need to create a new select, normalize the condition so that
6547 // PhiR is the last operand and include the header mask if needed.
6548 DebugLoc DL = FindLastSelect->getDefiningRecipe()->getDebugLoc();
6549 VPBuilder LoopBuilder(FindLastSelect->getDefiningRecipe());
6550 if (FindLastSelect->getDefiningRecipe()->getOperand(1) == PhiR)
6551 SelectCond = LoopBuilder.createNot(SelectCond);
6552
6553 // When tail folding, mask the condition with the header mask to prevent
6554 // propagating poison from inactive lanes in the last vector iteration.
6555 if (HeaderMask)
6556 SelectCond = LoopBuilder.createLogicalAnd(HeaderMask, SelectCond);
6557
6558 if (SelectCond != Cond || IVOfExpressionToSink) {
6559 NewFindLastSelect = LoopBuilder.createSelect(
6560 SelectCond,
6561 IVOfExpressionToSink ? IVOfExpressionToSink : FindLastExpression,
6562 PhiR, DL);
6563 }
6564 }
6565
6566 // Create the reduction result in the middle block using sentinel directly.
6567 RecurKind MinMaxKind =
6568 UseMax ? (UseSigned ? RecurKind::SMax : RecurKind::UMax)
6569 : (UseSigned ? RecurKind::SMin : RecurKind::UMin);
6570 VPIRFlags Flags(MinMaxKind, /*IsOrdered=*/false, /*IsInLoop=*/false,
6571 FastMathFlags());
6572 DebugLoc ExitDL = RdxResult->getDebugLoc();
6573 VPBuilder MiddleBuilder(RdxResult);
6574 VPValue *ReducedIV =
6576 NewFindLastSelect, Flags, ExitDL);
6577
6578 // If IVOfExpressionToSink is an expression to sink, sink it now.
6579 VPValue *VectorRegionExitingVal = ReducedIV;
6580 if (IVOfExpressionToSink)
6581 VectorRegionExitingVal =
6582 cloneBinOpForScalarIV(cast<VPWidenRecipe>(FindLastExpression),
6583 ReducedIV, IVOfExpressionToSink);
6584
6585 VPValue *NewRdxResult;
6586 VPValue *StartVPV = PhiR->getStartValue();
6587 if (SentinelVal) {
6588 // Sentinel-based approach: reduce IVs with min/max, compare against
6589 // sentinel to detect if condition was ever true, select accordingly.
6590 VPValue *Sentinel = Plan.getConstantInt(*SentinelVal);
6591 auto *Cmp = MiddleBuilder.createICmp(CmpInst::ICMP_NE, ReducedIV,
6592 Sentinel, ExitDL);
6593 NewRdxResult = MiddleBuilder.createSelect(Cmp, VectorRegionExitingVal,
6594 StartVPV, ExitDL);
6595 StartVPV = Sentinel;
6596 } else {
6597 // Introduce a boolean AnyOf reduction to track if the condition was ever
6598 // true in the loop. Use it to select the initial start value, if it was
6599 // never true.
6600 auto *AnyOfPhi = new VPReductionPHIRecipe(
6601 /*Phi=*/nullptr, RecurKind::Or, *Plan.getFalse(), *Plan.getFalse(),
6602 RdxUnordered{1}, {}, /*HasUsesOutsideReductionChain=*/false);
6603 AnyOfPhi->insertAfter(PhiR);
6604
6605 VPBuilder LoopBuilder(BackedgeVal->getDefiningRecipe());
6606 VPValue *OrVal = LoopBuilder.createOr(AnyOfPhi, SelectCond);
6607 AnyOfPhi->setOperand(1, OrVal);
6608
6609 NewRdxResult = MiddleBuilder.createAnyOfReduction(
6610 OrVal, VectorRegionExitingVal, StartVPV, ExitDL);
6611
6612 // Initialize the IV reduction phi with the neutral element, not the
6613 // original start value, to ensure correct min/max reduction results.
6614 StartVPV = Plan.getOrAddLiveIn(
6615 getRecurrenceIdentity(MinMaxKind, IVSCEV->getType(), {}));
6616 }
6617 RdxResult->replaceAllUsesWith(NewRdxResult);
6618 RdxResult->eraseFromParent();
6619
6620 auto *NewPhiR = new VPReductionPHIRecipe(
6621 cast<PHINode>(PhiR->getUnderlyingInstr()), RecurKind::FindIV, *StartVPV,
6622 *NewFindLastSelect, RdxUnordered{1}, {},
6623 PhiR->hasUsesOutsideReductionChain());
6624 NewPhiR->insertBefore(PhiR);
6625 PhiR->replaceAllUsesWith(NewPhiR);
6626 PhiR->eraseFromParent();
6627 }
6628}
6629
6630namespace {
6631
6632using ExtendKind = TTI::PartialReductionExtendKind;
6633struct ReductionExtend {
6634 Type *SrcType = nullptr;
6635 ExtendKind Kind = ExtendKind::PR_None;
6636};
6637
6638/// Describes the extends used to compute the extended reduction operand.
6639/// ExtendB is optional. If ExtendB is present, ExtendsUser is a binary
6640/// operation.
6641struct ExtendedReductionOperand {
6642 /// The recipe that consumes the extends.
6643 VPWidenRecipe *ExtendsUser = nullptr;
6644 /// Extend descriptions (inputs to getPartialReductionCost).
6645 ReductionExtend ExtendA, ExtendB;
6646};
6647
6648/// A chain of recipes that form a partial reduction. Matches either
6649/// reduction_bin_op (extended op, accumulator), or
6650/// reduction_bin_op (accumulator, extended op).
6651/// The possible forms of the "extended op" are listed in
6652/// matchExtendedReductionOperand.
6653struct VPPartialReductionChain {
6654 /// The top-level binary operation that forms the reduction to a scalar
6655 /// after the loop body.
6656 VPWidenRecipe *ReductionBinOp = nullptr;
6657 /// The user of the extends that is then reduced.
6658 ExtendedReductionOperand ExtendedOp;
6659 /// The recurrence kind for the entire partial reduction chain.
6660 /// This allows distinguishing between Sub and AddWithSub recurrences,
6661 /// when the ReductionBinOp is a Instruction::Sub.
6662 RecurKind RK;
6663 /// The index of the accumulator operand of ReductionBinOp. The extended op
6664 /// is `1 - AccumulatorOpIdx`.
6665 unsigned AccumulatorOpIdx;
6666 unsigned ScaleFactor;
6667 /// Optional blend to represent predication for the block that updates the
6668 /// reduction.
6669 VPBlendRecipe *Blend = nullptr;
6670};
6671
6672// Return the incoming index of the single-use value in the blend, which is
6673// expected to be the predicated reduction update.
6674static std::optional<unsigned>
6675getBlendReductionUpdateValueIdx(VPBlendRecipe *Blend) {
6676 assert(Blend && !Blend->isNormalized() &&
6677 Blend->getNumIncomingValues() == 2 &&
6678 "Expected a non-normalized blend with two incoming values");
6679 bool FirstIncomingHasOneUse = Blend->getIncomingValue(0)->hasOneUse();
6680
6681 // Only the update value should have one use (the blend). The previous
6682 // value should always have at least two uses, the blend and the reduction.
6683 if (FirstIncomingHasOneUse == Blend->getIncomingValue(1)->hasOneUse())
6684 return std::nullopt;
6685 return FirstIncomingHasOneUse ? 0 : 1;
6686}
6687
6688static VPSingleDefRecipe *
6689optimizeExtendsForPartialReduction(VPSingleDefRecipe *Op) {
6690 // reduce.add(mul(ext(A), C))
6691 // -> reduce.add(mul(ext(A), ext(trunc(C))))
6692 const APInt *Const;
6693 if (match(Op, m_Mul(m_ZExtOrSExt(m_VPValue()), m_APInt(Const)))) {
6694 auto *ExtA = cast<VPWidenCastRecipe>(Op->getOperand(0));
6695 Instruction::CastOps ExtOpc = ExtA->getOpcode();
6696 Type *NarrowTy = ExtA->getOperand(0)->getScalarType();
6697 if (!Op->hasOneUse() ||
6699 Const, NarrowTy, TTI::getPartialReductionExtendKind(ExtOpc)))
6700 return Op;
6701
6702 VPBuilder Builder(Op);
6703 auto *Trunc = Builder.createWidenCast(Instruction::CastOps::Trunc,
6704 Op->getOperand(1), NarrowTy);
6705 Type *WideTy = ExtA->getScalarType();
6706 Op->setOperand(1, Builder.createWidenCast(ExtOpc, Trunc, WideTy));
6707 return Op;
6708 }
6709
6710 // reduce.add(abs(sub(ext(A), ext(B))))
6711 // -> reduce.add(ext(absolute-difference(A, B)))
6712 VPValue *X, *Y;
6715 auto *Sub = Op->getOperand(0)->getDefiningRecipe();
6716 auto *Ext = cast<VPWidenCastRecipe>(Sub->getOperand(0));
6717 assert(Ext->getOpcode() ==
6718 cast<VPWidenCastRecipe>(Sub->getOperand(1))->getOpcode() &&
6719 "Expected both the LHS and RHS extends to be the same");
6720 bool IsSigned = Ext->getOpcode() == Instruction::SExt;
6721 VPBuilder Builder(Op);
6722 Type *SrcTy = X->getScalarType();
6723 auto *FreezeX = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {X}));
6724 auto *FreezeY = Builder.insert(new VPWidenRecipe(Instruction::Freeze, {Y}));
6725 auto *Max = Builder.insert(
6726 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smax : Intrinsic::umax,
6727 {FreezeX, FreezeY}, SrcTy));
6728 auto *Min = Builder.insert(
6729 new VPWidenIntrinsicRecipe(IsSigned ? Intrinsic::smin : Intrinsic::umin,
6730 {FreezeX, FreezeY}, SrcTy));
6731 auto *AbsDiff =
6732 Builder.insert(new VPWidenRecipe(Instruction::Sub, {Max, Min}));
6733 return Builder.createWidenCast(Instruction::CastOps::ZExt, AbsDiff,
6734 Op->getScalarType());
6735 }
6736
6737 // reduce.add(ext(mul(ext(A), ext(B))))
6738 // -> reduce.add(mul(wider_ext(A), wider_ext(B)))
6739 // TODO: Support this optimization for float types.
6741 m_ZExtOrSExt(m_VPValue()))))) {
6742 auto *Ext = cast<VPWidenCastRecipe>(Op);
6743 auto *Mul = cast<VPWidenRecipe>(Ext->getOperand(0));
6744 auto *MulLHS = cast<VPWidenCastRecipe>(Mul->getOperand(0));
6745 auto *MulRHS = cast<VPWidenCastRecipe>(Mul->getOperand(1));
6746 if (!Mul->hasOneUse() ||
6747 (Ext->getOpcode() != MulLHS->getOpcode() && MulLHS != MulRHS) ||
6748 MulLHS->getOpcode() != MulRHS->getOpcode())
6749 return Op;
6750 VPBuilder Builder(Mul);
6751 auto *NewLHS = Builder.createWidenCast(
6752 MulLHS->getOpcode(), MulLHS->getOperand(0), Ext->getScalarType());
6753 auto *NewRHS = MulLHS == MulRHS
6754 ? NewLHS
6755 : Builder.createWidenCast(MulRHS->getOpcode(),
6756 MulRHS->getOperand(0),
6757 Ext->getScalarType());
6758 auto *NewMul = Mul->cloneWithOperands({NewLHS, NewRHS});
6759 Builder.insert(NewMul);
6760 Op->replaceAllUsesWith(NewMul);
6761 Op->eraseFromParent();
6762 Mul->eraseFromParent();
6763 return NewMul;
6764 }
6765
6766 return Op;
6767}
6768
6769static VPExpressionRecipe *
6770createPartialReductionExpression(VPReductionRecipe *Red) {
6771 VPValue *VecOp = Red->getVecOp();
6772
6773 // reduce.[f]add(ext(op))
6774 // -> VPExpressionRecipe(op, red)
6775 if (match(VecOp, m_WidenAnyExtend(m_VPValue())))
6776 return new VPExpressionRecipe(cast<VPWidenCastRecipe>(VecOp), Red);
6777
6778 // reduce.[f]add(neg(ext(op)))
6779 // -> VPExpressionRecipe(op, sub/neg, red)
6780 if (match(VecOp, m_AnyNeg(m_WidenAnyExtend(m_VPValue())))) {
6781 auto *Neg = cast<VPWidenRecipe>(VecOp);
6782 auto *Ext =
6783 cast<VPWidenCastRecipe>(Neg->getOperand(Neg->getNumOperands() - 1));
6784 return new VPExpressionRecipe(Ext, Neg, Red);
6785 }
6786
6787 // reduce.[f]add([f]mul(ext(a), ext(b)))
6788 // -> VPExpressionRecipe(a, b, mul, red)
6789 if (match(VecOp, m_FMul(m_FPExt(m_VPValue()), m_FPExt(m_VPValue()))) ||
6790 match(VecOp,
6792 auto *Mul = cast<VPWidenRecipe>(VecOp);
6793 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
6794 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
6795 return new VPExpressionRecipe(ExtA, ExtB, Mul, Red);
6796 }
6797
6798 // reduce.fadd(fneg(fmul(fpext(a), fpext(b))))
6799 // -> VPExpressionRecipe(a, b, fmul, fsub, red)
6800 if (match(VecOp,
6802 auto *FNeg = cast<VPWidenRecipe>(VecOp);
6803 auto *FMul = cast<VPWidenRecipe>(FNeg->getOperand(0));
6804 auto *ExtA = cast<VPWidenCastRecipe>(FMul->getOperand(0));
6805 auto *ExtB = cast<VPWidenCastRecipe>(FMul->getOperand(1));
6806 return new VPExpressionRecipe(ExtA, ExtB, FMul, FNeg, Red);
6807 }
6808
6809 // reduce.add(neg(mul(ext(a), ext(b))))
6810 // -> VPExpressionRecipe(a, b, mul, sub, red)
6812 m_ZExtOrSExt(m_VPValue()))))) {
6813 auto *Sub = cast<VPWidenRecipe>(VecOp);
6814 auto *Mul = cast<VPWidenRecipe>(Sub->getOperand(1));
6815 auto *ExtA = cast<VPWidenCastRecipe>(Mul->getOperand(0));
6816 auto *ExtB = cast<VPWidenCastRecipe>(Mul->getOperand(1));
6817 return new VPExpressionRecipe(ExtA, ExtB, Mul, Sub, Red);
6818 }
6819
6820 llvm_unreachable("Unsupported expression");
6821}
6822
6823// Helper to transform a partial reduction chain into a partial reduction
6824// recipe. Assumes profitability has been checked.
6825static void transformToPartialReduction(const VPPartialReductionChain &Chain,
6826 VPlan &Plan,
6827 VPReductionPHIRecipe *RdxPhi) {
6828 VPWidenRecipe *WidenRecipe = Chain.ReductionBinOp;
6829 assert(WidenRecipe->getNumOperands() == 2 && "Expected binary operation");
6830
6831 VPValue *Accumulator = WidenRecipe->getOperand(Chain.AccumulatorOpIdx);
6832 auto *ExtendedOp = cast<VPSingleDefRecipe>(
6833 WidenRecipe->getOperand(1 - Chain.AccumulatorOpIdx));
6834
6835 // FIXME: Do these transforms before invoking the cost-model.
6836 ExtendedOp = optimizeExtendsForPartialReduction(ExtendedOp);
6837
6838 // Sub-reductions can be implemented in two ways:
6839 // (1) negate the operand in the vector loop (the default way).
6840 // (2) subtract the reduced value from the init value in the middle block.
6841 // Both ways keep the reduction itself as an 'add' reduction.
6842 //
6843 // The ISD nodes for partial reductions don't support folding the
6844 // sub/negation into its operands because the following is not a valid
6845 // transformation:
6846 // sub(0, mul(ext(a), ext(b)))
6847 // -> mul(ext(a), ext(sub(0, b)))
6848 //
6849 // It's therefore better to choose option (2) such that the partial
6850 // reduction is always positive (starting at '0') and to do a final
6851 // subtract in the middle block.
6852 if ((WidenRecipe->getOpcode() == Instruction::Sub &&
6853 Chain.RK != RecurKind::Sub) ||
6854 (WidenRecipe->getOpcode() == Instruction::FSub &&
6855 Chain.RK != RecurKind::FSub)) {
6856 VPBuilder Builder(WidenRecipe);
6857 Type *ElemTy = ExtendedOp->getScalarType();
6858 VPWidenRecipe *NegRecipe;
6859 if (WidenRecipe->getOpcode() == Instruction::FSub) {
6860 NegRecipe =
6861 new VPWidenRecipe(Instruction::FNeg, {ExtendedOp}, VPIRFlags(),
6863 } else {
6864 auto *Zero = Plan.getZero(ElemTy);
6865 NegRecipe =
6866 new VPWidenRecipe(Instruction::Sub, {Zero, ExtendedOp}, VPIRFlags(),
6868 }
6869 Builder.insert(NegRecipe);
6870 ExtendedOp = NegRecipe;
6871 }
6872
6873 // Check if WidenRecipe is the final result of the reduction. If so, look
6874 // through the Select recipe introduced by tail-folding, otherwise look
6875 // through any Blend recipe introduced by predication for the block.
6876 VPValue *ExitSearch =
6877 Chain.Blend ? cast<VPValue>(Chain.Blend) : cast<VPValue>(WidenRecipe);
6878
6879 VPValue *Cond = nullptr;
6881 findUserOf(ExitSearch, m_Select(m_VPValue(Cond), m_Specific(ExitSearch),
6882 m_Specific(RdxPhi))));
6883
6884 if (Chain.Blend) {
6885 std::optional<unsigned> BlendReductionIdx =
6886 getBlendReductionUpdateValueIdx(Chain.Blend);
6887 assert(BlendReductionIdx &&
6888 Chain.Blend->getIncomingValue(*BlendReductionIdx) == WidenRecipe &&
6889 "Expected blend to contain the reduction update");
6890 VPValue *BlendCond = Chain.Blend->getMask(*BlendReductionIdx);
6891 Cond = ExitValue ? VPBuilder(WidenRecipe)
6892 .createLogicalAnd(Cond, BlendCond,
6893 WidenRecipe->getDebugLoc())
6894 : BlendCond;
6895 }
6896
6897 bool IsLastInChain = RdxPhi->getBackedgeValue() == WidenRecipe ||
6898 RdxPhi->getBackedgeValue() == ExitValue ||
6899 RdxPhi->getBackedgeValue() == Chain.Blend;
6900 assert((!ExitValue || IsLastInChain) &&
6901 "if we found ExitValue, it must match RdxPhi's backedge value");
6902
6903 Type *PhiType = RdxPhi->getScalarType();
6904 RecurKind RdxKind =
6906 auto *PartialRed = new VPReductionRecipe(
6907 RdxKind,
6908 RdxKind == RecurKind::FAdd ? WidenRecipe->getFastMathFlagsOrNone()
6909 : FastMathFlags(),
6910 WidenRecipe->getUnderlyingInstr(), Accumulator, ExtendedOp, Cond,
6911 RdxUnordered{/*VFScaleFactor=*/Chain.ScaleFactor});
6912 PartialRed->insertBefore(WidenRecipe);
6913
6914 if (ExitValue)
6915 ExitValue->replaceAllUsesWith(PartialRed);
6916 if (Chain.Blend)
6917 Chain.Blend->replaceAllUsesWith(PartialRed);
6918 WidenRecipe->replaceAllUsesWith(PartialRed);
6919
6920 // For cost-model purposes, fold this into a VPExpression.
6921 VPExpressionRecipe *E = createPartialReductionExpression(PartialRed);
6922 E->insertBefore(WidenRecipe);
6923 PartialRed->replaceAllUsesWith(E);
6924
6925 // We only need to update the PHI node once, which is when we find the
6926 // last reduction in the chain.
6927 if (!IsLastInChain)
6928 return;
6929
6930 // Scale the PHI and ReductionStartVector by the VFScaleFactor
6931 assert(RdxPhi->getVFScaleFactor() == 1 && "scale factor must not be set");
6932 RdxPhi->setVFScaleFactor(Chain.ScaleFactor);
6933
6934 auto *StartInst = cast<VPInstruction>(RdxPhi->getStartValue());
6935 assert(StartInst->getOpcode() == VPInstruction::ReductionStartVector);
6936 auto *NewScaleFactor = Plan.getConstantInt(32, Chain.ScaleFactor);
6937 StartInst->setOperand(2, NewScaleFactor);
6938
6939 // If this is the last value in a sub-reduction chain, then update the PHI
6940 // node to start at `0` and update the reduction-result to subtract from
6941 // the PHI's start value.
6942 if (Chain.RK != RecurKind::Sub && Chain.RK != RecurKind::FSub)
6943 return;
6944
6945 VPValue *OldStartValue = StartInst->getOperand(0);
6946 StartInst->setOperand(0, StartInst->getOperand(1));
6947
6948 // Replace reduction_result by 'sub (startval, reductionresult)'.
6950 assert(RdxResult && "Could not find reduction result");
6951
6952 VPBuilder Builder = VPBuilder::getToInsertAfter(RdxResult);
6953 unsigned SubOpc = Chain.RK == RecurKind::FSub ? Instruction::BinaryOps::FSub
6954 : Instruction::BinaryOps::Sub;
6955 VPInstruction *NewResult = Builder.createNaryOp(
6956 SubOpc, {OldStartValue, RdxResult}, VPIRFlags::getDefaultFlags(SubOpc),
6957 RdxPhi->getDebugLoc());
6958 RdxResult->replaceUsesWithIf(
6959 NewResult,
6960 [&NewResult](VPUser &U, unsigned Idx) { return &U != NewResult; });
6961}
6962
6963/// Returns the cost of a link in a partial-reduction chain for a given VF.
6964static InstructionCost
6965getPartialReductionLinkCost(VPCostContext &CostCtx,
6966 const VPPartialReductionChain &Link,
6967 ElementCount VF) {
6968 Type *RdxType = Link.ReductionBinOp->getScalarType();
6969 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
6970 std::optional<unsigned> BinOpc = std::nullopt;
6971 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
6972 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
6973 BinOpc = ExtendedOp.ExtendsUser->getOpcode();
6974
6975 std::optional<llvm::FastMathFlags> Flags;
6976 if (RdxType->isFloatingPointTy())
6977 Flags = Link.ReductionBinOp->getFastMathFlagsOrNone();
6978
6979 auto GetLinkOpcode = [&Link]() -> unsigned {
6980 switch (Link.RK) {
6981 case RecurKind::Sub:
6982 return Instruction::Add;
6983 case RecurKind::FSub:
6984 return Instruction::FAdd;
6985 default:
6986 return Link.ReductionBinOp->getOpcode();
6987 }
6988 };
6989
6990 return CostCtx.TTI.getPartialReductionCost(
6991 GetLinkOpcode(), ExtendedOp.ExtendA.SrcType, ExtendedOp.ExtendB.SrcType,
6992 RdxType, VF, ExtendedOp.ExtendA.Kind, ExtendedOp.ExtendB.Kind, BinOpc,
6993 CostCtx.CostKind, Flags);
6994}
6995
6996static ExtendKind getPartialReductionExtendKind(VPWidenCastRecipe *Cast) {
6998}
6999
7000/// Checks if \p Op (which is an operand of \p UpdateR) is an extended reduction
7001/// operand. This is an operand where the source of the value (e.g. a load) has
7002/// been extended (sext, zext, or fpext) before it is used in the reduction.
7003///
7004/// Possible forms matched by this function:
7005/// - UpdateR(PrevValue, ext(...))
7006/// - UpdateR(PrevValue, mul(ext(...), ext(...)))
7007/// - UpdateR(PrevValue, mul(ext(...), Constant))
7008/// - UpdateR(PrevValue, ext(mul(ext(...), ext(...))))
7009/// - UpdateR(PrevValue, ext(mul(ext(...), Constant)))
7010/// - UpdateR(PrevValue, abs(sub(ext(...), ext(...)))
7011///
7012/// Note: The second operand of UpdateR corresponds to \p Op in the examples.
7013static std::optional<ExtendedReductionOperand>
7014matchExtendedReductionOperand(VPWidenRecipe *UpdateR, VPValue *Op) {
7015 assert(is_contained(UpdateR->operands(), Op) &&
7016 "Op should be operand of UpdateR");
7017
7018 // Try matching an absolute difference operand of the form
7019 // `abs(sub(ext(A), ext(B)))`. This will be later transformed into
7020 // `ext(absolute-difference(A, B))`. This allows us to perform the absolute
7021 // difference on a wider type and get the extend for "free" from the partial
7022 // reduction.
7023 VPValue *X, *Y;
7024 if (Op->hasOneUse() &&
7028 auto *Abs = cast<VPWidenIntrinsicRecipe>(Op);
7029 auto *Sub = cast<VPWidenRecipe>(Abs->getOperand(0));
7030 auto *LHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(0));
7031 auto *RHSExt = cast<VPWidenCastRecipe>(Sub->getOperand(1));
7032 Type *LHSInputType = X->getScalarType();
7033 Type *RHSInputType = Y->getScalarType();
7034 if (LHSInputType != RHSInputType ||
7035 LHSExt->getOpcode() != RHSExt->getOpcode())
7036 return std::nullopt;
7037 // Note: This is essentially the same as matching ext(...) as we will
7038 // rewrite this operand to ext(absolute-difference(A, B)).
7039 return ExtendedReductionOperand{
7040 Sub,
7041 /*ExtendA=*/{LHSInputType, getPartialReductionExtendKind(LHSExt)},
7042 /*ExtendB=*/{}};
7043 }
7044
7045 std::optional<TTI::PartialReductionExtendKind> OuterExtKind;
7047 auto *CastRecipe = cast<VPWidenCastRecipe>(Op);
7048 VPValue *CastSource = CastRecipe->getOperand(0);
7049 OuterExtKind = getPartialReductionExtendKind(CastRecipe);
7050 if (match(CastSource, m_Mul(m_VPValue(), m_VPValue())) ||
7051 match(CastSource, m_FMul(m_VPValue(), m_VPValue()))) {
7052 // Match: ext(mul(...))
7053 // Record the outer extend kind and set `Op` to the mul. We can then match
7054 // this as a binary operation. Note: We can optimize out the outer extend
7055 // by widening the inner extends to match it. See
7056 // optimizeExtendsForPartialReduction.
7057 Op = CastSource;
7058 } else {
7059 return ExtendedReductionOperand{
7060 UpdateR,
7061 /*ExtendA=*/{CastSource->getScalarType(), *OuterExtKind},
7062 /*ExtendB=*/{}};
7063 }
7064 }
7065
7066 if (!Op->hasOneUse())
7067 return std::nullopt;
7068
7070 if (!MulOp ||
7071 !is_contained({Instruction::Mul, Instruction::FMul}, MulOp->getOpcode()))
7072 return std::nullopt;
7073
7074 // The rest of the matching assumes `Op` is a (possibly extended) mul
7075 // operation.
7076
7077 VPValue *LHS = MulOp->getOperand(0);
7078 VPValue *RHS = MulOp->getOperand(1);
7079
7080 // The LHS of the operation must always be an extend.
7082 return std::nullopt;
7083
7084 auto *LHSCast = cast<VPWidenCastRecipe>(LHS);
7085 Type *LHSInputType = LHSCast->getOperand(0)->getScalarType();
7086 ExtendKind LHSExtendKind = getPartialReductionExtendKind(LHSCast);
7087
7088 // The RHS of the operation can be an extend or a constant integer.
7089 const APInt *RHSConst = nullptr;
7090 VPWidenCastRecipe *RHSCast = nullptr;
7092 RHSCast = cast<VPWidenCastRecipe>(RHS);
7093 else if (!match(RHS, m_APInt(RHSConst)) ||
7094 !canConstantBeExtended(RHSConst, LHSInputType, LHSExtendKind))
7095 return std::nullopt;
7096
7097 // The outer extend kind must match the inner extends for folding.
7098 for (VPWidenCastRecipe *Cast : {LHSCast, RHSCast})
7099 if (Cast && OuterExtKind &&
7100 getPartialReductionExtendKind(Cast) != OuterExtKind)
7101 return std::nullopt;
7102
7103 Type *RHSInputType = LHSInputType;
7104 ExtendKind RHSExtendKind = LHSExtendKind;
7105 if (RHSCast) {
7106 RHSInputType = RHSCast->getOperand(0)->getScalarType();
7107 RHSExtendKind = getPartialReductionExtendKind(RHSCast);
7108 }
7109
7110 return ExtendedReductionOperand{
7111 MulOp, {LHSInputType, LHSExtendKind}, {RHSInputType, RHSExtendKind}};
7112}
7113
7114/// Examines each operation in the reduction chain corresponding to \p RedPhiR,
7115/// and determines if the target can use a cheaper operation with a wider
7116/// per-iteration input VF and narrower PHI VF. If successful, returns the chain
7117/// of operations in the reduction.
7118static std::optional<SmallVector<VPPartialReductionChain>>
7119getScaledReductions(VPReductionPHIRecipe *RedPhiR) {
7120 // Get the backedge value from the reduction PHI and find the
7121 // ComputeReductionResult that uses it (directly or through a select for
7122 // predicated reductions).
7123 auto *RdxResult = vputils::findComputeReductionResult(RedPhiR);
7124 if (!RdxResult)
7125 return std::nullopt;
7126 VPValue *ExitValue = RdxResult->getOperand(0);
7127 match(ExitValue, m_Select(m_VPValue(), m_VPValue(ExitValue), m_VPValue()));
7128
7130 RecurKind RK = RedPhiR->getRecurrenceKind();
7131 Type *PhiType = RedPhiR->getScalarType();
7132 TypeSize PHISize = PhiType->getPrimitiveSizeInBits();
7133
7134 // Work backwards from the ExitValue examining each reduction operation.
7135 VPValue *CurrentValue = ExitValue;
7136 while (CurrentValue != RedPhiR) {
7137 VPBlendRecipe *Blend = dyn_cast<VPBlendRecipe>(CurrentValue);
7138 std::optional<unsigned> BlendReductionIdx;
7139 if (Blend) {
7140 assert(!Blend->isNormalized() && "Expect Blend not to be normalized.");
7141 if (Blend->getNumIncomingValues() != 2)
7142 return std::nullopt;
7143
7144 BlendReductionIdx = getBlendReductionUpdateValueIdx(Blend);
7145 if (!BlendReductionIdx)
7146 return std::nullopt;
7147
7148 CurrentValue = Blend->getIncomingValue(*BlendReductionIdx);
7149 }
7150
7151 auto *UpdateR = dyn_cast<VPWidenRecipe>(CurrentValue);
7152 if (!UpdateR || !Instruction::isBinaryOp(UpdateR->getOpcode()))
7153 return std::nullopt;
7154
7155 VPValue *Op = UpdateR->getOperand(1);
7156 VPValue *PrevValue = UpdateR->getOperand(0);
7157
7158 // Find the extended operand. The other operand (PrevValue) is the next link
7159 // in the reduction chain.
7160 std::optional<ExtendedReductionOperand> ExtendedOp =
7161 matchExtendedReductionOperand(UpdateR, Op);
7162 if (!ExtendedOp) {
7163 ExtendedOp = matchExtendedReductionOperand(UpdateR, PrevValue);
7164 if (!ExtendedOp)
7165 return std::nullopt;
7166 std::swap(Op, PrevValue);
7167 }
7168
7169 // Look for VPBlend(reduce(PrevValue, Op), PrevValue), where
7170 // reduce is equal to CurrentValue. This can be lowered as
7171 // a conditional reduction by hoisting the select to the inputs.
7172 if (Blend && Blend->getIncomingValue(1 - *BlendReductionIdx) != PrevValue)
7173 return std::nullopt;
7174
7175 Type *ExtSrcType = ExtendedOp->ExtendA.SrcType;
7176 TypeSize ExtSrcSize = ExtSrcType->getPrimitiveSizeInBits();
7177 if (!PHISize.hasKnownScalarFactor(ExtSrcSize))
7178 return std::nullopt;
7179
7180 VPPartialReductionChain Link(
7181 {UpdateR, *ExtendedOp, RK,
7182 PrevValue == UpdateR->getOperand(0) ? 0U : 1U,
7183 static_cast<unsigned>(PHISize.getKnownScalarFactor(ExtSrcSize)),
7184 Blend});
7185 Chain.push_back(Link);
7186 CurrentValue = PrevValue;
7187 }
7188
7189 // The chain links were collected by traversing backwards from the exit value.
7190 // Reverse the chains so they are in program order.
7191 std::reverse(Chain.begin(), Chain.end());
7192 return Chain;
7193}
7194} // namespace
7195
7197 VPCostContext &CostCtx,
7198 VFRange &Range) {
7199 // Find all possible valid partial reductions, grouping chains by their PHI.
7200 // This grouping allows invalidating the whole chain, if any link is not a
7201 // valid partial reduction.
7203 ChainsByPhi;
7204 VPBasicBlock *HeaderVPBB = Plan.getVectorLoopRegion()->getEntryBasicBlock();
7205 for (VPRecipeBase &R : HeaderVPBB->phis()) {
7206 auto *RedPhiR = dyn_cast<VPReductionPHIRecipe>(&R);
7207 if (!RedPhiR)
7208 continue;
7209
7210 if (auto Chains = getScaledReductions(RedPhiR))
7211 ChainsByPhi.try_emplace(RedPhiR, std::move(*Chains));
7212 }
7213
7214 if (ChainsByPhi.empty())
7215 return;
7216
7217 // Build set of partial reduction operations and blends for user validation
7218 // and a map of reduction bin ops to their scale factors for scale validation.
7219 SmallPtrSet<VPRecipeBase *, 4> PartialReductionOps;
7220 SmallPtrSet<VPBlendRecipe *, 4> PartialReductionBlends;
7221 DenseMap<VPSingleDefRecipe *, unsigned> ScaledReductionMap;
7222 for (const auto &[_, Chains] : ChainsByPhi)
7223 for (const VPPartialReductionChain &Chain : Chains) {
7224 PartialReductionOps.insert(Chain.ExtendedOp.ExtendsUser);
7225 if (Chain.Blend)
7226 PartialReductionBlends.insert(Chain.Blend);
7227 ScaledReductionMap[Chain.ReductionBinOp] = Chain.ScaleFactor;
7228 }
7229
7230 // A partial reduction is invalid if any of its extends are used by
7231 // something that isn't another partial reduction. This is because the
7232 // extends are intended to be lowered along with the reduction itself.
7233 auto ExtendUsersValid = [&](VPValue *Ext) {
7234 return !isa<VPWidenCastRecipe>(Ext) || all_of(Ext->users(), [&](VPUser *U) {
7235 return PartialReductionOps.contains(cast<VPRecipeBase>(U));
7236 });
7237 };
7238
7239 auto IsProfitablePartialReductionChainForVF =
7240 [&](ArrayRef<VPPartialReductionChain> Chain, ElementCount VF) -> bool {
7241 InstructionCost PartialCost = 0, RegularCost = 0;
7242
7243 // The chain is a profitable partial reduction chain if the cost of handling
7244 // the entire chain is cheaper when using partial reductions than when
7245 // handling the entire chain using regular reductions.
7246 for (const VPPartialReductionChain &Link : Chain) {
7247 const ExtendedReductionOperand &ExtendedOp = Link.ExtendedOp;
7248 InstructionCost LinkCost = getPartialReductionLinkCost(CostCtx, Link, VF);
7249 if (!LinkCost.isValid())
7250 return false;
7251
7252 PartialCost += LinkCost;
7253 RegularCost += Link.ReductionBinOp->computeCost(VF, CostCtx);
7254 // If ExtendB is not none, then the "ExtendsUser" is the binary operation.
7255 if (ExtendedOp.ExtendB.Kind != ExtendKind::PR_None)
7256 RegularCost += ExtendedOp.ExtendsUser->computeCost(VF, CostCtx);
7257 for (VPValue *Op : ExtendedOp.ExtendsUser->operands())
7258 if (auto *Extend = dyn_cast<VPWidenCastRecipe>(Op))
7259 RegularCost += Extend->computeCost(VF, CostCtx);
7260 }
7261 return PartialCost.isValid() && PartialCost < RegularCost;
7262 };
7263
7264 // Validate chains: check that extends are only used by partial reductions,
7265 // and that reduction bin ops are only used by other partial reductions with
7266 // matching scale factors, are outside the loop region or the select
7267 // introduced by tail-folding. Otherwise we would create users of scaled
7268 // reductions where the types of the other operands don't match.
7269 for (auto &[RedPhiR, Chains] : ChainsByPhi) {
7270 for (const VPPartialReductionChain &Chain : Chains) {
7271 if (!all_of(Chain.ExtendedOp.ExtendsUser->operands(), ExtendUsersValid)) {
7272 Chains.clear();
7273 break;
7274 }
7275 auto UseIsValid = [&, RedPhiR = RedPhiR](VPUser *U) {
7276 if (auto *PhiR = dyn_cast<VPReductionPHIRecipe>(U))
7277 return PhiR == RedPhiR;
7278 auto *R = cast<VPSingleDefRecipe>(U);
7279
7280 if (auto *Blend = dyn_cast<VPBlendRecipe>(R))
7281 return Blend == Chain.Blend || PartialReductionBlends.contains(Blend);
7282
7283 return Chain.ScaleFactor == ScaledReductionMap.lookup_or(R, 0) ||
7285 m_Specific(Chain.ReductionBinOp))) ||
7286 match(R, m_Select(m_VPValue(), m_Specific(Chain.ReductionBinOp),
7287 m_Specific(RedPhiR)));
7288 };
7289 if (!all_of(Chain.ReductionBinOp->users(), UseIsValid)) {
7290 Chains.clear();
7291 break;
7292 }
7293
7294 // Check if the compute-reduction-result is used by a sunk store.
7295 // TODO: Also form partial reductions in those cases.
7296 if (auto *RdxResult = vputils::findComputeReductionResult(RedPhiR)) {
7297 if (any_of(RdxResult->users(), [](VPUser *U) {
7298 auto *RepR = dyn_cast<VPReplicateRecipe>(U);
7299 return RepR && RepR->getOpcode() == Instruction::Store;
7300 })) {
7301 Chains.clear();
7302 break;
7303 }
7304 }
7305 }
7306
7307 // Clear the chain if it is not profitable.
7309 [&, &Chains = Chains](ElementCount VF) {
7310 return IsProfitablePartialReductionChainForVF(Chains, VF);
7311 },
7312 Range))
7313 Chains.clear();
7314 }
7315
7316 for (auto &[Phi, Chains] : ChainsByPhi)
7317 for (const VPPartialReductionChain &Chain : Chains)
7318 transformToPartialReduction(Chain, Plan, Phi);
7319}
7320
7321/// If the pointer operand \p Addr of a memory access is an affine AddRec
7322/// w.r.t. \p L with a constant stride, return the stride in units of
7323/// \p AccessTy. Otherwise return std::nullopt.
7324static std::optional<int64_t> getConstantStride(VPValue *Addr, Type *AccessTy,
7326 const Loop *L) {
7327 const SCEV *AddrSCEV = vputils::getSCEVExprForVPValue(Addr, PSE, L);
7328 auto *AddRec = dyn_cast<SCEVAddRecExpr>(AddrSCEV);
7329 if (!AddRec)
7330 return {};
7331
7332 return getStrideFromAddRec(AddRec, L, AccessTy, /*Ptr=*/nullptr, PSE);
7333}
7334
7336 VPRecipeBuilder &RecipeBuilder,
7337 VPCostContext &CostCtx) {
7338 // Collect all loads/stores first. We will start with ones having simpler
7339 // decisions followed by more complex ones that are potentially
7340 // guided/dependent on the simpler ones.
7342 for (VPBasicBlock *VPBB :
7345 for (VPRecipeBase &R : *VPBB) {
7346 auto *VPI = dyn_cast<VPInstruction>(&R);
7347 if (VPI && VPI->getUnderlyingValue() &&
7348 is_contained({Instruction::Load, Instruction::Store},
7349 VPI->getOpcode()))
7350 MemOps.push_back(VPI);
7351 }
7352 }
7353
7354 // Few helpers to process different kinds of memory operations.
7355
7356 // To be used as argument to `VPlanTransforms::runPass` which explicitly
7357 // specified pass name, hence `VPlan &` parameter.
7358 auto ProcessSubset = [&](VPlan &, auto ProcessVPInst) {
7359 SmallVector<VPInstruction *> RemainingMemOps;
7360 for (VPInstruction *VPI : MemOps) {
7361 if (!ProcessVPInst(VPI))
7362 RemainingMemOps.push_back(VPI);
7363 }
7364
7365 MemOps.clear();
7366 std::swap(MemOps, RemainingMemOps);
7367 };
7368
7369 auto ReplaceWith = [&](VPInstruction *VPI, VPRecipeBase *New) {
7370 New->insertBefore(VPI);
7371 if (VPI->getOpcode() == Instruction::Load)
7372 VPI->replaceAllUsesWith(New->getVPSingleValue());
7373 VPI->eraseFromParent();
7374
7375 // VPI has been processed.
7376 return true;
7377 };
7378
7379 auto Scalarize = [&](VPInstruction *VPI) {
7380 return ReplaceWith(VPI, RecipeBuilder.handleReplication(VPI, Range));
7381 };
7382
7383 VPBasicBlock *MiddleVPBB = Plan.getMiddleBlock();
7384 VPBuilder FinalRedStoresBuilder(MiddleVPBB, MiddleVPBB->getFirstNonPhi());
7386 "lowerMemoryIdioms", ProcessSubset, Plan, [&](VPInstruction *VPI) {
7387 if (RecipeBuilder.replaceWithFinalIfReductionStore(
7388 VPI, FinalRedStoresBuilder))
7389 return true;
7390
7391 // Filter out scalar VPlan for the remaining idioms.
7393 [](ElementCount VF) { return VF.isScalar(); }, Range))
7394 return false;
7395
7396 if (VPHistogramRecipe *Histogram = RecipeBuilder.widenIfHistogram(VPI))
7397 return ReplaceWith(VPI, Histogram);
7398
7399 return false;
7400 });
7401
7402 // Filter out scalar VPlan for the remaining memory operations.
7404 [](ElementCount VF) { return VF.isScalar(); }, Range))
7405 return;
7406
7407 // If the instruction's allocated size doesn't equal it's type size, it
7408 // requires padding and will be scalarized.
7410 "scalarizeMemOpsWithIrregularTypes", ProcessSubset, Plan,
7411 [&](VPInstruction *VPI) {
7413 if (hasIrregularType(getLoadStoreType(I), I->getDataLayout()))
7414 return Scalarize(VPI);
7415
7416 return false;
7417 });
7418
7419 if (!RecipeBuilder.prefersVectorizedAddressing()) {
7421 "makeVPlanMemOpDecision", ProcessSubset, Plan, [&](VPInstruction *VPI) {
7423 bool IsLoad = VPI->getOpcode() == Instruction::Load;
7424 if (RecipeBuilder.isPredicatedInst(I) || !IsLoad ||
7426 return false;
7427
7428 // Scalarize loads used as addresses, matching the legacy CM. The load
7429 // is single-scalar if the pointer is loop-invariant, otherwise it is
7430 // replicated per-lane. No mask is needed as the load is not
7431 // predicated.
7432 VPValue *Ptr = VPI->getOperand(0);
7433 const SCEV *PtrSCEV =
7434 vputils::getSCEVExprForVPValue(Ptr, CostCtx.PSE, CostCtx.L);
7435 bool IsSingleScalarLoad =
7436 !isa<SCEVCouldNotCompute>(PtrSCEV) &&
7437 CostCtx.PSE.getSE()->isLoopInvariant(PtrSCEV, CostCtx.L);
7438
7439 ReplaceWith(VPI,
7441 I, Ptr, /*IsSingleScalar=*/IsSingleScalarLoad,
7442 /*Mask=*/nullptr, *VPI, *VPI, VPI->getDebugLoc()));
7443 return true;
7444 });
7445 }
7446
7447 // Widen unmasked unit-stride consecutive accesses, matching the legacy CM.
7449 "widenConsecutiveMemOps", ProcessSubset, Plan, [&](VPInstruction *VPI) {
7451 if (RecipeBuilder.isPredicatedInst(I))
7452 return false;
7453
7454 bool IsLoad = VPI->getOpcode() == Instruction::Load;
7455 VPValue *Ptr = VPI->getOperand(!IsLoad);
7456 Type *ScalarTy =
7457 IsLoad ? VPI->getScalarType() : VPI->getOperand(0)->getScalarType();
7458 if (getConstantStride(Ptr, ScalarTy, CostCtx.PSE, CostCtx.L) != 1)
7459 return false;
7460
7461 Type *StrideTy =
7463 VPValue *StrideOne = Plan.getConstantInt(StrideTy, 1);
7464 auto *VectorPtr = new VPVectorPointerRecipe(
7465 Ptr, ScalarTy, StrideOne, vputils::getGEPFlagsForPtr(Ptr),
7466 VPI->getDebugLoc());
7467 VectorPtr->insertBefore(VPI);
7468 VPRecipeBase *WidenedR;
7469 if (IsLoad)
7470 WidenedR = new VPWidenLoadRecipe(*cast<LoadInst>(I), VectorPtr,
7471 /*Mask=*/nullptr,
7472 /*Consecutive=*/true, *VPI,
7473 VPI->getDebugLoc());
7474 else
7475 WidenedR = new VPWidenStoreRecipe(
7476 *cast<StoreInst>(I), VectorPtr, VPI->getOperand(0),
7477 /*Mask=*/nullptr, /*Consecutive=*/true, *VPI, VPI->getDebugLoc());
7478 return ReplaceWith(VPI, WidenedR);
7479 });
7480
7481 VPlanTransforms::runPass("delegateMemOpWideningToLegacyCM", ProcessSubset,
7482 Plan, [&](VPInstruction *VPI) {
7483 if (VPRecipeBase *Recipe =
7484 RecipeBuilder.tryToWidenMemory(VPI, Range))
7485 return ReplaceWith(VPI, Recipe);
7486
7487 return Scalarize(VPI);
7488 });
7489}
7490
7493 [&](ElementCount VF) { return VF.isScalar(); }, Range))
7494 return;
7495
7497 Plan.getEntry());
7499 for (VPRecipeBase &R : make_early_inc_range(reverse(*VPBB))) {
7500 auto *VPI = dyn_cast<VPInstruction>(&R);
7501 if (!VPI)
7502 continue;
7503
7504 auto *I = cast_or_null<Instruction>(VPI->getUnderlyingValue());
7505 // Wouldn't be able to create a `VPReplicateRecipe` anyway.
7506 if (!I)
7507 continue;
7508
7509 // If executing other lanes produces side-effects we can't avoid them.
7510 if (VPI->mayHaveSideEffects())
7511 continue;
7512
7513 // We want to drop the mask operand, verify we can safely do that.
7514 if (VPI->isMasked() && !VPI->isSafeToSpeculativelyExecute())
7515 continue;
7516
7517 // Avoid rewriting IV increment as that interferes with
7518 // `removeRedundantCanonicalIVs`.
7519 if (VPI->getOpcode() == Instruction::Add &&
7521 continue;
7522
7523 // Other lanes are needed - can't drop them.
7525 continue;
7526
7527 auto *Recipe = VPBuilder::createSingleScalarOp(
7528 VPI->getOpcode(), VPI->operandsWithoutMask(), /*Mask=*/nullptr, *VPI,
7529 *VPI, VPI->getDebugLoc(), I);
7530 Recipe->insertBefore(VPI);
7531 VPI->replaceAllUsesWith(Recipe);
7532 VPI->eraseFromParent();
7533 }
7534 }
7535}
7536
7537/// Returns true if \p Info's parameter kinds are compatible with \p Args.
7538static bool areVFParamsOk(const VFInfo &Info, ArrayRef<VPValue *> Args,
7539 PredicatedScalarEvolution &PSE, const Loop *L) {
7540 ScalarEvolution *SE = PSE.getSE();
7541 return all_of(Info.Shape.Parameters, [&](VFParameter Param) {
7542 switch (Param.ParamKind) {
7543 case VFParamKind::Vector:
7544 case VFParamKind::GlobalPredicate:
7545 return true;
7546 case VFParamKind::OMP_Uniform:
7547 return SE->isSCEVable(Args[Param.ParamPos]->getScalarType()) &&
7548 SE->isLoopInvariant(
7549 vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
7550 L);
7551 case VFParamKind::OMP_Linear:
7552 return match(vputils::getSCEVExprForVPValue(Args[Param.ParamPos], PSE, L),
7553 m_scev_AffineAddRec(
7554 m_SCEV(), m_scev_SpecificSInt(Param.LinearStepOrPos),
7555 m_SpecificLoop(L)));
7556 default:
7557 return false;
7558 }
7559 });
7560}
7561
7562/// Find a vector variant of \p CI for \p VF, respecting \p MaskRequired.
7563/// Returns the variant function, or nullptr. Masked variants are assumed to
7564/// take the mask as a trailing parameter.
7566 ElementCount VF, bool MaskRequired,
7568 const Loop *L) {
7569 if (CI->isNoBuiltin())
7570 return nullptr;
7571 auto Mappings = VFDatabase::getMappings(*CI);
7572 const auto *It = find_if(Mappings, [&](const VFInfo &Info) {
7573 return Info.Shape.VF == VF && (!MaskRequired || Info.isMasked()) &&
7574 areVFParamsOk(Info, Args, PSE, L);
7575 });
7576 if (It == Mappings.end())
7577 return nullptr;
7578 return CI->getModule()->getFunction(It->VectorName);
7579}
7580
7581namespace {
7582/// The outcome of choosing how to widen a call at a given VF.
7583struct CallWideningDecision {
7584 enum class KindTy { Scalarize, Intrinsic, VectorVariant };
7585 CallWideningDecision(KindTy Kind, Function *Variant = nullptr)
7586 : Kind(Kind), Variant(Variant) {}
7587 KindTy Kind;
7588
7589 /// Set when Kind == VectorVariant.
7591
7592 bool operator==(const CallWideningDecision &Other) const {
7593 return Kind == Other.Kind && Variant == Other.Variant;
7594 }
7595};
7596} // namespace
7597
7598/// Pick the cheapest widening for the call \p VPI at \p VF among scalarization,
7599/// vector intrinsic, and vector library variant.
7600static CallWideningDecision decideCallWidening(VPInstruction &VPI,
7602 ElementCount VF,
7603 VPCostContext &CostCtx) {
7604 auto *CI = cast<CallInst>(VPI.getUnderlyingInstr());
7605
7606 // Scalar VFs and calls forced or known to scalarize always replicate.
7607 if (VF.isScalar() || CostCtx.willBeScalarized(CI, VF))
7608 return CallWideningDecision::KindTy::Scalarize;
7609
7610 auto *CalledFn = cast<Function>(
7612 Type *ResultTy = VPI.getScalarType();
7614 bool MaskRequired = CostCtx.isMaskRequired(CI);
7615
7616 // Pseudo intrinsics (assume, lifetime, ...) are always scalarized.
7618 return CallWideningDecision::KindTy::Scalarize;
7619
7620 InstructionCost ScalarCost =
7621 VPReplicateRecipe::computeCallCost(CalledFn, ResultTy, Ops,
7622 /*IsSingleScalar=*/false, VF, CostCtx);
7623
7624 Function *VecFunc =
7625 findVectorVariant(CI, Ops, VF, MaskRequired, CostCtx.PSE, CostCtx.L);
7627 if (VecFunc)
7628 VecCallCost = VPWidenCallRecipe::computeCallCost(VecFunc, CostCtx);
7629
7630 // Prefer the intrinsic if it is at least as cheap as scalarizing and any
7631 // available vector variant.
7632 if (ID) {
7635 if (IntrinsicCost.isValid() && ScalarCost >= IntrinsicCost &&
7636 (!VecFunc || VecCallCost >= IntrinsicCost))
7637 return CallWideningDecision::KindTy::Intrinsic;
7638 }
7639
7640 // Otherwise, use a vector library variant when it beats scalarizing.
7641 if (VecFunc && ScalarCost >= VecCallCost)
7642 return {CallWideningDecision::KindTy::VectorVariant, VecFunc};
7643
7644 return CallWideningDecision::KindTy::Scalarize;
7645}
7646
7648 VPRecipeBuilder &RecipeBuilder,
7649 VPCostContext &CostCtx) {
7652 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
7653 auto *VPI = dyn_cast<VPInstruction>(&R);
7654 if (!VPI || !VPI->getUnderlyingValue() ||
7655 VPI->getOpcode() != Instruction::Call)
7656 continue;
7657
7658 auto *CI = cast<CallInst>(VPI->getUnderlyingInstr());
7659 SmallVector<VPValue *, 4> Ops(VPI->op_begin(),
7660 VPI->op_begin() + CI->arg_size());
7661
7662 CallWideningDecision Decision =
7663 decideCallWidening(*VPI, Ops, Range.Start, CostCtx);
7665 [&](ElementCount VF) {
7666 return Decision == decideCallWidening(*VPI, Ops, VF, CostCtx);
7667 },
7668 Range);
7669
7670 VPSingleDefRecipe *Replacement = nullptr;
7671 switch (Decision.Kind) {
7672 case CallWideningDecision::KindTy::Intrinsic: {
7674 Type *ResultTy = VPI->getScalarType();
7675 Replacement = new VPWidenIntrinsicRecipe(*CI, ID, Ops, ResultTy, *VPI,
7676 *VPI, VPI->getDebugLoc());
7677 break;
7678 }
7679 case CallWideningDecision::KindTy::VectorVariant: {
7680 // Masked variants take the mask as a trailing parameter, so they have
7681 // one more parameter than the original call's arguments.
7682 if (Decision.Variant->arg_size() > Ops.size()) {
7683 VPValue *Mask = VPI->isMasked() ? VPI->getMask() : Plan.getTrue();
7684 Ops.push_back(Mask);
7685 }
7686 Ops.push_back(VPI->getOperand(VPI->getNumOperandsWithoutMask() - 1));
7687 Replacement = new VPWidenCallRecipe(CI, Decision.Variant, Ops, *VPI,
7688 *VPI, VPI->getDebugLoc());
7689 break;
7690 }
7691 case CallWideningDecision::KindTy::Scalarize:
7692 Replacement = RecipeBuilder.handleReplication(VPI, Range);
7693 break;
7694 }
7695
7696 Replacement->insertBefore(VPI);
7697 VPI->replaceAllUsesWith(Replacement);
7698 VPI->eraseFromParent();
7699 }
7700 }
7701}
7702
7705 Loop &L, VPCostContext &Ctx,
7706 VFRange &Range) {
7707 if (Plan.hasScalarVFOnly())
7708 return;
7709
7710 VPRegionBlock *VectorLoop = Plan.getVectorLoopRegion();
7711 VPValue *I32VF = nullptr;
7713 vp_depth_first_shallow(VectorLoop->getEntry()))) {
7714 for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
7715 auto *LoadR = dyn_cast<VPWidenLoadRecipe>(&R);
7716 // TODO: Support strided store.
7717 // TODO: Transform reverse access into strided access with -1 stride.
7718 // TODO: Transform gather/scatter with uniform address into strided access
7719 // with 0 stride.
7720 // TODO: Transform interleave access into multiple strided accesses.
7721 if (!LoadR || LoadR->isConsecutive())
7722 continue;
7723
7724 auto *Ptr = dyn_cast<VPWidenGEPRecipe>(LoadR->getAddr());
7725 if (!Ptr)
7726 continue;
7727
7728 // Check if this is a strided access by analyzing the address SCEV for an
7729 // affine addRec.
7730 const SCEV *PtrSCEV = vputils::getSCEVExprForVPValue(Ptr, PSE, &L);
7731 const SCEV *Start;
7732 const SCEVConstant *Step;
7733 // TODO: Support non-constant loop invariant stride.
7734 if (!match(PtrSCEV,
7736 m_SpecificLoop(&L))))
7737 continue;
7738
7739 Type *LoadTy = LoadR->getScalarType();
7740 Align Alignment = LoadR->getAlign();
7741 auto IsProfitable = [&](ElementCount VF) {
7742 Type *DataTy = toVectorTy(LoadTy, VF);
7743 if (!Ctx.TTI.isLegalStridedLoadStore(DataTy, Alignment))
7744 return false;
7745 const InstructionCost CurrentCost = LoadR->computeCost(VF, Ctx);
7746 const InstructionCost StridedLoadStoreCost =
7748 Intrinsic::experimental_vp_strided_load, DataTy,
7749 LoadR->isMasked(), Alignment, Ctx);
7750 return StridedLoadStoreCost < CurrentCost;
7751 };
7752
7754 Range))
7755 continue;
7756
7757 // Invalidate the legacy widening decision so the cost of replaced load is
7758 // not counted during precomputeCosts.
7759 // TODO: Remove once the legacy exit cost computation is retired.
7760 for (ElementCount VF : Range)
7761 Ctx.invalidateWideningDecision(&LoadR->getIngredient(), VF);
7762
7763 // Get VF as i32 for the vector length operand.
7764 if (!I32VF) {
7765 VPBuilder Builder(Plan.getVectorPreheader());
7766 I32VF = Builder.createScalarZExtOrTrunc(
7767 &Plan.getVF(), Type::getInt32Ty(Plan.getContext()),
7769 }
7770
7771 VPBuilder Builder(LoadR);
7772 // Create the base pointer of strided access.
7773 // TODO: reuse VPDerivedIVRecipe for base pointer computation when it
7774 // supports a general VPValue as the start value.
7775 VPValue *StartVPV =
7776 VPSCEVExpander(Builder, *PSE.getSE(), LoadR->getDebugLoc())
7777 .tryToExpand(Start);
7778 if (!StartVPV)
7779 StartVPV = VPBuilder(Plan.getEntry()).createExpandSCEV(Start);
7780 VPValue *StrideInBytes = Plan.getOrAddLiveIn(Step->getValue());
7781 Type *IndexTy = Plan.getDataLayout().getIndexType(Ptr->getScalarType());
7782 assert(IndexTy == StrideInBytes->getScalarType() &&
7783 "Stride type from SCEV must match the index type");
7784 VPValue *CanIV = Builder.createScalarSExtOrTrunc(
7785 VectorLoop->getCanonicalIV(), IndexTy,
7786 VectorLoop->getCanonicalIVType(), DebugLoc::getUnknown());
7787 auto *AddRecPtr = cast<SCEVAddRecExpr>(PtrSCEV);
7788 auto *Offset = Builder.createOverflowingOp(
7789 Instruction::Mul, {CanIV, StrideInBytes},
7790 {AddRecPtr->hasNoUnsignedWrap(), AddRecPtr->hasNoSignedWrap()});
7791 auto *BasePtr = Builder.createNoWrapPtrAdd(
7792 StartVPV, Offset,
7793 AddRecPtr->hasNoUnsignedWrap() ? GEPNoWrapFlags::noUnsignedWrap()
7795
7796 // Create a new vector pointer for strided access.
7797 VPValue *NewPtr = Builder.createVectorPointer(
7798 BasePtr, Type::getInt8Ty(Plan.getContext()), StrideInBytes,
7799 Ptr->getGEPNoWrapFlags(), Ptr->getDebugLoc());
7800
7801 VPValue *Mask = LoadR->getMask();
7802 if (!Mask)
7803 Mask = Plan.getTrue();
7804 auto *StridedLoad = Builder.createWidenMemIntrinsic(
7805 Intrinsic::experimental_vp_strided_load,
7806 {NewPtr, StrideInBytes, Mask, I32VF}, LoadTy, Alignment, *LoadR,
7807 LoadR->getDebugLoc());
7808 LoadR->replaceAllUsesWith(StridedLoad);
7809 }
7810 }
7811}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
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)
static const Function * getParent(const Value *V)
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
static cl::opt< IntrinsicCostStrategy > IntrinsicCost("intrinsic-cost-strategy", cl::desc("Costing strategy for intrinsic instructions"), cl::init(IntrinsicCostStrategy::InstructionCost), cl::values(clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost", "Use TargetTransformInfo::getInstructionCost"), clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost", "Use TargetTransformInfo::getIntrinsicInstrCost"), clEnumValN(IntrinsicCostStrategy::TypeBasedIntrinsicCost, "type-based-intrinsic-cost", "Calculate the intrinsic cost based only on argument types")))
@ Default
Hexagon Common GEP
#define _
iv Induction Variable Users
Definition IVUsers.cpp:48
iv users
Definition IVUsers.cpp:48
static std::pair< Value *, APInt > getMask(Value *WideMask, unsigned Factor, ElementCount LeafValueEC)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
licm
Definition LICM.cpp:383
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:81
#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.
MachineInstr unsigned OpIdx
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
R600 Clause Merge
const SmallVectorImpl< MachineOperand > & Cond
static bool dominates(InstrPosIndexes &PosIndexes, const MachineInstr &A, const MachineInstr &B)
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")
static SymbolRef::Type getType(const Symbol *Sym)
Definition TapiFile.cpp:39
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 bool handleUncountableExitsWithSideEffects(VPlan &Plan, SmallVectorImpl< EarlyExitInfo > &Exits, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB, 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 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 std::optional< VPValue * > getRecipesForUncountableExit(SmallVectorImpl< VPInstruction * > &Recipes, VPBasicBlock *LatchVPBB)
Returns the VPValue representing the uncountable exit comparison used by AnyOf if the recipes it depe...
static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder, bool CanCreateNewRecipe)
Try to simplify logical and bitwise recipes in Def.
static bool sinkScalarOperands(VPlan &Plan)
static 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.
static bool simplifyBranchConditionForVFAndUF(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
Try to simplify the branch condition of Plan.
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 bool tryToReplaceALMWithWideALM(VPlan &Plan, ElementCount VF, unsigned UF)
Try to replace multiple active lane masks used for control flow with a single, wide active lane mask ...
static std::optional< std::pair< bool, unsigned > > getOpcodeOrIntrinsicID(const VPSingleDefRecipe *R)
Get any instruction opcode or intrinsic ID data embedded in recipe R.
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 RemoveMask_match< Op0_t, Op1_t > m_RemoveMask(const Op0_t &In, Op1_t &Out)
Match a specific mask In, or a combination of it (logical-and In, Out).
static std::optional< ElementCount > isConsecutiveInterleaveGroup(VPInterleaveRecipe *InterleaveR, ArrayRef< ElementCount > VFs, const TargetTransformInfo &TTI)
Returns VF from VFs if IR is a full interleave group with factor and number of members both equal to ...
static Type * getLoadStoreValueType(VPReplicateRecipe *R, bool IsLoad)
Get the value type of the replicate load or store.
static VPIRMetadata getCommonMetadata(ArrayRef< VPReplicateRecipe * > Recipes)
static VPValue * getPredicatedMask(VPRegionBlock *R)
If R is a region with a VPBranchOnMaskRecipe in the entry block, return the mask.
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 VPScalarIVStepsRecipe * createScalarIVSteps(VPlan &Plan, InductionDescriptor::InductionKind Kind, Instruction::BinaryOps InductionOpcode, FPMathOperator *FPBinOp, Instruction *TruncI, VPIRValue *StartV, VPValue *Step, DebugLoc DL, VPBuilder &Builder)
static VPWidenInductionRecipe * getOptimizableIVOf(VPValue *VPV, PredicatedScalarEvolution &PSE)
Check if VPV is an untruncated wide induction, either before or after the increment.
static void fixupVFUsersForEVL(VPlan &Plan, VPValue &EVL)
After replacing the canonical IV with a EVL-based IV, fixup recipes that use VF to use the EVL instea...
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 void simplifyRecipe(VPSingleDefRecipe *Def)
Try to simplify VPSingleDefRecipe Def.
static bool isDeadRecipe(VPRecipeBase &R)
Returns true if R is dead and can be removed.
static void legalizeAndOptimizeInductions(VPlan &Plan)
Legalize VPWidenPointerInductionRecipe, by replacing it with a PtrAdd (IndStart, ScalarIVSteps (0,...
static void addReplicateRegions(VPlan &Plan)
static SmallVector< SmallVector< VPReplicateRecipe *, 4 > > collectGroupedReplicateMemOps(VPlan &Plan, PredicatedScalarEvolution &PSE, const Loop *L, function_ref< bool(VPReplicateRecipe *)> FilterFn)
Collect either replicated Loads or Stores grouped by their address SCEV and their load-store type,...
static VPValue * tryToComputeEndValueForInduction(VPWidenInductionRecipe *WideIV, VPBuilder &VectorPHBuilder, VPValue *VectorTC)
Compute the end value for WideIV, unless it is truncated.
static std::optional< Intrinsic::ID > getVPDivRemIntrinsic(Intrinsic::ID IntrID)
static void removeRedundantExpandSCEVRecipes(VPlan &Plan)
Remove redundant ExpandSCEVRecipes in Plan's entry block by replacing them with already existing reci...
static 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...
static VPValue * optimizeEarlyExitInductionUser(VPlan &Plan, VPValue *Op, PredicatedScalarEvolution &PSE)
Attempts to optimize the induction variable exit values for users in the early exit block.
static VPValue * narrowInterleaveGroupOp(ArrayRef< VPValue * > Members, SmallPtrSetImpl< VPValue * > &NarrowedOps, VPBasicBlock *Preheader)
static VPValue * scalarizeVPWidenPointerInduction(VPWidenPointerInductionRecipe *PtrIV, VPlan &Plan, VPBuilder &Builder)
Scalarize a VPWidenPointerInductionRecipe by replacing it with a PtrAdd (IndStart,...
static VPIRValue * tryToFoldLiveIns(VPSingleDefRecipe &R, ArrayRef< VPValue * > Operands, const DataLayout &DL)
Try to fold R using InstSimplifyFolder.
static SmallVector< VPUser * > collectUsersRecursively(VPValue *V)
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 recursivelyDeleteDeadRecipes(VPValue *V)
static void reassociateHeaderMask(VPlan &Plan)
Reassociate (headermask && x) && y -> headermask && (x && y) to allow the header mask to be simplifie...
static VPActiveLaneMaskPHIRecipe * addVPLaneMaskPhiAndUpdateExitBranch(VPlan &Plan)
static void expandVPDerivedIV(VPDerivedIVRecipe *R)
Expand a VPDerivedIVRecipe into executable recipes.
static VPBasicBlock * getPredicatedThenBlock(VPRegionBlock *R)
If R is a triangle region, return the 'then' block of the triangle.
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 std::optional< Instruction::BinaryOps > getUnmaskedDivRemOpcode(Intrinsic::ID ID)
static bool isAlreadyNarrow(VPValue *VPV)
Returns true if VPValue is a narrow VPValue.
static bool canNarrowOps(ArrayRef< VPValue * > Ops, bool IsScalable)
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 void expandVPWidenIntOrFpInduction(VPWidenIntOrFpInductionRecipe *WidenIVR)
Expand a VPWidenIntOrFpInduction into executable recipes, for the initial value, phi and backedge val...
static VPRecipeBase * optimizeMaskToEVL(VPValue *HeaderMask, VPRecipeBase &CurRecipe, VPValue &EVL)
Try to optimize a CurRecipe masked by HeaderMask to a corresponding EVL-based recipe without the head...
static void expandVPWidenPointerInduction(VPWidenPointerInductionRecipe *R)
Expand a VPWidenPointerInductionRecipe into executable recipes, for the initial value,...
static void narrowToSingleScalarRecipes(VPlan &Plan)
This file provides utility VPlan to VPlan transformations.
#define RUN_VPLAN_PASS(PASS,...)
This file declares the class VPlanVerifier, which contains utility functions to check the consistency...
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
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1055
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1537
APInt abs() const
Get the absolute value.
Definition APInt.h:1820
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1692
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
int32_t exactLogBase2() const
Definition APInt.h:1808
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1028
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:441
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
Definition APInt.h:1230
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
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
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
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...
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
Definition Constants.h:135
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.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
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 getCompilerGenerated()
Definition DebugLoc.h:154
static DebugLoc getUnknown()
Definition DebugLoc.h:153
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:250
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:260
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:151
constexpr bool isVector() const
One or more elements.
Definition TypeSize.h:324
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:312
constexpr bool isScalar() const
Exactly one element.
Definition TypeSize.h:320
Utility class for floating point operations which can have information about relaxed accuracy require...
Definition Operator.h:202
FastMathFlags getFastMathFlags() const
Convenience function for getting all the fast-math flags.
Definition Operator.h:291
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
size_t arg_size() const
Definition Function.h:875
Represents flags for the getelementptr instruction/expression.
static GEPNoWrapFlags noUnsignedWrap()
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.
static LLVM_ABI InductionDescriptor getCanonicalIntInduction(Type *Ty, ScalarEvolution &SE)
Returns the canonical integer induction for type Ty with start = 0 and step = 1.
InductionKind
This enum represents the kinds of inductions that we support.
@ IK_NoInduction
Not an induction variable.
@ IK_FpInduction
Floating point induction variable.
@ IK_PtrInduction
Pointer induction var. Step = C.
@ IK_IntInduction
Integer induction variable. Step = C.
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
static InstructionCost getInvalid(CostType Val=0)
bool isCast() const
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:348
The group of interleaved loads/stores sharing the same stride and close to each other.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
An instruction for reading from memory.
static bool getDecisionAndClampRange(const std::function< bool(ElementCount)> &Predicate, VFRange &Range)
Test a Predicate on a Range of VF's.
Definition VPlan.cpp:1654
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
Metadata node.
Definition Metadata.h:1069
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
unsigned getOpcode() const
Return the opcode for this Instruction or ConstantExpr.
Definition Operator.h:43
Post-order traversal of a graph.
An interface layer with SCEV used to manage how we see SCEV expressions for values in the context of ...
ScalarEvolution * getSE() const
Returns the ScalarEvolution analysis used.
LLVM_ABI const SCEV * getSCEV(Value *V)
Returns the SCEV expression of V, in the context of the current SCEV predicate.
static LLVM_ABI unsigned getOpcode(RecurKind Kind)
Returns the opcode corresponding to the RecurrenceKind.
static bool isFindLastRecurrenceKind(RecurKind Kind)
Returns true if the recurrence kind is of the form select(cmp(),x,y) where one of (x,...
RegionT * getParent() const
Get the parent of the Region.
Definition RegionInfo.h:362
This class represents a constant integer value.
ConstantInt * getValue() const
This class uses information about analyze scalars to rewrite expressions in canonical form.
LLVM_ABI Value * expandCodeFor(SCEVUse SH, Type *Ty, BasicBlock::iterator I)
Insert code to directly compute the specified SCEV expression into the program.
static const SCEV * rewrite(const SCEV *Scev, ScalarEvolution &SE, ValueToSCEVMapTy &Map)
This class represents an analyzed expression in the program.
LLVM_ABI Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
LLVM_ABI const SCEV * getUDivExpr(SCEVUse LHS, SCEVUse RHS)
Get a canonical unsigned division expression, or something simpler if possible.
const DataLayout & getDataLayout() const
Return the DataLayout associated with the module this SCEV instance is operating on.
LLVM_ABI const SCEV * getNegativeSCEV(const SCEV *V, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
Return the SCEV object corresponding to -V.
LLVM_ABI bool isKnownNonZero(const SCEV *S)
Test if the given expression is known to be non-zero.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
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.
LLVM_ABI const SCEV * getElementCount(Type *Ty, ElementCount EC, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
LLVM_ABI const SCEV * getMulExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical multiply expression, or something simpler if possible.
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,...
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:151
size_type size() const
Definition SmallPtrSet.h:99
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
iterator begin() const
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
static LLVM_ABI PartialReductionExtendKind getPartialReductionExtendKind(Instruction *I)
Get the kind of extension that an instruction represents.
TargetCostKind
The kind of cost model.
@ TCK_RecipThroughput
Reciprocal throughput.
LLVM_ABI InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, PartialReductionExtendKind OpAExtend, PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const
@ SK_Broadcast
Broadcast element 0 to all other elements.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class implements a switch-like dispatch statement for a value of 'T' using dyn_cast functionalit...
Definition TypeSwitch.h:89
TypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition TypeSwitch.h:98
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:282
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:368
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:276
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:197
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:232
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:306
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
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
A recipe for generating the active lane mask for the vector loop that is used to predicate the vector...
Definition VPlan.h:4024
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
Definition VPlan.h:4359
void appendRecipe(VPRecipeBase *Recipe)
Augment the existing recipes of a VPBasicBlock with an additional Recipe as the last recipe.
Definition VPlan.h:4434
RecipeListTy::iterator iterator
Instruction iterators...
Definition VPlan.h:4386
iterator end()
Definition VPlan.h:4396
iterator begin()
Recipe iterator methods.
Definition VPlan.h:4394
iterator_range< iterator > phis()
Returns an iterator range over the PHI-like recipes in the block.
Definition VPlan.h:4447
iterator getFirstNonPhi()
Return the position of the first non-phi node recipe in the block.
Definition VPlan.cpp:266
VPBasicBlock * splitAt(iterator SplitAt)
Split current block at SplitAt by inserting a new block between the current block and its successors ...
Definition VPlan.cpp:560
const VPRecipeBase & front() const
Definition VPlan.h:4406
VPRecipeBase * getTerminator()
If the block has multiple successors, return the branch recipe terminating the block.
Definition VPlan.cpp:639
const VPRecipeBase & back() const
Definition VPlan.h:4408
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
Definition VPlan.h:2936
VPValue * getIncomingValue(unsigned Idx) const
Return incoming value number Idx.
Definition VPlan.h:2981
VPValue * getMask(unsigned Idx) const
Return mask number Idx.
Definition VPlan.h:2986
unsigned getNumIncomingValues() const
Return the number of incoming values, taking into account when normalized the first incoming value wi...
Definition VPlan.h:2976
void setMask(unsigned Idx, VPValue *V)
Set mask number Idx to V.
Definition VPlan.h:2992
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:2972
VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
Definition VPlan.h:94
void setSuccessors(ArrayRef< VPBlockBase * > NewSuccs)
Set each VPBasicBlock in NewSuccss as successor of this VPBlockBase.
Definition VPlan.h:307
VPRegionBlock * getParent()
Definition VPlan.h:184
const VPBasicBlock * getExitingBasicBlock() const
Definition VPlan.cpp:236
size_t getNumSuccessors() const
Definition VPlan.h:235
void setPredecessors(ArrayRef< VPBlockBase * > NewPreds)
Set each VPBasicBlock in NewPreds as predecessor of this VPBlockBase.
Definition VPlan.h:298
const VPBlocksTy & getPredecessors() const
Definition VPlan.h:220
VPlan * getPlan()
Definition VPlan.cpp:211
const std::string & getName() const
Definition VPlan.h:175
void clearSuccessors()
Remove all the successors of this block.
Definition VPlan.h:317
VPBlockBase * getSinglePredecessor() const
Definition VPlan.h:231
void clearPredecessors()
Remove all the predecessor of this block.
Definition VPlan.h:314
const VPBasicBlock * getEntryBasicBlock() const
Definition VPlan.cpp:216
VPBlockBase * getSingleHierarchicalPredecessor()
Definition VPlan.h:271
VPBlockBase * getSingleSuccessor() const
Definition VPlan.h:225
const VPBlocksTy & getSuccessors() const
Definition VPlan.h:209
static auto blocksAs(T &&Range)
Return an iterator range over Range with each block cast to BlockTy.
Definition VPlanUtils.h:328
static void insertOnEdge(VPBlockBase *From, VPBlockBase *To, VPBlockBase *BlockPtr)
Inserts BlockPtr on the edge between From and To.
Definition VPlanUtils.h:347
static bool isLatch(const VPBlockBase *VPB, const VPDominatorTree &VPDT)
Returns true if VPB is a loop latch, using isHeader().
static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse, VPBlockBase *BlockPtr)
Insert disconnected VPBlockBases IfTrue and IfFalse after BlockPtr.
Definition VPlanUtils.h:237
static void connectBlocks(VPBlockBase *From, VPBlockBase *To, unsigned PredIdx=-1u, unsigned SuccIdx=-1u)
Connect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:255
static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To)
Disconnect VPBlockBases From and To bi-directionally.
Definition VPlanUtils.h:273
static auto blocksOnly(T &&Range)
Return an iterator range over Range which only includes BlockTy blocks.
Definition VPlanUtils.h:309
static void transferSuccessors(VPBlockBase *Old, VPBlockBase *New)
Transfer successors from Old to New. New must have no successors.
Definition VPlanUtils.h:293
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:3479
RAII object that stores the current insertion point and restores it when the object is destroyed.
VPlan-based builder utility analogous to IRBuilder.
VPDerivedIVRecipe * createDerivedIV(InductionDescriptor::InductionKind Kind, FPMathOperator *FPBinOp, VPValue *Start, VPValue *Current, VPValue *Step)
Convert the input value Current to the corresponding value of an induction with Start and Step values...
VPInstruction * createFirstActiveLane(ArrayRef< VPValue * > Masks, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createAdd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", VPRecipeWithIRFlags::WrapFlagsTy WrapFlags={false, false})
VPInstruction * createOr(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPValue * createScalarZExtOrTrunc(VPValue *Op, Type *ResultTy, Type *SrcTy, DebugLoc DL)
VPInstruction * createLogicalOr(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createNot(VPValue *Operand, 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 ...
Definition VPlan.cpp:1641
VPInstruction * createLogicalAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
VPInstruction * createScalarCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy, DebugLoc DL, const VPIRMetadata &Metadata={})
VPWidenPHIRecipe * createWidenPhi(ArrayRef< VPValue * > IncomingValues, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="")
static VPBuilder getToInsertAfter(VPRecipeBase *R)
Create a VPBuilder to insert after R.
VPWidenCastRecipe * createWidenCast(Instruction::CastOps Opcode, VPValue *Op, Type *ResultTy)
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.
VPPhi * createScalarPhi(ArrayRef< VPValue * > IncomingValues, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", const VPIRFlags &Flags={}, Type *ResultTy=nullptr)
VPInstruction * createSelect(VPValue *Cond, VPValue *TrueVal, VPValue *FalseVal, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", const VPIRFlags &Flags={})
VPExpandSCEVRecipe * createExpandSCEV(const SCEV *Expr)
VPInstruction * createNaryOp(unsigned Opcode, ArrayRef< VPValue * > Operands, Instruction *Inst=nullptr, const VPIRFlags &Flags={}, const VPIRMetadata &MD={}, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", Type *ResultTy=nullptr)
Create an N-ary operation with Opcode, Operands and set Inst as its underlying Instruction.
static VPSingleDefRecipe * createSingleScalarOp(unsigned Opcode, ArrayRef< VPValue * > Operands, VPValue *Mask, const VPIRFlags &Flags, const VPIRMetadata &Metadata, DebugLoc DL, Instruction *UV)
Create a single-scalar recipe with Opcode and Operands without inserting it.
void setInsertPoint(VPBasicBlock *TheBB)
This specifies that created VPInstructions should be appended to the end of the specified block.
A recipe for generating the phi node tracking the current scalar iteration index.
Definition VPlan.h:4056
unsigned getNumDefinedValues() const
Returns the number of values defined by the VPDef.
Definition VPlanValue.h:576
VPValue * getVPSingleValue()
Returns the only VPValue defined by the VPDef.
Definition VPlanValue.h:549
VPValue * getVPValue(unsigned I)
Returns the VPValue with index I defined by the VPDef.
Definition VPlanValue.h:561
ArrayRef< VPRecipeValue * > definedValues()
Returns an ArrayRef of the values defined by the VPDef.
Definition VPlanValue.h:571
A recipe for converting the input value IV value to the corresponding value of an IV with different s...
Definition VPlan.h:4157
Template specialization of the standard LLVM dominator tree utility for VPBlockBases.
bool properlyDominates(const VPRecipeBase *A, const VPRecipeBase *B) const
A recipe to combine multiple recipes into a single 'expression' recipe, which should be considered a ...
Definition VPlan.h:3524
A pure virtual base class for all recipes modeling header phis, including phis for first order recurr...
Definition VPlan.h:2431
virtual VPValue * getBackedgeValue()
Returns the incoming value from the loop backedge.
Definition VPlan.h:2478
VPValue * getStartValue()
Returns the start value of the phi, if one is set.
Definition VPlan.h:2467
A recipe representing a sequence of load -> update -> store as part of a histogram operation.
Definition VPlan.h:2158
A special type of VPBasicBlock that wraps an existing IR basic block.
Definition VPlan.h:4512
Class to record and manage LLVM IR flags.
Definition VPlan.h:693
static VPIRFlags getDefaultFlags(unsigned Opcode)
Returns default flags for Opcode for opcodes that support it, asserts otherwise.
LLVM_ABI_FOR_TEST FastMathFlags getFastMathFlagsOrNone() const
void dropPoisonGeneratingFlags()
Drop all poison-generating flags.
Definition VPlan.h:891
static LLVM_ABI_FOR_TEST VPIRInstruction * create(Instruction &I)
Create a new VPIRPhi for \I , if it is a PHINode, otherwise create a VPIRInstruction.
Helper to manage IR metadata for recipes.
Definition VPlan.h:1167
void intersect(const VPIRMetadata &MD)
Intersect this VPIRMetadata object with MD, keeping only metadata nodes that are common to both.
This is a concrete Recipe that models a single VPlan-level instruction.
Definition VPlan.h:1222
unsigned getNumOperandsWithoutMask() const
Returns the number of operands, excluding the mask if the VPInstruction is masked.
Definition VPlan.h:1469
@ ExtractLane
Extracts a single lane (first operand) from a set of vector operands.
Definition VPlan.h:1315
@ Unpack
Extracts all lanes from its (non-scalable) vector operand.
Definition VPlan.h:1265
@ ReductionStartVector
Start vector for reductions with 3 operands: the original start value, the identity value for the red...
Definition VPlan.h:1311
@ BuildVector
Creates a fixed-width vector containing all operands.
Definition VPlan.h:1260
@ BuildStructVector
Given operands of (the same) struct type, creates a struct of fixed- width vectors each containing a ...
Definition VPlan.h:1257
@ CanonicalIVIncrementForPart
Definition VPlan.h:1241
@ ComputeReductionResult
Reduce the operands to the final reduction result using the operation specified via the operation's V...
Definition VPlan.h:1268
unsigned getOpcode() const
Definition VPlan.h:1413
const InterleaveGroup< Instruction > * getInterleaveGroup() const
Definition VPlan.h:3087
VPValue * getMask() const
Return the mask used by this recipe.
Definition VPlan.h:3079
ArrayRef< VPValue * > getStoredValues() const
Return the VPValues stored by this interleave group.
Definition VPlan.h:3108
A recipe for interleaved memory operations with vector-predication intrinsics.
Definition VPlan.h:3160
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
Definition VPlan.h:3118
void addIncoming(VPValue *IncomingV)
Append IncomingV as an incoming value to the phi-like recipe.
Definition VPlan.h:1661
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
Definition VPlan.h:3682
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition VPlan.h:400
VPBasicBlock * getParent()
Definition VPlan.h:472
DebugLoc getDebugLoc() const
Returns the debug location of the recipe.
Definition VPlan.h:550
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:352
A recipe to represent inloop reduction operations with vector-predication intrinsics,...
Definition VPlan.h:3330
A recipe for handling reduction phis.
Definition VPlan.h:2843
void setVFScaleFactor(unsigned ScaleFactor)
Set the VFScaleFactor for this reduction phi.
Definition VPlan.h:2894
unsigned getVFScaleFactor() const
Get the factor that the VF of this recipe's output should be scaled by, or 1 if it isn't scaled.
Definition VPlan.h:2887
RecurKind getRecurrenceKind() const
Returns the recurrence kind of the reduction.
Definition VPlan.h:2900
A recipe to represent inloop, ordered or partial reduction operations.
Definition VPlan.h:3211
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition VPlan.h:4584
const VPBlockBase * getEntry() const
Definition VPlan.h:4628
bool isReplicator() const
An indicator whether this region is to generate multiple replicated instances of output IR correspond...
Definition VPlan.h:4660
VPRegionValue * getUsedHeaderMask() const
Return the header mask if it exists and is used, or null otherwise.
Definition VPlan.h:4716
VPInstruction * getOrCreateCanonicalIVIncrement()
Get the canonical IV increment instruction if it exists.
Definition VPlan.cpp:864
void setExiting(VPBlockBase *ExitingBlock)
Set ExitingBlock as the exiting VPBlockBase of this VPRegionBlock.
Definition VPlan.h:4645
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
Definition VPlan.h:4704
void clearCanonicalIVNUW(VPInstruction *Increment)
Unsets NUW for the canonical IV increment Increment, for loop regions.
Definition VPlan.h:4743
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
Definition VPlan.h:4696
const VPBlockBase * getExiting() const
Definition VPlan.h:4640
VPBasicBlock * getPreheaderVPBB()
Returns the pre-header VPBasicBlock of the loop region.
Definition VPlan.h:4653
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
Definition VPlan.h:4709
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition VPlan.h:3375
bool isSingleScalar() const
Definition VPlan.h:3433
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:3458
bool isPredicated() const
Definition VPlan.h:3435
VPValue * getMask()
Return the mask of a predicated VPReplicateRecipe.
Definition VPlan.h:3452
Lightweight SCEV-to-VPlan expander.
Definition VPlanUtils.h:175
VPValue * tryToExpand(const SCEV *S)
Try to 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:4217
VPSingleDefRecipe is a base class for recipes that model a sequence of one or more output IR that def...
Definition VPlan.h:608
Instruction * getUnderlyingInstr()
Returns the underlying instruction.
Definition VPlan.h:678
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:217
bool isMaterialized() const
Returns true if this value has been materialized.
Definition VPlanValue.h:235
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition VPlanValue.h:399
operand_range operands()
Definition VPlanValue.h:472
void setOperand(unsigned I, VPValue *New)
Definition VPlanValue.h:445
unsigned getNumOperands() const
Definition VPlanValue.h:439
VPValue * getOperand(unsigned N) const
Definition VPlanValue.h:440
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:149
Value * getLiveInIRValue() const
Return the underlying IR value for a VPIRValue.
Definition VPlan.cpp:143
bool isDefinedOutsideLoopRegions() const
Returns true if the VPValue is defined outside any loop.
Definition VPlan.cpp:1465
VPRecipeBase * getDefiningRecipe()
Returns the recipe defining this VPValue or nullptr if it is not defined by a recipe,...
Definition VPlan.cpp:130
bool hasMoreThanOneUniqueUser() const
Returns true if the value has more than one unique user.
Definition VPlanValue.h:164
Value * getUnderlyingValue() const
Return the underlying Value attached to this VPValue.
Definition VPlanValue.h:75
bool user_empty() const
Definition VPlanValue.h:161
bool hasOneUse() const
Definition VPlanValue.h:175
void setUnderlyingValue(Value *Val)
Definition VPlanValue.h:209
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:1468
unsigned getNumUsers() const
Definition VPlanValue.h:115
void replaceUsesWithIf(VPValue *New, llvm::function_ref< bool(VPUser &U, unsigned Idx)> ShouldReplace)
Go through the uses list for this VPValue and make each use point to New if the callback ShouldReplac...
Definition VPlan.cpp:1474
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:2261
A recipe to compute the pointers for widened memory accesses of SourceElementTy, with the Stride expr...
Definition VPlan.h:2343
A recipe for widening Call instructions using library calls.
Definition VPlan.h:2092
static InstructionCost computeCallCost(Function *Variant, VPCostContext &Ctx)
Return the cost of widening a call using the vector function Variant.
A Recipe for widening the canonical induction variable of the vector loop.
Definition VPlan.h:4100
VPWidenCastRecipe is a recipe to create vector cast instructions.
Definition VPlan.h:1874
Instruction::CastOps getOpcode() const
Definition VPlan.h:1910
A recipe for handling GEP instructions.
Definition VPlan.h:2201
Base class for widened induction (VPWidenIntOrFpInductionRecipe and VPWidenPointerInductionRecipe),...
Definition VPlan.h:2505
VPIRValue * getStartValue() const
Returns the start value of the induction.
Definition VPlan.h:2553
PHINode * getPHINode() const
Returns the underlying PHINode if one exists, or null otherwise.
Definition VPlan.h:2571
VPValue * getStepValue()
Returns the step value of the induction.
Definition VPlan.h:2556
const InductionDescriptor & getInductionDescriptor() const
Returns the induction descriptor for the recipe.
Definition VPlan.h:2576
A recipe for handling phi nodes of integer and floating-point inductions, producing their vector valu...
Definition VPlan.h:2605
VPValue * getSplatVFValue() const
If the recipe has been unrolled, return the VPValue for the induction increment, otherwise return nul...
Definition VPlan.h:2653
TruncInst * getTruncInst()
Returns the first defined value as TruncInst, if it is one or nullptr otherwise.
Definition VPlan.h:2664
VPValue * getLastUnrolledPartOperand()
Returns the VPValue representing the value of this induction at the last unrolled part,...
Definition VPlan.h:2675
A recipe for widening vector intrinsics.
Definition VPlan.h:1921
static InstructionCost computeCallCost(Intrinsic::ID ID, ArrayRef< const VPValue * > Operands, const VPRecipeWithIRFlags &R, ElementCount VF, VPCostContext &Ctx)
Compute the cost of a vector intrinsic with ID and Operands.
static InstructionCost computeMemIntrinsicCost(Intrinsic::ID IID, Type *Ty, bool IsMasked, Align Alignment, VPCostContext &Ctx)
Helper function for computing the cost of vector memory intrinsic.
A common mixin class for widening memory operations.
Definition VPlan.h:3718
virtual VPRecipeBase * getAsRecipe()=0
Return a VPRecipeBase* to the current object.
A recipe for widened phis.
Definition VPlan.h:2733
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition VPlan.h:1813
InstructionCost computeCost(ElementCount VF, VPCostContext &Ctx) const override
Return the cost of this VPWidenRecipe.
VPWidenRecipe * clone() override
Clone the current recipe.
Definition VPlan.h:1834
unsigned getOpcode() const
Definition VPlan.h:1853
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition VPlan.h:4763
VPIRValue * getLiveIn(Value *V) const
Return the live-in VPIRValue for V, if there is one or nullptr otherwise.
Definition VPlan.h:5095
bool hasVF(ElementCount VF) const
Definition VPlan.h:4988
const DataLayout & getDataLayout() const
Definition VPlan.h:4970
LLVMContext & getContext() const
Definition VPlan.h:4966
VPBasicBlock * getEntry()
Definition VPlan.h:4859
bool hasScalableVF() const
Definition VPlan.h:4989
VPValue * getTripCount() const
The trip count of the original loop.
Definition VPlan.h:4924
VPValue * getOrCreateBackedgeTakenCount()
The backedge taken count of the original loop.
Definition VPlan.h:4945
iterator_range< SmallSetVector< ElementCount, 2 >::iterator > vectorFactors() const
Returns an iterator range over all VFs of the plan.
Definition VPlan.h:4995
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
Definition VPlan.h:5061
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
Definition VPlan.h:4964
VPIRValue * getAllOnesValue(Type *Ty)
Return a VPIRValue wrapping the AllOnes value of type Ty.
Definition VPlan.h:5067
VPRegionBlock * createReplicateRegion(VPBlockBase *Entry, VPBlockBase *Exiting, const std::string &Name="")
Create a new replicate region with Entry, Exiting and Name.
Definition VPlan.h:5144
auto getLiveIns() const
Return the list of live-in VPValues available in the VPlan.
Definition VPlan.h:5098
bool hasUF(unsigned UF) const
Definition VPlan.h:5013
VPIRValue * getPoison(Type *Ty)
Return a VPIRValue wrapping a poison value of type Ty.
Definition VPlan.h:5089
ArrayRef< VPIRBasicBlock * > getExitBlocks() const
Return an ArrayRef containing VPIRBasicBlocks wrapping the exit blocks of the original scalar loop.
Definition VPlan.h:4918
VPSymbolicValue & getVectorTripCount()
The vector trip count.
Definition VPlan.h:4954
VPValue * getBackedgeTakenCount() const
Definition VPlan.h:4951
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:5038
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
Definition VPlan.h:5064
void setVF(ElementCount VF)
Definition VPlan.h:4976
bool isUnrolled() const
Returns true if the VPlan already has been unrolled, i.e.
Definition VPlan.h:5029
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition VPlan.cpp:1060
unsigned getConcreteUF() const
Returns the concrete UF of the plan, after unrolling.
Definition VPlan.h:5016
void resetTripCount(VPValue *NewTripCount)
Resets the trip count for the VPlan.
Definition VPlan.h:4938
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
Definition VPlan.h:4894
VPBasicBlock * createVPBasicBlock(const Twine &Name, VPRecipeBase *Recipe=nullptr)
Create a new VPBasicBlock with Name and containing Recipe if present.
Definition VPlan.h:5121
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
Definition VPlan.h:5058
VPBasicBlock * getVectorPreheader() const
Returns the preheader of the vector loop region, if one exists, or null otherwise.
Definition VPlan.h:4864
VPSymbolicValue & getUF()
Returns the UF of the vector loop region.
Definition VPlan.h:4961
bool hasScalarVFOnly() const
Definition VPlan.h:5006
VPBasicBlock * getScalarPreheader() const
Return the VPBasicBlock for the preheader of the scalar loop.
Definition VPlan.h:4908
bool hasTailFolded() const
Returns true if the vector loop region is tail-folded.
Definition VPlan.h:4880
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
Definition VPlan.h:4957
void setUF(unsigned UF)
Definition VPlan.h:5021
bool hasScalarTail() const
Returns true if the scalar tail may execute after the vector loop, i.e.
Definition VPlan.h:5186
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:1216
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:5072
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
iterator_range< user_iterator > users()
Definition Value.h:426
bool hasName() const
Definition Value.h:261
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
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.multiplyCoefficientBy(X) will result in a value whos...
Definition TypeSize.h:269
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:200
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS.multiplyCoefficientBy(X) will result in a value whose quantity matches ou...
Definition TypeSize.h:277
static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition TypeSize.h:216
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition TypeSize.h:168
constexpr LeafTy multiplyCoefficientBy(ScalarTy RHS) const
Definition TypeSize.h:256
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
Definition TypeSize.h:171
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Definition ilist_node.h:123
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM)
Return A unsign-divided by B, rounded by the given rounding mode.
Definition APInt.cpp:2798
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
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
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
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_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
cst_pred_ty< is_all_ones > m_AllOnes()
Match an integer or vector with all bits set.
auto m_Cmp()
Matches any compare instruction and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, TruncInst >, OpTy > m_TruncOrSelf(const OpTy &Op)
auto m_Poison()
Match an arbitrary poison constant.
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)
match_combine_or< CastInst_match< OpTy, ZExtInst >, OpTy > m_ZExtOrSelf(const OpTy &Op)
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.
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)
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.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_MaskedStore(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2)
Matches MaskedStore Intrinsic.
auto m_MaskedLoad(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2)
Matches MaskedLoad Intrinsic.
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.
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
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.
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::StepVector > m_StepVector()
auto m_VPPhi(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::BranchOnTwoConds > m_BranchOnTwoConds()
AllRecipe_match< Opcode, Op0_t, Op1_t > m_Binary(const Op0_t &Op0, const Op1_t &Op1)
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)
specific_intval< 1 > m_False()
VPInstruction_match< VPInstruction::ExtractLastLane, Op0_t > m_ExtractLastLane(const Op0_t &Op0)
VPInstruction_match< VPInstruction::ActiveLaneMask, Op0_t, Op1_t, Op2_t > m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
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)
specific_intval< 1 > m_True()
auto m_VPValue()
Match an arbitrary VPValue and ignore it.
VectorEndPointerRecipe_match< Op0_t, Op1_t > m_VecEndPtr(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)
header_mask_match m_HeaderMask()
VPInstruction_match< VPInstruction::ExplicitVectorLength, Op0_t > m_EVL(const Op0_t &Op0)
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)
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:386
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.
Intrinsic::ID getIntrinsicID(const Ty *R)
Return the intrinsic ID underlying a call.
Definition VPlanUtils.h:81
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.
VPValue * findIncomingAliasMask(const VPlan &Plan)
Finds the incoming alias-mask within the vector preheader.
VPRecipeBase * findRecipe(VPValue *Start, PredT Pred)
Search Start's users for a recipe satisfying Pred, looking through recipes with definitions.
Definition VPlanUtils.h:133
bool isElementwise(const VPValue *V)
Return true if V is elementwise, i.e. none of the lanes are permuted.
bool onlyScalarValuesUsed(const VPValue *Def)
Returns true if only scalar values of Def are used by all users.
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.
GEPNoWrapFlags getGEPFlagsForPtr(VPValue *Ptr)
Returns the GEP nowrap flags for Ptr, looking through pointer casts mirroring Value::stripPointerCast...
const SCEV * getSCEVExprForVPValue(const VPValue *V, PredicatedScalarEvolution &PSE, const Loop *L=nullptr)
Return the SCEV expression for V.
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:315
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:573
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:2180
void stable_sort(R &&Range)
Definition STLExtras.h:2116
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:2078
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:1739
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:1669
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:840
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:2554
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.
constexpr from_range_t from_range
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:2208
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:633
auto cast_or_null(const Y &Val)
Definition Casting.h:714
iterator_range< df_iterator< VPBlockShallowTraversalWrapper< VPBlockBase * > > > vp_depth_first_shallow(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order.
Definition VPlanCFG.h:250
constexpr auto bind_back(FnT &&Fn, BindArgsT &&...BindArgs)
C++23 bind_back.
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:2173
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
SmallVector< VPRegisterUsage, 8 > calculateRegisterUsageForPlan(VPlan &Plan, ArrayRef< ElementCount > VFs, const TargetTransformInfo &TTI, const SmallPtrSetImpl< const Value * > &ValuesToIgnore)
Estimate the register usage for Plan and vectorization factors in VFs by calculating the highest numb...
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:365
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1151
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:385
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:2200
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:1746
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
constexpr size_t range_size(R &&Range)
Returns the size of the Range, i.e., the number of elements.
Definition STLExtras.h:1694
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
bool hasIrregularType(Type *Ty, const DataLayout &DL)
A helper function that returns true if the given type is irregular.
LLVM_ABI_FOR_TEST cl::opt< bool > EnableWideActiveLaneMask
UncountableExitStyle
Different methods of handling early exits.
Definition VPlan.h:79
@ MaskedHandleExitInScalarLoop
All memory operations other than the load(s) required to determine whether an uncountable exit occurr...
Definition VPlan.h:89
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:1753
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:551
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:1859
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:1837
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:322
@ 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:2012
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:2088
ArrayRef(const T &OneElt) -> ArrayRef< T >
auto make_second_range(ContainerTy &&c)
Given a container of pairs, return a range over the second elements.
Definition STLExtras.h:1409
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
Definition STLExtras.h:2019
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:1772
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
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:2166
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:305
LLVM_ABI std::optional< int64_t > getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy, Value *Ptr, PredicatedScalarEvolution &PSE)
If AR is an affine AddRec for Lp with a constant step, return the step in units of AccessTy's allocat...
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:2146
Type * toVectorTy(Type *Scalar, ElementCount EC)
A helper function for converting Scalar types to vector types.
LLVM_ABI bool isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L, ScalarEvolution &SE, DominatorTree &DT, AssumptionCache *AC=nullptr, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Return true if we can prove that the given load (which is assumed to be within the specified loop) wo...
Definition Loads.cpp:304
@ Default
The result value is uniform if and only if all operands are uniform.
Definition Uniformity.h:20
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:285
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:862
#define N
VPBasicBlock * EarlyExitingVPBB
VPIRBasicBlock * EarlyExitVPBB
RemoveMask_match(const Op0_t &In, Op1_t &Out)
bool match(OpTy *V) const
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:2825
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.
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:1955
bool isMaskRequired(Instruction *I) const
Forwards to LoopVectorizationCostModel::isMaskRequired.
PredicatedScalarEvolution & PSE
bool willBeScalarized(Instruction *I, ElementCount VF) const
Returns true if I is known to be scalarized at VF.
TargetTransformInfo::TargetCostKind CostKind
const TargetLibraryInfo & TLI
const TargetTransformInfo & TTI
A VPValue representing a live-in from the input IR or a constant.
Definition VPlanValue.h:277
Type * getType() const
Returns the type of the underlying IR value.
Definition VPlan.cpp:147
A struct that represents some properties of the register usage of a loop.
SmallMapVector< unsigned, unsigned, 4 > MaxLocalUsers
Holds the maximum number of concurrent live intervals in the loop.
InstructionCost spillCost(const TargetTransformInfo &TTI, TargetTransformInfo::TargetCostKind CostKind, unsigned OverrideMaxNumRegs=0) const
Calculate the estimated cost of any spills due to using more registers than the number available for ...
A recipe for widening load operations with vector-predication intrinsics, using the address to load f...
Definition VPlan.h:3832
A recipe for widening load operations, using the address to load from and an optional mask.
Definition VPlan.h:3782
A recipe for widening store operations with vector-predication intrinsics, using the value to store,...
Definition VPlan.h:3935
A recipe for widening store operations, using the stored value, the address to store to and an option...
Definition VPlan.h:3881
static VPValue * materializeAliasMask(VPlan &Plan, VPBasicBlock *AliasCheckVPBB, ArrayRef< PointerDiffInfo > DiffChecks)
Materializes within the AliasCheckVPBB block.
static LLVM_ABI_FOR_TEST bool tryToConvertVPInstructionsToVPRecipes(VPlan &Plan, const TargetLibraryInfo &TLI)
Replaces the VPInstructions in Plan with corresponding widen recipes.
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 expandSCEVsToVPInstructions(VPlan &Plan, ScalarEvolution &SE)
Try to expand VPExpandSCEVRecipes in Plan's entry block to VPInstructions.
static void materializeBroadcasts(VPlan &Plan)
Add explicit broadcasts for live-ins and VPValues defined in Plan's entry block if they are used as v...
static void materializePacksAndUnpacks(VPlan &Plan)
Add explicit Build[Struct]Vector recipes to Pack multiple scalar values into vectors and Unpack recip...
static void createInterleaveGroups(VPlan &Plan, const SmallPtrSetImpl< const InterleaveGroup< Instruction > * > &InterleaveGroups, const bool &EpilogueAllowed)
static bool simplifyKnownEVL(VPlan &Plan, ElementCount VF, PredicatedScalarEvolution &PSE)
Try to simplify VPInstruction::ExplicitVectorLength recipes when the AVL is known to be <= VF,...
static void materializeFactors(VPlan &Plan, VPBasicBlock *VectorPH, ElementCount VF)
Materialize UF, VF and VFxUF to be computed explicitly using VPInstructions.
static void materializeBackedgeTakenCount(VPlan &Plan, VPBasicBlock *VectorPH)
Materialize the backedge-taken count to be computed explicitly using VPInstructions.
static void replaceWideCanonicalIVWithWideIV(VPlan &Plan, ScalarEvolution &SE, const TargetTransformInfo &TTI, TargetTransformInfo::TargetCostKind CostKind, ElementCount VF, unsigned UF, const SmallPtrSetImpl< const Value * > &ValuesToIgnore)
Replace a VPWidenCanonicalIVRecipe if it is present in Plan, with a VPWidenIntOrFpInductionRecipe,...
static void createAndOptimizeReplicateRegions(VPlan &Plan)
Wrap predicated VPReplicateRecipes with a mask operand in an if-then region block and remove the mask...
static void convertToVariableLengthStep(VPlan &Plan)
Transform loops with variable-length stepping after region dissolution.
static void materializeHeaderMask(VPlan &Plan, bool UseActiveLaneMask, bool UseActiveLaneMaskForControlFlow)
Materialize the abstract header mask of the loop region into concrete recipes: an active-lane-mask if...
static void addBranchWeightToMiddleTerminator(VPlan &Plan, ElementCount VF, std::optional< unsigned > VScaleForTuning)
Add branch weight metadata, if the Plan's middle block is terminated by a BranchOnCond recipe.
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 optimizeInductionLiveOutUsers(VPlan &Plan, PredicatedScalarEvolution &PSE)
If there's a single exit block, optimize its phi recipes that use exiting IV values by feeding them p...
static void materializeAliasMaskCheckBlock(VPlan &Plan, ArrayRef< PointerDiffInfo > DiffChecks, bool HasBranchWeights)
Materializes the alias mask within a check block before the loop.
static DenseMap< const SCEV *, Value * > expandSCEVs(VPlan &Plan, ScalarEvolution &SE)
Expand remaining VPExpandSCEVRecipes in Plan's entry block using SCEVExpander.
static void convertToConcreteRecipes(VPlan &Plan)
Lower abstract recipes to concrete ones, that can be codegen'd.
static void makeMemOpWideningDecisions(VPlan &Plan, VFRange &Range, VPRecipeBuilder &RecipeBuilder, VPCostContext &CostCtx)
Convert load/store VPInstructions in Plan into widened or replicate recipes.
static void expandBranchOnTwoConds(VPlan &Plan)
Expand BranchOnTwoConds instructions into explicit CFG with BranchOnCond instructions.
static void materializeVectorTripCount(VPlan &Plan, VPBasicBlock *VectorPHVPBB, bool TailByMasking, bool RequiresScalarEpilogue, VPValue *Step, std::optional< uint64_t > MaxRuntimeStep=std::nullopt)
Materialize vector trip count computations to a set of VPInstructions.
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 attachAliasMaskToHeaderMask(VPlan &Plan)
Attaches the alias-mask to the existing header-mask.
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 materializeConstantVectorTripCount(VPlan &Plan, ElementCount BestVF, unsigned BestUF, PredicatedScalarEvolution &PSE)
static void makeScalarizationDecisions(VPlan &Plan, VFRange &Range)
Make VPlan-based scalarization decision prior to delegating to the ones made by the legacy CM.
static void addExplicitVectorLength(VPlan &Plan, const std::optional< unsigned > &MaxEVLSafeElements)
Add a VPCurrentIterationPHIRecipe and related recipes to Plan and replaces all uses of the canonical ...
static void simplifyReverses(VPlan &Plan)
Cancel out redundant reverses in Plan, e.g. reverse(reverse(x)) -> x.
static void 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 void adjustFirstOrderRecurrenceMiddleUsers(VPlan &Plan, VFRange &Range)
Adjust first-order recurrence users in the middle block: create penultimate element extracts for LCSS...
static void optimizeEVLMasks(VPlan &Plan)
Optimize recipes which use an EVL-based header mask to VP intrinsics, for example:
static void removeDeadRecipes(VPlan &Plan)
Remove dead recipes from Plan.
static void simplifyRecipes(VPlan &Plan)
Perform instcombine-like simplifications on recipes in 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 void replaceSymbolicStrides(VPlan &Plan, PredicatedScalarEvolution &PSE, const DenseMap< Value *, const SCEV * > &StridesMap, const VPDominatorTree &VPDT)
Replace symbolic strides from StridesMap in Plan with constants when possible.
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 bool handleUncountableEarlyExits(VPlan &Plan, VPBasicBlock *HeaderVPBB, VPBasicBlock *LatchVPBB, VPBasicBlock *MiddleVPBB, 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 void clearReductionWrapFlags(VPlan &Plan)
Clear NSW/NUW flags from reduction instructions if necessary.
static void createPartialReductions(VPlan &Plan, VPCostContext &CostCtx, VFRange &Range)
Detect and create partial reduction recipes for scaled reductions in Plan.
static void cse(VPlan &Plan)
Perform common-subexpression-elimination on Plan.
static void attachVPCheckBlock(VPlan &Plan, VPValue *Cond, VPBasicBlock *CheckBlock, bool AddBranchWeights)
Wrap runtime check block CheckBlock in a VPIRBB and Cond in a VPValue and connect the block to Plan,...
static LLVM_ABI_FOR_TEST void optimize(VPlan &Plan)
Apply VPlan-to-VPlan optimizations to Plan, including induction recipe optimizations,...
static void dissolveLoopRegions(VPlan &Plan)
Replace loop regions with explicit CFG.
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 convertEVLExitCond(VPlan &Plan)
Replaces the exit condition from (branch-on-cond eq CanonicalIVInc, VectorTripCount) to (branch-on-co...