3511 Commits

Author SHA1 Message Date
Sushant Gokhale
778d3c8ccc
[NFC] Partial reduce test to demonstrate regression post commit #cc9c64d (#162681)
We have seen performance regression for several instances of the Numba
benchmark, with some ranging around 70%, on Neoverse-v2 post #158641.
The mentioned case is short reproducer of the same. See
https://godbolt.org/z/j9Mj5WM7c for the IR differences.. A future patch
will address this.
2025-10-14 23:51:36 -07:00
Florian Hahn
0fefa56b03
[LV] Add additional min/max reduction tests.
Add test coverage for min/max reductions with various combinations of
users (in and outside loops, used by stores) and predicated variants.

This adds missing test coverage for min/max reductions.
2025-10-14 22:26:59 +01:00
Ramkumar Ramachandra
4ec78f56c2
[LV] Increase coverage of uniformity-rewriter (#161219)
Add a test with a non-uniform load of an argument (SCEVUnknown), showing
that SCEVUnknown cannot always be considered uniform.
2025-10-13 10:15:34 +00:00
Florian Hahn
5e3ac2a6f2
[LV] Bail out on loops with switch as latch terminator.
Currently we cannot vectorize loops with latch blocks terminated by a
switch. In the future this could be handled by materializing appropriate
compares.

Fixes https://github.com/llvm/llvm-project/issues/156894.
2025-10-12 21:20:35 +01:00
Florian Hahn
4bf5ab4f9d
[VPlan] Set flags when constructing truncs using VPWidenCastRecipe.
VPWidenCastRecipes with Trunc opcodes where missing the correct OpType
for IR flags. Update createWidenCast to set the correct flags for
truncs, and use it consistenly.

Fixes https://github.com/llvm/llvm-project/issues/162374.
2025-10-12 14:01:12 +01:00
Florian Hahn
5db774a822
[LV] Add additional test for narrowing to single scalars.
Add extra test coverage for narrowing stores to single scalars, with the
store address being uniform-per-part, not uniform-across-all-parts.

Test for https://github.com/llvm/llvm-project/issues/162498.
2025-10-12 10:27:20 +01:00
Florian Hahn
ae7b15f2e2
[VPlan] Return invalid for scalable VF in VPReplicateRecipe::computeCost
Replication is currently not supported for scalable VFs. Make sure
VPReplicateRecipe::computeCost returns an invalid cost early, for
scalable VFs if the recipe is not a single-scalar.

Note that this moves the existing invalid-costs.ll out of the AArch64
subdirectory, as it does not use a target triple.

Fixes https://github.com/llvm/llvm-project/issues/160792.
2025-10-11 19:28:02 +01:00
Yingwei Zheng
9e63b7ae4c
[InstCombine] Fix flag propagation in foldSelectIntoOp (#162003)
Consider the following transform:
```
C = binop float A, nnan OOp
D = select ninf, i1 cond, float C, float A
->
E = select ninf, i1 cond, float OOp, float Identity
F = binop float A, E
```
We cannot propagate ninf from the original select, because OOp may be
inf, and the flag only guarantees that FalseVal (op OOp) is never
infinity.
Examples: -inf + +inf = NaN, -inf - -inf = NaN, 0 * inf = NaN
Specifically, if the original select has both ninf and nnan, we can
safely propagate the flag.

Alive2: 
+ fadd: https://alive2.llvm.org/ce/z/TWfktv
+ fsub: https://alive2.llvm.org/ce/z/RAsjJb
+ fmul: https://alive2.llvm.org/ce/z/8eg4ND

Closes https://github.com/llvm/llvm-project/issues/161634.
2025-10-11 10:04:55 +08:00
Florian Hahn
ba69e33e13
[LV] Consistently apply address def scalarization across loop.
Consistently scalarize loads used as part of address computations across
all uses in the loop. This aligns the VPlan and legacy cost model and
fixes a divergence crash. It doesn't matter if the load and address
users are in different blocks, as long as they are in the same loop, the
scalar value can be used. This removes a number of insert/extracts.
2025-10-09 22:04:15 +01:00
Florian Hahn
6d905e41bc
[SCEV] Use getConstantMultiple in to get divisibility info from guards. (#162617)
Simplify and generalize the code to get a common constant multiple for
expressions when collecting guards, replacing the manual implementation.

Split off from https://github.com/llvm/llvm-project/pull/160012.

PR: https://github.com/llvm/llvm-project/pull/162617
2025-10-09 10:51:36 +01:00
Ramkumar Ramachandra
2a02d57efb
[IR] Mark vector intrinsics speculatable (#162334)
The vector intrinsics in question have no undefined behavior, and have
no other effect besides returning the result: they should hence be
marked speculatable.
2025-10-09 09:41:59 +01:00
Florian Hahn
98ce434870
[VPlan] Skip VPBlendRecipe in isUsedByLoadStoreAddress.
VPBlendRecipes are introduced as part of if-conversion, potentially adding
a def-use chain from a load used in a compare to another load/store. In
the scalar IR, there is no connection via def-use chains, so the legacy
cost model won't consider the load used by memory operation.

Skipping blends brings the VPlan-based cost-computation in line with the
legacy cost model after https://github.com/llvm/llvm-project/pull/162157.
2025-10-08 18:43:23 +01:00
Ramkumar Ramachandra
7296734394
[VPlan] Mark ActiveLaneMask as not having mem effects (#162330)
VPInstruction::ActiveLaneMask does not read or write memory. This allows
us to clean up some dead recipes.
2025-10-08 09:19:24 +01:00
Florian Hahn
70c1c8f800
[VPlan] Create SCEV expansion for epilogue check first.
VPExpandSCEVRecipes must be at the beginning of the entry block.
addMinimumEpilogueIterationCheck currently creates VPInstructions to
compute the remaining iterations before potentially creating
VPExpandSCEVRecipes.

Fix this by first creating any SCEV expansions if needed.

Fixes https://github.com/llvm/llvm-project/issues/162128.
2025-10-07 21:16:00 +01:00
Joel E. Denny
6d44b9082e
[LoopUnroll] Skip remainder loop guard if skip unrolled loop (#156549)
The original loop (OL) that serves as input to LoopUnroll has basic
blocks that are arranged as follows:

```
OLPreHeader
OLHeader <-.
...        |
OLLatch ---'
OLExit
```

In this depiction, every block has an implicit edge to the next block
below, so any explicit edge indicates a conditional branch.

Given OL and unroll count N, LoopUnroll sometimes creates an unrolled
loop (UL) with a remainder loop (RL) epilogue arranged like this:

```
,-- ULGuard
|   ULPreHeader
|   ULHeader <-.
|   ...        |
|   ULLatch ---'
|   ULExit
`-> RLGuard -----.
    RLPreHeader  |
,-> RLHeader     |
|   ...          |
`-- RLLatch      |
    RLExit       |
    OLExit <-----'
```

Each UL iteration executes N OL iterations, but each RL iteration
executes 1 OL iteration. ULGuard or RLGuard checks whether the first
iteration of UL or RL should execute, respectively. If so, ULLatch or
RLLatch checks whether to execute each subsequent iteration.

Once reached, OL always executes its first iteration but not necessarily
the next N-1 iterations. Thus, ULGuard is always required before the
first UL iteration. However, when control flows from ULGuard directly to
RLGuard, the first OL iteration has yet to execute, so RLGuard is then
redundant before the first RL iteration.

Thus, this patch makes the following changes:
- Adjust ULGuard to branch to RLPreHeader instead of RLGuard, thus
eliminating RLGuard's unnecessary branch instruction for that path.
- Eliminate the creation of RLGuard phi node poison values. Without this
patch, RLGuard has such a phi node for each value that is defined by any
OL iteration and used in OLExit. The poison value is required where
ULGuard is the predecessor. The poison value indicates that control flow
from ULGuard to RLGuard to Exit has no counterpart in OL because the
first OL iteration must execute either in UL or RL.
- Simplify the CFG by not splitting ULExit and RLGuard because, without
the ULGuard predecessor, the single block can now be a dedicated UL
exit.
- To RLPreHeader, add an `llvm.assume` call that asserts the RL trip
count is non-zero. Without this patch, RLPreHeader is reachable only
when RLGuard guarantees that assertion is true. With this patch, RLGuard
guarantees it only when RLGuard is the predecessor, and the OL structure
guarantees it when ULGuard is the predecessor. If RL itself is unrolled
later, this guarantee somehow prevents ScalarEvolution from giving up
when trying to compute a maximum trip count for RL. That maximum trip
count enables the branch instruction in the final unrolled instance of
RLLatch to be eliminated. Without the `llvm.assume` call, some existing
unroll tests start to fail because that instruction is not eliminated.

The original motivation for this patch is to facilitate later patches
that fix LoopUnroll's computation of branch weights so that they
maintain the block frequency of OL's body (see #135812). Specifically,
this patch ensures RLGuard's branch weights do not affect RL's
contribution to the block frequency of OL's body in the case that
ULGuard skips UL.
2025-10-07 10:45:49 -04:00
Florian Hahn
8b8c59c31f
[Loads] Check if Ptr can be freed between Assume and CtxI. (#161255)
When using information from dereferenceable assumptions, we need to make
sure that the memory is not freed between the assume and the specified
context instruction. Instead of just checking canBeFreed, check if there
any calls that may free between the assume and the context instruction.

Note that this also adjusts the context instruction to be the terminator
in the loop predecessor, if there is one and it is a branch (to avoid
things like invoke).

PR: https://github.com/llvm/llvm-project/pull/161255
2025-10-07 09:15:25 +00:00
Florian Hahn
9c0e09e0c1
[VPlan] Process ExpressionRecipes in reverse order in constructor.
Currently there's a crash when trying to construct VPExpressionRecipes
for a mul (ext, ext), if the multiply has outside users; the mul will be
cloned to serve its external users, but the extends won't get cloned and
will stay connected to users outside the loop (the cloned multiply).

To fix this, process recipes in reverse order. This ensures that we
visit bundled users before their operands, properly ensuring that the
extends for the external user are cloned as well.
2025-10-06 22:24:02 +01:00
Florian Hahn
74af5784a5
Reapply "[VPlan] Compute cost of more replicating loads/stores in ::computeCost. (#160053)" (#162157)
This reverts commit f80c0baf058dbdc5 and 94eade61a02ae5.

Recommit a small fix for targets using prefersVectorizedAddressing.

Original message:
Update VPReplicateRecipe::computeCost to compute costs of more
replicating loads/stores.

There are 2 cases that require extra checks to match the legacy cost
model:
1. If the pointer is based on an induction, the legacy cost model passes
its SCEV to getAddressComputationCost. In those cases, still fall back
to the legacy cost. SCEV computations will be added as follow-up
2. If a load is used as part of an address of another load, the legacy
cost model skips the scalarization overhead. Those cases are currently
handled by a usedByLoadOrStore helper.

Note that getScalarizationOverhead also needs updating, because when the
legacy cost model computes the scalarization overhead, scalars have not
been collected yet, so we can't each for replicating recipes to skip
their cost, except other loads. This again can be further improved by
modeling inserts/extracts explicitly and consistently, and compute costs
for those operations directly where needed.

PR: https://github.com/llvm/llvm-project/pull/160053
2025-10-06 22:16:08 +01:00
Sander de Smalen
f3a952311c
[AArch64] Return Invalid partial reduction cost for i128 accumulator. (#162066)
PR #158641 introduced an issue where i128 accumulator types resulted
in a valid cost, because for a <2 x i128> type the code that
checks for unsupported type legalization would see a type action
of 'TypeSplitVector' which is supported, even though the legalised
type of <1 x i128> would require further scalarization.

This fixes https://github.com/llvm/llvm-project/issues/162009
2025-10-06 15:32:13 +01:00
Alexey Bataev
94eade61a0 Revert "[VPlan] Match legacy CM in ::computeCost if load is used by load/store."
This reverts commit 1d65d9ce06fef890389e61990d9c748162334e55 to fix
crashes, reported in the commits
2025-10-05 08:37:52 -07:00
Florian Hahn
1d65d9ce06
[VPlan] Match legacy CM in ::computeCost if load is used by load/store.
If a load is scalarized because it is used by a load/store address, the
legacy cost model does not pass ScalarEvolution to getAddressComputationCost.

Match the behavior in VPReplicateRecipe::computeCost.
2025-10-03 22:01:46 +01:00
Florian Hahn
7ceef762c8
[LAA] Check if Ptr can be freed between Assume and CtxI. (#161725)
When using information from dereferenceable assumptions, we need to make
sure that the memory is not freed between the assume and the specified
context instruction. Instead of just checking canBeFreed, check if there
any calls that may free between the assume and the context instruction.

This patch introduces a willNotFreeBetween to check for calls that may
free between an assume and a context instructions, to also be used in
https://github.com/llvm/llvm-project/pull/161255.

PR: https://github.com/llvm/llvm-project/pull/161725
2025-10-03 13:44:58 +00:00
Sander de Smalen
cc9c64d525
[AArch64] Refactor and refine cost-model for partial reductions (#158641)
This cost-model takes into account any type-legalisation that would
happen on vectors such as splitting and promotion. This results in wider
VFs being chosen for loops that can use partial reductions.

The cost-model now also assumes that when SVE is available, the SVE dot
instructions for i16 -> i64 dot products can be used for fixed-length
vectors. In practice this means that loops with non-scalable VFs are
vectorized using partial reductions where they wouldn't before, e.g.

```
  int64_t foo2(int8_t *src1, int8_t *src2, int N) {
    int64_t sum = 0;
    for (int i=0; i<N; ++i)
      sum += (int64_t)src1[i] * (int64_t)src2[i];
    return sum;
  }
```

These changes also fix an issue where previously a partial reduction
would be used for mixed sign/zero-extends (USDOT), even when +i8mm was
not available.
2025-10-03 10:07:07 +01:00
Florian Hahn
2b2bc6320f
[LV] Add tests with multiple F(Max|Min)Num reductions w/o fast-math.
Pre-commits extra test coverage for loops with multiple F(Max|Min)Num
reductions w/o fast-math-flags for follow-up PR.
2025-10-02 21:30:54 +01:00
Florian Hahn
9133fc8cb0
[LAA,LV] Add early-exit tests with deref assumes and nofree via context.
Add tests with early exits and dereferenceable assumptions that need
proving no-free via the context.
2025-10-02 19:24:56 +01:00
Florian Hahn
f646d766de
[LV] Extend test coverage for tail-folding with recurrences.
Add additional test coverage for tail-folding loops with first-order
recurrences and users outside the loop. Test a combination of
vectorization factors and interleave counts.

Also update check lines in reduction-order.ll and adjust naming for
clarity.

This adds extra test coverage for
https://github.com/llvm/llvm-project/pull/149042.
2025-10-02 16:27:16 +01:00
Florian Hahn
7c4f188f27
[LV] Support multiplies by constants when forming scaled reductions. (#161092)
We can create partial reductions for multiplies with constants, if the
constant is small enough to be extended from source to destination type
w/o changing the value.

This only handles constant on the right side of a multiply, relying on
other passes to canonicalize the input.

Alive2 Proofs: https://alive2.llvm.org/ce/z/iWRMr6

PR: https://github.com/llvm/llvm-project/pull/161092
2025-10-02 10:53:17 +00:00
Florian Hahn
1a850279c5
[LV] Re-compute cost of scalarized load users.
If there are direct memory op users of the newly scalarized load,
their cost may have changed because there's no scalarization
overhead for the operand. Update it.

This ensures assigning consistent costs to scalarized memory
instructions that themselves have scalarized memory instructions as
operands.
2025-10-01 22:30:18 +01:00
Alexey Bader
2d6e7ef567
[LV] Add additional tests for replicating load/store costs.
Includes test for https://github.com/llvm/llvm-project/issues/161404
2025-10-01 19:15:19 +01:00
Florian Hahn
8907b6d393
[VPlan] Remove original loop blocks if dead. (#155497)
Build on top of https://github.com/llvm/llvm-project/pull/154510 to
completely remove the blocks of dead scalar loops.

Depends on https://github.com/llvm/llvm-project/pull/154510. 

PR: https://github.com/llvm/llvm-project/pull/155497
2025-10-01 16:53:59 +00:00
Sam Tebbs
664b227089
[LV] Keep duplicate recipes in VPExpressionRecipe (#156976)
The VPExpressionRecipe class uses a set to store its bundled recipes. If
repeated recipes are bundled then the duplicates will be lost, causing
the following recipes to not be at the expected place in the set.

When printing a reduce.add(mul(ext, ext)) bundle, for example, if the
extends are the same then the 3rd element of the set will be the
reduction, rather than the expected mul, causing a cast error. With this
change, the recipes are at the expected index in the set.

Fixes #156464
2025-10-01 16:01:54 +01:00
Paul Walker
9e0c0a0939
[LLVM][SCEV] udiv (mul nuw a, vscale), (mul nuw b, vscale) -> udiv a, b (#157836) 2025-10-01 15:46:12 +01:00
Ramkumar Ramachandra
2f7252a841
[LV] Preserve GEP nusw when widening memory (#160885) 2025-09-30 10:42:45 +00:00
Florian Hahn
45ce88758d
[LV] Don't preserve LCSSA in SCEVExpander for runtime checks. (#159556)
LV does not preserve LCSSA, it constructs it just before processing a
loop to vectorize. Runtime check expressions are invariant to that loop,
so expanding them should not break LCSSA form for the loop we are about
to vectorize.

This fixes a crash when discarding instructions generated when expanding
runtime checks, if the expansion introduces LCSSA phis for values from
other loops which are not in LCSSA form: we would introduce new LCSSA
phis and update all outside users, some of which are not created by the
expander and cannot be cleaned up.

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

PR: https://github.com/llvm/llvm-project/pull/159556
2025-09-30 10:03:55 +00:00
Sam Tebbs
88658dbbc5
[LV] Add ExtNegatedMulAccReduction expression type (#160154)
This PR adds the ExtNegatedMulAccReduction expression type for
VPExpressionRecipe so that extend-multiply-accumulate reductions with a
negated multiply can be bundled.

Stacked PRs:

1. https://github.com/llvm/llvm-project/pull/156976
2. -> https://github.com/llvm/llvm-project/pull/160154
3. https://github.com/llvm/llvm-project/pull/147302
2025-09-30 10:10:37 +01:00
Florian Hahn
8dde784135
[LV] Add test for more precise no-free checks w/o nosync attribute.
Also filter out uninteresting parts from check lines.
2025-09-29 19:17:48 +01:00
Florian Hahn
b51b967671
[LV] Add test for more precise no-free checks. 2025-09-29 17:46:22 +01:00
Florian Hahn
71be13a6f0
[VPlan] Rewrite VPExpandSCEVExprs in replaceSymbolicStrides.
Extend replaceSymbolicStrides to also replace SCEVUnknowns in
VPExpandSCEVExprs using the information from StridesMaps.

This results in simpler SCEV expansions in some cases.
2025-09-28 21:55:31 +01:00
Florian Hahn
41a2dfc0d7
[VPlan] Allow multiple users of (broadcast %evl).
CSE may replace multiple redundant broadcasts of EVL with a single
broadcast which may have more than 1 user. Adjust the verifier to allow
this.

Fixes a crash when building llvm-test-suite with EVL:
https://lab.llvm.org/buildbot/#/builders/210/builds/3303
2025-09-27 21:47:54 +01:00
Florian Hahn
8460dbb450
[VPlan] Mark VPInstruction::Broadcast as not reading/writing memory.
This enables additional DCE/CSE opportunities and ensures that we don't
end up with multiple redundant users of a VPInstruction using EVL. It
fixes a verifier error in the added test_3_inductions test.
2025-09-27 20:48:42 +01:00
Florian Hahn
78af056137
[VPlan] Run CSE closer to VPlan::execute. (#160572)
Additional CSE opportunities are exposed after converting to concrete
recipes/dissolving regions and materializing various expressions. Run
CSE later, to capitalize on some of the late opportunities.

PR: https://github.com/llvm/llvm-project/pull/160572
2025-09-26 09:38:58 +00:00
Luke Lau
7275c178bd
[VPlan] Fix packed replication of struct types (#160274)
I ran into this crash when #158690 caused a loop with a struct call to
be vectorized.

If we have a replicate recipe in a branch-on-mask predicated region
that's used by a widened recipe in another block then it will be packed
together with the other lanes via a VPPredInstPHIRecipe.

If we're replicating a call with a struct return type then we currently
crash. The code that handles structs in packScalarIntoVectorizedValue
seemed to be untested at least on test/Transforms/LoopVectorize.

There's two places that need to be fixed. The poison value that the
scalar is packed into needs to use toVectorizedTy to correctly handle
structs (not to be confused with toVectorTy!)

The other is that VPPredInstPHIRecipe expects its operand to be an
InsertElementInstr when stringing together the different lanes. For
structs this will be an InsertVlaueInstr, and the value for the previous
lane will be at the back of a chain of InsertValueInstrs.
2025-09-26 02:22:15 +00:00
Ramkumar Ramachandra
4769e52bb6
[LV] Fixup a test after c1f8dbb (#160688)
Follow up on c1f8dbb ([LV] Add coverage for fixing-up scalar resume
values) to regenerate a test with UTC.
2025-09-25 12:04:26 +00:00
Ramkumar Ramachandra
c1f8dbb11c
[LV] Add coverage for fixing-up scalar resume values (#160492)
Increase coverage of the routine fixScalarResumeValuesFromBypass in the
case where the original scalar resume value is zero.

Co-authored-by: Florian Hahn <flo@fhahn.com>
2025-09-25 11:39:55 +01:00
Florian Hahn
ce63093e2b
[LV] Add partial reduction tests multiplying extend with constants. 2025-09-25 11:13:21 +01:00
Florian Hahn
70a26da639
[VPlan] Set correct flags when creating and cloning VPWidenCastRecipe.
Make sure that we set the correct wrap flags when creating new
VPWidenCastRecipes for truncs and preserve the flags from the recipe
directly when cloning, to make sure they are not dropped.

Fixes https://github.com/llvm/llvm-project/issues/160396
2025-09-25 09:00:47 +01:00
Florian Hahn
2016af5652
[VPlan] Create epilogue minimum iteration check in VPlan. (#157545)
Move creation of the minimum iteration check for the epilogue vector
loop to VPlan. This is a first step towards breaking up and moving
skeleton creation for epilogue vectorization to VPlan.

It moves most logic out of EpilogueVectorizerEpilogueLoop: the minimum
iteration check is created directly in VPlan, connecting the check
blocks from the main vector loop is done as post-processing. Next steps
are to move connecting and updating the branches from the check blocks
to VPlan, as well as updating the incoming values for phis.

Test changes are improvements due to folding of live-ins.

PR: https://github.com/llvm/llvm-project/pull/157545
2025-09-25 07:13:38 +00:00
Luke Lau
aa6a33ae65
[LV] Remove EVLIndVarSimplify pass (#160454)
Initially this was needed to replace the fixed-step canonical IV with
the variable-step EVL IV, but this was eventually superseded by the loop
vectorizer doing this transform itself in #147222. The pass was then
removed from the RISC-V pipeline in #151483 and the loop vectorizer
stopped emitting the metadata used by the pass in #155760, so now
there's no users of it.
2025-09-25 12:18:20 +08:00
Shilei Tian
2195fe7e01
[AMDGPU] Add the support for 45-bit buffer resource (#159702)
On new targets like `gfx1250`, the buffer resource (V#) now uses this
format:

```
base (57-bit): resource[56:0]
num_records (45-bit): resource[101:57]
reserved (6-bit): resource[107:102]
stride (14-bit): resource[121:108]
```

This PR changes the type of `num_records` from `i32` to `i64` in both
builtin and intrinsic, and also adds the support for lowering the new
format.

Fixes SWDEV-554034.

---------

Co-authored-by: Krzysztof Drewniak <Krzysztof.Drewniak@amd.com>
2025-09-24 11:12:02 -04:00
Ramkumar Ramachandra
844e47c60c
[LV] Fixup a test after 66fd420 (#160505)
Follow up on 66fd420 ([LV] Don't ignore invariant stores when costing)
to regen a test with UTC.
2025-09-24 11:56:18 +00:00