LLVM 24.0.0git
VPlanEVLTailFolding.cpp
Go to the documentation of this file.
1//===- VPlanEVLTailFolding.cpp - EVL tail folding 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 the VPlan-to-VPlan transforms related to explicit
11/// vector length (EVL) tail folding support.
12///
13//===----------------------------------------------------------------------===//
14
16#include "VPlan.h"
17#include "VPlanCFG.h"
18#include "VPlanHelpers.h"
19#include "VPlanPatternMatch.h"
20#include "VPlanTransforms.h"
21#include "VPlanUtils.h"
22#include "llvm/ADT/SetVector.h"
24#include "llvm/IR/Intrinsics.h"
25
26using namespace llvm;
27using namespace VPlanPatternMatch;
28
29/// From the definition of llvm.experimental.get.vector.length,
30/// VPInstruction::ExplicitVectorLength(%AVL) = %AVL when %AVL <= VF.
35 for (VPRecipeBase &R : *VPBB) {
36 VPValue *AVL;
37 if (!match(&R, m_EVL(m_VPValue(AVL))))
38 continue;
39
40 const SCEV *AVLSCEV = vputils::getSCEVExprForVPValue(AVL, PSE);
41 if (isa<SCEVCouldNotCompute>(AVLSCEV))
42 continue;
43 ScalarEvolution &SE = *PSE.getSE();
44 const SCEV *VFSCEV = SE.getElementCount(AVLSCEV->getType(), VF);
45 if (!SE.isKnownPredicate(CmpInst::ICMP_ULE, AVLSCEV, VFSCEV))
46 continue;
47
49 AVL, Type::getInt32Ty(Plan.getContext()), R.getDebugLoc());
50 if (Trunc != AVL) {
51 auto *TruncR = cast<VPSingleDefRecipe>(Trunc);
52 const DataLayout &DL = Plan.getDataLayout();
53 if (VPValue *Folded =
54 vputils::tryToFoldLiveIns(*TruncR, TruncR->operands(), DL))
55 Trunc = Folded;
56 }
57 R.getVPSingleValue()->replaceAllUsesWith(Trunc);
58 return true;
59 }
60 }
61 return false;
62}
63
64static std::optional<Intrinsic::ID> getVPDivRemIntrinsic(Intrinsic::ID IntrID) {
65 switch (IntrID) {
66 case Intrinsic::masked_udiv:
67 return Intrinsic::vp_udiv;
68 case Intrinsic::masked_sdiv:
69 return Intrinsic::vp_sdiv;
70 case Intrinsic::masked_urem:
71 return Intrinsic::vp_urem;
72 case Intrinsic::masked_srem:
73 return Intrinsic::vp_srem;
74 default:
75 return std::nullopt;
76 }
77}
78
79/// Try to optimize a \p CurRecipe masked by \p HeaderMask to a corresponding
80/// EVL-based recipe without the header mask. Returns nullptr if no EVL-based
81/// recipe could be created.
82/// \p HeaderMask Header Mask.
83/// \p CurRecipe Recipe to be transform.
84/// \p EVL The explicit vector length parameter of vector-predication
85/// intrinsics.
87 VPRecipeBase &CurRecipe, VPValue &EVL) {
88 VPlan *Plan = CurRecipe.getParent()->getPlan();
89 DebugLoc DL = CurRecipe.getDebugLoc();
90 VPValue *Addr, *Mask, *EndPtr;
91
92 /// Adjust any end pointers so that they point to the end of EVL lanes not VF.
93 auto AdjustEndPtr = [&CurRecipe, &EVL](VPValue *EndPtr) {
94 auto *EVLEndPtr = cast<VPVectorEndPointerRecipe>(EndPtr)->clone();
95 EVLEndPtr->insertBefore(&CurRecipe);
96 // Cast EVL (i32) to match the VF operand's type.
97 VPValue *EVLAsVF = VPBuilder(EVLEndPtr).createScalarZExtOrTrunc(
98 &EVL, EVLEndPtr->getOperand(1)->getScalarType(),
100 EVLEndPtr->setOperand(1, EVLAsVF);
101 return EVLEndPtr;
102 };
103
104 auto GetVPReverse = [&CurRecipe, &EVL, Plan,
106 if (!V)
107 return nullptr;
109 Intrinsic::experimental_vp_reverse, {V, Plan->getTrue(), &EVL},
110 V->getScalarType(), {}, {}, DL);
111 Reverse->insertBefore(&CurRecipe);
112 return Reverse;
113 };
114
115 if (match(&CurRecipe,
116 m_MaskedLoad(m_VPValue(Addr), m_RemoveMask(HeaderMask, Mask))))
117 return new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe), Addr,
118 EVL, Mask);
119
120 if (match(&CurRecipe,
121 m_MaskedLoad(m_VPValue(EndPtr),
122 m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
123 match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
124 Mask = GetVPReverse(Mask);
125 Addr = AdjustEndPtr(EndPtr);
126 auto *LoadR = new VPWidenLoadEVLRecipe(cast<VPWidenLoadRecipe>(CurRecipe),
127 Addr, EVL, Mask);
128 LoadR->insertBefore(&CurRecipe);
129 VPValue *Poison = Plan->getPoison(LoadR->getScalarType());
130 return new VPWidenIntrinsicRecipe(Intrinsic::vector_splice_left,
131 {Poison, LoadR, &EVL},
132 LoadR->getScalarType(), {}, {}, DL);
133 }
134
135 if (match(&CurRecipe,
137 m_VPValue(), m_VPValue(), m_RemoveMask(HeaderMask, Mask),
138 m_TruncOrSelf(m_Specific(&Plan->getVF()))))) {
139 auto *NewLoad = cast<VPWidenMemIntrinsicRecipe>(&CurRecipe)->clone();
140 NewLoad->setOperand(2, Mask ? Mask : Plan->getTrue());
141 NewLoad->setOperand(3, &EVL);
142 return NewLoad;
143 }
144
145 VPValue *StoredVal;
146 if (match(&CurRecipe, m_MaskedStore(m_VPValue(Addr), m_VPValue(StoredVal),
147 m_RemoveMask(HeaderMask, Mask))))
148 return new VPWidenStoreEVLRecipe(cast<VPWidenStoreRecipe>(CurRecipe), Addr,
149 StoredVal, EVL, Mask);
150
151 if (match(&CurRecipe,
152 m_MaskedStore(m_VPValue(EndPtr), m_VPValue(StoredVal),
153 m_Reverse(m_RemoveMask(HeaderMask, Mask)))) &&
154 match(EndPtr, m_VecEndPtr(m_VPValue(), m_Specific(&Plan->getVF())))) {
155 Mask = GetVPReverse(Mask);
156 Addr = AdjustEndPtr(EndPtr);
157 VPValue *Poison = Plan->getPoison(StoredVal->getScalarType());
158 auto *SpliceR = new VPWidenIntrinsicRecipe(
159 Intrinsic::vector_splice_right, {StoredVal, Poison, &EVL},
160 StoredVal->getScalarType(), {}, {}, DL);
161 SpliceR->insertBefore(&CurRecipe);
162 return new VPWidenStoreEVLRecipe(cast<VPWidenStoreRecipe>(CurRecipe), Addr,
163 SpliceR, EVL, Mask);
164 }
165
168 m_RemoveMask(HeaderMask, Mask),
169 m_TruncOrSelf(m_Specific(&Plan->getVF()))))) {
170 auto *NewStore = cast<VPWidenMemIntrinsicRecipe>(&CurRecipe)->clone();
171 NewStore->setOperand(3, Mask ? Mask : Plan->getTrue());
172 NewStore->setOperand(4, &EVL);
173 return NewStore;
174 }
175
176 if (auto *Rdx = dyn_cast<VPReductionRecipe>(&CurRecipe))
177 if (Rdx->isConditional() &&
178 match(Rdx->getCondOp(), m_RemoveMask(HeaderMask, Mask)))
179 return new VPReductionEVLRecipe(*Rdx, EVL, Mask);
180
181 if (auto *Interleave = dyn_cast<VPInterleaveRecipe>(&CurRecipe))
182 if (Interleave->getMask() &&
183 match(Interleave->getMask(), m_RemoveMask(HeaderMask, Mask)))
184 return new VPInterleaveEVLRecipe(*Interleave, EVL, Mask);
185
186 VPValue *LHS, *RHS;
187 if (match(&CurRecipe, m_SelectLike(m_RemoveMask(HeaderMask, Mask),
189 return new VPWidenIntrinsicRecipe(
190 Intrinsic::vp_merge, {Mask ? Mask : Plan->getTrue(), LHS, RHS, &EVL},
191 LHS->getScalarType(), {}, {}, DL);
192
193 if (match(&CurRecipe, m_LastActiveLane(m_Specific(HeaderMask)))) {
194 Type *Ty = CurRecipe.getVPSingleValue()->getScalarType();
195 VPValue *ZExt = VPBuilder(&CurRecipe).createScalarZExtOrTrunc(&EVL, Ty, DL);
196 return new VPInstruction(
197 Instruction::Sub, {ZExt, Plan->getConstantInt(Ty, 1)},
198 VPIRFlags::getDefaultFlags(Instruction::Sub), {}, DL);
199 }
200
201 // lhs | (headermask && rhs) -> vp.merge rhs, true, lhs, evl
202 if (match(&CurRecipe,
204 m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(RHS)))))
205 return new VPWidenIntrinsicRecipe(Intrinsic::vp_merge,
206 {RHS, Plan->getTrue(), LHS, &EVL},
207 LHS->getScalarType(), {}, {}, DL);
208
209 if (auto *IntrR = dyn_cast<VPWidenIntrinsicRecipe>(&CurRecipe))
210 if (auto VPID = getVPDivRemIntrinsic(IntrR->getVectorIntrinsicID()))
211 if (match(IntrR->getOperand(2), m_RemoveMask(HeaderMask, Mask)))
212 return new VPWidenIntrinsicRecipe(*VPID,
213 {IntrR->getOperand(0),
214 IntrR->getOperand(1),
215 Mask ? Mask : Plan->getTrue(), &EVL},
216 IntrR->getScalarType(), {}, {}, DL);
217
218 return nullptr;
219}
220
221// Decompose the expression recipe and transform each contained recipe into
222// an EVL recipe.
223static bool
225 VPValue &EVL,
226 SmallVector<VPRecipeBase *> &OldRecipes) {
227
228 auto *Expr = dyn_cast<VPExpressionRecipe>(&CurRecipe);
229 if (!Expr)
230 return false;
231
232 // Decompose first and construct with EVL recipes later.
233 SmallVector<VPSingleDefRecipe *> ExpressionRecipes(Expr->decompose());
234 SmallSetVector<VPSingleDefRecipe *, 4> UniqueExpressionRecipes(
235 from_range, ExpressionRecipes);
236
237 // Convert recipes to EVL recipes.
238 for (auto *R : UniqueExpressionRecipes)
239 if (auto *EVLR = cast_if_present<VPSingleDefRecipe>(
240 optimizeMaskToEVL(HeaderMask, *R, EVL))) {
241 EVLR->insertBefore(R);
242 R->replaceAllUsesWith(EVLR);
243 OldRecipes.push_back(R);
244 replace(ExpressionRecipes, R, EVLR);
245 }
246
247 auto *NewExpr =
248 new VPExpressionRecipe(Expr->getExpressionType(), ExpressionRecipes);
249 ExpressionRecipes.back()->replaceAllUsesWith(NewExpr);
250 NewExpr->insertBefore(Expr);
251 OldRecipes.push_back(Expr);
252 return true;
253}
254
255/// Optimize away any EVL-based header masks to VP intrinsic based recipes.
256/// The transforms here need to preserve the original semantics.
258 // Find the EVL-based header mask if it exists: icmp ult step-vector, EVL
259 VPValue *HeaderMask = nullptr, *EVL = nullptr;
262 m_VPValue(EVL))) &&
263 match(EVL, m_EVL(m_VPValue()))) {
264 HeaderMask = R.getVPSingleValue();
265 break;
266 }
267 }
268 if (!HeaderMask)
269 return;
270
272 for (VPUser *U : vputils::collectUsersRecursively(HeaderMask)) {
274 // Transform recipes contained by an expression recipe into EVL recipes.
275 if (optimizeExpressionRecipeToEVL(HeaderMask, *R, *EVL, OldRecipes))
276 continue;
277 if (auto *NewR = optimizeMaskToEVL(HeaderMask, *R, *EVL)) {
278 NewR->insertBefore(R);
279 for (auto [Old, New] :
280 zip_equal(R->definedValues(), NewR->definedValues()))
281 Old->replaceAllUsesWith(New);
282 OldRecipes.push_back(R);
283 }
284 }
285
286 // Replace remaining (HeaderMask && Mask) with vp.merge (True, Mask,
287 // False, EVL)
288 for (VPUser *U : vputils::collectUsersRecursively(HeaderMask)) {
289 VPValue *Mask;
290 if (match(U, m_LogicalAnd(m_Specific(HeaderMask), m_VPValue(Mask)))) {
291 auto *LogicalAnd = cast<VPInstruction>(U);
292 auto *Merge = new VPWidenIntrinsicRecipe(
293 Intrinsic::vp_merge, {Plan.getTrue(), Mask, Plan.getFalse(), EVL},
294 Mask->getScalarType(), {}, {}, LogicalAnd->getDebugLoc());
295 Merge->insertBefore(LogicalAnd);
296 LogicalAnd->replaceAllUsesWith(Merge);
297 OldRecipes.push_back(LogicalAnd);
298 }
299 }
300
301 // Pull out left splices from any elementwise op.
302 // binop(splice.left(poison, x, evl), live-in)
303 // -> splice.left(poison, binop(x,live-in), evl)
305 Plan,
306 [&EVL](VPValue *&X) {
308 m_Poison(), m_VPValue(X), m_Specific(EVL));
309 },
310 [&Plan, &EVL](auto *X) {
311 return new VPWidenIntrinsicRecipe(
312 Intrinsic::vector_splice_left,
313 {Plan.getPoison(X->getScalarType()), X, EVL}, X->getScalarType(),
314 {}, {}, X->getDebugLoc());
315 });
316
317 // Fold the following splice patterns:
318 // splice.right(splice.left(poison, x, evl), poison, evl) -> x
319 // vector.reverse(splice.left(poison, x, evl)) -> vp.reverse(x, true, evl)
320 // splice.right(vector.reverse(x), poison, evl) -> vp.reverse(x, true, evl)
322 auto *R = cast<VPRecipeBase>(U);
323 // Remove potentially dead left splices from the transform above.
325 R->getVPSingleValue()->getNumUsers() == 0) {
326 OldRecipes.push_back(R);
327 continue;
328 }
329
330 VPValue *X;
333 m_Poison(), m_VPValue(X), m_Specific(EVL)),
334 m_Poison(), m_Specific(EVL)))) {
335 R->getVPSingleValue()->replaceAllUsesWith(X);
336 OldRecipes.push_back(R);
337 continue;
338 }
339
340 if (!match(U,
343 m_Poison(), m_VPValue(X), m_Specific(EVL))),
346 continue;
347
348 auto *VPReverse = new VPWidenIntrinsicRecipe(
349 Intrinsic::experimental_vp_reverse, {X, Plan.getTrue(), EVL},
350 X->getScalarType(), {}, {}, R->getDebugLoc());
351 VPReverse->insertBefore(R);
352 R->getVPSingleValue()->replaceAllUsesWith(VPReverse);
353 OldRecipes.push_back(R);
354 }
355
356 for (VPRecipeBase *R : reverse(OldRecipes)) {
357 SmallVector<VPValue *> PossiblyDead(R->operands());
358 R->eraseFromParent();
359 for (VPValue *Op : PossiblyDead)
361 }
362}
363
364/// After replacing the canonical IV with a EVL-based IV, fixup recipes that use
365/// VF to use the EVL instead to avoid incorrect updates on the penultimate
366/// iteration.
367static void fixupVFUsersForEVL(VPlan &Plan, VPValue &EVL) {
368 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
369 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
370
371 // EVL is i32 but VF/VFxUF are IdxTy. Convert as needed.
372 VPValue *EVLAsIdx =
376
377 Plan.getVF().replaceUsesWithIf(EVLAsIdx, [](VPUser &U, unsigned Idx) {
379 });
380
381 Plan.getVFxUF().replaceUsesWithIf(EVLAsIdx, [](VPUser &U, unsigned Idx) {
382 // Only replace uses in VPWidenPointerInductionRecipe; The increment of the
383 // canonical induction must not be updated.
385 });
386
387 // Create a scalar phi to track the previous EVL if fixed-order recurrence is
388 // contained.
389 bool ContainsFORs =
391 if (ContainsFORs) {
392 // TODO: Use VPInstruction::ExplicitVectorLength to get maximum EVL.
393 VPValue *MaxEVL = &Plan.getVF();
394 // Emit VPScalarCastRecipe in preheader if VF is not a 32 bits integer.
395 VPBuilder Builder(LoopRegion->getPreheaderVPBB());
396 MaxEVL = Builder.createScalarZExtOrTrunc(
398
399 Builder.setInsertPoint(Header, Header->getFirstNonPhi());
400 VPValue *PrevEVL = Builder.createScalarPhi(
401 {MaxEVL, &EVL}, DebugLoc::getUnknown(), "prev.evl");
402
405 for (VPRecipeBase &R : *VPBB) {
406 VPValue *V1, *V2;
407 if (!match(&R,
409 m_VPValue(V1), m_VPValue(V2))))
410 continue;
411 VPValue *Imm = Plan.getOrAddLiveIn(
414 Intrinsic::experimental_vp_splice,
415 {V1, V2, Imm, Plan.getTrue(), PrevEVL, &EVL},
416 R.getVPSingleValue()->getScalarType(), {}, {}, R.getDebugLoc());
417 VPSplice->insertBefore(&R);
418 R.getVPSingleValue()->replaceAllUsesWith(VPSplice);
419 }
420 }
421 }
422
423 VPValue *HeaderMask = LoopRegion->getHeaderMask();
424 if (!HeaderMask)
425 return;
426
427 // Ensure that any reduction that uses a select to mask off tail lanes does so
428 // in the vector loop, not the middle block, since EVL tail folding can have
429 // tail elements in the penultimate iteration.
430 assert(all_of(*Plan.getMiddleBlock(), [&Plan, HeaderMask](VPRecipeBase &R) {
431 if (match(&R, m_ComputeReductionResult(m_Select(m_Specific(HeaderMask),
432 m_VPValue(), m_VPValue()))))
433 return R.getOperand(0)->getDefiningRecipe()->getRegion() ==
434 Plan.getVectorLoopRegion();
435 return true;
436 }));
437
438 // Replace the abstract header mask with a mask equivalent to predicating by
439 // EVL: icmp ult step-vector, EVL
440 VPRecipeBase *EVLR = EVL.getDefiningRecipe();
441 VPBuilder Builder(EVLR->getParent(), std::next(EVLR->getIterator()));
442 Type *EVLType = EVL.getScalarType();
443 VPValue *EVLMask = Builder.createICmp(
445 Builder.createNaryOp(VPInstruction::StepVector, {}, EVLType), &EVL);
446 HeaderMask->replaceAllUsesWith(EVLMask);
447}
448
449/// Converts a tail folded vector loop region to step by
450/// VPInstruction::ExplicitVectorLength elements instead of VF elements each
451/// iteration.
452///
453/// - Add a VPCurrentIterationPHIRecipe and related recipes to \p Plan and
454/// replaces all uses of the canonical IV except for the canonical IV
455/// increment with a VPCurrentIterationPHIRecipe. The canonical IV is used
456/// only for loop iterations counting after this transformation.
457///
458/// - The header mask is replaced with a header mask based on the EVL.
459///
460/// - Plans with FORs have a new phi added to keep track of the EVL of the
461/// previous iteration, and VPFirstOrderRecurrencePHIRecipes are replaced with
462/// @llvm.vp.splice.
463///
464/// The function uses the following definitions:
465/// %StartV is the canonical induction start value.
466///
467/// The function adds the following recipes:
468///
469/// vector.ph:
470/// ...
471///
472/// vector.body:
473/// ...
474/// %CurrentIter = CURRENT-ITERATION-PHI [ %StartV, %vector.ph ],
475/// [ %NextIter, %vector.body ]
476/// %AVL = phi [ trip-count, %vector.ph ], [ %NextAVL, %vector.body ]
477/// %VPEVL = EXPLICIT-VECTOR-LENGTH %AVL
478/// ...
479/// %OpEVL = cast i32 %VPEVL to IVSize
480/// %NextIter = add IVSize %OpEVL, %CurrentIter
481/// %NextAVL = sub IVSize nuw %AVL, %OpEVL
482/// ...
483///
484/// If MaxSafeElements is provided, the function adds the following recipes:
485/// vector.ph:
486/// ...
487///
488/// vector.body:
489/// ...
490/// %CurrentIter = CURRENT-ITERATION-PHI [ %StartV, %vector.ph ],
491/// [ %NextIter, %vector.body ]
492/// %AVL = phi [ trip-count, %vector.ph ], [ %NextAVL, %vector.body ]
493/// %cmp = cmp ult %AVL, MaxSafeElements
494/// %SAFE_AVL = select %cmp, %AVL, MaxSafeElements
495/// %VPEVL = EXPLICIT-VECTOR-LENGTH %SAFE_AVL
496/// ...
497/// %OpEVL = cast i32 %VPEVL to IVSize
498/// %NextIter = add IVSize %OpEVL, %CurrentIter
499/// %NextAVL = sub IVSize nuw %AVL, %OpEVL
500/// ...
501///
503 VPlan &Plan, const std::optional<unsigned> &MaxSafeElements) {
504 if (Plan.hasScalarVFOnly())
505 return;
506 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
507 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
508
509 auto *CanonicalIV = LoopRegion->getCanonicalIV();
510 auto *CanIVTy = LoopRegion->getCanonicalIVType();
511 VPValue *StartV = Plan.getZero(CanIVTy);
512 auto *CanonicalIVIncrement = LoopRegion->getOrCreateCanonicalIVIncrement();
513
514 // Create the CurrentIteration recipe in the vector loop.
515 auto *CurrentIteration =
517 CurrentIteration->insertBefore(*Header, Header->begin());
518 VPBuilder Builder(Header, Header->getFirstNonPhi());
519 // Create the AVL (application vector length), starting from TC -> 0 in steps
520 // of EVL.
521 VPPhi *AVLPhi = Builder.createScalarPhi(
523 VPValue *AVL = AVLPhi;
524
525 if (MaxSafeElements) {
526 // Support for MaxSafeDist for correct loop emission.
527 VPValue *AVLSafe = Plan.getConstantInt(CanIVTy, *MaxSafeElements);
528 VPValue *Cmp = Builder.createICmp(ICmpInst::ICMP_ULT, AVL, AVLSafe);
529 AVL = Builder.createSelect(Cmp, AVL, AVLSafe, DebugLoc::getUnknown(),
530 "safe_avl");
531 }
532 auto *VPEVL = Builder.createNaryOp(VPInstruction::ExplicitVectorLength, AVL,
533 DebugLoc::getUnknown(), "evl");
534
535 Builder.setInsertPoint(CanonicalIVIncrement);
536 VPValue *OpVPEVL = VPEVL;
537
538 OpVPEVL = Builder.createScalarZExtOrTrunc(
539 OpVPEVL, CanIVTy, CanonicalIVIncrement->getDebugLoc());
540
541 auto *NextIter = Builder.createAdd(
542 OpVPEVL, CurrentIteration, CanonicalIVIncrement->getDebugLoc(),
543 "current.iteration.next", CanonicalIVIncrement->getNoWrapFlags());
544 CurrentIteration->addBackedgeValue(NextIter);
545
546 VPValue *NextAVL =
547 Builder.createSub(AVLPhi, OpVPEVL, DebugLoc::getCompilerGenerated(),
548 "avl.next", {/*NUW=*/true, /*NSW=*/false});
549 AVLPhi->addIncoming(NextAVL);
550
551 fixupVFUsersForEVL(Plan, *VPEVL);
552 removeDeadRecipes(Plan);
553
554 // Replace all uses of the canonical IV with VPCurrentIterationPHIRecipe
555 // except for the canonical IV increment.
556 CanonicalIV->replaceUsesWithIf(CurrentIteration,
557 [CanonicalIVIncrement](VPUser &U, unsigned) {
558 return &U != CanonicalIVIncrement;
559 });
560 // TODO: support unroll factor > 1.
561 Plan.setUF(1);
562}
563
565 // Find the vector loop entry by locating VPCurrentIterationPHIRecipe.
566 // There should be only one VPCurrentIteration in the entire plan.
567 VPCurrentIterationPHIRecipe *CurrentIteration = nullptr;
568
571 for (VPCurrentIterationPHIRecipe &PhiR :
573 assert(!CurrentIteration &&
574 "Found multiple CurrentIteration. Only one expected");
575 CurrentIteration = &PhiR;
576 }
577
578 // Early return if it is not variable-length stepping.
579 if (!CurrentIteration)
580 return;
581
582 VPBasicBlock *HeaderVPBB = CurrentIteration->getParent();
583 VPValue *CurrentIterationIncr = CurrentIteration->getBackedgeValue();
584
585 // Convert CurrentIteration to concrete recipe.
586 auto *ScalarR =
587 VPBuilder(CurrentIteration)
589 {CurrentIteration->getStartValue(), CurrentIterationIncr},
590 CurrentIteration->getDebugLoc(), "current.iteration.iv");
591 CurrentIteration->replaceAllUsesWith(ScalarR);
592 CurrentIteration->eraseFromParent();
593
594 // Replace CanonicalIVInc with CurrentIteration increment if it exists.
595 auto *CanonicalIV = cast<VPPhi>(&*HeaderVPBB->begin());
596 if (auto *CanIVInc = findUserOf(
597 CanonicalIV, m_c_Add(m_VPValue(), m_Specific(&Plan.getVFxUF())))) {
598 cast<VPInstruction>(CanIVInc)->replaceAllUsesWith(CurrentIterationIncr);
599 CanIVInc->eraseFromParent();
600 }
601}
602
604 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
605 if (!LoopRegion)
606 return;
607 VPBasicBlock *Header = LoopRegion->getEntryBasicBlock();
608 if (Header->empty())
609 return;
610 // The EVL IV is always at the beginning.
611 auto *EVLPhi = dyn_cast<VPCurrentIterationPHIRecipe>(&Header->front());
612 if (!EVLPhi)
613 return;
614
615 // Bail if not an EVL tail folded loop.
616 VPValue *AVL;
617 if (!match(EVLPhi->getBackedgeValue(),
619 return;
620
621 // The AVL may be capped to a safe distance.
622 VPValue *SafeAVL, *UnsafeAVL;
623 if (match(AVL,
625 m_VPValue(SafeAVL)),
626 m_Deferred(UnsafeAVL), m_Deferred(SafeAVL))))
627 AVL = UnsafeAVL;
628
629 VPValue *AVLNext;
630 [[maybe_unused]] bool FoundAVLNext =
632 m_Specific(Plan.getTripCount()), m_VPValue(AVLNext)));
633 assert(FoundAVLNext && "Didn't find AVL backedge?");
634
635 VPBasicBlock *Latch = LoopRegion->getExitingBasicBlock();
636 auto *LatchBr = cast<VPInstruction>(Latch->getTerminator());
637 if (match(LatchBr, m_BranchOnCond(m_True())))
638 return;
639
640 VPValue *CanIVInc;
641 [[maybe_unused]] bool FoundIncrement = match(
642 LatchBr,
644 m_Specific(&Plan.getVectorTripCount()))));
645 assert(FoundIncrement &&
646 match(CanIVInc, m_Add(m_Specific(LoopRegion->getCanonicalIV()),
647 m_Specific(&Plan.getVFxUF()))) &&
648 "Expected BranchOnCond with ICmp comparing CanIV + VFxUF with vector "
649 "trip count");
650
651 Type *AVLTy = AVLNext->getScalarType();
652 VPBuilder Builder(LatchBr);
653 LatchBr->setOperand(
654 0, Builder.createICmp(CmpInst::ICMP_EQ, AVLNext, Plan.getZero(AVLTy)));
655}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
This file provides a LoopVectorizationPlanner class.
R600 Clause Merge
This file implements a set that has insertion order iteration characteristics.
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 std::optional< Intrinsic::ID > getVPDivRemIntrinsic(Intrinsic::ID IntrID)
static bool optimizeExpressionRecipeToEVL(VPValue *HeaderMask, VPRecipeBase &CurRecipe, VPValue &EVL, SmallVector< VPRecipeBase * > &OldRecipes)
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...
This file contains the declarations of different VPlan-related auxiliary helpers.
This file provides utility VPlan to VPlan transformations.
This file contains the declarations of the Vectorization Plan base classes:
Value * RHS
Value * LHS
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
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
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
A debug info location.
Definition DebugLoc.h:126
static DebugLoc getCompilerGenerated()
Definition DebugLoc.h:154
static DebugLoc getUnknown()
Definition DebugLoc.h:153
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.
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
LLVM_ABI const SCEV * getElementCount(Type *Ty, ElementCount EC, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
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,...
A SetVector that performs no allocations if smaller than a certain size.
Definition SetVector.h:345
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
Definition VPlan.h:4418
iterator begin()
Recipe iterator methods.
Definition VPlan.h:4453
VPRecipeBase * getTerminator()
If the block has multiple successors, return the branch recipe terminating the block.
Definition VPlan.cpp:610
const VPBasicBlock * getExitingBasicBlock() const
Definition VPlan.cpp:203
VPlan * getPlan()
Definition VPlan.h:197
const VPBasicBlock * getEntryBasicBlock() const
Definition VPlan.cpp:188
static auto blocksAs(T &&Range)
Return an iterator range over Range with each block cast to BlockTy.
Definition VPlanUtils.h:424
static auto blocksOnly(T &&Range)
Return an iterator range over Range which only includes BlockTy blocks.
Definition VPlanUtils.h:417
VPlan-based builder utility analogous to IRBuilder.
VPPhi * createScalarPhi(ArrayRef< VPValue * > IncomingValues, DebugLoc DL=DebugLoc::getUnknown(), const Twine &Name="", std::optional< VPIRFlags > Flags=std::nullopt, Type *ResultTy=nullptr)
Create a phi with IncomingValues, using the default flags for the result type, unless Flags is set.
VPValue * createScalarZExtOrTrunc(VPValue *Op, Type *ResultTy, DebugLoc DL)
static VPBuilder getToInsertAfter(VPRecipeBase *R)
Create a VPBuilder to insert after R.
A recipe for generating the phi node tracking the current scalar iteration index.
Definition VPlan.h:4098
VPValue * getVPSingleValue()
Returns the only VPValue defined by the VPDef.
Definition VPlanValue.h:552
A recipe to combine multiple recipes into a single 'expression' recipe, which should be considered a ...
Definition VPlan.h:3557
virtual VPValue * getBackedgeValue()
Returns the incoming value from the loop backedge.
Definition VPlan.h:2493
VPValue * getStartValue()
Returns the start value of the phi, if one is set.
Definition VPlan.h:2482
static VPIRFlags getDefaultFlags(unsigned Opcode, Type *ResultTy=nullptr)
Returns default flags for Opcode and scalar ResultTy for opcodes that support it, asserts otherwise.
This is a concrete Recipe that models a single VPlan-level instruction.
Definition VPlan.h:1305
A recipe for interleaved memory operations with vector-predication intrinsics.
Definition VPlan.h:3183
void addIncoming(VPValue *IncomingV)
Append IncomingV as an incoming value to the phi-like recipe.
Definition VPlan.h:1671
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition VPlan.h:411
VPBasicBlock * getParent()
Definition VPlan.h:483
DebugLoc getDebugLoc() const
Returns the debug location of the recipe.
Definition VPlan.h:561
void insertBefore(VPRecipeBase *InsertPos)
Insert an unlinked recipe into a basic block immediately before the specified recipe.
iplist< VPRecipeBase >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A recipe to represent inloop reduction operations with vector-predication intrinsics,...
Definition VPlan.h:3355
VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks which form a Single-Entry-S...
Definition VPlan.h:4643
const VPBlockBase * getEntry() const
Definition VPlan.h:4687
VPInstruction * getOrCreateCanonicalIVIncrement()
Get the canonical IV increment instruction if it exists.
Definition VPlan.cpp:851
Type * getCanonicalIVType() const
Return the type of the canonical IV for loop regions.
Definition VPlan.h:4771
VPRegionValue * getCanonicalIV()
Return the canonical induction variable of the region, null for replicating regions.
Definition VPlan.h:4763
VPBasicBlock * getPreheaderVPBB()
Returns the pre-header VPBasicBlock of the loop region.
Definition VPlan.h:4712
VPRegionValue * getHeaderMask() const
Return the header mask of the region, or null if not set.
Definition VPlan.h:4776
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition VPlanValue.h:401
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:147
VPRecipeBase * getDefiningRecipe()
Returns the recipe defining this VPValue or nullptr if it is not defined by a recipe,...
Definition VPlan.cpp:128
void replaceAllUsesWith(VPValue *New)
Definition VPlan.cpp:1450
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:1456
A recipe for widening vector intrinsics.
Definition VPlan.h:1936
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition VPlan.h:4830
const DataLayout & getDataLayout() const
Definition VPlan.h:5044
LLVMContext & getContext() const
Definition VPlan.h:5040
VPBasicBlock * getEntry()
Definition VPlan.h:4926
VPValue * getTripCount() const
The trip count of the original loop.
Definition VPlan.h:4998
VPIRValue * getFalse()
Return a VPIRValue wrapping i1 false.
Definition VPlan.h:5135
VPSymbolicValue & getVFxUF()
Returns VF * UF of the vector loop region.
Definition VPlan.h:5038
VPIRValue * getPoison(Type *Ty)
Return a VPIRValue wrapping a poison value of type Ty.
Definition VPlan.h:5163
VPSymbolicValue & getVectorTripCount()
The vector trip count.
Definition VPlan.h:5028
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:5112
VPIRValue * getZero(Type *Ty)
Return a VPIRValue wrapping the null value of type Ty.
Definition VPlan.h:5138
LLVM_ABI_FOR_TEST VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition VPlan.cpp:1033
VPBasicBlock * getMiddleBlock()
Returns the 'middle' block of the plan, that is the block that selects whether to execute the scalar ...
Definition VPlan.h:4968
VPIRValue * getTrue()
Return a VPIRValue wrapping i1 true.
Definition VPlan.h:5132
bool hasScalarVFOnly() const
Definition VPlan.h:5080
VPSymbolicValue & getVF()
Returns the VF of the vector loop region.
Definition VPlan.h:5031
void setUF(unsigned UF)
Definition VPlan.h:5095
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:5146
self_iterator getIterator()
Definition ilist_node.h:123
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
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.
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.
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)
SpecificCmpClass_match< LHS, RHS, ICmpInst > m_SpecificICmp(CmpPredicate MatchPred, 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.
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
AllRecipe_commutative_match< Instruction::Or, Op0_t, Op1_t > m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
VPInstruction_match< VPInstruction::StepVector > m_StepVector()
VPInstruction_match< VPInstruction::LastActiveLane, Op0_t > m_LastActiveLane(const Op0_t &Op0)
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)
VPRecipeBase * findUserOf(VPValue *V, const MatchT &P)
If V is used by a recipe matching pattern P, return it.
VPInstruction_match< VPInstruction::ExplicitVectorLength, Op0_t > m_EVL(const Op0_t &Op0)
match_bind< VPInstruction > m_VPInstruction(VPInstruction *&V)
Match a VPInstruction, capturing if we match.
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).
int_pred_ty< is_one, 1 > m_True()
VPInstruction_match< VPInstruction::BranchOnCond > m_BranchOnCond()
VPInstruction_match< VPInstruction::Reverse, Op0_t > m_Reverse(const Op0_t &Op0)
VPIRValue * tryToFoldLiveIns(VPSingleDefRecipe &R, ArrayRef< VPValue * > Operands, const DataLayout &DL)
Try to fold R using InstSimplifyFolder.
void recursivelyDeleteDeadRecipes(VPValue *V)
Recursively delete V and any of its operands that become dead.
const SCEV * getSCEVExprForVPValue(const VPValue *V, PredicatedScalarEvolution &PSE, const Loop *L=nullptr)
Return the SCEV expression for V.
void pullOutPermutations(VPlan &Plan, Match_t Perm, Builder Build)
Removes the permutation pattern Perm from any elementwise operations in the plan, by constructing a n...
Definition VPlanUtils.h:264
SmallVector< VPUser * > collectUsersRecursively(VPValue *V)
Collect all users of V, looking through recipes that define other values.
This is an optimization pass for GlobalISel generic memory operations.
auto cast_if_present(const Y &Val)
cast_if_present<X> - Functionally identical to cast, except that a null value is accepted.
Definition Casting.h:683
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
Definition STLExtras.h:856
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
constexpr from_range_t from_range
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
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
auto make_isa_range(RangeT &&Range)
Return a range over Range containing only elements for which isa<T> holds, casting each of them to T.
Definition STLExtras.h:567
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
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
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1926
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
A recipe for widening load operations with vector-predication intrinsics, using the address to load f...
Definition VPlan.h:3871
A recipe for widening store operations with vector-predication intrinsics, using the value to store,...
Definition VPlan.h:3977
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 convertToVariableLengthStep(VPlan &Plan)
Transform loops with variable-length stepping after region dissolution.
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 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 convertEVLExitCond(VPlan &Plan)
Replaces the exit condition from (branch-on-cond eq CanonicalIVInc, VectorTripCount) to (branch-on-co...