1//===-- VPlanUnroll.cpp - VPlan unroller ----------------------------------===//
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 explicit unrolling for VPlans.
11///
12//===----------------------------------------------------------------------===//
13
14#include "VPRecipeBuilder.h"
15#include "VPlan.h"
16#include "VPlanAnalysis.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/PostOrderIterator.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/ScopeExit.h"
25#include "llvm/Analysis/IVDescriptors.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/Intrinsics.h"
28#include "llvm/IR/MDBuilder.h"
29#include <numeric>
30
31using namespace llvm;
32using namespace llvm::VPlanPatternMatch;
33
34namespace {
35
36/// Helper to hold state needed for unrolling. It holds the Plan to unroll by
37/// UF. It also holds copies of VPValues across UF-1 unroll parts to facilitate
38/// the unrolling transformation, where the original VPValues are retained for
39/// part zero.
40class UnrollState {
41 /// Plan to unroll.
42 VPlan &Plan;
43 /// Unroll factor to unroll by.
44 const unsigned UF;
45
46 /// Unrolling may create recipes that should not be unrolled themselves.
47 /// Those are tracked in ToSkip.
48 SmallPtrSet<VPRecipeBase *, 8> ToSkip;
49
50 // Associate with each VPValue of part 0 its unrolled instances of parts 1,
51 // ..., UF-1.
52 DenseMap<VPValue *, SmallVector<VPValue *>> VPV2Parts;
53
54 /// Unroll replicate region \p VPR by cloning the region UF - 1 times.
55 void unrollReplicateRegionByUF(VPRegionBlock *VPR);
56
57 /// Unroll recipe \p R by cloning it UF - 1 times, unless it is uniform across
58 /// all parts.
59 void unrollRecipeByUF(VPRecipeBase &R);
60
61 /// Unroll header phi recipe \p R. How exactly the recipe gets unrolled
62 /// depends on the concrete header phi. Inserts newly created recipes at \p
63 /// InsertPtForPhi.
64 void unrollHeaderPHIByUF(VPHeaderPHIRecipe *R,
65 VPBasicBlock::iterator InsertPtForPhi);
66
67 /// Unroll a widen induction recipe \p IV. This introduces recipes to compute
68 /// the induction steps for each part.
69 void unrollWidenInductionByUF(VPWidenInductionRecipe *IV,
70 VPBasicBlock::iterator InsertPtForPhi);
71
72 VPValue *getConstantInt(unsigned Part) {
73 Type *CanIVIntTy = Plan.getVectorLoopRegion()->getCanonicalIVType();
74 return Plan.getConstantInt(Ty: CanIVIntTy, Val: Part);
75 }
76
77public:
78 UnrollState(VPlan &Plan, unsigned UF) : Plan(Plan), UF(UF) {}
79
80 void unrollBlock(VPBlockBase *VPB);
81
82 VPValue *getValueForPart(VPValue *V, unsigned Part) {
83 if (Part == 0 || isa<VPIRValue, VPSymbolicValue>(Val: V))
84 return V;
85 assert((VPV2Parts.contains(V) && VPV2Parts[V].size() >= Part) &&
86 "accessed value does not exist");
87 return VPV2Parts[V][Part - 1];
88 }
89
90 /// Given a single original recipe \p OrigR (of part zero), and its copy \p
91 /// CopyR for part \p Part, map every VPValue defined by \p OrigR to its
92 /// corresponding VPValue defined by \p CopyR.
93 void addRecipeForPart(VPRecipeBase *OrigR, VPRecipeBase *CopyR,
94 unsigned Part) {
95 for (const auto &[Idx, VPV] : enumerate(First: OrigR->definedValues())) {
96 const auto &[V, _] = VPV2Parts.try_emplace(Key: VPV);
97 assert(V->second.size() == Part - 1 && "earlier parts not set");
98 V->second.push_back(Elt: CopyR->getVPValue(I: Idx));
99 }
100 }
101
102 /// Given a uniform recipe \p R, add it for all parts.
103 void addUniformForAllParts(VPSingleDefRecipe *R) {
104 const auto &[V, Inserted] = VPV2Parts.try_emplace(Key: R);
105 assert(Inserted && "uniform value already added");
106 for (unsigned Part = 0; Part != UF; ++Part)
107 V->second.push_back(Elt: R);
108 }
109
110 bool contains(VPValue *VPV) const { return VPV2Parts.contains(Val: VPV); }
111
112 /// Update \p R's operand at \p OpIdx with its corresponding VPValue for part
113 /// \p P.
114 void remapOperand(VPRecipeBase *R, unsigned OpIdx, unsigned Part) {
115 auto *Op = R->getOperand(N: OpIdx);
116 R->setOperand(I: OpIdx, New: getValueForPart(V: Op, Part));
117 }
118
119 /// Update \p R's operands with their corresponding VPValues for part \p P.
120 void remapOperands(VPRecipeBase *R, unsigned Part) {
121 for (const auto &[OpIdx, Op] : enumerate(First: R->operands()))
122 R->setOperand(I: OpIdx, New: getValueForPart(V: Op, Part));
123 }
124};
125} // namespace
126
127static void addStartIndexForScalarSteps(VPScalarIVStepsRecipe *Steps,
128 unsigned Part, VPlan &Plan) {
129 if (Part == 0)
130 return;
131
132 VPBuilder Builder(Steps);
133 Type *BaseIVTy = Steps->getOperand(N: 0)->getScalarType();
134 Type *IntStepTy =
135 IntegerType::get(C&: BaseIVTy->getContext(), NumBits: BaseIVTy->getScalarSizeInBits());
136 VPValue *StartIndex = Steps->getVFValue();
137 if (Part > 1) {
138 StartIndex = Builder.createOverflowingOp(
139 Opcode: Instruction::Mul,
140 Operands: {StartIndex, Plan.getConstantInt(Ty: StartIndex->getScalarType(), Val: Part)});
141 }
142 StartIndex = Builder.createScalarSExtOrTrunc(Op: StartIndex, ResultTy: IntStepTy,
143 DL: Steps->getDebugLoc());
144
145 if (BaseIVTy->isFloatingPointTy())
146 StartIndex = Builder.createScalarCast(Opcode: Instruction::SIToFP, Op: StartIndex,
147 ResultTy: BaseIVTy, DL: Steps->getDebugLoc());
148
149 Steps->setStartIndex(StartIndex);
150}
151
152void UnrollState::unrollReplicateRegionByUF(VPRegionBlock *VPR) {
153 VPBlockBase *InsertPt = VPR->getSingleSuccessor();
154 for (unsigned Part = 1; Part != UF; ++Part) {
155 auto *Copy = VPR->clone();
156 VPBlockUtils::insertBlockBefore(NewBlock: Copy, BlockPtr: InsertPt);
157
158 auto PartI = vp_depth_first_shallow(G: Copy->getEntry());
159 auto Part0 = vp_depth_first_shallow(G: VPR->getEntry());
160 for (const auto &[PartIVPBB, Part0VPBB] :
161 zip(t: VPBlockUtils::blocksAs<VPBasicBlock>(Range&: PartI),
162 u: VPBlockUtils::blocksAs<VPBasicBlock>(Range&: Part0))) {
163 for (const auto &[PartIR, Part0R] : zip(t&: *PartIVPBB, u&: *Part0VPBB)) {
164 remapOperands(R: &PartIR, Part);
165 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: &PartIR))
166 addStartIndexForScalarSteps(Steps, Part, Plan);
167
168 addRecipeForPart(OrigR: &Part0R, CopyR: &PartIR, Part);
169 }
170 }
171 }
172}
173
174void UnrollState::unrollWidenInductionByUF(
175 VPWidenInductionRecipe *IV, VPBasicBlock::iterator InsertPtForPhi) {
176 VPBasicBlock *PH = cast<VPBasicBlock>(
177 Val: IV->getParent()->getEnclosingLoopRegion()->getSinglePredecessor());
178 Type *IVTy = IV->getScalarType();
179 auto &ID = IV->getInductionDescriptor();
180 FastMathFlags FMF;
181 VPIRFlags::WrapFlagsTy WrapFlags(false, false);
182 if (auto *IntOrFPInd = dyn_cast<VPWidenIntOrFpInductionRecipe>(Val: IV)) {
183 FMF = IntOrFPInd->getFastMathFlagsOrNone();
184 WrapFlags = IntOrFPInd->getNoWrapFlagsOrNone();
185 }
186
187 VPValue *ScalarStep = IV->getStepValue();
188 VPBuilder Builder(PH);
189 Type *VectorStepTy = IVTy->isPointerTy() ? ScalarStep->getScalarType() : IVTy;
190 VPInstruction *VectorStep = Builder.createNaryOp(
191 Opcode: VPInstruction::WideIVStep, Operands: {&Plan.getVF(), ScalarStep}, ResultTy: VectorStepTy, Flags: FMF,
192 DL: IV->getDebugLoc());
193
194 ToSkip.insert(Ptr: VectorStep);
195
196 // Now create recipes to compute the induction steps for part 1 .. UF. Part 0
197 // remains the header phi. Parts > 0 are computed by adding Step to the
198 // previous part. The header phi recipe will get 2 new operands: the step
199 // value for a single part and the last part, used to compute the backedge
200 // value during VPWidenInductionRecipe::execute.
201 // %Part.0 = VPWidenInductionRecipe %Start, %ScalarStep, %VectorStep, %Part.3
202 // %Part.1 = %Part.0 + %VectorStep
203 // %Part.2 = %Part.1 + %VectorStep
204 // %Part.3 = %Part.2 + %VectorStep
205 //
206 // The newly added recipes are added to ToSkip to avoid interleaving them
207 // again.
208 VPValue *Prev = IV;
209 Builder.setInsertPoint(TheBB: IV->getParent(), IP: InsertPtForPhi);
210 unsigned AddOpc;
211 VPIRFlags AddFlags;
212 if (IVTy->isPointerTy()) {
213 AddOpc = VPInstruction::WidePtrAdd;
214 AddFlags = GEPNoWrapFlags::none();
215 } else if (IVTy->isFloatingPointTy()) {
216 AddOpc = ID.getInductionOpcode();
217 AddFlags = FMF;
218 } else {
219 AddOpc = Instruction::Add;
220 AddFlags = WrapFlags;
221 if (cast<VPWidenIntOrFpInductionRecipe>(Val: IV)->isCanonical())
222 AddFlags = VPIRFlags::WrapFlagsTy(/*NUW=*/true, /*NSW=*/false);
223 }
224 for (unsigned Part = 1; Part != UF; ++Part) {
225 std::string Name =
226 Part > 1 ? "step.add." + std::to_string(val: Part) : "step.add";
227
228 VPInstruction *Add =
229 Builder.createNaryOp(Opcode: AddOpc,
230 Operands: {
231 Prev,
232 VectorStep,
233 },
234 Flags: AddFlags, DL: IV->getDebugLoc(), Name);
235 ToSkip.insert(Ptr: Add);
236 addRecipeForPart(OrigR: IV, CopyR: Add, Part);
237 Prev = Add;
238 }
239 IV->addUnrolledPartOperands(SplatVFStep: VectorStep, LastPart: Prev);
240}
241
242void UnrollState::unrollHeaderPHIByUF(VPHeaderPHIRecipe *R,
243 VPBasicBlock::iterator InsertPtForPhi) {
244 // First-order recurrences pass a single vector or scalar through their header
245 // phis, irrespective of interleaving.
246 if (isa<VPFirstOrderRecurrencePHIRecipe>(Val: R))
247 return;
248
249 // Generate step vectors for each unrolled part.
250 if (auto *IV = dyn_cast<VPWidenInductionRecipe>(Val: R)) {
251 unrollWidenInductionByUF(IV, InsertPtForPhi);
252 return;
253 }
254
255 auto *RdxPhi = dyn_cast<VPReductionPHIRecipe>(Val: R);
256 if (RdxPhi && RdxPhi->isOrdered())
257 return;
258
259 auto InsertPt = std::next(x: R->getIterator());
260 for (unsigned Part = 1; Part != UF; ++Part) {
261 VPRecipeBase *Copy = R->clone();
262 Copy->insertBefore(BB&: *R->getParent(), IP: InsertPt);
263 addRecipeForPart(OrigR: R, CopyR: Copy, Part);
264 if (RdxPhi) {
265 // If the start value is a ReductionStartVector, use the identity value
266 // (second operand) for unrolled parts. If the scaling factor is > 1,
267 // create a new ReductionStartVector with the scale factor and both
268 // operands set to the identity value.
269 if (auto *VPI = dyn_cast<VPInstruction>(Val: RdxPhi->getStartValue())) {
270 assert(VPI->getOpcode() == VPInstruction::ReductionStartVector &&
271 "unexpected start VPInstruction");
272 if (Part != 1)
273 continue;
274 VPValue *StartV;
275 if (match(V: VPI->getOperand(N: 2), P: m_One())) {
276 StartV = VPI->getOperand(N: 1);
277 } else {
278 auto *C = VPI->clone();
279 C->setOperand(I: 0, New: C->getOperand(N: 1));
280 C->insertAfter(InsertPos: VPI);
281 StartV = C;
282 }
283 for (unsigned Part = 1; Part != UF; ++Part)
284 VPV2Parts[VPI][Part - 1] = StartV;
285 }
286 } else {
287 assert(isa<VPActiveLaneMaskPHIRecipe>(R) &&
288 "unexpected header phi recipe not needing unrolled part");
289 }
290 }
291}
292
293/// Handle non-header-phi recipes.
294void UnrollState::unrollRecipeByUF(VPRecipeBase &R) {
295 if (match(V: &R, P: m_CombineOr(Ps: m_BranchOnCond(), Ps: m_BranchOnCount())))
296 return;
297
298 if (auto *VPI = dyn_cast<VPInstruction>(Val: &R)) {
299 if (vputils::onlyFirstPartUsed(Def: VPI)) {
300 addUniformForAllParts(R: VPI);
301 return;
302 }
303 }
304 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: &R)) {
305 if (isa<StoreInst>(Val: RepR->getUnderlyingValue()) &&
306 RepR->getOperand(N: 1)->isDefinedOutsideLoopRegions()) {
307 // Stores to an invariant address only need to store the last part.
308 remapOperands(R: &R, Part: UF - 1);
309 return;
310 }
311 if (match(V: RepR,
312 P: m_Intrinsic<Intrinsic::experimental_noalias_scope_decl>())) {
313 addUniformForAllParts(R: RepR);
314 return;
315 }
316 }
317
318 // Unroll non-uniform recipes.
319 auto InsertPt = std::next(x: R.getIterator());
320 VPBasicBlock &VPBB = *R.getParent();
321 for (unsigned Part = 1; Part != UF; ++Part) {
322 VPRecipeBase *Copy = R.clone();
323 Copy->insertBefore(BB&: VPBB, IP: InsertPt);
324 addRecipeForPart(OrigR: &R, CopyR: Copy, Part);
325
326 // Phi operands are updated once all other recipes have been unrolled.
327 if (isa<VPWidenPHIRecipe>(Val: Copy))
328 continue;
329
330 VPValue *Op;
331 if (match(V: &R, P: m_VPInstruction<VPInstruction::FirstOrderRecurrenceSplice>(
332 Ops: m_VPValue(), Ops: m_VPValue(V&: Op)))) {
333 Copy->setOperand(I: 0, New: getValueForPart(V: Op, Part: Part - 1));
334 Copy->setOperand(I: 1, New: getValueForPart(V: Op, Part));
335 continue;
336 }
337 if (match(V: &R, P: m_VPInstruction<VPInstruction::ExtractVectorForPart>(
338 Ops: m_VPValue(V&: Op), Ops: m_VPValue()))) {
339 Copy->setOperand(I: 0, New: Op);
340 Copy->setOperand(I: 1, New: Plan.getConstantInt(BitWidth: 64, Val: Part));
341 continue;
342 }
343 if (isa<VPVectorPointerRecipe, VPWidenCanonicalIVRecipe>(Val: R)) {
344 VPBuilder Builder(&R);
345 const DataLayout &DL = Plan.getDataLayout();
346 Type *IndexTy =
347 isa<VPWidenCanonicalIVRecipe>(Val: R)
348 ? Plan.getVectorLoopRegion()->getCanonicalIVType()
349 : DL.getIndexType(PtrTy: R.getVPSingleValue()->getScalarType());
350 VPValue *VF = Builder.createScalarZExtOrTrunc(Op: &Plan.getVF(), ResultTy: IndexTy,
351 DL: DebugLoc::getUnknown());
352 // VFxUF does not wrap, so VF * Part also cannot wrap.
353 VPValue *VFxPart = Builder.createOverflowingOp(
354 Opcode: Instruction::Mul, Operands: {VF, Plan.getConstantInt(Ty: IndexTy, Val: Part)},
355 WrapFlags: {true, true});
356 if (auto *VecPtr = dyn_cast<VPVectorPointerRecipe>(Val: Copy))
357 VecPtr->addPerPartOffset(VFxPart);
358 else
359 cast<VPWidenCanonicalIVRecipe>(Val: Copy)->addPerPartStep(Step: VFxPart);
360 continue;
361 }
362 if (auto *Red = dyn_cast<VPReductionRecipe>(Val: &R)) {
363 auto *Phi = dyn_cast<VPReductionPHIRecipe>(Val: R.getOperand(N: 0));
364 if (Phi && Phi->isOrdered()) {
365 auto &Parts = VPV2Parts[Phi];
366 if (Part == 1) {
367 Parts.clear();
368 Parts.push_back(Elt: Red);
369 }
370 Parts.push_back(Elt: Copy->getVPSingleValue());
371 Phi->setOperand(I: 1, New: Copy->getVPSingleValue());
372 }
373 }
374 if (auto *VEPR = dyn_cast<VPVectorEndPointerRecipe>(Val: Copy)) {
375 // Materialize PartN offset for VectorEndPointer.
376 VEPR->setOperand(I: 0, New: R.getOperand(N: 0));
377 VEPR->setOperand(I: 1, New: R.getOperand(N: 1));
378 VEPR->materializeOffset(Part);
379 continue;
380 }
381
382 remapOperands(R: Copy, Part);
383
384 if (auto *ScalarIVSteps = dyn_cast<VPScalarIVStepsRecipe>(Val: Copy))
385 addStartIndexForScalarSteps(Steps: ScalarIVSteps, Part, Plan);
386
387 if (match(V: Copy,
388 P: m_VPInstruction<VPInstruction::CanonicalIVIncrementForPart>())) {
389 VPBuilder Builder(Copy);
390 VPValue *ScaledByPart = Builder.createOverflowingOp(
391 Opcode: Instruction::Mul, Operands: {Copy->getOperand(N: 1), getConstantInt(Part)});
392 Copy->setOperand(I: 1, New: ScaledByPart);
393 }
394 }
395 if (auto *VEPR = dyn_cast<VPVectorEndPointerRecipe>(Val: &R)) {
396 // Materialize Part0 offset for VectorEndPointer.
397 VEPR->materializeOffset();
398 }
399 if (auto *WideCanIV = dyn_cast<VPWidenCanonicalIVRecipe>(Val: &R)) {
400 // Set Part0 step for WidenCanonicalIV.
401 WideCanIV->addPerPartStep(Step: getConstantInt(Part: 0));
402 }
403}
404
405void UnrollState::unrollBlock(VPBlockBase *VPB) {
406 auto *VPR = dyn_cast<VPRegionBlock>(Val: VPB);
407 if (VPR) {
408 if (VPR->isReplicator())
409 return unrollReplicateRegionByUF(VPR);
410
411 // Traverse blocks in region in RPO to ensure defs are visited before uses
412 // across blocks.
413 ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>>
414 RPOT(VPR->getEntry());
415 for (VPBlockBase *VPB : RPOT)
416 unrollBlock(VPB);
417 return;
418 }
419
420 // VPB is a VPBasicBlock; unroll it, i.e., unroll its recipes.
421 auto *VPBB = cast<VPBasicBlock>(Val: VPB);
422 auto InsertPtForPhi = VPBB->getFirstNonPhi();
423 for (VPRecipeBase &R : make_early_inc_range(Range&: *VPBB)) {
424 if (ToSkip.contains(Ptr: &R) || isa<VPIRInstruction>(Val: &R))
425 continue;
426
427 // Add all VPValues for all parts to AnyOf, FirstActiveLaneMask and
428 // ComputeReductionResult which combine all parts to compute the final
429 // value.
430 VPValue *Op1;
431 if (match(V: &R, P: m_VPInstruction<VPInstruction::AnyOf>(Ops: m_VPValue(V&: Op1))) ||
432 match(V: &R,
433 P: m_VPInstruction<VPInstruction::ConcatVectors>(Ops: m_VPValue(V&: Op1))) ||
434 match(V: &R, P: m_FirstActiveLane(Op0: m_VPValue(V&: Op1))) ||
435 match(V: &R, P: m_LastActiveLane(Op0: m_VPValue(V&: Op1))) ||
436 match(V: &R, P: m_ComputeReductionResult(Op0: m_VPValue(V&: Op1)))) {
437 auto *VPI = cast<VPInstruction>(Val: &R);
438 addUniformForAllParts(R: VPI);
439 for (unsigned Part = 1; Part != UF; ++Part)
440 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
441 continue;
442 }
443 VPValue *Op0;
444 if (match(V: &R, P: m_ExtractLane(Op0: m_VPValue(V&: Op0), Op1: m_VPValue(V&: Op1)))) {
445 auto *VPI = cast<VPInstruction>(Val: &R);
446 addUniformForAllParts(R: VPI);
447 for (unsigned Part = 1; Part != UF; ++Part)
448 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
449 continue;
450 }
451
452 VPValue *Op2;
453 if (match(V: &R, P: m_ExtractLastActive(Op0: m_VPValue(), Op1: m_VPValue(V&: Op1),
454 Op2: m_VPValue(V&: Op2)))) {
455 auto *VPI = cast<VPInstruction>(Val: &R);
456 addUniformForAllParts(R: VPI);
457 for (unsigned Part = 1; Part != UF; ++Part) {
458 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
459 VPI->addOperand(Op: getValueForPart(V: Op2, Part));
460 }
461 continue;
462 }
463
464 if (Plan.hasScalarVFOnly()) {
465 if (match(V: &R, P: m_ExtractLastPart(Op0: m_VPValue(V&: Op0))) ||
466 match(V: &R, P: m_ExtractPenultimateElement(Op0: m_VPValue(V&: Op0)))) {
467 auto *I = cast<VPInstruction>(Val: &R);
468 bool IsPenultimatePart =
469 I->getOpcode() == VPInstruction::ExtractPenultimateElement;
470 unsigned PartIdx = IsPenultimatePart ? UF - 2 : UF - 1;
471 // For scalar VF, directly use the scalar part value.
472 I->replaceAllUsesWith(New: getValueForPart(V: Op0, Part: PartIdx));
473 continue;
474 }
475 }
476 // For vector VF, the penultimate element is always extracted from the last part.
477 if (match(V: &R, P: m_ExtractLastLaneOfLastPart(Op0: m_VPValue(V&: Op0))) ||
478 match(V: &R, P: m_ExtractPenultimateElement(Op0: m_VPValue(V&: Op0)))) {
479 addUniformForAllParts(R: cast<VPSingleDefRecipe>(Val: &R));
480 R.setOperand(I: 0, New: getValueForPart(V: Op0, Part: UF - 1));
481 continue;
482 }
483
484 if (match(V: &R,
485 P: m_WideActiveLaneMask(Op0: m_VPValue(), Op1: m_VPValue(), Op2: m_VPValue()))) {
486 auto *ALM = cast<VPInstruction>(Val: &R);
487 ALM->setOperand(I: 2, New: getConstantInt(Part: UF));
488 continue;
489 }
490
491 if (match(V: &R,
492 P: m_CombineOr(Ps: m_VPInstruction<VPInstruction::WideVectorLoad>(),
493 Ps: m_VPInstruction<VPInstruction::WideVectorStore>()))) {
494 cast<VPInstruction>(Val: &R)->setOperand(I: 0, New: Plan.getConstantInt(BitWidth: 64, Val: UF));
495 continue;
496 }
497
498 auto *SingleDef = dyn_cast<VPSingleDefRecipe>(Val: &R);
499 if (SingleDef && vputils::isUniformAcrossVFsAndUFs(V: SingleDef)) {
500 addUniformForAllParts(R: SingleDef);
501 continue;
502 }
503
504 if (auto *H = dyn_cast<VPHeaderPHIRecipe>(Val: &R)) {
505 unrollHeaderPHIByUF(R: H, InsertPtForPhi);
506 continue;
507 }
508
509 unrollRecipeByUF(R);
510 }
511}
512
513void VPlanTransforms::unrollByUF(VPlan &Plan, unsigned UF) {
514 assert(UF > 0 && "Unroll factor must be positive");
515 Plan.setUF(UF);
516 llvm::scope_exit Cleanup([&Plan, UF]() {
517 auto Iter = vp_depth_first_deep(G: Plan.getEntry());
518 // Remove recipes that are redundant after unrolling.
519 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Range&: Iter)) {
520 for (VPInstruction &VPI :
521 make_early_inc_range(Range: make_isa_range<VPInstruction>(Range&: *VPBB))) {
522 if (VPI.getOpcode() == VPInstruction::CanonicalIVIncrementForPart &&
523 VPI.getOperand(N: 1) == &Plan.getVF()) {
524 VPI.replaceAllUsesWith(New: VPI.getOperand(N: 0));
525 VPI.eraseFromParent();
526 }
527 }
528 }
529
530 Type *TCTy = Plan.getTripCount()->getScalarType();
531 Plan.getUF().replaceAllUsesWith(New: Plan.getConstantInt(Ty: TCTy, Val: UF));
532 });
533 if (UF == 1) {
534 return;
535 }
536
537 UnrollState Unroller(Plan, UF);
538
539 // Iterate over all blocks in the plan starting from Entry, and unroll
540 // recipes inside them. This includes the vector preheader and middle blocks,
541 // which may set up or post-process per-part values.
542 ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> RPOT(
543 Plan.getEntry());
544 for (VPBlockBase *VPB : RPOT)
545 Unroller.unrollBlock(VPB);
546
547 unsigned Part = 1;
548 // Remap operands of cloned header phis to update backedge values. The header
549 // phis cloned during unrolling are just after the header phi for part 0.
550 // Reset Part to 1 when reaching the first (part 0) recipe of a block.
551 for (VPRecipeBase &H :
552 Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
553 // The second operand of Fixed Order Recurrence phi's, feeding the spliced
554 // value across the backedge, needs to remap to the last part of the spliced
555 // value.
556 if (isa<VPFirstOrderRecurrencePHIRecipe>(Val: &H)) {
557 Unroller.remapOperand(R: &H, OpIdx: 1, Part: UF - 1);
558 continue;
559 }
560 if (Unroller.contains(VPV: H.getVPSingleValue())) {
561 Part = 1;
562 continue;
563 }
564 Unroller.remapOperands(R: &H, Part);
565 Part++;
566 }
567
568 VPlanTransforms::removeDeadRecipes(Plan);
569}
570
571/// Add a lane offset to the start index of \p Steps.
572static void addLaneToStartIndex(VPScalarIVStepsRecipe *Steps, unsigned Lane,
573 VPlan &Plan, VPRecipeBase *InsertPt) {
574 assert(Lane > 0 && "Zero lane adds no offset to start index");
575 Type *BaseIVTy = Steps->getOperand(N: 0)->getScalarType();
576
577 VPValue *OldStartIndex = Steps->getStartIndex();
578 VPValue *LaneOffset;
579 unsigned AddOpcode;
580 // TODO: Retrieve the flags from Steps unconditionally.
581 VPIRFlags Flags;
582 if (BaseIVTy->isFloatingPointTy()) {
583 // The start index counts upwards, so accumulate with FAdd regardless of the
584 // induction opcode; see VPScalarIVStepsRecipe.
585 LaneOffset = Plan.getOrAddLiveIn(V: ConstantFP::get(Ty: BaseIVTy, V: Lane));
586 AddOpcode = Instruction::FAdd;
587 Flags = VPIRFlags(FastMathFlags());
588 } else {
589 unsigned BaseIVBits = BaseIVTy->getScalarSizeInBits();
590 LaneOffset = Plan.getConstantInt(
591 Val: APInt(BaseIVBits, Lane, /*isSigned*/ false, /*implicitTrunc*/ true));
592 AddOpcode = Instruction::Add;
593 Flags = VPIRFlags(VPIRFlags::WrapFlagsTy(false, false));
594 }
595
596 VPValue *NewStartIndex = LaneOffset;
597 if (OldStartIndex) {
598 VPBuilder Builder(InsertPt);
599 NewStartIndex =
600 Builder.createNaryOp(Opcode: AddOpcode, Operands: {OldStartIndex, LaneOffset}, Flags);
601 }
602 Steps->setStartIndex(NewStartIndex);
603}
604
605/// Create a single-scalar clone of \p DefR (must be a VPReplicateRecipe,
606/// VPInstruction or VPScalarIVStepsRecipe) for lane \p Lane. Use \p
607/// Def2LaneDefs to look up scalar definitions for operands of \DefR.
608static VPValue *
609cloneForLane(VPlan &Plan, VPBuilder &Builder, Type *IdxTy,
610 VPSingleDefRecipe *DefR, VPLane Lane,
611 const DenseMap<VPValue *, SmallVector<VPValue *>> &Def2LaneDefs) {
612 assert((isa<VPInstruction, VPReplicateRecipe, VPScalarIVStepsRecipe>(DefR)) &&
613 "DefR must be a VPReplicateRecipe, VPInstruction or "
614 "VPScalarIVStepsRecipe");
615 VPValue *Op;
616 if (match(R: DefR, P: m_VPInstruction<VPInstruction::Unpack>(Ops: m_VPValue(V&: Op)))) {
617 auto LaneDefs = Def2LaneDefs.find(Val: Op);
618 if (LaneDefs != Def2LaneDefs.end())
619 return LaneDefs->second[Lane.getKnownLane()];
620
621 VPValue *Idx = Plan.getConstantInt(Ty: IdxTy, Val: Lane.getKnownLane());
622 return Builder.createNaryOp(Opcode: Instruction::ExtractElement, Operands: {Op, Idx});
623 }
624
625 // Collect the operands at Lane, creating extracts as needed.
626 SmallVector<VPValue *> NewOps;
627 for (VPValue *Op : DefR->operands()) {
628 // If Op is a definition that has been unrolled, directly use the clone for
629 // the corresponding lane.
630 auto LaneDefs = Def2LaneDefs.find(Val: Op);
631 if (LaneDefs != Def2LaneDefs.end()) {
632 NewOps.push_back(Elt: LaneDefs->second[Lane.getKnownLane()]);
633 continue;
634 }
635 if (Lane.getKind() == VPLane::Kind::ScalableLast) {
636 // Look through mandatory Unpack.
637 [[maybe_unused]] bool Matched =
638 match(V: Op, P: m_VPInstruction<VPInstruction::Unpack>(Ops: m_VPValue(V&: Op)));
639 assert(Matched && "original op must have been Unpack");
640 auto *ExtractPart =
641 Builder.createNaryOp(Opcode: VPInstruction::ExtractLastPart, Operands: {Op});
642 NewOps.push_back(
643 Elt: Builder.createNaryOp(Opcode: VPInstruction::ExtractLastLane, Operands: {ExtractPart}));
644 continue;
645 }
646 if (vputils::isSingleScalar(VPV: Op)) {
647 NewOps.push_back(Elt: Op);
648 continue;
649 }
650
651 VPValue *Idx = Plan.getConstantInt(Ty: IdxTy, Val: Lane.getKnownLane());
652 VPValue *Ext = Builder.createNaryOp(Opcode: Instruction::ExtractElement, Operands: {Op, Idx});
653 NewOps.push_back(Elt: Ext);
654 }
655
656 VPSingleDefRecipe *New;
657 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: DefR)) {
658 // TODO: have cloning of replicate recipes also provide the desired result
659 // coupled with setting its operands to NewOps (deriving IsSingleScalar and
660 // Mask from the operands?)
661 New = VPBuilder::createSingleScalarOp(
662 Opcode: RepR->getOpcode(), Operands: NewOps, /*Mask=*/nullptr, Flags: *RepR, Metadata: *RepR,
663 DL: RepR->getDebugLoc(), ResultTy: RepR->getScalarType(), UV: RepR->getUnderlyingInstr());
664 } else {
665 New = DefR->clone();
666 for (const auto &[Idx, Op] : enumerate(First&: NewOps)) {
667 New->setOperand(I: Idx, New: Op);
668 }
669 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: New)) {
670 // Skip lane 0: an absent start index is implicitly zero.
671 unsigned KnownLane = Lane.getKnownLane();
672 if (KnownLane != 0)
673 addLaneToStartIndex(Steps, Lane: KnownLane, Plan, InsertPt: DefR);
674 }
675 }
676 New->insertBefore(InsertPos: DefR);
677 return New;
678}
679
680/// Converts the frequency \p Freq with which a block is entered to branch
681/// weights for the branch guarding it, or nullptr if \p Freq is unknown or
682/// estimated.
683static MDNode *
684convertFrequencyToBranchWeights(std::optional<VPExecutionFrequency> Freq,
685 LLVMContext &Ctx) {
686 if (!Freq || Freq->IsEstimated)
687 return nullptr;
688 BranchProbability P = vputils::getExecutionProbability(Freq: Freq->Freq);
689
690 // Use the numerators of P and its complement as weights and reduce them via
691 // gcd to keep them small. Neither is zero, as P is neither zero nor one.
692 uint32_t Taken = P.getNumerator();
693 uint32_t NotTaken = P.getCompl().getNumerator();
694 uint32_t GCD = std::gcd(m: Taken, n: NotTaken);
695 return MDBuilder(Ctx).createBranchWeights(TrueWeight: Taken / GCD, FalseWeight: NotTaken / GCD);
696}
697
698/// Convert recipes in region blocks to operate on a single lane 0.
699/// VPReplicateRecipes are converted to single-scalar ones, branch-on-mask is
700/// converted into BranchOnCond, PredInstPhi recipes are replaced by scalar phi
701/// recipes with an additional poison operand, and extracts are created as
702/// needed.
703static void convertRecipesInRegionBlocksToSingleScalar(VPlan &Plan, Type *IdxTy,
704 VPBlockBase *Entry,
705 ElementCount VF) {
706 VPValue *Idx0 = Plan.getZero(Ty: IdxTy);
707 for (VPBlockBase *VPB : vp_depth_first_shallow(G: Entry)) {
708 for (VPRecipeBase &OldR : make_early_inc_range(Range&: cast<VPBasicBlock>(Val&: *VPB))) {
709 assert(
710 !isa<VPWidenPHIRecipe>(&OldR) &&
711 !match(&OldR,
712 m_CombineOr(
713 m_InsertElement(m_VPValue(), m_VPValue(), m_VPValue()),
714 m_ExtractElement(m_VPValue(), m_VPValue()))) &&
715 "must not contain wide phis, inserts or extracts before conversion");
716
717 VPBuilder Builder(&OldR);
718 DebugLoc OldDL = OldR.getDebugLoc();
719 // For scalar VF, operands are already scalar; no extraction needed.
720 if (!VF.isScalar()) {
721 for (const auto &[I, Op] : enumerate(First: OldR.operands())) {
722 // Skip operands that don't need extraction: values defined in the
723 // same block (already scalar), or values that are already single
724 // scalars.
725 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
726 auto *DefR = Op->getDefiningRecipe();
727 if ((isa_and_present<VPScalarIVStepsRecipe>(Val: DefR) &&
728 DefR->getParent() == VPB) ||
729 vputils::isSingleScalar(VPV: Op))
730 continue;
731
732 // Extract lane zero from values defined outside the region.
733 VPValue *Extract = Builder.createNaryOp(Opcode: Instruction::ExtractElement,
734 Operands: {Op, Idx0}, DL: OldDL);
735 OldR.setOperand(I, New: Extract);
736 }
737 }
738
739 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: &OldR)) {
740 auto *NewR = VPBuilder::createSingleScalarOp(
741 Opcode: RepR->getOpcode(), Operands: to_vector(Range: RepR->operands()), /*Mask=*/nullptr,
742 Flags: *RepR, Metadata: *RepR, DL: OldDL, ResultTy: RepR->getScalarType(),
743 UV: RepR->getUnderlyingInstr());
744 NewR->insertBefore(InsertPos: RepR);
745 RepR->replaceAllUsesWith(New: NewR);
746 RepR->eraseFromParent();
747 } else if (auto *BranchOnMask = dyn_cast<VPBranchOnMaskRecipe>(Val: &OldR)) {
748 // Turn the frequency of the predicated block into branch weights.
749 auto *BOC = Builder.createNaryOp(Opcode: VPInstruction::BranchOnCond,
750 Operands: {BranchOnMask->getOperand(N: 0)}, DL: OldDL);
751 if (MDNode *Weights = convertFrequencyToBranchWeights(
752 Freq: BranchOnMask->getExecutionFrequency(), Ctx&: Plan.getContext()))
753 BOC->setMetadata(Kind: LLVMContext::MD_prof, Node: Weights);
754 BranchOnMask->eraseFromParent();
755 } else if (auto *PredPhi = dyn_cast<VPPredInstPHIRecipe>(Val: &OldR)) {
756 VPValue *PredOp = PredPhi->getOperand(N: 0);
757 Type *PredTy = PredOp->getScalarType();
758 VPValue *Poison = Plan.getPoison(Ty: PredTy);
759 VPPhi *NewPhi = Builder.createScalarPhi(IncomingValues: {Poison, PredOp}, DL: OldDL);
760 PredPhi->replaceAllUsesWith(New: NewPhi);
761 PredPhi->eraseFromParent();
762 } else {
763 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
764 assert((isa<VPScalarIVStepsRecipe>(OldR) ||
765 (isa<VPInstruction>(OldR) &&
766 vputils::isSingleScalar(OldR.getVPSingleValue()))) &&
767 "unexpected unhandled recipe");
768 }
769 }
770 }
771}
772
773/// Update recipes in the cloned blocks rooted at \p NewEntry to match \p Lane,
774/// using the original blocks rooted at \p OldEntry as reference.
775static void processLaneForReplicateRegion(VPlan &Plan, Type *IdxTy,
776 unsigned Lane, VPBasicBlock *OldEntry,
777 VPBasicBlock *NewEntry) {
778 DenseMap<VPValue *, VPValue *> Old2NewVPValues;
779 VPValue *IdxLane = Plan.getConstantInt(Ty: IdxTy, Val: Lane);
780 for (const auto &[OldBB, NewBB] :
781 zip_equal(t: vp_depth_first_shallow(G: OldEntry),
782 u: vp_depth_first_shallow(G: NewEntry))) {
783 for (auto &&[OldR, NewR] :
784 zip_equal(t&: *cast<VPBasicBlock>(Val: OldBB), u&: *cast<VPBasicBlock>(Val: NewBB))) {
785 for (const auto &[OldV, NewV] :
786 zip_equal(t: OldR.definedValues(), u: NewR.definedValues()))
787 Old2NewVPValues[OldV] = NewV;
788
789 // Remap operands to use lane-specific values.
790 for (const auto &[I, OldOp] : enumerate(First: NewR.operands())) {
791 // Use cloned value if operand was defined in the region.
792 if (auto *NewOp = Old2NewVPValues.lookup(Val: OldOp))
793 NewR.setOperand(I, New: NewOp);
794 }
795
796 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: &NewR)) {
797 addLaneToStartIndex(Steps, Lane, Plan, InsertPt: Steps);
798 } else if (match(V: &NewR, P: m_ExtractElement(Op0: m_VPValue(), Op1: m_VPValue()))) {
799 assert(match(NewR.getOperand(1), m_ZeroInt()) &&
800 "extract indices must be zero");
801 NewR.setOperand(I: 1, New: IdxLane);
802 } else if (auto *NewPhi = dyn_cast<VPPhi>(Val: &NewR)) {
803 auto *OldPhi = cast<VPPhi>(Val: &OldR);
804 assert(vputils::onlyFirstLaneUsed(OldPhi) &&
805 "VPPhis expected to have only first lane used");
806 auto *BVUser = dyn_cast_or_null<VPInstruction>(Val: OldPhi->getSingleUser());
807 if (BVUser && match(V: BVUser, P: m_BuildVector())) {
808 assert(BVUser->getOperand(0) == OldPhi &&
809 "Unexpected first operand of build vector user");
810 BVUser->setOperand(I: Lane, New: NewPhi);
811 }
812 }
813 }
814 }
815}
816
817/// Dissolve a single replicate region by replicating its blocks for each lane
818/// of \p VF. The region is disconnected, its blocks are reparented, cloned for
819/// each lane, and reconnected in sequence.
820static void dissolveReplicateRegion(VPRegionBlock *Region, ElementCount VF,
821 VPlan &Plan, Type *IdxTy) {
822 auto *FirstLaneEntry = cast<VPBasicBlock>(Val: Region->getEntry());
823 auto *FirstLaneExiting = cast<VPBasicBlock>(Val: Region->getExiting());
824
825 // Disconnect and dissolve the region.
826 VPBlockBase *Predecessor = Region->getSinglePredecessor();
827 assert(Predecessor && "Replicate region must have a single predecessor");
828 auto *Successor = cast<VPBasicBlock>(Val: Region->getSingleSuccessor());
829 VPBlockUtils::disconnectBlocks(From: Predecessor, To: Region);
830 VPBlockUtils::disconnectBlocks(From: Region, To: Successor);
831
832 VPRegionBlock *ParentRegion = Region->getParent();
833 for (VPBlockBase *VPB : vp_depth_first_shallow(G: FirstLaneEntry))
834 VPB->setParent(ParentRegion);
835
836 // Process the original blocks for lane 0: converting their recipes to
837 // single-scalar.
838 convertRecipesInRegionBlocksToSingleScalar(Plan, IdxTy, Entry: FirstLaneEntry, VF);
839
840 // For scalar VF, just wire the blocks and return; no cloning or packing
841 // needed.
842 if (VF.isScalar()) {
843 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
844 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: Successor);
845 return;
846 }
847
848 // Create a BuildVector in successor block for every VPPhi in (first lane's)
849 // exiting block having vector uses. All their
850 // operands are initialized to poison and will be replaced when processing
851 // each clone, except for the operand of the first lane which set here.
852 // BuildVectors are recorded to be replaced later by chains of insert-element
853 // and widen phis.
854 unsigned NumLanes = VF.getFixedValue();
855 SmallVector<VPInstruction *> BuildVectors;
856 for (auto &R : FirstLaneExiting->phis()) {
857 auto *Phi = cast<VPPhi>(Val: &R);
858 if (vputils::onlyFirstLaneUsed(Def: Phi))
859 continue;
860
861 Type *ScalarTy = Phi->getScalarType();
862 VPValue *Poison = Plan.getPoison(Ty: ScalarTy);
863 SmallVector<VPValue *> BVOps(NumLanes, Poison);
864 auto *BV = new VPInstruction(VPInstruction::BuildVector, BVOps);
865 BuildVectors.push_back(Elt: BV);
866 Phi->replaceAllUsesWith(New: BV);
867 BV->setOperand(I: 0, New: Phi);
868 BV->insertBefore(BB&: *Successor, IP: Successor->getFirstNonPhi());
869 }
870
871 // Clone converted blocks for remaining lanes and process each in reverse
872 // order, connecting each lane's Exiting block to the subsequent lane's entry.
873 VPBlockBase *NextLaneEntry = Successor;
874 for (int Lane = NumLanes - 1; Lane > 0; --Lane) {
875 const auto &[CurrentLaneEntry, CurrentLaneExiting] =
876 VPBlockUtils::cloneFrom(Entry: FirstLaneEntry);
877 for (VPBlockBase *VPB : vp_depth_first_shallow(G: CurrentLaneEntry))
878 VPB->setParent(ParentRegion);
879 processLaneForReplicateRegion(Plan, IdxTy, Lane,
880 OldEntry: cast<VPBasicBlock>(Val: FirstLaneEntry),
881 NewEntry: cast<VPBasicBlock>(Val: CurrentLaneEntry));
882 VPBlockUtils::connectBlocks(From: CurrentLaneExiting, To: NextLaneEntry);
883 NextLaneEntry = CurrentLaneEntry;
884 }
885
886 // Connect Predecessor to FirstLaneEntry, and FirstLaneRegionExit to
887 // NextLaneEntry which is the second lane region entry. The latter is
888 // done last so that earlier clonings from FirstLaneEntry stop at
889 // FirstLaneExiting.
890 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
891 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: NextLaneEntry);
892
893 // Fold BuildVector fed by scalar phis into VPWidenPHIRecipes with
894 // InsertElement per lane.
895 // TODO: check if this folding should be dropped.
896 for (VPInstruction *BV : BuildVectors) {
897 assert(BV->getNumOperands() == NumLanes &&
898 "BuildVector must have one operand per lane");
899 for (const auto &[Idx, Op] : enumerate(First: BV->operands())) {
900 auto *ScalarPhi = cast<VPPhi>(Val: Op);
901 auto DL = ScalarPhi->getDebugLoc();
902 auto *PredOp = cast<VPSingleDefRecipe>(Val: ScalarPhi->getOperand(N: 1));
903 VPValue *Poison = ScalarPhi->getOperand(N: 0);
904 VPValue *PrevVal = Idx == 0 ? Poison : BV->getOperand(N: Idx - 1);
905 auto Builder = VPBuilder::getToInsertAfter(R: PredOp->getDefiningRecipe());
906 auto *Insert = Builder.createNaryOp(
907 Opcode: Instruction::InsertElement,
908 Operands: {PrevVal, PredOp, Plan.getConstantInt(BitWidth: 64, Val: Idx)}, DL);
909 Builder.setInsertPoint(ScalarPhi);
910 auto *NewPhi = Builder.createWidenPhi(IncomingValues: {PrevVal, Insert}, DL);
911 ScalarPhi->replaceAllUsesWith(New: NewPhi);
912 ScalarPhi->eraseFromParent();
913 }
914 BV->replaceAllUsesWith(New: BV->getOperand(N: NumLanes - 1));
915 BV->eraseFromParent();
916 }
917}
918
919/// Collect and dissolve all replicate regions in the vector loop, replicating
920/// their blocks and recipes for each lane of \p VF.
921static void replicateReplicateRegionsByVF(VPlan &Plan, ElementCount VF,
922 Type *IdxTy) {
923 // Collect all replicate regions before modifying the CFG.
924 SmallVector<VPRegionBlock *> ReplicateRegions;
925 for (VPRegionBlock *Region : VPBlockUtils::blocksOnly<VPRegionBlock>(
926 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()))) {
927 if (Region->isReplicator())
928 ReplicateRegions.push_back(Elt: Region);
929 }
930
931 assert((ReplicateRegions.empty() || !VF.isScalable()) &&
932 "cannot replicate across scalable VFs");
933
934 // Dissolve replicate regions by replicating their blocks for each lane.
935 // Traversing regions in reverse ensures that the successor of every region
936 // being processed is a basic-block, rather than another region.
937 for (VPRegionBlock *Region : reverse(C&: ReplicateRegions))
938 dissolveReplicateRegion(Region, VF, Plan, IdxTy);
939
940 VPlanTransforms::mergeBlocksIntoPredecessors(Plan);
941}
942
943void VPlanTransforms::replicateByVF(VPlan &Plan, ElementCount VF) {
944 Type *IdxTy = IntegerType::get(
945 C&: Plan.getScalarHeader()->getIRBasicBlock()->getContext(), NumBits: 32);
946
947 if (Plan.hasScalarVFOnly()) {
948 // When Plan is only unrolled by UF, replicating by VF amounts to dissolving
949 // replicate regions.
950 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
951 return;
952 }
953
954 // Visit all VPBBs outside the loop region and directly inside the top-level
955 // loop region.
956 auto VPBBsOutsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
957 Range: vp_depth_first_shallow(G: Plan.getEntry()));
958 auto VPBBsInsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
959 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()));
960 auto VPBBsToUnroll =
961 concat<VPBasicBlock *>(Ranges&: VPBBsOutsideLoopRegion, Ranges&: VPBBsInsideLoopRegion);
962 // A mapping of current VPValue definitions to collections of new VPValues
963 // defined per lane. Serves to hook-up potential users of current VPValue
964 // definition that are replicated-per-VF later.
965 DenseMap<VPValue *, SmallVector<VPValue *>> Def2LaneDefs;
966 // The removal of current recipes being replaced by new ones needs to be
967 // delayed after Def2LaneDefs is no longer in use.
968 SmallVector<VPSingleDefRecipe *> ToRemove;
969 for (VPBasicBlock *VPBB : VPBBsToUnroll) {
970 for (VPRecipeBase &R : make_early_inc_range(Range&: *VPBB)) {
971 if (!vputils::doesGeneratePerAllLanes(R: &R))
972 continue;
973
974 auto *DefR = cast<VPSingleDefRecipe>(Val: &R);
975 VPBuilder Builder(DefR);
976 if (DefR->user_empty()) {
977 // Create single-scalar version of DefR for all lanes.
978 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
979 cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs);
980 DefR->eraseFromParent();
981 continue;
982 }
983 /// Create single-scalar version of DefR for all lanes.
984 SmallVector<VPValue *> LaneDefs;
985 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
986 LaneDefs.push_back(
987 Elt: cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs));
988
989 Def2LaneDefs[DefR] = LaneDefs;
990 // Pack the lanes for vector users.
991 if (!vputils::onlyScalarValuesUsed(Def: DefR)) {
992 DefR->replaceUsesWithIf(
993 New: Builder.createNaryOp(Opcode: VPInstruction::BuildVector, Operands: LaneDefs),
994 ShouldReplace: [DefR](VPUser *U) { return !U->usesScalars(Op: DefR); });
995 }
996 /// Users that only demand the first lane can use the definition for lane
997 /// 0.
998 DefR->replaceUsesWithIf(New: LaneDefs[0], ShouldReplace: [DefR](VPUser *U) {
999 if (U->usesFirstLaneOnly(Op: DefR))
1000 return true;
1001 auto *VPI = dyn_cast<VPInstruction>(Val: U);
1002 return VPI && Instruction::isCast(Opcode: VPI->getOpcode());
1003 });
1004 ToRemove.push_back(Elt: DefR);
1005 }
1006 }
1007
1008 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
1009 // Replace the lane extracts created when dissolving replicate regions.
1010 for (VPSingleDefRecipe *DefR : reverse(C&: ToRemove)) {
1011 for (VPUser *U : to_vector(Range: DefR->users())) {
1012 uint64_t Lane;
1013 [[maybe_unused]] bool Match =
1014 match(U, P: m_ExtractElement(Op0: m_Specific(VPV: DefR), Op1: m_ConstantInt(C&: Lane)));
1015 assert(Match && "unexpected remaining user");
1016 auto *Ext = cast<VPInstruction>(Val: U);
1017 Ext->replaceAllUsesWith(New: Def2LaneDefs.at(Val: DefR)[Lane]);
1018 Ext->eraseFromParent();
1019 }
1020 DefR->eraseFromParent();
1021 }
1022}
1023