3773 Commits

Author SHA1 Message Date
Florian Hahn
7b445ddcd2
[LV] Add additional tests for early-exit loops loads not known deref.
Add additional test coverage for loops with loads that are not known to
be dereferenceable.
2026-01-25 23:09:58 +00:00
Mircea Trofin
b39568d782
[LV] capture branch weights for constant trip counts (#175096)
When a vectorized loop has constant trip, it's important to update the
profile information accordingly. Hotness analysis will only look at
profile info.

For example, in the `tripcount.ll` test, without producing the profile
info, in the `const_trip_over_profile` function, the BFI of the
`vector.body` would be 32 (this is the expected value when synthetic
branch weights are used, in loops). The real value is 250. The
`for.body`value was _very_ incorrect before, too (and detrimentally so,
as it would have appeared as "very hot" when it wasn't):

The table below was obtained by printing BFI in the RUN: command, i.e.
`build/bin/opt < llvm/test/Transforms/LoopVectorize/tripcount.ll
-passes="loop-vectorize,print<block-freq>"
-loop-vectorize-with-block-frequency -S -o /dev/null`. Showing only the
`float` value, i.e. the BFI relative to the function entry BB.

```

Printing analysis results of BFI for function 'const_trip_over_profile':  
block-frequency-info: const_trip_over_profile

```

| Block | Before | After |
| ----- | ------ | ----- |
| `entry` | float = 1.0 | float = 1.0 |
| `vector.ph` | float = 1.0 | float = 1.0 |
| `vector.body` | float = **32.0** | float = **250.0** |
| `middle.block` | float = 1.0 | float = 1.0 |
| `scalar.ph` | float = 1.0 | float = 1.0 |
| `for.body` | float = **2147483647.8** | float = **1.0** |
| `for.end` | float = 1.0 | float = 1.0 |
2026-01-23 14:31:05 -08:00
Mel Chen
149c76538e
[LV] Separate runtime check cost from total overhead in profitability check (#176754)
In isOutsideLoopWorkProfitable function, there are two places where only
the runtime check cost (RtC) should be used, but incorrectly included
the costs of middle blocks and early-exit blocks.
1. VectorizeMemoryCheckThreshold comparison for interleaving-only
2. Minimum trip count that bounds runtime check overhead, i.e. MinTC2
calculation
This results in an overly conservative minimum profitable trip count.

This patch separates the runtime check cost from the total overhead
cost, and uses only RtC for VectorizeMemoryCheckThreshold comparison and
the MinTC2 calculation.
2026-01-23 07:29:56 +00:00
Florian Hahn
7ea1fa591a
[LV] Skip FindLast reductions in collectInLoopReductions.
FindLast in-loop reductions are not supported, similarly to FindLastIV
reductions. Skip them in collectInLoopReductions, to avoid a crash for
loops with FindLast reductions and in-loop reductions preferred.
2026-01-22 21:49:52 +00:00
Florian Hahn
14a209f852
[VPlan] Replace ComputeFindIVRes with ComputeRdxRes + cmp + sel (NFC) (#176672)
Replace ComputeFindIVResult with ComputeReductionResult + explicit
compare + select, to more explicitly and simpler model computing finding
the first/last induction, which boils down to a min/max reduction +
compare and select of the sentinel value.

PR: https://github.com/llvm/llvm-project/pull/176672
2026-01-22 19:28:47 +00:00
Florian Hahn
f41767db9d
[LV] Add replicating load/store cost tests for Apple CPUs.
Add dedicated tests to check replicating load/store costs on Apple CPUs.
2026-01-21 16:37:12 +00:00
Florian Hahn
d3f2f1366d
[LV] Consider UserIC when limiting VF. (#174573)
If a UserIC is provided, the vector loop will process VF * UserIC. Pass
it through UserIC to computeFeasibleMaxVF and use it to limit the max VF
to factors where VF * UserIC <= MaxTripCount. This avoids creating dead
vector loops with user provided interleave counts.

PR: https://github.com/llvm/llvm-project/pull/174573
2026-01-20 14:19:11 +00:00
David Sherwood
abc924356e
[LV][NFC] Update low trip count tail-folding tests (#176898)
Whilst reviewing PR #176754 I realised there seemed to be some odd cost
model issues for the tests in file

LoopVectorize/AArch64/fold-tail-low-trip-count.ll

where we seemed to be vectorising loops that aren't worth it. It turns
out the tests were not targeting AArch64 despite being in the AArch64
directory. I fixed the RUN line for the file and also added a new file
for RISCV so we get more test coverage.
2026-01-20 12:15:50 +00:00
Florian Hahn
69fbab2b72
[VPlan] Fall back to legacy cost if operands may be force-scalarized.
If any of the operands of a VPReplicateRecipe have been
force-scalarized, then the legacy cost model skips the scalarization
overhead, but we cannot match this in the VPlan cost model.

Bail out for now in those very rare cases.

Fixes https://github.com/llvm/llvm-project/issues/176720.
2026-01-19 21:25:54 +00:00
Florian Hahn
e34fefdb35
[LV] Add extra tests with sink-able recipes.
Add extra test coverage for
https://github.com/llvm/llvm-project/pull/168031.
2026-01-19 18:33:55 +00:00
Florian Hahn
c6f3bc888b
[LV] Add single-iteration epilogue test with de-generate reduction.
While at it, also modernize the check lines to reduce diff of future
changes.
2026-01-19 17:43:40 +00:00
Florian Hahn
5e5d6389f6
[LV] Allow loops with multiple early exits in legality checks. (#176403)
This patch removes the single uncountable exit constraint, allowing
loops with multiple early exits, if the exits form a dominance chain and
all other constraints hold for all uncountable early exits.

While legality now accepts such loops, vectorization is not yet
supported. VPlan support will be added in a follow up:
https://github.com/llvm/llvm-project/pull/174864

PR: https://github.com/llvm/llvm-project/pull/176403
2026-01-19 12:32:04 +00:00
Florian Hahn
497a6d6722
Recommit "[VPlan] Only use isAddressSCEVForCost in legacy getAddressAccSCEV"
This reverts commit ed004cf42bf57ca79b57bc3076ef83a8477426ea.

The original commit exposed an independent cost issue, triggering an
assertion. That issue has been fixed in 3457e7efc3.

Reland the patch now that the assertion has been fixed.
2026-01-18 19:55:46 +00:00
Florian Hahn
3457e7efc3
[VPlan] Match inverted logical AND/OR for select costs.
VPlan transforms may invert logical AND/OR selects, which can impact
costs on targets the select is not cheap but the boolean AND/OR is.
Also match the inverted logical AND/OR to improve accuracy of the
cost estimation and fixes the underlying issue for the cost
divergence between legacy and VPlan-based cost model that caused
the revert of 01d34eb38fa058 in ed004cf42bf57c.
2026-01-18 16:15:42 +00:00
Florian Hahn
123acb24da
[LV] Add missing coverage for LV cost model code paths.
Add a set of tests that expose crashes with some upcoming and pending
patches.
2026-01-17 21:59:50 +00:00
Florian Hahn
5995fe951f
[VPlan] Normalize selects to always select the data op when cond is true.
Fix a miscompile in the FindLast handling by normalizing selects
with the phi node as the first op to ones that select the data value
when the condition is true, by swapping operands and inverting the
condition.

This should ensure correct codegen for both cases.

Select normalization:
https://alive2.llvm.org/ce/z/yFdivK

Fixes a miscompile reported for 2abd6d6d7ac (#158088).
2026-01-17 18:30:52 +00:00
Florian Hahn
421d50b5bf
[LV] Add additional tests for miscompile caused by 2abd6d6d7a.
Add tests showing mis-compiles caused by 2abd6d6d7a (#158088).
2026-01-17 16:30:54 +00:00
Florian Hahn
459990dcf7
[VPlan] Replace PhiR operand of ComputeFindIVResult with VPIRFlags. #174026 (#175461)
Replace the Phi recipe operand of ComputeFindIVResult with VPIRFlags,
building on top of https://github.com/llvm/llvm-project/pull/174026.

PR: https://github.com/llvm/llvm-project/pull/175461
2026-01-17 16:23:33 +00:00
Florian Hahn
1056e32785
[LV] Precommit additional early-exit tests from #174864.
Pre-commit tests from https://github.com/llvm/llvm-project/pull/174864.
2026-01-16 15:18:20 +00:00
Florian Hahn
3fb914d851
[SCEV] Add initial support for ptrtoaddr. (#158032)
Add initial support for PtrToAddr to SCEV, including a new
SCEVPtrToAddrExpr and SCEV expansion support for it.

PR: https://github.com/llvm/llvm-project/pull/158032
2026-01-16 11:58:04 +00:00
Vishruth Thimmaiah
04baf1105f
[LoopVectorize] Support vectorization of overflow intrinsics (#174835)
Enables support for marking overflow intrinsics `uadd`, `sadd`, `usub`,
`ssub`, `umul` and `smul` as trivially vectorizable.

Fixes #174617

---------

Signed-off-by: vishruth-thimmaiah <vishruththimmaiah@gmail.com>
2026-01-16 10:09:42 +00:00
Elvis Wang
aa11629192
[LV] Prevent extract-lane generate unused IRs with single vector operand. (#172798)
When `extract-lane` only contains single vector operand. We can simplify
it to `extractelement`.

This patch makes `extract-lane` generate simple `extractelement` when it
only contains single vector operand to prevent unused IR generated.

This patch is mostly NFC, the unused IR should be removed in following
IR passes.
2026-01-16 13:59:51 +08:00
Mircea Trofin
88d3078e81
[NFC] use UTC for LoopVectorize/tripcount.ll (#175095) 2026-01-15 15:01:26 -08:00
Florian Hahn
f14577fa6f
[VPlan] Fold boolean select to xor if possible.
Fold select c, false, true -> not c. This allows for more accurate cost
estimation and fixes the underlying issue for the cost divergence
between legacy and VPlan-based cost model that caused the revert of
01d34eb38fa058 in ed004cf42bf57c.

https://alive2.llvm.org/ce/z/yVuSgW.
2026-01-15 22:13:47 +00:00
Florian Hahn
808a6ba345
[VPlan] Bail out when rdx result cannot be found in handleFindLast.
Turn assertion from 2abd6d6d7ac
(https://github.com/llvm/llvm-project/pull/158088) into a bail
out to prevent crash when tail-folding.

Fixes https://github.com/llvm/llvm-project/issues/175990.
2026-01-15 09:09:19 +00:00
Luke Lau
d023577ef9 [VPlan] Explicitly test EVL recipe has "evl" name. NFC
Addresses the comment in
https://github.com/llvm/llvm-project/pull/175493#pullrequestreview-3651607778
2026-01-15 15:25:01 +08:00
Florian Hahn
8c5352cf3e
[LV] Add additional cost and folding test coverage. (NFC) 2026-01-14 22:19:11 +00:00
Florian Hahn
f61aab79ce
[VPlan] Handle min/max recur kinds in ::printFlags.
Following up to d5c11b9a24c84f, also handle min/max recurrence kinds in
::printFlags, so the proper kind is imprinted instead of icmp.

NFC modulo debug printing changes
2026-01-14 18:16:11 +00:00
Florian Hahn
b59a3dfaf1
[VPlan] Add printing test for UMax reduction (NFC).
Currently compute-reduction-result prints (icmp) instead of the correct
min/max kind.
2026-01-14 17:44:02 +00:00
Graham Hunter
8866af03c2 Require asserts for a debug printing test 2026-01-14 16:07:35 +00:00
Graham Hunter
2abd6d6d7a
[LV] Vectorize conditional scalar assignments (#158088)
Based on Michael Maitland's previous work:
https://github.com/llvm/llvm-project/pull/121222

This PR uses the existing recurrences code instead of introducing a
new pass just for CSA autovec. I've also made recipes that are more
generic.
2026-01-14 14:59:18 +00:00
Florian Hahn
d5c11b9a24
[VPlan] Replace PhiR operand of ComputeRdxResult with VPIRFlags. (#174026)
Remove the artificial PhiR operand of ComputeReductionResult, which was
only used to look up recurrence kind, in-loop and ordered properties.

Instead, encode them as VPIRFlags as suggested by @ayalz in
https://github.com/llvm/llvm-project/pull/170223.

This addresses a TODO to make codegen for ComputeReductionResult
independent of looking up information from other recipes.

This is NFC w.r.t. codegen, the printing has been improved to include
the reduction type, and whether it is in-loop/ordered.

PR: https://github.com/llvm/llvm-project/pull/174026
2026-01-14 07:45:44 +00:00
David Sherwood
48ce7bb038
[LV] Fix bug in setVectorizedCallDecision (#175742)
There is a bug in this logic:

```
   InstructionCost Cost = ScalarCost;
   InstWidening Decision = CM_Scalarize;

   if (VectorCost <= Cost) {
     Cost = VectorCost;
     Decision = CM_VectorCall;
   }

   if (IntrinsicCost <= Cost) {
     Cost = IntrinsicCost;
     Decision = CM_IntrinsicCall;
   }
```

because it assumes that the comparisons behave sensibly in the face of
invalid costs. Unfortunately, PR #174835 exposes an issue when
attempting to vectorise the new test
uadd_with_overflow_i32 for AArch64 targets. Specifically, there are
situations where all costs are invalid (e.g. VF=vscale x 1), but some
costs are more invalid than others. For example, when querying the
intrinsic cost via the TTI hook we get an invalid cost with a non-zero
value, whereas the vector cost is invalid with a zero value. That leads
to us erroneously choosing CM_VectorCall as the call widening decision,
despite the lack of a vector math variant. Inevitably this causes
crashes because we create a VPCallWidenRecipe without a variant
function.

Fix this by only performing comparisons if the costs are valid. It now
leads to us choosing CM_Scalarize more often, but it's a toin coss
anyway between CM_Scalarize and CM_IntrinsicCall when both strategies
are invalid. Potentially we could also create a new strategy called
CM_Invalid, and avoid the creation of VPlans entirely.
2026-01-14 07:28:38 +00:00
Florian Hahn
4a807e8dd9
[VPlan] Optimize BranchOnTwoConds to chain of 2 simple branches. (#174016)
This patch improves the lowering for BranchOnTwoConds added in
https://github.com/llvm/llvm-project/pull/172750 by replacing the branch
on OR with a chain of 2 branches.

On Apple M cores, the new lowering is ~8-10% faster for std::find-like
loops. It also makes it easier to determine the early exits in VPlan. I
am also planning on extensions to support loops with multiple early
exits and early-exits at different positions, which should also be
slightly easier to do with the new representation.


PR: https://github.com/llvm/llvm-project/pull/174016
2026-01-13 20:14:15 +00:00
Luke Lau
e9f758a59b
[VPlan] Allow VPInstruction::PtrAdd as a user of EVL (#175506)
Fixes #175058

Similar to #175028, on RV64 we insert a zext in between most uses of EVL
so most of the VPlanVerifier EVL checks don't fire unless we're
compiling for RV32.
In this case, we're experiencing a crash because we can have a PtrAdd
that uses EVL. This fixes it by adding PtrAdd to the list of allowed
instructions
2026-01-13 07:55:15 +00:00
Mel Chen
ee3f4bc92f
[LV][NFC] Follow-up fix for #173262 (#175513) 2026-01-13 02:35:35 +00:00
Mircea Trofin
f9c561b561
[profcheck] Fix encoding of 0 loopEstimatedTrip count (#174896)
We currently encode an estimated trip count of 0 as the latch having branch probabilities 0-0. That's an invalid pair of weights. The probability of a branch is computed as a fraction of its corresponding weight and the sum of the weights. In fact, `BranchProbabilityInfo::calcMetadataWeights` will convert this to a 1-1, meaning 50% - 50%, which isn't quite what we want. To indicate the loop is never taken, we just need to initialize the exit probability to non-zero (hence, 1)

Related: https://reviews.llvm.org/D67905

Issue #147390
2026-01-12 17:12:35 -08:00
Ramkumar Ramachandra
e8cceccea1
[IVDesc] Fix off-by-one error in FindFirstIV ranges (#174441)
ConstantRange::getNonEmpty was excluding MAX and MAX - 1 in FindFirstIV
vectorization, and this was discovered in an i1 miscompile, where it
returns the full range: fix it to exclude MAX only. The change has also
necessitated fixing a test that's not supposed to be vectorized.

Fixes #173459.

Co-authored-by: Nikita Popov <npopov@redhat.com>
2026-01-12 18:08:49 +00:00
Sander de Smalen
de9120dd3b
[AArch64] Define cost of i16->i32 udot/sdot instructions (#174102)
i16 -> i32 dot-product operations are natively supported with SVE2p1 and
SME2. This updates the cost-model so that those operations are
recognized as cheap by the LoopVectorizer.
2026-01-12 16:46:25 +00:00
Luke Lau
b04cf3b0fd
[VPlan] Remove verifier check that EVL can only be used by VPInstruction with one use (#175502)
Fixes #175028

We have a VPlanVerifier assertion that a VPInstruction that uses EVL
only has one use. This used to hold until we implemented CSE, but now we
can run into the case where e.g. a multiply from an expanded
VPWidenPointerInductionRecipe gets cse'd, causing it to have multiple
uses:

    EMIT ir<%0> = WIDEN-POINTER-INDUCTION ir<%.pre3>, ir<6>, vp<%5>
    EMIT ir<%1> = WIDEN-POINTER-INDUCTION ir<%.pre>, ir<6>, vp<%5>
    EMIT-SCALAR vp<%5> = EXPLICIT-VECTOR-LENGTH vp<%avl>

    -->

    EMIT-SCALAR vp<%10> = EXPLICIT-VECTOR-LENGTH vp<%avl>
    EMIT vp<%11> = mul ir<6>, vp<%10>
    EMIT vp<%ptr.ind> = ptradd vp<%pointer.phi>, vp<%11>
    EMIT vp<%12> = mul ir<6>, vp<%10>
    EMIT vp<%ptr.ind>.1 = ptradd vp<%pointer.phi>.1, vp<%12>

    -->

    EMIT-SCALAR vp<%5> = EXPLICIT-VECTOR-LENGTH vp<%avl>
    EMIT vp<%6> = mul ir<6>, vp<%5>
    EMIT vp<%ptr.ind> = ptradd vp<%pointer.phi>, vp<%6>
    EMIT vp<%ptr.ind>.1 = ptradd vp<%pointer.phi>.1, vp<%6>

This removes the check, as I'm not sure it's that useful anymore now
that we have CSE. Coincidentally, this crash only happened on RV32
because RV64 requires zexting the EVL, which sidesteps a lot of the
checks to begin with.
2026-01-12 14:58:04 +00:00
Florian Hahn
8f182526de
[VPlan] Don't fold UDiv in replicate regions. (#175460)
The UDiv fold added in d12e993 (#174581) is currently also applied to
replicate regions, which means we may end up with VPInstructions in
replicate regions, which is currently nots supported.

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

PR: https://github.com/llvm/llvm-project/pull/175460
2026-01-12 12:16:48 +00:00
Sam Parker
e5b6833e49
[WebAssembly] vi8 mul cost modelling. (#175177)
We've already optimised these, so update the cost model to reflect it.
And skip the isBeforeLegalize check when lowering i8 muls, because it
then misses the cases where, say v32i8, has been type legalised into 2x
v16i8.

Also explicitly disable memory interleaving for any factor other than
two or four.
2026-01-12 09:25:54 +00:00
Elvis Wang
cd2caf6580
[LV] Simplify extract-lane with scalar operand to the scalar value itself. (#174534)
This patch simplifies extract-lane(%lane_num, %X) to %X when %X is a
scalar value. Extracting from a scalar is redundant since there is only
one value to extract.
2026-01-12 10:03:44 +08:00
Florian Hahn
2f7e218017
[VPlan] Add missing sext(sub) SCEV fold to getSCEVExprForVPValue.
SCEV has a manual fold when doing SCEV construction from IR, that is not
integrated in the regular SCEV construction functions. Mirror the
behavior in getSCEVExprForVPValue, to match results when constructing
SCEVs from IR.

Fixes https://github.com/llvm/llvm-project/issues/174622.
2026-01-11 20:51:13 +00:00
Florian Hahn
d620ea7657
[LV] Handle live-ins in findRecipe.
Skip live-ins in findRecipe to prevent a crash for cases with degenerate
reductions (where the backedge value is a live-in). Such reductions
should be removed, but this requires further changes.

Fixes https://github.com/llvm/llvm-project/issues/175229.
2026-01-11 11:19:30 +00:00
Aiden Grossman
7450a75b93
[VPlan] Allow truncation for lanes in VPScalarIVStepsRecipe (#175268)
VPScalarIVStepsRecipe relies on APInt truncation in order to vectorize
blocks with a width greater than the maximum value the types of some of
their (changing) operands are able to hold (e.g., an i1 input with a
vector width of 4). Simply reenable implicit truncation in
ConstantInt::get() to cover this case.

Remove the helper function given it is only called in one place to
prevent accidentally using it elsewhere where we probably do not want
implicit truncation turned on.

This fixes another case that we saw after
acb78bde6fb613a9af2a604bc69fa744a8cee850 did not fix that issue, which
had the same stack trace. We still want to keep lane constants as
unsigned.

Somewhat similar to 6d1e7d4982fabc9e245897056a5425496df6a7a3.

This test case comes from a tensorflow/XLA compilation from a test case
in https://github.com/google-research/spherical-cnn.
2026-01-10 10:34:46 -05:00
Aiden Grossman
acb78bde6f
[VPlan] Use unsigned integers for lane start indices (#175231)
a83c89495ba6fe0134dcaa02372c320cc7ff0dbf caused assertion failures here
as if we have a single bit induction variable and two lanes (0 and 1),
then the second lane index (1) will be out of bounds of what a signed
1-bit integer can hold. Lane indices are always >0 according to
VPlanHelpers.h:125, and the lane representation in this code is also
unsigned.

The test case come from tensorflow/XLA.
2026-01-09 14:28:28 -08:00
Paul Osmialowski
6ca6a328ae
[AArch64][VecLib] Add vector function mappings for the modf, sincos, sincospi vector intrinsics (#175098)
Following the improvements introduced in #109833 and the most recent
development of the libamath library (used by `-fveclib=ArmPL`), this
patch adds the missing mappings for the functions that return literal
struct values.
2026-01-09 18:08:16 +00:00
Hans Wennborg
ed004cf42b Revert "[VPlan] Only use isAddressSCEVForCost in legacy getAddressAccSCEV (NFCI)"
This caused assertion failures:

  llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7265:
  VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF():
  Assertion `(BestFactor.Width == LegacyVF.Width || BestPlan.hasEarlyExit() || !Legal->getLAI()->getSymbolicStrides().empty() || UsesEVLGatherScatter || planContainsAdditionalSimplifications( getPlanFor(BestFactor.Width), CostCtx, OrigLoop, BestFactor.Width) || planContainsAdditionalSimplifications( getPlanFor(LegacyVF.Width), CostCtx, OrigLoop, LegacyVF.Width))
  && " VPlan cost model and legacy cost model disagreed"' failed.

see comment on https://github.com/llvm/llvm-project/pull/171204

This reverts commit 01d34eb38fa0587cb95eedd3bada8257abc122f8.
2026-01-09 15:38:32 +01:00
Florian Hahn
6e6996e893
[LV] Add tests for argmin/argmax with epilogue vectorization. (NFC)
Add additional test coverage for vectorizing argmin/argmax with epilogue
vectorization.
2026-01-07 20:26:49 +00:00