3177 Commits

Author SHA1 Message Date
David Sherwood
f575b18fdc
[LV] Add support for partial reductions without a binary op (#133922)
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 13:05:51 +01:00
Mel Chen
bc8dad1c7e
[VPlan] Emit VPVectorEndPointerRecipe for reverse interleave pointer 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-02 18:16:02 +08:00
Florian Hahn
6b3d2b629c
[VPlan] Add VPExpressionRecipe, replacing extended reduction recipes. (#144281)
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-07-01 20:44:50 +01:00
David Sherwood
9b13dfdfbc
[LV] Use vscale for tuning to improve branch weight estimates (#144733)
In addBranchWeightToMiddleTerminator we attempt to add branch weights to
the middle block terminator. We pessimistically assume vscale=1, whereas
we can improve the estimate by using the value of vscale used for
tuning.
2025-07-01 13:23:38 +01:00
Luke Lau
4a2fa0847f
[VPlan] Support VPWidenIntOrFpInductionRecipes with EVL tail folding (#144666)
Following on from #118638, this handles widened induction variables with
EVL tail folding by setting the VF operand to be EVL, calculated in the
vector body.

We need to do this for correctness since with EVL tail folding the
number of elements processed in the penultimate iteration may not be VF,
but the runtime EVL, and we need take this into account when updating
the backedge value.

- Because the VF may now not be a live-in we need to move the insertion
point to just after the VFs definition
- We also need to avoid truncating it when it's the same size as the
step type, previously this wasn't a problem for live-ins.
- Also because the VF may be smaller than the IV type, since the EVL is
always i32, we may need to zext it.

On -march=rva23u64 -O3 we get 87.1% more loops vectorized on TSVC, and
42.8% more loops vectorized on SPEC CPU 2017
2025-07-01 12:29:24 +01:00
Florian Hahn
59a7185dd9
[VPlan] Truncate/Extend ComputeReductionResult at construction (NFC). (#141860)
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-30 22:39:17 +01:00
Luke Lau
f01a7936be
[VPlan] Replace all uses of VF when EVL tail folding. NFCI (#146339)
With EVL tail folding, any use of the VF live in should be replaced by
the EVL. Otherwise, it should likely be directly emitted as a constant
via VPTransformState::VF.

This strengthens the EVL transformation by replacing all uses of VF with
EVL and asserting that the only users are VPVectorEndPointerRecipe and
VPScalarIVStepsRecipe, the latter of which is new.

This should be NFC because even though we didn't previously replace the
EVL of VPScalarIVStepsRecipe, it's only used when unrolling which we
don't allow with EVL tail folding yet.
2025-06-30 13:47:38 +01:00
Florian Hahn
b822a32659
[VPlan] Fix crash when trying to narrow interleave group storing const.
Use dyn_cast_null to handle the case where an interleave groups stores a
constant in any of its lanes.
2025-06-29 21:29:12 +01:00
Florian Hahn
f5ed863176
Revert "[VPlan] Allow derived IVs and scalar-steps in narrowing interleave."
This reverts commit 2787759ef2e41b19f8bfde06fe9a26b25d1f5834.

This exposed a crash on some build bots. Revert to investigate.
2025-06-29 14:40:03 +01:00
Florian Hahn
2787759ef2
[VPlan] Allow derived IVs and scalar-steps in narrowing interleave.
Both VPDerivedIVRecipe and VPScalarIVSteps recipe should be supported in
narrowInterleaveGroups:
 * VPDerivedIVRecipe is based on the canonical IV and independent of VF,
 * VPScalarIVSteps takes the VF as operand, so it will be updated by
   narrowInterleaveGroup.
2025-06-29 13:18:51 +01:00
Florian Hahn
20fbbd7675
[LV] Add support for cmp reductions with decreasing IVs. (#140451)
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-29 11:17:03 +01:00
Florian Hahn
1949536494
[VPlan] Also visit VPBBs outside loop region when unrolling by VF.
Make sure all VPBBs outside the top-level loop region and directly
inside the region are visited; all those blocks may contain
VPReplicateRecipes that need unrolling.

This makes sure we unroll VPRepicateRecipes by VF if they are hoisted
out of the loop, but cannot be converted to single scalar recipes yet.
2025-06-28 19:02:22 +01:00
Florian Hahn
526701f8dc
[LV] Add additional tests for narrowing interleave groups.
Add additional test coverage for narrowing interleave groups with
derived IVs & scalar steps.
2025-06-27 21:18:14 +01:00
Florian Hahn
3b7b95f78e
[VPlan] Support VPWidenSelectRecipe in narrowToSingleScalar.
VPWidenSelectRecipes are single scalars if all their operands are. Add
support for narrowing them to a single scalar VPReplicateRecipe.

This fixes a crash after
https://github.com/llvm/llvm-project/pull/142433 (aa24029319083) when
due to a replicate recipe not being converted to single-scalar being
hoisted to the vector preheader.
2025-06-27 15:42:42 +01:00
David Sherwood
bf2b14acf3
[LV] Enable auto-vectorisation of loops with uncountable exits (#133099)
Until now the feature to enable vectorisation of some early exit
loops with uncountable exits was controlled under a flag, off by
default. Now that we have efficient code generation for
vectorising such loops (see PR #130766) and we still have some
time from the next LLVM release it seems like a good time point
to enable the feature by default. If any issues arise post-commit
it can be easily reverted.

Using this patch I built and ran the LLVM test suite successfully,
which on neoverse-v1 led to the vectorisation of 114 additional
early exit loops. I also built and ran SPEC2017 successfully for
both neoverse-v1 and neoverse-v2.
2025-06-27 10:39:33 +01:00
David Sherwood
ddb8493ca7
[LV] Fix test issue caused by #145877 (#146041) 2025-06-27 10:02:57 +01:00
David Sherwood
6f43754e9c
[LV] Disable interleaving via hints for uncountable early exit loops (#145877)
Currently if the user enables interleaving during vectorisation of
uncountable early exit loops via the interleave_count pragma and the
enable-early-exit-vectorization option, it will miscompile. There is
ongoing work to fix this, but for now it seems safer to ignore the hint
until it is supported.

---------

Co-authored-by: Paul Walker <paul.walker@arm.com>
2025-06-27 09:09:55 +01:00
Florian Hahn
ec62dee703
[VPlan] Handle FirstActiveLane when unrolling. (#145394)
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-27 08:44:57 +01:00
Florian Hahn
5b76cdba5a
[VPlan] Handle AnyOf when unrolling. (#145340)
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 14:19:38 +01:00
Florian Hahn
aa24029319
[VPlan] Unroll VPReplicateRecipe by VF. (#142433)
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-26 11:19:09 +01:00
Florian Hahn
ecff028a96
[LV] Update test after 4ac4726d00.
Update missed test checks after #144644.
2025-06-25 09:54:54 +01:00
Florian Hahn
17c5c19902
[Verifier] Always verify all assume bundles. (#145586)
For some reason, some of the checks for specific assumbe bundle elements
exit early if the check pass, meaning we don't verify other entries.
Replace the early returns with early continues.

This also requires removing some tests that are currently rejected. They will
be added back as part of https://github.com/llvm/llvm-project/pull/128436.

PR: https://github.com/llvm/llvm-project/pull/145586
2025-06-25 09:31:02 +01:00
Florian Hahn
830b2c842e
[LV] Replace redundant ExtractLastElement of reduction result (NFC).
Replace redundant ExtractLastElement VPInstructions early. This is NFC,
as the VPInstruction computing the final result is vector-to-scalar,
producing a single scalar already. This enables follow-up changes to
model more aspects of reductions directly in VPlan.
2025-06-24 21:48:58 +01:00
Florian Hahn
5d01697ec6
[LAA] Be more careful when evaluating AddRecs at symbolic max BTC. (#128061)
Evaluating AR at the symbolic max BTC may wrap and create an expression
that is less than the start of the AddRec due to wrapping (for example
consider MaxBTC = -2).

If that's the case, set ScEnd to -(EltSize + 1). ScEnd will get
incremented by EltSize before returning, so this effectively sets ScEnd
to unsigned max. Note that LAA separately checks that accesses cannot
not wrap (52ded672492,
https://github.com/llvm/llvm-project/pull/127543), so unsigned max
represents an upper bound.

When there is a computable backedge-taken count, we are guaranteed to
execute the number of iterations, and if any pointer would wrap it would
be UB (or the access will never be executed, so cannot alias). It
includes new tests from the previous discussion that show a case we wrap
with a BTC, but it is UB due to the pointer after the object wrapping
(in `evaluate-at-backedge-taken-count-wrapping.ll`)

When we have only a maximum backedge taken count, we instead try to use
dereferenceability information to determine if the pointer access must be in
bounds for the maximum backedge taken count.

PR: https://github.com/llvm/llvm-project/pull/128061
2025-06-23 20:23:40 +01:00
Florian Hahn
b054363645
[LV] Add tests showing incorrect vector interleaving with early exits.
When interleaving is forced for early-exit loops, we currently create
incorrect code.

Test coverage for scalable vectors is added as AArch64 specific test.
2025-06-23 16:24:13 +01:00
Ramkumar Ramachandra
bb8c42e859
[LV] Extend FindLastIV to unsigned case (#141752)
Split the FindLastIV RecurKind into SMax and UMax variants, depending on
the reduction op produced.
2025-06-23 15:27:49 +01:00
Florian Hahn
f9c9a32e9c
[LV] Add tests with fmax reductions without fast-math flags.
Adds extra tests with fmax reductions without fast-math flags for
upcoming patches.
2025-06-22 20:35:38 +01:00
Florian Hahn
0dc0aeb14f
[LV] Add additional tests for replicating calls returning structs.
Add additional test coverage for replicating calls return structs, in
particular cases where the number of struct elements does not match the
VF.

Extra test coverage for
https://github.com/llvm/llvm-project/pull/142433.
2025-06-22 13:48:25 +01:00
Florian Hahn
58b939abe5
[VPlan] Support matching constants in narrowInterleaveGroups.
Matching constants can trivially be broadcasted, allow them if the same
constant is used for all recipes in a bundle.
2025-06-22 08:45:40 +01:00
Florian Hahn
c455f4a32d
[LV] Add more tests for narrowing interleave groups with live-ins. 2025-06-21 22:03:19 +01:00
Florian Hahn
2f5d965bb5
[VPlan] Use EMIT-SCALAR when printing casts.
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-21 10:23:53 +01:00
Florian Hahn
f8ffb4e7cd
[VPlan] Simplify ExtractLastElement(Broadcast(A)) -> A.
Remove trivial ExtractLastElement VPInstructions.
2025-06-20 21:08:14 +01:00
Philip Reames
c103bbc836
[LV] Consider whether vscale is a known power of two for iteration check (#144963)
Going mostly by the comment here - but it says "vscale is not
necessarily a power-of-2". Both in tree targets have vscale as a power
of two, and we have an existing TTI hook for that.
2025-06-20 11:37:27 -07:00
Luke Lau
521adc9fa2 [VPlan] Use createScalarZExtOrTrunc when expanding expandVPWidenIntOrFpInduction
Split off from #144666
2025-06-20 19:18:49 +01:00
Florian Hahn
7f74a377d0
[LV] Regenerate uniform_across_vf* check lines.
Re-generate check lines to reduce diff in upcoming changes.

Also filters out the code after scalar.ph:, which is dead.
2025-06-20 19:10:26 +01:00
Graham Hunter
3ff69c8078
[LV] Add early-exit-with-store tests (#140899)
Adds some additional LoopVectorizeLegality tests for early exit loops
with a store that we don't vectorize.

Test precommit split from #137774
2025-06-20 14:49:50 +01:00
Ramkumar Ramachandra
c8c4bd1ebc
[LV] Stengthen loop-invariance checks in isPredicatedInst (#140744)
Check loop-invariance against SCEV as well.
2025-06-20 14:01:48 +01:00
Florian Hahn
fd97dfbb78
[LV] Don't mark ptrs as safe to speculate if fed by UB/poison op. (#143204)
Add additional checks before marking pointers safe to load
speculatively. If some computations feeding the pointer may trigger UB,
we cannot load the pointer speculatively, because we cannot compute the
address speculatively. The UB triggering instructions will be
predicated, but if the predicated block does not execute the result is
poison.

Similarly, we also cannot load the pointer speculatively if it may be
poison. The patch also checks if any of the operands defined outside the
loop may be poison when entering the loop. We *don't* need to check if
any operation inside the loop may produce poison due to flags, as those
will be dropped if needed.

There are some types of instructions inside the loop that can produce
poison independent of flags. Currently loads are also checked, not sure
if there's a convenient API to check for all such operands.

Fixes https://github.com/llvm/llvm-project/issues/142957.

PR: https://github.com/llvm/llvm-project/pull/143204
2025-06-20 13:05:19 +01:00
Florian Hahn
e8be733a3c
[VPlan] Remove redundant ExtractLastElement from vector-to-scalar VPI.
Recipes that are vector-to-scalar are guaranteed to generate a scalar
value, so the extract is redundant after VPlan unrolling. Remove it.

This removes unneeded ExtractLastElement VPInstruction of reduction
result computations.
2025-06-20 12:45:20 +01:00
Florian Hahn
74ec1c287a
[LV] Add tests interleaving extended and multiply/accumulate reductions.
Add missing test coverage for interleaving with
VPExtendedReduction/VPMulAccumulateReduction recipes.

Adds missing test coverage in preparation for
https://github.com/llvm/llvm-project/pull/144281.
2025-06-19 18:56:25 +01:00
Florian Hahn
c4c2d777f4
[VPlan] Fix handling of ReductionStartVector for rdxs when unrolling.
Update handling of ReductionStartVector in VPlanUnroll for partial
reductions. The new code makes sure all parts are properly set to the
cloned ReductionStartVector.

Fixes a mis-compile reported for
https://github.com/llvm/llvm-project/pull/142290.
2025-06-19 13:26:19 +01:00
Paul Walker
e478a22d54
[LLVM][IRBuilder] Use NUW arithmetic for Create{ElementCount,TypeSize}. (#143532)
This put the onus on the caller to ensure the result type is big enough.
In the unlikely event a cropped result is required then explicitly
truncate a safe value.
2025-06-19 13:24:39 +01:00
Florian Hahn
046e2f545e
[LV] Add interleaving test with partial reductions and non-const start.
Add test coverage for mis-compile after
https://github.com/llvm/llvm-project/pull/142290.
2025-06-19 12:55:16 +01:00
David Sherwood
af51c9d9df
[LV][NFC] Add branch weight test showing incorrect behaviour (#144682)
This patch adds a test that shows incorrect branch weights being set in
function

EpilogueVectorizerEpilogueLoop::emitMinimumVectorEpilogueIterCountCheck
2025-06-19 10:49:40 +01:00
Mel Chen
ba40a7bc2e
[LoopVectorize] Vectorize fixed-order recurrence with vscale x 1. (#142772)
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-18 16:03:20 +08:00
Luke Lau
9dd1c66e8f
[VPlan] Expand VPWidenIntOrFpInductionRecipe into separate recipes (#118638)
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-17 18:24:07 +01:00
Mary Kassayova
c377ce1216
[AArch64][VecLib] Add libmvec support for AArch64 targets (#143696)
This patch adds support for the `libmvec` vector library on AArch64
targets. Currently, all `libmvec` functions in GLIBC version 2.40 are
supported. The full list of math functions enabled can be found
[here](96abd59bf2/sysdeps/aarch64/fpu/Versions)
(up to GLIBC 2.40).

Previously, `libmvec` was only supported on x86_64 targets. Attempts to
use it on AArch64 resulted in the following error from Clang:
`unsupported option 'libmvec' for target 'aarch64'`.
2025-06-17 11:07:43 +01:00
Florian Hahn
30b16ec341
[VPlan] Simplify trivial VPFirstOrderRecurrencePHI recipes.
VPFirstOrderRecurrencePHIRecipes where the incoming values are the same
can be simplified and removed.

Fixes https://github.com/llvm/llvm-project/issues/144212.

The new test is added together with other related tests from
first-order-recurrence.ll
2025-06-16 22:54:26 +01:00
Florian Hahn
d3bc834ece
[LV] Update check to find epilogue resume value to check all incoming.
This fixes a crash where all incoming values for the epilogue resume
value are zero, because there are no remaining iterations to execute for
the epilogue loop.
2025-06-16 21:10:12 +01:00
Philip Reames
90d62e0ae3
[RISCV][TTI] Refine reverse shuffle costing for high LMUL (#144155)
This contains two closely related changes:
1) Explicitly recurse on the i1 case - "3" happens to be the right
   magic constant at m1, but is not otherwise correct, and we're
   better off deferring this to existing logic.
2) Match the lowering for high LMUL shuffles - we've switched to using
   a linear number of m1 vrgather instead of a single big vrgather.
   This results in substantially faster (but also larger) code for
   reverse shuffles larger than m1.  Note that fixed vectors need
   a slide at the end, but scalable ones don't.

This will have the effect of biasing the vectorizer towards larger
(particularly scalable larger) vector factors. This increases VF for the
s112 and s1112 loops from TSVC_2 (in all configurations).

We could refine the high LMUL estimates a bit more, but I think getting
the linear scaling right is probably close enough for the moment.
2025-06-16 10:20:09 -07:00