-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[VPlan] Expand VPWidenIntOrFpInductionRecipe into separate recipes #118638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 32 commits
e72140a
6fc4a7c
e7f5a4e
31bdc7c
42dc912
6839647
6c659ca
1cd6c81
dcc6640
ca81015
8b77af4
5ad4cc1
d183c91
79b9700
d3d85f6
8f94610
dff84ec
5457030
68b6b66
8257a57
0f8b4f6
7fc4859
61bd641
ec5fe59
466ed14
b315afb
993ba23
894bde0
8037a19
ddca9b9
27c724e
b83af78
55deb1c
7cf85b9
4f3acf0
e8d64a4
f34b569
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -943,6 +943,7 @@ bool VPInstruction::onlyFirstLaneUsed(const VPValue *Op) const { | |
| case VPInstruction::CanonicalIVIncrementForPart: | ||
| case VPInstruction::BranchOnCount: | ||
| case VPInstruction::BranchOnCond: | ||
| case VPInstruction::Broadcast: | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was needed since we're now using VPInstruction::Broadcasts for arbitrary VPValues |
||
| case VPInstruction::ReductionStartVector: | ||
| return true; | ||
| case VPInstruction::PtrAdd: | ||
|
|
@@ -1068,15 +1069,14 @@ void VPInstruction::print(raw_ostream &O, const Twine &Indent, | |
|
|
||
| void VPInstructionWithType::execute(VPTransformState &State) { | ||
| State.setDebugLocFrom(getDebugLoc()); | ||
| switch (getOpcode()) { | ||
| case Instruction::ZExt: | ||
| case Instruction::Trunc: { | ||
| if (isScalarCast()) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needed because one of the recipes expanded to is Instruction::UIToFP. Happy to split this off to an NFC if wanted. |
||
| Value *Op = State.get(getOperand(0), VPLane(0)); | ||
| Value *Cast = State.Builder.CreateCast(Instruction::CastOps(getOpcode()), | ||
| Op, ResultTy); | ||
| State.set(this, Cast, VPLane(0)); | ||
| break; | ||
| return; | ||
| } | ||
| switch (getOpcode()) { | ||
| case VPInstruction::StepVector: { | ||
| Value *StepVector = | ||
| State.Builder.CreateStepVector(VectorType::get(ResultTy, State.VF)); | ||
|
|
@@ -1956,149 +1956,13 @@ InstructionCost VPHeaderPHIRecipe::computeCost(ElementCount VF, | |
| return Ctx.TTI.getCFInstrCost(Instruction::PHI, Ctx.CostKind); | ||
| } | ||
|
|
||
| /// This function adds | ||
| /// (0 * Step, 1 * Step, 2 * Step, ...) | ||
| /// to each vector element of Val. | ||
| /// \p Opcode is relevant for FP induction variable. | ||
| /// \p InitVec is an integer step vector from 0 with a step of 1. | ||
| static Value *getStepVector(Value *Val, Value *Step, Value *InitVec, | ||
| Instruction::BinaryOps BinOp, ElementCount VF, | ||
| IRBuilderBase &Builder) { | ||
| assert(VF.isVector() && "only vector VFs are supported"); | ||
|
|
||
| // Create and check the types. | ||
| auto *ValVTy = cast<VectorType>(Val->getType()); | ||
| ElementCount VLen = ValVTy->getElementCount(); | ||
|
|
||
| Type *STy = Val->getType()->getScalarType(); | ||
| assert((STy->isIntegerTy() || STy->isFloatingPointTy()) && | ||
| "Induction Step must be an integer or FP"); | ||
| assert(Step->getType() == STy && "Step has wrong type"); | ||
|
|
||
| if (STy->isIntegerTy()) { | ||
| Step = Builder.CreateVectorSplat(VLen, Step); | ||
| assert(Step->getType() == Val->getType() && "Invalid step vec"); | ||
| // FIXME: The newly created binary instructions should contain nsw/nuw | ||
| // flags, which can be found from the original scalar operations. | ||
| Step = Builder.CreateMul(InitVec, Step); | ||
| return Builder.CreateAdd(Val, Step, "induction"); | ||
| } | ||
|
|
||
| // Floating point induction. | ||
| assert((BinOp == Instruction::FAdd || BinOp == Instruction::FSub) && | ||
| "Binary Opcode should be specified for FP induction"); | ||
| InitVec = Builder.CreateUIToFP(InitVec, ValVTy); | ||
|
|
||
| Step = Builder.CreateVectorSplat(VLen, Step); | ||
| Value *MulOp = Builder.CreateFMul(InitVec, Step); | ||
| return Builder.CreateBinOp(BinOp, Val, MulOp, "induction"); | ||
| } | ||
|
|
||
| /// A helper function that returns an integer or floating-point constant with | ||
| /// value C. | ||
| static Constant *getSignedIntOrFpConstant(Type *Ty, int64_t C) { | ||
| return Ty->isIntegerTy() ? ConstantInt::getSigned(Ty, C) | ||
| : ConstantFP::get(Ty, C); | ||
| } | ||
|
|
||
| void VPWidenIntOrFpInductionRecipe::execute(VPTransformState &State) { | ||
| assert(!State.Lane && "Int or FP induction being replicated."); | ||
|
|
||
| Value *Start = getStartValue()->getLiveInIRValue(); | ||
| const InductionDescriptor &ID = getInductionDescriptor(); | ||
| TruncInst *Trunc = getTruncInst(); | ||
| IRBuilderBase &Builder = State.Builder; | ||
| assert(getPHINode()->getType() == ID.getStartValue()->getType() && | ||
| "Types must match"); | ||
| assert(State.VF.isVector() && "must have vector VF"); | ||
|
|
||
| // The value from the original loop to which we are mapping the new induction | ||
| // variable. | ||
| Instruction *EntryVal = Trunc ? cast<Instruction>(Trunc) : getPHINode(); | ||
|
|
||
| // Fast-math-flags propagate from the original induction instruction. | ||
| IRBuilder<>::FastMathFlagGuard FMFG(Builder); | ||
| if (isa_and_present<FPMathOperator>(ID.getInductionBinOp())) | ||
| Builder.setFastMathFlags(ID.getInductionBinOp()->getFastMathFlags()); | ||
|
|
||
| // Now do the actual transformations, and start with fetching the step value. | ||
| Value *Step = State.get(getStepValue(), VPLane(0)); | ||
|
|
||
| assert((isa<PHINode, TruncInst>(EntryVal)) && | ||
| "Expected either an induction phi-node or a truncate of it!"); | ||
|
|
||
| // Construct the initial value of the vector IV in the vector loop preheader | ||
| auto CurrIP = Builder.saveIP(); | ||
| BasicBlock *VectorPH = | ||
| State.CFG.VPBB2IRBB.at(getParent()->getCFGPredecessor(0)); | ||
| Builder.SetInsertPoint(VectorPH->getTerminator()); | ||
| if (isa<TruncInst>(EntryVal)) { | ||
| assert(Start->getType()->isIntegerTy() && | ||
| "Truncation requires an integer type"); | ||
| auto *TruncType = cast<IntegerType>(EntryVal->getType()); | ||
| Step = Builder.CreateTrunc(Step, TruncType); | ||
| Start = Builder.CreateCast(Instruction::Trunc, Start, TruncType); | ||
| } | ||
|
|
||
| Value *SplatStart = Builder.CreateVectorSplat(State.VF, Start); | ||
| Value *SteppedStart = | ||
| ::getStepVector(SplatStart, Step, State.get(getStepVector()), | ||
| ID.getInductionOpcode(), State.VF, State.Builder); | ||
|
|
||
| // We create vector phi nodes for both integer and floating-point induction | ||
| // variables. Here, we determine the kind of arithmetic we will perform. | ||
| Instruction::BinaryOps AddOp; | ||
| Instruction::BinaryOps MulOp; | ||
| if (Step->getType()->isIntegerTy()) { | ||
| AddOp = Instruction::Add; | ||
| MulOp = Instruction::Mul; | ||
| } else { | ||
| AddOp = ID.getInductionOpcode(); | ||
| MulOp = Instruction::FMul; | ||
| } | ||
|
|
||
| Value *SplatVF; | ||
| if (VPValue *SplatVFOperand = getSplatVFValue()) { | ||
| // The recipe has been unrolled. In that case, fetch the splat value for the | ||
| // induction increment. | ||
| SplatVF = State.get(SplatVFOperand); | ||
| } else { | ||
| // Multiply the vectorization factor by the step using integer or | ||
| // floating-point arithmetic as appropriate. | ||
| Type *StepType = Step->getType(); | ||
| Value *RuntimeVF = State.get(getVFValue(), VPLane(0)); | ||
| if (Step->getType()->isFloatingPointTy()) | ||
| RuntimeVF = Builder.CreateUIToFP(RuntimeVF, StepType); | ||
| else | ||
| RuntimeVF = Builder.CreateZExtOrTrunc(RuntimeVF, StepType); | ||
| Value *Mul = Builder.CreateBinOp(MulOp, Step, RuntimeVF); | ||
|
|
||
| // Create a vector splat to use in the induction update. | ||
| SplatVF = Builder.CreateVectorSplat(State.VF, Mul); | ||
| } | ||
|
|
||
| Builder.restoreIP(CurrIP); | ||
|
|
||
| // We may need to add the step a number of times, depending on the unroll | ||
| // factor. The last of those goes into the PHI. | ||
| PHINode *VecInd = PHINode::Create(SteppedStart->getType(), 2, "vec.ind"); | ||
| VecInd->insertBefore(State.CFG.PrevBB->getFirstInsertionPt()); | ||
| VecInd->setDebugLoc(getDebugLoc()); | ||
| State.set(this, VecInd); | ||
|
|
||
| Instruction *LastInduction = cast<Instruction>( | ||
| Builder.CreateBinOp(AddOp, VecInd, SplatVF, "vec.ind.next")); | ||
| LastInduction->setDebugLoc(getDebugLoc()); | ||
|
|
||
| VecInd->addIncoming(SteppedStart, VectorPH); | ||
| // Add induction update using an incorrect block temporarily. The phi node | ||
| // will be fixed after VPlan execution. Note that at this point the latch | ||
| // block cannot be used, as it does not exist yet. | ||
| // TODO: Model increment value in VPlan, by turning the recipe into a | ||
| // multi-def and a subclass of VPHeaderPHIRecipe. | ||
|
||
| VecInd->addIncoming(LastInduction, VectorPH); | ||
| } | ||
|
|
||
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent, | ||
| VPSlotTracker &SlotTracker) const { | ||
|
|
@@ -3863,12 +3727,14 @@ void VPReductionPHIRecipe::print(raw_ostream &O, const Twine &Indent, | |
| #endif | ||
|
|
||
| void VPWidenPHIRecipe::execute(VPTransformState &State) { | ||
| assert(EnableVPlanNativePath && | ||
| "Non-native vplans are not expected to have VPWidenPHIRecipes."); | ||
|
|
||
| Value *Op0 = State.get(getOperand(0)); | ||
| Type *VecTy = Op0->getType(); | ||
| Value *VecPhi = State.Builder.CreatePHI(VecTy, 2, Name); | ||
| Instruction *VecPhi = State.Builder.CreatePHI(VecTy, 2, Name); | ||
| // Manually move it with the other PHIs in case PHI recipes above this one | ||
| // also inserted non-phi instructions. | ||
| // TODO: Remove once VPWidenPointerInductionRecipe is also expanded in | ||
| // convertToConcreteRecipes. | ||
| VecPhi->moveBefore(State.Builder.GetInsertBlock()->getFirstNonPHIIt()); | ||
| State.set(this, VecPhi); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed because we're now using VPWidenPHI on the non-vplan-native path. Happy to split this off into an NFC as well if wanted