summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
AgeCommit message (Collapse)Author
2025-07-03[VPlan] Remove redundant debug location setting in ↵Mel Chen
VPInterleaveRecipe::execute. nfc (#146670) Remove it since we already set debug loc in VPBasicBlock::executeRecipes.
2025-07-03[VPlan] Early assert for unsupported interleaved access features. nfc (#146669)Mel Chen
2025-07-02[LV] Add support for partial reductions without a binary op (#133922)David Sherwood
Consider IR such as this: for.body: %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ] %accum = phi i32 [ 0, %entry ], [ %add, %for.body ] %gep.a = getelementptr i8, ptr %a, i64 %iv %load.a = load i8, ptr %gep.a, align 1 %ext.a = zext i8 %load.a to i32 %add = add i32 %ext.a, %accum %iv.next = add i64 %iv, 1 %exitcond.not = icmp eq i64 %iv.next, 1025 br i1 %exitcond.not, label %for.exit, label %for.body Conceptually we can vectorise this using partial reductions too, although the current loop vectoriser implementation requires the accumulation of a multiply. For AArch64 this is easily done with a udot or sdot with an identity operand, i.e. a vector of (i16 1). In order to do this I had to teach getScaledReductions that the accumulated value may come from a unary op, hence there is only one extension to consider. Similarly, I updated the vplan and AArch64 TTI cost model to understand the possible unary op. --------- Co-authored-by: Matt Devereau <matthew.devereau@arm.com>
2025-07-02[VPlan] Emit VPVectorEndPointerRecipe for reverse interleave pointer ↵Mel Chen
adjustment (#144864) A reverse interleave access is essentially composed of multiple load/store operations with same negative stride, and their addresses are based on the last lane address of member 0 in the interleaved group. Currently, we already have VPVectorEndPointerRecipe for computing the last lane address of consecutive reverse memory accesses. This patch extends VPVectorEndPointerRecipe to support constant stride and extracts the reverse interleave group address adjustment from VPInterleaveRecipe::execute, replacing it with a VPVectorEndPointerRecipe. The final goal is to support interleaved accesses with EVL tail folding. Given that VPInterleaveRecipe is large and tightly coupled — combining both load and store, and embedding operations like reverse pointer adjustion (GEP), widen load/store, deinterleave/interleave, and reversal — breaking it down into smaller, dedicated recipes may allow VPlanTransforms::tryAddExplicitVectorLength to lower them into EVL-aware form more effectively. One foreseeable challenge is that VPlanTransforms::convertToConcreteRecipes currently runs after tryAddExplicitVectorLength, so decomposing VPInterleaveRecipe will likely need to happen earlier in the pipeline to be effective.
2025-07-02VPlanRecipes.cpp - fix "'llvm::VPExpressionRecipe::computeCost': not all ↵Simon Pilgrim
control paths return a value" MSVC warning. NFC.
2025-07-01[VPlan] Add VPExpressionRecipe, replacing extended reduction recipes. (#144281)Florian Hahn
This patch adds a new recipe to combine multiple recipes into an 'expression' recipe, which should be considered as single entity for cost-modeling and transforms. The recipe needs to be 'decomposed', i.e. replaced by its individual recipes before execute. This subsumes VPExtendedReductionRecipe and VPMulAccumulateReductionRecipe and should make it easier to extend to include more types of bundled patterns, like e.g. extends folded into loads or various arithmetic instructions, if supported by the target. It allows avoiding re-creating the original recipes when converting to concrete recipes, together with removing the need to record various information. The current version of the patch still retains the original printing matching VPExtendedReductionRecipe and VPMulAccumulateReductionRecipe, but this specialized print could be replaced with printing the bundled recipes directly. PR: https://github.com/llvm/llvm-project/pull/144281
2025-06-30[VPlan] Truncate/Extend ComputeReductionResult at construction (NFC). (#141860)Florian Hahn
Instead of looking up the narrower reduction type via getRecurrenceType we can generate the needed extend directly at constructiond re-use the truncated value from the loop. PR: https://github.com/llvm/llvm-project/pull/141860
2025-06-29[LV] Add support for cmp reductions with decreasing IVs. (#140451)Florian Hahn
Similar to FindLastIV, add FindFirstIVSMin to support select (icmp(), x, y) reductions where one of x or y is a decreasing induction, producing a SMin reduction. It uses signed max as sentinel value. PR: https://github.com/llvm/llvm-project/pull/140451
2025-06-27[VPlan] Handle FirstActiveLane when unrolling. (#145394)Florian Hahn
Currently FirstActiveLane is not handled correctly during unrolling. This is currently causing mis-compiles when vectorizing early-exit loops with interleaving forced. This patch updates handling of FirstActiveLane to be analogous to computing final reduction results: during unrolling, the created copies for its original operand are added as additional operands, and FirstActiveLane will always produce the index of the first active lane across all unrolled iterations. Note that some of the generated code is still incorrect, as we also need to handle ExtractElement with FirstActiveLane operands. I will share patches for those soon as well. PR: https://github.com/llvm/llvm-project/pull/145394
2025-06-26[VPlan] Handle AnyOf when unrolling. (#145340)Florian Hahn
Currently AnyOf is not handled correctly during unrolling. This is currently causing mis-compiles when vectorizing early-exit loops with interleaving forced (even though selectInterleaveCount will currently only pick IC = 1, unless forced by the user). This patch updates handling of AnyOf to be analogous to computing final reduction results: during unrolling, the created copies for its original operand are added as additional operands, and AnyOf will always produce the reduced value across all unrolled iterations. Note that the generated code is still incorrect, as we also need to handle FirstActiveLane and ExtractElement with FirstActiveLane operands. I will share patches for those soon as well. PR: https://github.com/llvm/llvm-project/pull/145340
2025-06-26[VPlan] Unroll VPReplicateRecipe by VF. (#142433)Florian Hahn
Explicitly unroll VPReplicateRecipes outside replicate regions by VF, replacing them by VF single-scalar recipes. Extracts for operands are added as needed and the scalar results are combined to a vector using a new BuildVector VPInstruction. It also adds a few folds to simplify unnecessary extracts/BuildVectors. It also adds a BuildStructVector opcode for handling of calls that have struct return types. VPReplicateRecipe in replicate regions can will be unrolled as follow up, turing non-single-scalar VPReplicateRecipes into 'abstract', i.e. not executable. PR: https://github.com/llvm/llvm-project/pull/142433
2025-06-24[VPlan] Add VPInst::getNumOperandsForOpcode, use to verify in ctor (NFC) ↵Florian Hahn
(#142284) Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments. PR: https://github.com/llvm/llvm-project/pull/142284
2025-06-23[LV] Extend FindLastIV to unsigned case (#141752)Ramkumar Ramachandra
Split the FindLastIV RecurKind into SMax and UMax variants, depending on the reduction op produced.
2025-06-21[VPlan] Update packScalarIntoVector to take and return wide value (NFC)Florian Hahn
Make the function more flexible in preparation for new users.
2025-06-21[CostModel] Add a DstTy to getShuffleCost (#141634)David Green
A shuffle will take two input vectors and a mask, to produce a new vector of size <MaskElts x SrcEltTy>. Historically it has been assumed that the SrcTy and the DstTy are the same for getShuffleCost, with that being relaxed in recent years. If the Tp passed to getShuffleCost is the SrcTy, then the DstTy can be calculated from the Mask elts and the src elt size, but the Mask is not always provided and the Tp is not reliably always the SrcTy. This has led to situations notably in the SLP vectorizer but also in the generic cost routines where assumption about how vectors will be legalized are built into the generic cost routines - for example whether they will widen or promote, with the cost modelling assuming they will widen but the default lowering to promote for integer vectors. This patch attempts to start improving that - it originally tried to alter more of the cost model but that too quickly became too many changes at once, so this patch just plumbs in a DstTy to getShuffleCost so that DstTy and SrcTy can be reliably distinguished. The callers of getShuffleCost have been updated to try and include a DstTy that is more accurate. Otherwise it tries to be fairly non-functional, keeping the SrcTy used as the primary type used in shuffle cost routines, only using DstTy where it was in the past (for InsertSubVector for example). Some asserts have been added that help to check for consistent values when a Mask and a DstTy are provided to getShuffleCost. Some of them took a while to get right, and some non-mask calls might still be incorrect. Hopefully this will provide a useful base to build more shuffles that alter size.
2025-06-21[VPlan] Use EMIT-SCALAR when printing casts.Florian Hahn
Split off EMIT-SCALAR printing changes from already approved https://github.com/llvm/llvm-project/pull/140623. Currently all casts are single scalars, this brings printing in line with printing for other VPInstructions.
2025-06-20[VPlan] Pass NumUnrolledElems as operand to VPWidenPointerInductionRecipe. ↵Luke Lau
NFC (#119859) Similarly to VPWidenIntOrFpInductionRecipe, if we want to support it in EVL tail folding we need to increment the induction by EVL steps instead of VF*UF steps, but currently this is hard-wired in VPWidenPointerInductionRecipe. This adds an operand for the number of elements unrolled and plumbs it through, so that we can swap it out in VPlanTransforms::tryAddExplicitVectorLength further down the line.
2025-06-19[llvm] Migrate away from ArrayRef(std::nullopt) (NFC) (#144967)Kazu Hirata
ArrayRef has a constructor that accepts std::nullopt. This constructor dates back to the days when we still had llvm::Optional. Since the use of std::nullopt outside the context of std::optional is kind of abuse and not intuitive to new comers, I would like to move away from the constructor and eventually remove it. This patch takes care of the llvm side of the migration.
2025-06-19[TTI] Plumb CostKind through getPartialReductionCost (#144953)Philip Reames
Purely for the sake of being idiomatic with other TTI costing routines, no direct motivation beyond that.
2025-06-18[LoopVectorize] Vectorize fixed-order recurrence with vscale x 1. (#142772)Mel Chen
When the fixed-order recurrence phi is live-out from the loop, the vectorizer uses VPInstruction::ExtractPenultimateElement to extract the penultimate element from the recurrence vector. However, this is not feasible when the VF is vscale x 1, since vscale could be 1, making the vector contain only one element. This patch changes the behavior for vscale x 1 by extracting the last element from the vector produced by splicing the recurrence phi and the previous value. This ensures we can still determine the correct live-out value of the recurrence phi.
2025-06-17[VPlan] Expand VPWidenIntOrFpInductionRecipe into separate recipes (#118638)Luke Lau
The motivation of this PR is to make #115274 easier to implement, and should allow us to add EVL support by just passing EVL to the VF operand. The current difficulty with widening IVs with EVL is that VPWidenIntOrFpInductionRecipe generates its own backedge value. Since it's a VPHeaderPHIRecipe the VF operand must be in the preheader, which means we can't use the EVL since it's defined in the loop body. The gist in this PR is to take the approach in #114305 and expand VPWidenIntOrFpInductionRecipe into several recipes for the initial value, phi and backedge value just before execution. I.e. this example: ``` vector.ph: Successor(s): vector loop <x1> vector loop: { vector.body: WIDEN-INDUCTION %i = phi %start, %step, %vf ... EMIT branch-on-count ... No successors } ``` gets expanded to: ``` vector.ph: ... vp<%induction.start> = ... vp<%induction.increment> = ... Successor(s): vector loop <x1> vector loop: { vector.body: ir<%i> = WIDEN-PHI vp<%induction.start>, vp<%vec.ind.next> ... vp<%vec.ind.next> = add ir<%i>, vp<%induction.increment> EMIT branch-on-count ... No successors } ``` This allows us to a value defined in the loop in the backedge value, and also means we can just reuse the existing backedge fixups in VPlan::execute without having to specially handle it ourselves. After this #115274 should just become a matter of setting the VF operand to EVL (and building the increment step in the loop body, not the preheader).
2025-06-15[VPlan] Mark VPFirstOrderRecurrencePHI as not reading/writing memory.Florian Hahn
First-order recurrence phis don't have side-effects and don't read or write memory. Mark them as such.
2025-06-14Reapply "[VPlan] Set branch weight metadata on middle term in VPlan (NFC) ↵Florian Hahn
(#143035)" This reverts commit 0604dc199c019b23746f4a54885ba0c75569cdae. The recommitted version addresses post-commit comments and adjusts the place the branch weights are added. It now runs before VPlans are optimized for VF and UF, which may remove the vector loop region, causing a crash trying to get the middle block after that. Test case added in 72f99b75afc12bb. Original message: Manage branch weights for the BranchOnCond in the middle block in VPlan. This requires updating VPInstruction to inherit from VPIRMetadata, which in general makes sense as there are a number of opcodes that could take metadata. There are other branches (part of the skeleton) that also need branch weights adding. PR: https://github.com/llvm/llvm-project/pull/143035
2025-06-14[VPlan] Address post-commit comments for f68848015f62.Florian Hahn
Assign sentinel value to named variable to clarify naming and update comments. Addresses post-commit comments from https://github.com/llvm/llvm-project/pull/142291.
2025-06-13[VPlan] Manage Sentinel value for FindLastIV in VPlan. (#142291)Florian Hahn
Similar to modeling the start value as operand, also model the sentinel value as operand explicitly. This makes all require information for code-gen available directly in VPlan. PR: https://github.com/llvm/llvm-project/pull/142291
2025-06-13[LV] Use getFixedValue instead of getKnownMinValue when appropriate (#143526)David Sherwood
There are many places in VPlan and LoopVectorize where we use getKnownMinValue to discover the number of elements in a vector. Where we expect the vector to have a fixed length, I have used the stronger getFixedValue call. I believe this is clearer and adds extra protection in the form of an assert in getFixedValue that the vector is not scalable. While looking at VPFirstOrderRecurrencePHIRecipe::computeCost I also took the liberty of simplifying the code. In theory I believe this patch should be NFC, but I'm reluctant to add that to the title in case we're just missing tests for some of the VPlan changes. I built and ran the LLVM test suite when targeting neoverse-v1 and it seemed ok.
2025-06-12[LV] Simplify creation of vp.load/vp.store/vp.reduce intrinsics (#143804)Philip Reames
The use of VectorBuilder here was simply obscuring what was actually going on. For vp.load and vp.store, the resulting code is significantly more idiomatic. For the vp.reduce cases, we remove several layers of indirection, including passing parameters via implicit state on the builder. In both cases, the code is significantly easier to follow.
2025-06-12Revert "[VPlan] Set branch weight metadata on middle term in VPlan (NFC) ↵Hans Wennborg
(#143035)" This caused assertion failures: llvm/lib/Transforms/Vectorize/VPlan.h:4021: llvm::VPBasicBlock* llvm::VPlan::getMiddleBlock(): Assertion `LoopRegion && "cannot call the function after vector loop region has been removed"' failed. See comment on the PR. > Manage branch weights for the BranchOnCond in the middle block in VPlan. > This requires updating VPInstruction to inherit from VPIRMetadata, which > in general makes sense as there are a number of opcodes that could take > metadata. > > There are other branches (part of the skeleton) that also need branch > weights adding. > > PR: https://github.com/llvm/llvm-project/pull/143035 This reverts commit db8d34db26e9ea92c08d6e813eca9cce40c48478.
2025-06-12[LV] Support scalable interleave groups for factors 3,5,6 and 7 (#141865)Luke Lau
Currently the loop vectorizer can only vectorize interleave groups for power-of-2 factors at scalable VFs by recursively interleaving [de]interleave2 intrinsics. However after https://github.com/llvm/llvm-project/pull/124825 and #139893, we now have [de]interleave intrinsics for all factors up to 8, which is enough to support all types of segmented loads and stores on RISC-V. Now that the interleaved access pass has been taught to lower these in #139373 and #141512, this patch teaches the loop vectorizer to emit these intrinsics for factors up to 8, which enables scalable vectorization for non-power-of-2 factors. As far as I'm aware, no in-tree target will vectorize a scalable interelave group above factor 8 because the maximum interleave factor is capped at 4 on AArch64 and 8 on RISC-V, and the `-max-interleave-group-factor` CLI option defaults to 8, so the recursive [de]interleaving code has been removed for now. Factors of 3 with scalable VFs are also turned off in AArch64 since there's no lowering for [de]interleave3 just yet either.
2025-06-12[VPlan] Set branch weight metadata on middle term in VPlan (NFC) (#143035)Florian Hahn
Manage branch weights for the BranchOnCond in the middle block in VPlan. This requires updating VPInstruction to inherit from VPIRMetadata, which in general makes sense as there are a number of opcodes that could take metadata. There are other branches (part of the skeleton) that also need branch weights adding. PR: https://github.com/llvm/llvm-project/pull/143035
2025-06-09[VPlan] Add ReductionStartVector VPInstruction. (#142290)Florian Hahn
Add a new VPInstruction::ReductionStartVector opcode to create the start values for wide reductions. This more accurately models the start value creation in VPlan and simplifies VPReductionPHIRecipe::execute. Down the line it also allows removing VPReductionPHIRecipe::RdxDesc. PR: https://github.com/llvm/llvm-project/pull/142290
2025-06-08[VPlan] Infer result type for ComptueReductionResult in ::execute (NFC).Florian Hahn
Remove explicit use of underlying instruction to get type.
2025-06-07[VPlan] Use regular phi printing for resume phis.Florian Hahn
As discussed in https://github.com/llvm/llvm-project/pull/140405, remove custom printing for resume-phis and update tests.
2025-06-03[VPlan] Add ComputeAnyOfResult VPInstruction (NFC) (#141932)Florian Hahn
Add a dedicated opcode for any-of reduction, similar to https://github.com/llvm/llvm-project/pull/132689 and https://github.com/llvm/llvm-project/pull/132690. The patch also explictly adds the start value to not require RecurrenceDescriptor during execute. It also allows freezing the start value to make it poison-safe. PR: https://github.com/llvm/llvm-project/pull/141932
2025-05-31[VPlan] Simplify branch on False in VPlan transform (NFC). (#140409)Florian Hahn
Simplify branch on false, starting with the branch from the middle block to the scalar preheader. Initially this helps simplifying the initial VPlan construction. Depends on https://github.com/llvm/llvm-project/pull/140405. PR: https://github.com/llvm/llvm-project/pull/140409
2025-05-31[VPlan] Improve code in VPWidenCallRecipe (NFC) (#141926)Ramkumar Ramachandra
Use operands() instead of {op_begin(), op_end()}. Also rename arg_operands to args to match CallBase.
2025-05-30[VPlan] Simplify VPReductionPHIRecipe::execute (NFC).Florian Hahn
Simplify VPReductionPHIRecipe::execute by handling the simple cases first, by directly using State.get() to the appropriate start value.
2025-05-30[VPlan] Remove ResumePhi opcode, use regular PHI instead (NFC). (#140405)Florian Hahn
Use regular VPPhi instead of a separate opcode for resume phis. This removes an unneeded specialized opcode and unifies the code (verification, printing, updating when CFG is changed). Depends on https://github.com/llvm/llvm-project/pull/140132. PR: https://github.com/llvm/llvm-project/pull/140405
2025-05-29[VPlan] Use EMIT-SCALAR for single-scalar VPPhis (NFC).Florian Hahn
Follow-up to https://github.com/llvm/llvm-project/pull/141428, to also use EMIT-SCALAR for VPPhis that are single scalars.
2025-05-29[VPlan] Use EMIT-SCALAR when printing single-scalar VPInstructions. (#141428)Florian Hahn
By using SINGLE-SCALAR when printing, it is clear in the debug output that those VPInstructions only produce a single scalar. Split off in preparation for https://github.com/llvm/llvm-project/pull/140623. PR: https://github.com/llvm/llvm-project/pull/141428
2025-05-29[VPlan] Implement VPlan-based cost model for VPReduction, ↵Elvis Wang
VPExtendedReduction and VPMulAccumulateReduction. (#113903) This patch implement the VPlan-based cost model for VPReduction, VPExtendedReduction and VPMulAccumulateReduction. With this patch, we can calculate the reduction cost by the VPlan-based cost model so remove the reduction costs in `precomputeCost()`. Ref: Original instruction based implementation: https://reviews.llvm.org/D93476
2025-05-28[LoopUtils] Pass sentinel value directly to createFindLastIVRed (NFC).Florian Hahn
Now that there is only a single FindLastIV recurrence kind, simply pass the sentinel value instead of the full recurrence descriptor to tighten the interface.
2025-05-28[LoopUtils] Pass start value directly to createAnyOfReduction (NFC).Florian Hahn
Now that there is only a single AnyOf recurrence kind, simply pass the start value instead of the full recurrence descriptor, to tighten the interface.
2025-05-28[VPlan] Use VPIRFlags to manage FMFs for ComputeReductionResult (NFC).Florian Hahn
Manage fast-math flags using VPIRFlags from VPInstruciton, in inline with other VPInstructions. With this change, we now print the correctly flags for ComputeReductionResult, other than that NFC.
2025-05-27[VPlan] Improve cast code in VPlanRecipes (NFC) (#141240)Ramkumar Ramachandra
2025-05-25VPlanRecipes.cpp - fix "not all control paths return a value" MSVC warningSimon Pilgrim
2025-05-25[VPlan] Separate out logic to manage IR flags to VPIRFlags (NFC). (#140621)Florian Hahn
This patch moves the logic to manage IR flags to a separate VPIRFlags class. For now, VPRecipeWithIRFlags is the only class that inherits VPIRFlags. The new class allows for simpler passing of flags when constructing recipes, simplifying the constructors for various recipes (VPInstruction in particular, which now just has 2 constructors, one taking an extra VPIRFlags argument. This mirrors the approach taken for VPIRMetadata and makes it easier to extend in the future. The patch also adds a unified flagsValidForOpcode to check if the flags in a VPIRFlags match the provided opcode. PR: https://github.com/llvm/llvm-project/pull/140621
2025-05-24[VPlan] Replace VPRegionBlock with explicit CFG before execute (NFCI). (#117506)Florian Hahn
Building on top of https://github.com/llvm/llvm-project/pull/114305, replace VPRegionBlocks with explicit CFG before executing. This brings the final VPlan closer to the IR that is generated and helps to simplify codegen. It will also enable further simplifications of phi handling during execution and transformations that do not have to preserve the canonical IV required by loop regions. This for example could include replacing the canonical IV with an EVL based phi while completely removing the original canonical IV. PR: https://github.com/llvm/llvm-project/pull/117506
2025-05-19[VPlan] Clean up the function VPInstruction::generate for ↵Mel Chen
ComputeReductionResult, nfc (#140245) When reducing unrolled parts, explicitly check for min/max reductions using the function RecurrenceDescriptor::isMinMaxRecurrenceKind. Only if the reduction is not min/max reduction, call RecurrenceDescriptor::getOpcode() to handle other cases via CreateBinOp. Based on https://github.com/llvm/llvm-project/pull/140242 Related to https://github.com/llvm/llvm-project/pull/118393
2025-05-19[IVDescriptor][LV] Return Instruction::Or for IAnyOf/FAnyOf in getOpcode(), ↵Mel Chen
nfc (#140242)