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, P: m_FirstActiveLane(Op0: m_VPValue(V&: Op1))) ||
433 match(V: &R, P: m_LastActiveLane(Op0: m_VPValue(V&: Op1))) ||
434 match(V: &R, P: m_ComputeReductionResult(Op0: m_VPValue(V&: Op1)))) {
435 auto *VPI = cast<VPInstruction>(Val: &R);
436 addUniformForAllParts(R: VPI);
437 for (unsigned Part = 1; Part != UF; ++Part)
438 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
439 continue;
440 }
441 VPValue *Op0;
442 if (match(V: &R, P: m_ExtractLane(Op0: m_VPValue(V&: Op0), Op1: m_VPValue(V&: Op1)))) {
443 auto *VPI = cast<VPInstruction>(Val: &R);
444 addUniformForAllParts(R: VPI);
445 for (unsigned Part = 1; Part != UF; ++Part)
446 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
447 continue;
448 }
449
450 VPValue *Op2;
451 if (match(V: &R, P: m_ExtractLastActive(Op0: m_VPValue(), Op1: m_VPValue(V&: Op1),
452 Op2: m_VPValue(V&: Op2)))) {
453 auto *VPI = cast<VPInstruction>(Val: &R);
454 addUniformForAllParts(R: VPI);
455 for (unsigned Part = 1; Part != UF; ++Part) {
456 VPI->addOperand(Op: getValueForPart(V: Op1, Part));
457 VPI->addOperand(Op: getValueForPart(V: Op2, Part));
458 }
459 continue;
460 }
461
462 if (Plan.hasScalarVFOnly()) {
463 if (match(V: &R, P: m_ExtractLastPart(Op0: m_VPValue(V&: Op0))) ||
464 match(V: &R, P: m_ExtractPenultimateElement(Op0: m_VPValue(V&: Op0)))) {
465 auto *I = cast<VPInstruction>(Val: &R);
466 bool IsPenultimatePart =
467 I->getOpcode() == VPInstruction::ExtractPenultimateElement;
468 unsigned PartIdx = IsPenultimatePart ? UF - 2 : UF - 1;
469 // For scalar VF, directly use the scalar part value.
470 I->replaceAllUsesWith(New: getValueForPart(V: Op0, Part: PartIdx));
471 continue;
472 }
473 }
474 // For vector VF, the penultimate element is always extracted from the last part.
475 if (match(V: &R, P: m_ExtractLastLaneOfLastPart(Op0: m_VPValue(V&: Op0))) ||
476 match(V: &R, P: m_ExtractPenultimateElement(Op0: m_VPValue(V&: Op0)))) {
477 addUniformForAllParts(R: cast<VPSingleDefRecipe>(Val: &R));
478 R.setOperand(I: 0, New: getValueForPart(V: Op0, Part: UF - 1));
479 continue;
480 }
481
482 if (match(V: &R,
483 P: m_WideActiveLaneMask(Op0: m_VPValue(), Op1: m_VPValue(), Op2: m_VPValue()))) {
484 auto *ALM = cast<VPInstruction>(Val: &R);
485 ALM->setOperand(I: 2, New: getConstantInt(Part: UF));
486 continue;
487 }
488
489 auto *SingleDef = dyn_cast<VPSingleDefRecipe>(Val: &R);
490 if (SingleDef && vputils::isUniformAcrossVFsAndUFs(V: SingleDef)) {
491 addUniformForAllParts(R: SingleDef);
492 continue;
493 }
494
495 if (auto *H = dyn_cast<VPHeaderPHIRecipe>(Val: &R)) {
496 unrollHeaderPHIByUF(R: H, InsertPtForPhi);
497 continue;
498 }
499
500 unrollRecipeByUF(R);
501 }
502}
503
504void VPlanTransforms::unrollByUF(VPlan &Plan, unsigned UF) {
505 assert(UF > 0 && "Unroll factor must be positive");
506 Plan.setUF(UF);
507 llvm::scope_exit Cleanup([&Plan, UF]() {
508 auto Iter = vp_depth_first_deep(G: Plan.getEntry());
509 // Remove recipes that are redundant after unrolling.
510 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Range&: Iter)) {
511 for (VPInstruction &VPI :
512 make_early_inc_range(Range: make_isa_range<VPInstruction>(Range&: *VPBB))) {
513 if (VPI.getOpcode() == VPInstruction::CanonicalIVIncrementForPart &&
514 VPI.getOperand(N: 1) == &Plan.getVF()) {
515 VPI.replaceAllUsesWith(New: VPI.getOperand(N: 0));
516 VPI.eraseFromParent();
517 }
518 }
519 }
520
521 Type *TCTy = Plan.getTripCount()->getScalarType();
522 Plan.getUF().replaceAllUsesWith(New: Plan.getConstantInt(Ty: TCTy, Val: UF));
523 });
524 if (UF == 1) {
525 return;
526 }
527
528 UnrollState Unroller(Plan, UF);
529
530 // Iterate over all blocks in the plan starting from Entry, and unroll
531 // recipes inside them. This includes the vector preheader and middle blocks,
532 // which may set up or post-process per-part values.
533 ReversePostOrderTraversal<VPBlockShallowTraversalWrapper<VPBlockBase *>> RPOT(
534 Plan.getEntry());
535 for (VPBlockBase *VPB : RPOT)
536 Unroller.unrollBlock(VPB);
537
538 unsigned Part = 1;
539 // Remap operands of cloned header phis to update backedge values. The header
540 // phis cloned during unrolling are just after the header phi for part 0.
541 // Reset Part to 1 when reaching the first (part 0) recipe of a block.
542 for (VPRecipeBase &H :
543 Plan.getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
544 // The second operand of Fixed Order Recurrence phi's, feeding the spliced
545 // value across the backedge, needs to remap to the last part of the spliced
546 // value.
547 if (isa<VPFirstOrderRecurrencePHIRecipe>(Val: &H)) {
548 Unroller.remapOperand(R: &H, OpIdx: 1, Part: UF - 1);
549 continue;
550 }
551 if (Unroller.contains(VPV: H.getVPSingleValue())) {
552 Part = 1;
553 continue;
554 }
555 Unroller.remapOperands(R: &H, Part);
556 Part++;
557 }
558
559 VPlanTransforms::removeDeadRecipes(Plan);
560}
561
562/// Add a lane offset to the start index of \p Steps.
563static void addLaneToStartIndex(VPScalarIVStepsRecipe *Steps, unsigned Lane,
564 VPlan &Plan, VPRecipeBase *InsertPt) {
565 assert(Lane > 0 && "Zero lane adds no offset to start index");
566 Type *BaseIVTy = Steps->getOperand(N: 0)->getScalarType();
567
568 VPValue *OldStartIndex = Steps->getStartIndex();
569 VPValue *LaneOffset;
570 unsigned AddOpcode;
571 // TODO: Retrieve the flags from Steps unconditionally.
572 VPIRFlags Flags;
573 if (BaseIVTy->isFloatingPointTy()) {
574 // The start index counts upwards, so accumulate with FAdd regardless of the
575 // induction opcode; see VPScalarIVStepsRecipe.
576 LaneOffset = Plan.getOrAddLiveIn(V: ConstantFP::get(Ty: BaseIVTy, V: Lane));
577 AddOpcode = Instruction::FAdd;
578 Flags = VPIRFlags(FastMathFlags());
579 } else {
580 unsigned BaseIVBits = BaseIVTy->getScalarSizeInBits();
581 LaneOffset = Plan.getConstantInt(
582 Val: APInt(BaseIVBits, Lane, /*isSigned*/ false, /*implicitTrunc*/ true));
583 AddOpcode = Instruction::Add;
584 Flags = VPIRFlags(VPIRFlags::WrapFlagsTy(false, false));
585 }
586
587 VPValue *NewStartIndex = LaneOffset;
588 if (OldStartIndex) {
589 VPBuilder Builder(InsertPt);
590 NewStartIndex =
591 Builder.createNaryOp(Opcode: AddOpcode, Operands: {OldStartIndex, LaneOffset}, Flags);
592 }
593 Steps->setStartIndex(NewStartIndex);
594}
595
596/// Create a single-scalar clone of \p DefR (must be a VPReplicateRecipe,
597/// VPInstruction or VPScalarIVStepsRecipe) for lane \p Lane. Use \p
598/// Def2LaneDefs to look up scalar definitions for operands of \DefR.
599static VPValue *
600cloneForLane(VPlan &Plan, VPBuilder &Builder, Type *IdxTy,
601 VPSingleDefRecipe *DefR, VPLane Lane,
602 const DenseMap<VPValue *, SmallVector<VPValue *>> &Def2LaneDefs) {
603 assert((isa<VPInstruction, VPReplicateRecipe, VPScalarIVStepsRecipe>(DefR)) &&
604 "DefR must be a VPReplicateRecipe, VPInstruction or "
605 "VPScalarIVStepsRecipe");
606 VPValue *Op;
607 if (match(R: DefR, P: m_VPInstruction<VPInstruction::Unpack>(Ops: m_VPValue(V&: Op)))) {
608 auto LaneDefs = Def2LaneDefs.find(Val: Op);
609 if (LaneDefs != Def2LaneDefs.end())
610 return LaneDefs->second[Lane.getKnownLane()];
611
612 VPValue *Idx = Plan.getConstantInt(Ty: IdxTy, Val: Lane.getKnownLane());
613 return Builder.createNaryOp(Opcode: Instruction::ExtractElement, Operands: {Op, Idx});
614 }
615
616 // Collect the operands at Lane, creating extracts as needed.
617 SmallVector<VPValue *> NewOps;
618 for (VPValue *Op : DefR->operands()) {
619 // If Op is a definition that has been unrolled, directly use the clone for
620 // the corresponding lane.
621 auto LaneDefs = Def2LaneDefs.find(Val: Op);
622 if (LaneDefs != Def2LaneDefs.end()) {
623 NewOps.push_back(Elt: LaneDefs->second[Lane.getKnownLane()]);
624 continue;
625 }
626 if (Lane.getKind() == VPLane::Kind::ScalableLast) {
627 // Look through mandatory Unpack.
628 [[maybe_unused]] bool Matched =
629 match(V: Op, P: m_VPInstruction<VPInstruction::Unpack>(Ops: m_VPValue(V&: Op)));
630 assert(Matched && "original op must have been Unpack");
631 auto *ExtractPart =
632 Builder.createNaryOp(Opcode: VPInstruction::ExtractLastPart, Operands: {Op});
633 NewOps.push_back(
634 Elt: Builder.createNaryOp(Opcode: VPInstruction::ExtractLastLane, Operands: {ExtractPart}));
635 continue;
636 }
637 if (vputils::isSingleScalar(VPV: Op)) {
638 NewOps.push_back(Elt: Op);
639 continue;
640 }
641
642 // Look through buildvector to avoid unnecessary extracts.
643 if (match(V: Op, P: m_BuildVector())) {
644 NewOps.push_back(
645 Elt: cast<VPInstruction>(Val: Op)->getOperand(N: Lane.getKnownLane()));
646 continue;
647 }
648 VPValue *Idx = Plan.getConstantInt(Ty: IdxTy, Val: Lane.getKnownLane());
649 VPValue *Ext = Builder.createNaryOp(Opcode: Instruction::ExtractElement, Operands: {Op, Idx});
650 NewOps.push_back(Elt: Ext);
651 }
652
653 VPSingleDefRecipe *New;
654 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: DefR)) {
655 // TODO: have cloning of replicate recipes also provide the desired result
656 // coupled with setting its operands to NewOps (deriving IsSingleScalar and
657 // Mask from the operands?)
658 New = VPBuilder::createSingleScalarOp(
659 Opcode: RepR->getOpcode(), Operands: NewOps, /*Mask=*/nullptr, Flags: *RepR, Metadata: *RepR,
660 DL: RepR->getDebugLoc(), UV: RepR->getUnderlyingInstr());
661 } else {
662 New = DefR->clone();
663 for (const auto &[Idx, Op] : enumerate(First&: NewOps)) {
664 New->setOperand(I: Idx, New: Op);
665 }
666 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: New)) {
667 // Skip lane 0: an absent start index is implicitly zero.
668 unsigned KnownLane = Lane.getKnownLane();
669 if (KnownLane != 0)
670 addLaneToStartIndex(Steps, Lane: KnownLane, Plan, InsertPt: DefR);
671 }
672 }
673 New->insertBefore(InsertPos: DefR);
674 return New;
675}
676
677/// Converts the frequency \p Freq with which a block is entered to branch
678/// weights for the branch guarding it, or nullptr if \p Freq is unknown or
679/// estimated.
680static MDNode *
681convertFrequencyToBranchWeights(std::optional<VPExecutionFrequency> Freq,
682 LLVMContext &Ctx) {
683 if (!Freq || Freq->IsEstimated)
684 return nullptr;
685 BranchProbability P = vputils::getExecutionProbability(Freq: Freq->Freq);
686
687 // Use the numerators of P and its complement as weights and reduce them via
688 // gcd to keep them small. Neither is zero, as P is neither zero nor one.
689 uint32_t Taken = P.getNumerator();
690 uint32_t NotTaken = P.getCompl().getNumerator();
691 uint32_t GCD = std::gcd(m: Taken, n: NotTaken);
692 return MDBuilder(Ctx).createBranchWeights(TrueWeight: Taken / GCD, FalseWeight: NotTaken / GCD);
693}
694
695/// Convert recipes in region blocks to operate on a single lane 0.
696/// VPReplicateRecipes are converted to single-scalar ones, branch-on-mask is
697/// converted into BranchOnCond, PredInstPhi recipes are replaced by scalar phi
698/// recipes with an additional poison operand, and extracts are created as
699/// needed.
700static void convertRecipesInRegionBlocksToSingleScalar(VPlan &Plan, Type *IdxTy,
701 VPBlockBase *Entry,
702 ElementCount VF) {
703 VPValue *Idx0 = Plan.getZero(Ty: IdxTy);
704 for (VPBlockBase *VPB : vp_depth_first_shallow(G: Entry)) {
705 for (VPRecipeBase &OldR : make_early_inc_range(Range&: cast<VPBasicBlock>(Val&: *VPB))) {
706 assert(
707 !isa<VPWidenPHIRecipe>(&OldR) &&
708 !match(&OldR,
709 m_CombineOr(
710 m_InsertElement(m_VPValue(), m_VPValue(), m_VPValue()),
711 m_ExtractElement(m_VPValue(), m_VPValue()))) &&
712 "must not contain wide phis, inserts or extracts before conversion");
713
714 VPBuilder Builder(&OldR);
715 DebugLoc OldDL = OldR.getDebugLoc();
716 // For scalar VF, operands are already scalar; no extraction needed.
717 if (!VF.isScalar()) {
718 for (const auto &[I, Op] : enumerate(First: OldR.operands())) {
719 // Skip operands that don't need extraction: values defined in the
720 // same block (already scalar), or values that are already single
721 // scalars.
722 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
723 auto *DefR = Op->getDefiningRecipe();
724 if ((isa_and_present<VPScalarIVStepsRecipe>(Val: DefR) &&
725 DefR->getParent() == VPB) ||
726 vputils::isSingleScalar(VPV: Op))
727 continue;
728
729 // Extract lane zero from values defined outside the region.
730 VPValue *Extract = Builder.createNaryOp(Opcode: Instruction::ExtractElement,
731 Operands: {Op, Idx0}, DL: OldDL);
732 OldR.setOperand(I, New: Extract);
733 }
734 }
735
736 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: &OldR)) {
737 auto *NewR = VPBuilder::createSingleScalarOp(
738 Opcode: RepR->getOpcode(), Operands: to_vector(Range: RepR->operands()), /*Mask=*/nullptr,
739 Flags: *RepR, Metadata: *RepR, DL: OldDL, UV: RepR->getUnderlyingInstr());
740 NewR->insertBefore(InsertPos: RepR);
741 RepR->replaceAllUsesWith(New: NewR);
742 RepR->eraseFromParent();
743 } else if (auto *BranchOnMask = dyn_cast<VPBranchOnMaskRecipe>(Val: &OldR)) {
744 // Turn the frequency of the predicated block into branch weights.
745 auto *BOC = Builder.createNaryOp(Opcode: VPInstruction::BranchOnCond,
746 Operands: {BranchOnMask->getOperand(N: 0)}, DL: OldDL);
747 if (MDNode *Weights = convertFrequencyToBranchWeights(
748 Freq: BranchOnMask->getExecutionFrequency(), Ctx&: Plan.getContext()))
749 BOC->setMetadata(Kind: LLVMContext::MD_prof, Node: Weights);
750 BranchOnMask->eraseFromParent();
751 } else if (auto *PredPhi = dyn_cast<VPPredInstPHIRecipe>(Val: &OldR)) {
752 VPValue *PredOp = PredPhi->getOperand(N: 0);
753 Type *PredTy = PredOp->getScalarType();
754 VPValue *Poison = Plan.getPoison(Ty: PredTy);
755 VPPhi *NewPhi = Builder.createScalarPhi(IncomingValues: {Poison, PredOp}, DL: OldDL);
756 PredPhi->replaceAllUsesWith(New: NewPhi);
757 PredPhi->eraseFromParent();
758 } else {
759 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
760 assert((isa<VPScalarIVStepsRecipe>(OldR) ||
761 (isa<VPInstruction>(OldR) &&
762 vputils::isSingleScalar(OldR.getVPSingleValue()))) &&
763 "unexpected unhandled recipe");
764 }
765 }
766 }
767}
768
769/// Update recipes in the cloned blocks rooted at \p NewEntry to match \p Lane,
770/// using the original blocks rooted at \p OldEntry as reference.
771static void processLaneForReplicateRegion(VPlan &Plan, Type *IdxTy,
772 unsigned Lane, VPBasicBlock *OldEntry,
773 VPBasicBlock *NewEntry) {
774 DenseMap<VPValue *, VPValue *> Old2NewVPValues;
775 VPValue *IdxLane = Plan.getConstantInt(Ty: IdxTy, Val: Lane);
776 for (const auto &[OldBB, NewBB] :
777 zip_equal(t: vp_depth_first_shallow(G: OldEntry),
778 u: vp_depth_first_shallow(G: NewEntry))) {
779 for (auto &&[OldR, NewR] :
780 zip_equal(t&: *cast<VPBasicBlock>(Val: OldBB), u&: *cast<VPBasicBlock>(Val: NewBB))) {
781 for (const auto &[OldV, NewV] :
782 zip_equal(t: OldR.definedValues(), u: NewR.definedValues()))
783 Old2NewVPValues[OldV] = NewV;
784
785 // Remap operands to use lane-specific values.
786 for (const auto &[I, OldOp] : enumerate(First: NewR.operands())) {
787 // Use cloned value if operand was defined in the region.
788 if (auto *NewOp = Old2NewVPValues.lookup(Val: OldOp))
789 NewR.setOperand(I, New: NewOp);
790 }
791
792 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: &NewR)) {
793 addLaneToStartIndex(Steps, Lane, Plan, InsertPt: Steps);
794 } else if (match(V: &NewR, P: m_ExtractElement(Op0: m_VPValue(), Op1: m_VPValue()))) {
795 assert(match(NewR.getOperand(1), m_ZeroInt()) &&
796 "extract indices must be zero");
797 NewR.setOperand(I: 1, New: IdxLane);
798 } else if (auto *NewPhi = dyn_cast<VPPhi>(Val: &NewR)) {
799 auto *OldPhi = cast<VPPhi>(Val: &OldR);
800 assert(vputils::onlyFirstLaneUsed(OldPhi) &&
801 "VPPhis expected to have only first lane used");
802 auto *BVUser = dyn_cast_or_null<VPInstruction>(Val: OldPhi->getSingleUser());
803 if (BVUser && match(V: BVUser, P: m_CombineOr(Ps: m_BuildVector(),
804 Ps: m_BuildStructVector()))) {
805 assert(BVUser->getOperand(0) == OldPhi &&
806 "Unexpected first operand of build vector user");
807 BVUser->setOperand(I: Lane, New: NewPhi);
808 }
809 }
810 }
811 }
812}
813
814/// Dissolve a single replicate region by replicating its blocks for each lane
815/// of \p VF. The region is disconnected, its blocks are reparented, cloned for
816/// each lane, and reconnected in sequence.
817static void dissolveReplicateRegion(VPRegionBlock *Region, ElementCount VF,
818 VPlan &Plan, Type *IdxTy) {
819 auto *FirstLaneEntry = cast<VPBasicBlock>(Val: Region->getEntry());
820 auto *FirstLaneExiting = cast<VPBasicBlock>(Val: Region->getExiting());
821
822 // Disconnect and dissolve the region.
823 VPBlockBase *Predecessor = Region->getSinglePredecessor();
824 assert(Predecessor && "Replicate region must have a single predecessor");
825 auto *Successor = cast<VPBasicBlock>(Val: Region->getSingleSuccessor());
826 VPBlockUtils::disconnectBlocks(From: Predecessor, To: Region);
827 VPBlockUtils::disconnectBlocks(From: Region, To: Successor);
828
829 VPRegionBlock *ParentRegion = Region->getParent();
830 for (VPBlockBase *VPB : vp_depth_first_shallow(G: FirstLaneEntry))
831 VPB->setParent(ParentRegion);
832
833 // Process the original blocks for lane 0: converting their recipes to
834 // single-scalar.
835 convertRecipesInRegionBlocksToSingleScalar(Plan, IdxTy, Entry: FirstLaneEntry, VF);
836
837 // For scalar VF, just wire the blocks and return; no cloning or packing
838 // needed.
839 if (VF.isScalar()) {
840 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
841 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: Successor);
842 return;
843 }
844
845 // Create a BuildVector or BuildStructVector in successor block for every
846 // VPPhi in (first lane's) exiting block having vector uses. All their
847 // operands are initialized to poison and will be replaced when processing
848 // each clone, except for the operand of the first lane which set here.
849 // BuildVectors are recorded to be replaced later by chains of insert-element
850 // and widen phi's.
851 unsigned NumLanes = VF.getFixedValue();
852 SmallVector<VPInstruction *> BuildVectors;
853 for (auto &R : FirstLaneExiting->phis()) {
854 auto *Phi = cast<VPPhi>(Val: &R);
855 if (vputils::onlyFirstLaneUsed(Def: Phi))
856 continue;
857
858 Type *ScalarTy = Phi->getScalarType();
859 bool IsStruct = isa<StructType>(Val: ScalarTy);
860 VPValue *Poison = Plan.getPoison(Ty: ScalarTy);
861 SmallVector<VPValue *> BVOps(NumLanes, Poison);
862 auto *BV = new VPInstruction(IsStruct ? VPInstruction::BuildStructVector
863 : VPInstruction::BuildVector,
864 BVOps);
865 if (!IsStruct)
866 BuildVectors.push_back(Elt: BV);
867 Phi->replaceAllUsesWith(New: BV);
868 BV->setOperand(I: 0, New: Phi);
869 BV->insertBefore(BB&: *Successor, IP: Successor->getFirstNonPhi());
870 }
871
872 // Clone converted blocks for remaining lanes and process each in reverse
873 // order, connecting each lane's Exiting block to the subsequent lane's entry.
874 VPBlockBase *NextLaneEntry = Successor;
875 for (int Lane = NumLanes - 1; Lane > 0; --Lane) {
876 const auto &[CurrentLaneEntry, CurrentLaneExiting] =
877 VPBlockUtils::cloneFrom(Entry: FirstLaneEntry);
878 for (VPBlockBase *VPB : vp_depth_first_shallow(G: CurrentLaneEntry))
879 VPB->setParent(ParentRegion);
880 processLaneForReplicateRegion(Plan, IdxTy, Lane,
881 OldEntry: cast<VPBasicBlock>(Val: FirstLaneEntry),
882 NewEntry: cast<VPBasicBlock>(Val: CurrentLaneEntry));
883 VPBlockUtils::connectBlocks(From: CurrentLaneExiting, To: NextLaneEntry);
884 NextLaneEntry = CurrentLaneEntry;
885 }
886
887 // Connect Predecessor to FirstLaneEntry, and FirstLaneRegionExit to
888 // NextLaneEntry which is the second lane region entry. The latter is
889 // done last so that earlier clonings from FirstLaneEntry stop at
890 // FirstLaneExiting.
891 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
892 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: NextLaneEntry);
893
894 // Fold BuildVector fed by scalar phis into VPWidenPHIRecipes with
895 // InsertElement per lane.
896 // TODO: check if this folding should be dropped.
897 for (VPInstruction *BV : BuildVectors) {
898 assert(BV->getNumOperands() == NumLanes &&
899 "BuildVector must have one operand per lane");
900 for (const auto &[Idx, Op] : enumerate(First: BV->operands())) {
901 auto *ScalarPhi = cast<VPPhi>(Val: Op);
902 auto DL = ScalarPhi->getDebugLoc();
903 auto *PredOp = cast<VPSingleDefRecipe>(Val: ScalarPhi->getOperand(N: 1));
904 VPValue *Poison = ScalarPhi->getOperand(N: 0);
905 VPValue *PrevVal = Idx == 0 ? Poison : BV->getOperand(N: Idx - 1);
906 auto Builder = VPBuilder::getToInsertAfter(R: PredOp->getDefiningRecipe());
907 auto *Insert = Builder.createNaryOp(
908 Opcode: Instruction::InsertElement,
909 Operands: {PrevVal, PredOp, Plan.getConstantInt(BitWidth: 64, Val: Idx)}, DL);
910 Builder.setInsertPoint(ScalarPhi);
911 auto *NewPhi = Builder.createWidenPhi(IncomingValues: {PrevVal, Insert}, DL);
912 ScalarPhi->replaceAllUsesWith(New: NewPhi);
913 ScalarPhi->eraseFromParent();
914 }
915 BV->replaceAllUsesWith(New: BV->getOperand(N: NumLanes - 1));
916 BV->eraseFromParent();
917 }
918}
919
920/// Collect and dissolve all replicate regions in the vector loop, replicating
921/// their blocks and recipes for each lane of \p VF.
922static void replicateReplicateRegionsByVF(VPlan &Plan, ElementCount VF,
923 Type *IdxTy) {
924 // Collect all replicate regions before modifying the CFG.
925 SmallVector<VPRegionBlock *> ReplicateRegions;
926 for (VPRegionBlock *Region : VPBlockUtils::blocksOnly<VPRegionBlock>(
927 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()))) {
928 if (Region->isReplicator())
929 ReplicateRegions.push_back(Elt: Region);
930 }
931
932 assert((ReplicateRegions.empty() || !VF.isScalable()) &&
933 "cannot replicate across scalable VFs");
934
935 // Dissolve replicate regions by replicating their blocks for each lane.
936 // Traversing regions in reverse ensures that the successor of every region
937 // being processed is a basic-block, rather than another region.
938 for (VPRegionBlock *Region : reverse(C&: ReplicateRegions))
939 dissolveReplicateRegion(Region, VF, Plan, IdxTy);
940
941 VPlanTransforms::mergeBlocksIntoPredecessors(Plan);
942}
943
944void VPlanTransforms::replicateByVF(VPlan &Plan, ElementCount VF) {
945 Type *IdxTy = IntegerType::get(
946 C&: Plan.getScalarHeader()->getIRBasicBlock()->getContext(), NumBits: 32);
947
948 if (Plan.hasScalarVFOnly()) {
949 // When Plan is only unrolled by UF, replicating by VF amounts to dissolving
950 // replicate regions.
951 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
952 return;
953 }
954
955 // Visit all VPBBs outside the loop region and directly inside the top-level
956 // loop region.
957 auto VPBBsOutsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
958 Range: vp_depth_first_shallow(G: Plan.getEntry()));
959 auto VPBBsInsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
960 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()));
961 auto VPBBsToUnroll =
962 concat<VPBasicBlock *>(Ranges&: VPBBsOutsideLoopRegion, Ranges&: VPBBsInsideLoopRegion);
963 // A mapping of current VPValue definitions to collections of new VPValues
964 // defined per lane. Serves to hook-up potential users of current VPValue
965 // definition that are replicated-per-VF later.
966 DenseMap<VPValue *, SmallVector<VPValue *>> Def2LaneDefs;
967 // The removal of current recipes being replaced by new ones needs to be
968 // delayed after Def2LaneDefs is no longer in use.
969 SmallVector<VPRecipeBase *> ToRemove;
970 for (VPBasicBlock *VPBB : VPBBsToUnroll) {
971 for (VPRecipeBase &R : make_early_inc_range(Range&: *VPBB)) {
972 if (!vputils::doesGeneratePerAllLanes(R: &R))
973 continue;
974
975 auto *DefR = cast<VPSingleDefRecipe>(Val: &R);
976 VPBuilder Builder(DefR);
977 if (DefR->user_empty()) {
978 // Create single-scalar version of DefR for all lanes.
979 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
980 cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs);
981 DefR->eraseFromParent();
982 continue;
983 }
984 /// Create single-scalar version of DefR for all lanes.
985 SmallVector<VPValue *> LaneDefs;
986 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
987 LaneDefs.push_back(
988 Elt: cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs));
989
990 Def2LaneDefs[DefR] = LaneDefs;
991 /// Users that only demand the first lane can use the definition for lane
992 /// 0.
993 DefR->replaceUsesWithIf(New: LaneDefs[0], ShouldReplace: [DefR](VPUser &U, unsigned) {
994 if (U.usesFirstLaneOnly(Op: DefR))
995 return true;
996 auto *VPI = dyn_cast<VPInstruction>(Val: &U);
997 return VPI && Instruction::isCast(Opcode: VPI->getOpcode());
998 });
999
1000 // Update each build vector user that currently has DefR as its only
1001 // operand, to have all LaneDefs as its operands.
1002 for (VPUser *U : to_vector(Range: DefR->users())) {
1003 auto *VPI = dyn_cast<VPInstruction>(Val: U);
1004 if (!VPI || (VPI->getOpcode() != VPInstruction::BuildVector &&
1005 VPI->getOpcode() != VPInstruction::BuildStructVector))
1006 continue;
1007 assert(VPI->getNumOperands() == 1 &&
1008 "Build(Struct)Vector must have a single operand before "
1009 "replicating by VF");
1010 VPI->setOperand(I: 0, New: LaneDefs[0]);
1011 for (VPValue *LaneDef : drop_begin(RangeOrContainer&: LaneDefs))
1012 VPI->addOperand(Op: LaneDef);
1013 }
1014 ToRemove.push_back(Elt: DefR);
1015 }
1016 }
1017 for (auto *R : reverse(C&: ToRemove))
1018 R->eraseFromParent();
1019
1020 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
1021}
1022