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 // Look through buildvector to avoid unnecessary extracts.
652 if (match(V: Op, P: m_BuildVector())) {
653 NewOps.push_back(
654 Elt: cast<VPInstruction>(Val: Op)->getOperand(N: Lane.getKnownLane()));
655 continue;
656 }
657 VPValue *Idx = Plan.getConstantInt(Ty: IdxTy, Val: Lane.getKnownLane());
658 VPValue *Ext = Builder.createNaryOp(Opcode: Instruction::ExtractElement, Operands: {Op, Idx});
659 NewOps.push_back(Elt: Ext);
660 }
661
662 VPSingleDefRecipe *New;
663 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: DefR)) {
664 // TODO: have cloning of replicate recipes also provide the desired result
665 // coupled with setting its operands to NewOps (deriving IsSingleScalar and
666 // Mask from the operands?)
667 New = VPBuilder::createSingleScalarOp(
668 Opcode: RepR->getOpcode(), Operands: NewOps, /*Mask=*/nullptr, Flags: *RepR, Metadata: *RepR,
669 DL: RepR->getDebugLoc(), ResultTy: RepR->getScalarType(), UV: RepR->getUnderlyingInstr());
670 } else {
671 New = DefR->clone();
672 for (const auto &[Idx, Op] : enumerate(First&: NewOps)) {
673 New->setOperand(I: Idx, New: Op);
674 }
675 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: New)) {
676 // Skip lane 0: an absent start index is implicitly zero.
677 unsigned KnownLane = Lane.getKnownLane();
678 if (KnownLane != 0)
679 addLaneToStartIndex(Steps, Lane: KnownLane, Plan, InsertPt: DefR);
680 }
681 }
682 New->insertBefore(InsertPos: DefR);
683 return New;
684}
685
686/// Converts the frequency \p Freq with which a block is entered to branch
687/// weights for the branch guarding it, or nullptr if \p Freq is unknown or
688/// estimated.
689static MDNode *
690convertFrequencyToBranchWeights(std::optional<VPExecutionFrequency> Freq,
691 LLVMContext &Ctx) {
692 if (!Freq || Freq->IsEstimated)
693 return nullptr;
694 BranchProbability P = vputils::getExecutionProbability(Freq: Freq->Freq);
695
696 // Use the numerators of P and its complement as weights and reduce them via
697 // gcd to keep them small. Neither is zero, as P is neither zero nor one.
698 uint32_t Taken = P.getNumerator();
699 uint32_t NotTaken = P.getCompl().getNumerator();
700 uint32_t GCD = std::gcd(m: Taken, n: NotTaken);
701 return MDBuilder(Ctx).createBranchWeights(TrueWeight: Taken / GCD, FalseWeight: NotTaken / GCD);
702}
703
704/// Convert recipes in region blocks to operate on a single lane 0.
705/// VPReplicateRecipes are converted to single-scalar ones, branch-on-mask is
706/// converted into BranchOnCond, PredInstPhi recipes are replaced by scalar phi
707/// recipes with an additional poison operand, and extracts are created as
708/// needed.
709static void convertRecipesInRegionBlocksToSingleScalar(VPlan &Plan, Type *IdxTy,
710 VPBlockBase *Entry,
711 ElementCount VF) {
712 VPValue *Idx0 = Plan.getZero(Ty: IdxTy);
713 for (VPBlockBase *VPB : vp_depth_first_shallow(G: Entry)) {
714 for (VPRecipeBase &OldR : make_early_inc_range(Range&: cast<VPBasicBlock>(Val&: *VPB))) {
715 assert(
716 !isa<VPWidenPHIRecipe>(&OldR) &&
717 !match(&OldR,
718 m_CombineOr(
719 m_InsertElement(m_VPValue(), m_VPValue(), m_VPValue()),
720 m_ExtractElement(m_VPValue(), m_VPValue()))) &&
721 "must not contain wide phis, inserts or extracts before conversion");
722
723 VPBuilder Builder(&OldR);
724 DebugLoc OldDL = OldR.getDebugLoc();
725 // For scalar VF, operands are already scalar; no extraction needed.
726 if (!VF.isScalar()) {
727 for (const auto &[I, Op] : enumerate(First: OldR.operands())) {
728 // Skip operands that don't need extraction: values defined in the
729 // same block (already scalar), or values that are already single
730 // scalars.
731 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
732 auto *DefR = Op->getDefiningRecipe();
733 if ((isa_and_present<VPScalarIVStepsRecipe>(Val: DefR) &&
734 DefR->getParent() == VPB) ||
735 vputils::isSingleScalar(VPV: Op))
736 continue;
737
738 // Extract lane zero from values defined outside the region.
739 VPValue *Extract = Builder.createNaryOp(Opcode: Instruction::ExtractElement,
740 Operands: {Op, Idx0}, DL: OldDL);
741 OldR.setOperand(I, New: Extract);
742 }
743 }
744
745 if (auto *RepR = dyn_cast<VPReplicateRecipe>(Val: &OldR)) {
746 auto *NewR = VPBuilder::createSingleScalarOp(
747 Opcode: RepR->getOpcode(), Operands: to_vector(Range: RepR->operands()), /*Mask=*/nullptr,
748 Flags: *RepR, Metadata: *RepR, DL: OldDL, ResultTy: RepR->getScalarType(),
749 UV: RepR->getUnderlyingInstr());
750 NewR->insertBefore(InsertPos: RepR);
751 RepR->replaceAllUsesWith(New: NewR);
752 RepR->eraseFromParent();
753 } else if (auto *BranchOnMask = dyn_cast<VPBranchOnMaskRecipe>(Val: &OldR)) {
754 // Turn the frequency of the predicated block into branch weights.
755 auto *BOC = Builder.createNaryOp(Opcode: VPInstruction::BranchOnCond,
756 Operands: {BranchOnMask->getOperand(N: 0)}, DL: OldDL);
757 if (MDNode *Weights = convertFrequencyToBranchWeights(
758 Freq: BranchOnMask->getExecutionFrequency(), Ctx&: Plan.getContext()))
759 BOC->setMetadata(Kind: LLVMContext::MD_prof, Node: Weights);
760 BranchOnMask->eraseFromParent();
761 } else if (auto *PredPhi = dyn_cast<VPPredInstPHIRecipe>(Val: &OldR)) {
762 VPValue *PredOp = PredPhi->getOperand(N: 0);
763 Type *PredTy = PredOp->getScalarType();
764 VPValue *Poison = Plan.getPoison(Ty: PredTy);
765 VPPhi *NewPhi = Builder.createScalarPhi(IncomingValues: {Poison, PredOp}, DL: OldDL);
766 PredPhi->replaceAllUsesWith(New: NewPhi);
767 PredPhi->eraseFromParent();
768 } else {
769 // TODO: Support isSingleScalar for VPScalarIVStepsRecipe.
770 assert((isa<VPScalarIVStepsRecipe>(OldR) ||
771 (isa<VPInstruction>(OldR) &&
772 vputils::isSingleScalar(OldR.getVPSingleValue()))) &&
773 "unexpected unhandled recipe");
774 }
775 }
776 }
777}
778
779/// Update recipes in the cloned blocks rooted at \p NewEntry to match \p Lane,
780/// using the original blocks rooted at \p OldEntry as reference.
781static void processLaneForReplicateRegion(VPlan &Plan, Type *IdxTy,
782 unsigned Lane, VPBasicBlock *OldEntry,
783 VPBasicBlock *NewEntry) {
784 DenseMap<VPValue *, VPValue *> Old2NewVPValues;
785 VPValue *IdxLane = Plan.getConstantInt(Ty: IdxTy, Val: Lane);
786 for (const auto &[OldBB, NewBB] :
787 zip_equal(t: vp_depth_first_shallow(G: OldEntry),
788 u: vp_depth_first_shallow(G: NewEntry))) {
789 for (auto &&[OldR, NewR] :
790 zip_equal(t&: *cast<VPBasicBlock>(Val: OldBB), u&: *cast<VPBasicBlock>(Val: NewBB))) {
791 for (const auto &[OldV, NewV] :
792 zip_equal(t: OldR.definedValues(), u: NewR.definedValues()))
793 Old2NewVPValues[OldV] = NewV;
794
795 // Remap operands to use lane-specific values.
796 for (const auto &[I, OldOp] : enumerate(First: NewR.operands())) {
797 // Use cloned value if operand was defined in the region.
798 if (auto *NewOp = Old2NewVPValues.lookup(Val: OldOp))
799 NewR.setOperand(I, New: NewOp);
800 }
801
802 if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Val: &NewR)) {
803 addLaneToStartIndex(Steps, Lane, Plan, InsertPt: Steps);
804 } else if (match(V: &NewR, P: m_ExtractElement(Op0: m_VPValue(), Op1: m_VPValue()))) {
805 assert(match(NewR.getOperand(1), m_ZeroInt()) &&
806 "extract indices must be zero");
807 NewR.setOperand(I: 1, New: IdxLane);
808 } else if (auto *NewPhi = dyn_cast<VPPhi>(Val: &NewR)) {
809 auto *OldPhi = cast<VPPhi>(Val: &OldR);
810 assert(vputils::onlyFirstLaneUsed(OldPhi) &&
811 "VPPhis expected to have only first lane used");
812 auto *BVUser = dyn_cast_or_null<VPInstruction>(Val: OldPhi->getSingleUser());
813 if (BVUser && match(V: BVUser, P: m_CombineOr(Ps: m_BuildVector(),
814 Ps: m_BuildStructVector()))) {
815 assert(BVUser->getOperand(0) == OldPhi &&
816 "Unexpected first operand of build vector user");
817 BVUser->setOperand(I: Lane, New: NewPhi);
818 }
819 }
820 }
821 }
822}
823
824/// Dissolve a single replicate region by replicating its blocks for each lane
825/// of \p VF. The region is disconnected, its blocks are reparented, cloned for
826/// each lane, and reconnected in sequence.
827static void dissolveReplicateRegion(VPRegionBlock *Region, ElementCount VF,
828 VPlan &Plan, Type *IdxTy) {
829 auto *FirstLaneEntry = cast<VPBasicBlock>(Val: Region->getEntry());
830 auto *FirstLaneExiting = cast<VPBasicBlock>(Val: Region->getExiting());
831
832 // Disconnect and dissolve the region.
833 VPBlockBase *Predecessor = Region->getSinglePredecessor();
834 assert(Predecessor && "Replicate region must have a single predecessor");
835 auto *Successor = cast<VPBasicBlock>(Val: Region->getSingleSuccessor());
836 VPBlockUtils::disconnectBlocks(From: Predecessor, To: Region);
837 VPBlockUtils::disconnectBlocks(From: Region, To: Successor);
838
839 VPRegionBlock *ParentRegion = Region->getParent();
840 for (VPBlockBase *VPB : vp_depth_first_shallow(G: FirstLaneEntry))
841 VPB->setParent(ParentRegion);
842
843 // Process the original blocks for lane 0: converting their recipes to
844 // single-scalar.
845 convertRecipesInRegionBlocksToSingleScalar(Plan, IdxTy, Entry: FirstLaneEntry, VF);
846
847 // For scalar VF, just wire the blocks and return; no cloning or packing
848 // needed.
849 if (VF.isScalar()) {
850 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
851 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: Successor);
852 return;
853 }
854
855 // Create a BuildVector or BuildStructVector in successor block for every
856 // VPPhi in (first lane's) exiting block having vector uses. All their
857 // operands are initialized to poison and will be replaced when processing
858 // each clone, except for the operand of the first lane which set here.
859 // BuildVectors are recorded to be replaced later by chains of insert-element
860 // and widen phi's.
861 unsigned NumLanes = VF.getFixedValue();
862 SmallVector<VPInstruction *> BuildVectors;
863 for (auto &R : FirstLaneExiting->phis()) {
864 auto *Phi = cast<VPPhi>(Val: &R);
865 if (vputils::onlyFirstLaneUsed(Def: Phi))
866 continue;
867
868 Type *ScalarTy = Phi->getScalarType();
869 bool IsStruct = isa<StructType>(Val: ScalarTy);
870 VPValue *Poison = Plan.getPoison(Ty: ScalarTy);
871 SmallVector<VPValue *> BVOps(NumLanes, Poison);
872 auto *BV = new VPInstruction(IsStruct ? VPInstruction::BuildStructVector
873 : VPInstruction::BuildVector,
874 BVOps);
875 if (!IsStruct)
876 BuildVectors.push_back(Elt: BV);
877 Phi->replaceAllUsesWith(New: BV);
878 BV->setOperand(I: 0, New: Phi);
879 BV->insertBefore(BB&: *Successor, IP: Successor->getFirstNonPhi());
880 }
881
882 // Clone converted blocks for remaining lanes and process each in reverse
883 // order, connecting each lane's Exiting block to the subsequent lane's entry.
884 VPBlockBase *NextLaneEntry = Successor;
885 for (int Lane = NumLanes - 1; Lane > 0; --Lane) {
886 const auto &[CurrentLaneEntry, CurrentLaneExiting] =
887 VPBlockUtils::cloneFrom(Entry: FirstLaneEntry);
888 for (VPBlockBase *VPB : vp_depth_first_shallow(G: CurrentLaneEntry))
889 VPB->setParent(ParentRegion);
890 processLaneForReplicateRegion(Plan, IdxTy, Lane,
891 OldEntry: cast<VPBasicBlock>(Val: FirstLaneEntry),
892 NewEntry: cast<VPBasicBlock>(Val: CurrentLaneEntry));
893 VPBlockUtils::connectBlocks(From: CurrentLaneExiting, To: NextLaneEntry);
894 NextLaneEntry = CurrentLaneEntry;
895 }
896
897 // Connect Predecessor to FirstLaneEntry, and FirstLaneRegionExit to
898 // NextLaneEntry which is the second lane region entry. The latter is
899 // done last so that earlier clonings from FirstLaneEntry stop at
900 // FirstLaneExiting.
901 VPBlockUtils::connectBlocks(From: Predecessor, To: FirstLaneEntry);
902 VPBlockUtils::connectBlocks(From: FirstLaneExiting, To: NextLaneEntry);
903
904 // Fold BuildVector fed by scalar phis into VPWidenPHIRecipes with
905 // InsertElement per lane.
906 // TODO: check if this folding should be dropped.
907 for (VPInstruction *BV : BuildVectors) {
908 assert(BV->getNumOperands() == NumLanes &&
909 "BuildVector must have one operand per lane");
910 for (const auto &[Idx, Op] : enumerate(First: BV->operands())) {
911 auto *ScalarPhi = cast<VPPhi>(Val: Op);
912 auto DL = ScalarPhi->getDebugLoc();
913 auto *PredOp = cast<VPSingleDefRecipe>(Val: ScalarPhi->getOperand(N: 1));
914 VPValue *Poison = ScalarPhi->getOperand(N: 0);
915 VPValue *PrevVal = Idx == 0 ? Poison : BV->getOperand(N: Idx - 1);
916 auto Builder = VPBuilder::getToInsertAfter(R: PredOp->getDefiningRecipe());
917 auto *Insert = Builder.createNaryOp(
918 Opcode: Instruction::InsertElement,
919 Operands: {PrevVal, PredOp, Plan.getConstantInt(BitWidth: 64, Val: Idx)}, DL);
920 Builder.setInsertPoint(ScalarPhi);
921 auto *NewPhi = Builder.createWidenPhi(IncomingValues: {PrevVal, Insert}, DL);
922 ScalarPhi->replaceAllUsesWith(New: NewPhi);
923 ScalarPhi->eraseFromParent();
924 }
925 BV->replaceAllUsesWith(New: BV->getOperand(N: NumLanes - 1));
926 BV->eraseFromParent();
927 }
928}
929
930/// Collect and dissolve all replicate regions in the vector loop, replicating
931/// their blocks and recipes for each lane of \p VF.
932static void replicateReplicateRegionsByVF(VPlan &Plan, ElementCount VF,
933 Type *IdxTy) {
934 // Collect all replicate regions before modifying the CFG.
935 SmallVector<VPRegionBlock *> ReplicateRegions;
936 for (VPRegionBlock *Region : VPBlockUtils::blocksOnly<VPRegionBlock>(
937 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()))) {
938 if (Region->isReplicator())
939 ReplicateRegions.push_back(Elt: Region);
940 }
941
942 assert((ReplicateRegions.empty() || !VF.isScalable()) &&
943 "cannot replicate across scalable VFs");
944
945 // Dissolve replicate regions by replicating their blocks for each lane.
946 // Traversing regions in reverse ensures that the successor of every region
947 // being processed is a basic-block, rather than another region.
948 for (VPRegionBlock *Region : reverse(C&: ReplicateRegions))
949 dissolveReplicateRegion(Region, VF, Plan, IdxTy);
950
951 VPlanTransforms::mergeBlocksIntoPredecessors(Plan);
952}
953
954void VPlanTransforms::replicateByVF(VPlan &Plan, ElementCount VF) {
955 Type *IdxTy = IntegerType::get(
956 C&: Plan.getScalarHeader()->getIRBasicBlock()->getContext(), NumBits: 32);
957
958 if (Plan.hasScalarVFOnly()) {
959 // When Plan is only unrolled by UF, replicating by VF amounts to dissolving
960 // replicate regions.
961 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
962 return;
963 }
964
965 // Visit all VPBBs outside the loop region and directly inside the top-level
966 // loop region.
967 auto VPBBsOutsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
968 Range: vp_depth_first_shallow(G: Plan.getEntry()));
969 auto VPBBsInsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
970 Range: vp_depth_first_shallow(G: Plan.getVectorLoopRegion()->getEntry()));
971 auto VPBBsToUnroll =
972 concat<VPBasicBlock *>(Ranges&: VPBBsOutsideLoopRegion, Ranges&: VPBBsInsideLoopRegion);
973 // A mapping of current VPValue definitions to collections of new VPValues
974 // defined per lane. Serves to hook-up potential users of current VPValue
975 // definition that are replicated-per-VF later.
976 DenseMap<VPValue *, SmallVector<VPValue *>> Def2LaneDefs;
977 // The removal of current recipes being replaced by new ones needs to be
978 // delayed after Def2LaneDefs is no longer in use.
979 SmallVector<VPRecipeBase *> ToRemove;
980 for (VPBasicBlock *VPBB : VPBBsToUnroll) {
981 for (VPRecipeBase &R : make_early_inc_range(Range&: *VPBB)) {
982 if (!vputils::doesGeneratePerAllLanes(R: &R))
983 continue;
984
985 auto *DefR = cast<VPSingleDefRecipe>(Val: &R);
986 VPBuilder Builder(DefR);
987 if (DefR->user_empty()) {
988 // Create single-scalar version of DefR for all lanes.
989 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
990 cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs);
991 DefR->eraseFromParent();
992 continue;
993 }
994 /// Create single-scalar version of DefR for all lanes.
995 SmallVector<VPValue *> LaneDefs;
996 for (unsigned I = 0; I != VF.getKnownMinValue(); ++I)
997 LaneDefs.push_back(
998 Elt: cloneForLane(Plan, Builder, IdxTy, DefR, Lane: VPLane(I), Def2LaneDefs));
999
1000 Def2LaneDefs[DefR] = LaneDefs;
1001 /// Users that only demand the first lane can use the definition for lane
1002 /// 0.
1003 DefR->replaceUsesWithIf(New: LaneDefs[0], ShouldReplace: [DefR](VPUser &U) {
1004 if (U.usesFirstLaneOnly(Op: DefR))
1005 return true;
1006 auto *VPI = dyn_cast<VPInstruction>(Val: &U);
1007 return VPI && Instruction::isCast(Opcode: VPI->getOpcode());
1008 });
1009
1010 // Update each build vector user that currently has DefR as its only
1011 // operand, to have all LaneDefs as its operands.
1012 for (VPUser *U : to_vector(Range: DefR->users())) {
1013 auto *VPI = dyn_cast<VPInstruction>(Val: U);
1014 if (!VPI || (VPI->getOpcode() != VPInstruction::BuildVector &&
1015 VPI->getOpcode() != VPInstruction::BuildStructVector))
1016 continue;
1017 assert(VPI->getNumOperands() == 1 &&
1018 "Build(Struct)Vector must have a single operand before "
1019 "replicating by VF");
1020 VPI->setOperand(I: 0, New: LaneDefs[0]);
1021 for (VPValue *LaneDef : drop_begin(RangeOrContainer&: LaneDefs))
1022 VPI->addOperand(Op: LaneDef);
1023 }
1024 ToRemove.push_back(Elt: DefR);
1025 }
1026 }
1027 for (auto *R : reverse(C&: ToRemove))
1028 R->eraseFromParent();
1029
1030 replicateReplicateRegionsByVF(Plan, VF, IdxTy);
1031}
1032