7002 Commits

Author SHA1 Message Date
Florian Hahn
8a8d65a0c5
[VPlan] Consistently use MinOrMax* in VPlanConstruction transforms (NFC)
Make sure variables/functions consistently use MinOrMax*, as suggested
in https://github.com/llvm/llvm-project/pull/170223. Split off from the
PR.
2026-01-14 21:19:24 +00:00
Florian Hahn
90961df83b
[VPlan] Strip phi operand from compute-reduction-result comments (NFC).
After d5c11b9a24c84f1, compute-reduction-result does not have the
reduction phi recipe as operand. Update stale comments pointed out
independently in https://github.com/llvm/llvm-project/pull/175461.
2026-01-14 19:39:43 +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
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
Luke Lau
0ae23ca9e6
[VPlan] Split out optimizeEVLMasks. NFC (#174925)
Addresses part of #153144 and splits off part of #166164

There are two parts to the EVL transform:

1) Convert the loop so the number of elements processed each iteration
is EVL, not VF. The IV and header mask are replaced with EVL-based
variants.
2) Optimize users of the EVL based header mask to VP intrinsic based
recipes.

(1) changes the semantics of the vector loop region, whereas (2) needs
to preserve them. This splits (2) out so we don't mix the two up, and
allows us to move (1) earlier in the pipeline in a future PR.
2026-01-14 07:01:14 +00:00
Ramkumar Ramachandra
d69335bac9
[LLVM] Clean up code using [not_]equal_to (NFC) (#175824)
Use llvm::[not_]equal_to landed in d2a521750 ([ADT] Introduce
bind_{front,back}, [not_]equal_to, #175056) across LLVM for cleaner
code.
2026-01-13 21:19:39 +00:00
Ramkumar Ramachandra
bd2cfc52e4
[PatternMatch] Implement match_fn using bind_back (NFC) (#175811)
Use llvm::bind_back landed in d2a521750 ([ADT] Introduce
bind_{front,back}, [not_]equal_to, #175056) to simplify implementations
of match_fn in PatternMatch and VPlanPatternMatch.
2026-01-13 20:55: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
Florian Hahn
d27d75ee94
[VPlan] Use createHeaderPHIRecipes in native path (NFCI).
Simplify tryToBuildVPlan by using createHeaderPHIRecipes in the native
path as well.
2026-01-13 20:12:21 +00:00
Pankaj Dwivedi
8246257cac
Reapply "[VectorCombine] Fold scalar selects from bitcast into vector select" (#174762)
Reapply https://github.com/llvm/llvm-project/pull/173990 with fixes for
post-commit review comments.

---------

Co-authored-by: padivedi <padivedi@amd.com>
Co-authored-by: Christudasan Devadasan <christudasan.devadasan@amd.com>
2026-01-13 16:25:09 +05:30
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
Florian Hahn
f9a8096067
[VPlan] Merge Select with previous cases in ::computeCost (NFC).
Merge cases calling the same helper, as suggested post-commit in
https://github.com/llvm/llvm-project/pull/174234
2026-01-12 22:19:28 +00:00
Florian Hahn
564c0c169f
[VPlan] Cache other type for VPWidenRecipe with Select opcode (NFC).
Add back caching + assertions after landing
https://github.com/llvm/llvm-project/pull/174234.
2026-01-12 20:39:52 +00:00
Julian Pokrovsky
38cb7ddca2
[VectorCombine] foldPermuteOfIntrinsic - support multiple uses of shuffled ops (#175299)
Fixes #173039
2026-01-12 20:34:06 +00:00
Florian Hahn
acf82c1083
[VPlan] Check for store group once in VPInterleaveBase() (NFC)
Avoid repeated check as suggeted independently in
https://github.com/llvm/llvm-project/pull/172758.
2026-01-12 19:27:04 +00:00
Luke Lau
123b6a2766
[VPlan] Give VPInstruction::ExplicitVectorLength name. NFC (#175493)
This makes it a tad easier to read VPlan dumps, e.g.

    WIDEN vp.store vp<%7>, ir<%val>, vp<%5>
    ->
    WIDEN vp.store vp<%7>, ir<%val>, vp<%evl>
2026-01-13 00:05:30 +08: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
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
Alexey Bataev
a96cda0e33 [SLP]Update deps for copyables operands, if the user is used several times in node
If the user instruction is used several times in the node, and in one
cases its operand is copyable, but in another is not, need to check all
operands to be sure we do not miss scheduling
2026-01-09 15:18:31 -08: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
Florian Hahn
a5fcd840e7
[VPlan] Document getSplatVFValue (NFC).
Document helper, as suggested independently in
https://github.com/llvm/llvm-project/pull/174234.
2026-01-09 20:47:52 +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
Alexey Bataev
125a53ce59 Revert "[SLP]Update deps for copyables operands, if the user is used several times in node"
This reverts commit 6e1acd061e74f44df6d53d54c78d1e50790456a8 to fix
crashes detected in  https://lab.llvm.org/buildbot/#/builders/25/builds/14678.
2026-01-08 14:15:25 -08:00
Florian Hahn
8c830d3117
[VPlan] Merge cases inferring type of operand 0 (NFC).
Merge all cases that infer the scalar type of operand 0 in
inferScalarTypeForRecipe(const VPInstruction).
2026-01-08 21:03:00 +00:00
Alexey Bataev
6e1acd061e [SLP]Update deps for copyables operands, if the user is used several times in node
If the user instruction is used several times in the node, and in one
cases its operand is copyable, but in another is not, need to check all
operands to be sure we do not miss scheduling
2026-01-08 12:50:32 -08:00
Alex Bradbury
3ae71d30be
[SLP] Use ConstantInt::getSigned for stride argument to strided load/store intrinsics (#175007)
strided-stores-vectorized.ll crashes for RV32 without fixing the
relevant logic in vectorizeTree, because the argument can't be
represented as a 32-bit unsigned value:
```
llvm::APInt::APInt(unsigned int, uint64_t, bool, bool): Assertion `llvm::isUIntN(BitWidth, val) && "Value is not an N-bit unsigned value"' failed.
```

It is intended to be signed, so we simply use ConstantInt::getSigned
instead. This fixes other stride-related instances in the file as well.
For further context, this change is part of unblocking rv32gcv
llvm-test-suite in CI.
2026-01-08 16:45:02 +00:00
Alexey Bataev
9fb45c5959 [SLP]Do not generate extractelement subnodes with the same indeces
The compiler should not generate subvectors with the same extractelement
instructions, it may cause a crash and leads to inefficient
vectorization.

Fixes #174773
2026-01-08 07:23:06 -08:00
Ramkumar Ramachandra
78f1de803a
[VPlan] Strip iterator-invalidation guard in findHeaderMask (NFC) (#174930)
It is unnecessary, as the users are never modified.
2026-01-08 09:42:18 +00:00
Florian Hahn
4998280c3f
[LV] Find reduction result VPInstruction from backedge value (NFC).
Split off from https://github.com/llvm/llvm-project/pull/174026. Make
the lookup of the reduction phi recipe/compute-reduction-result
VPInstruction independent of the latter having the reduction phi as
operand.
2026-01-07 21:12:07 +00:00
Florian Hahn
31b93d6e38
[VPlan] Add specialized VPValue subclasses for different types (NFC) (#172758)
This patch adds VPValue sub-classes for the different cases we currently
have:
 * VPIRValue: A live-in VPValue that wraps an underlying IR value
* VPSymbolicValue: A symbolic VPValue not tied to an underlying value,
e.g. the vector trip count or VF VPValues
 * VPRecipeValue: A VPValue defined by a VPDef/VPRecipeBase.

This has multiple benefits:
 * clearer constructors for each kind of VPValue
* limited scope: for example allows moving VPDef member to VPRecipeValue,
reducing size of other VPValues.
* stricter type checking for member variables (e.g. using VPLiveIn in
the Value -> live-in map in VPlan, or using VPSymbolicValue for symbolic
member VPValues)

There probably are additional opportunities for cleanups as follow-ups.

PR: https://github.com/llvm/llvm-project/pull/172758
2026-01-07 20:29:05 +00:00
Alexey Bataev
39456e4226 [SLP]Do not increment dep count for non-schedulable nodes with non-schedulable parents
If the node is non-scedulable, all instructions are used outside only
and parent is non-schedulable non-phi node, the dependency count should be
increased for such nodes

Fixes #174599
2026-01-07 10:26:19 -08:00
Pankaj Dwivedi
1ab7b6655d
Revert "[VectorCombine] Fold scalar selects from bitcast into vector select" (#174758)
Reverts llvm/llvm-project#173990
Reverting to address post-commit review feedback. Will recommit with
fixes.
2026-01-07 18:59:32 +05:30
David Sherwood
97ee9b66c0
[LV] Teach m_One, m_ZeroInt patterns to look through broadcasts (#170159)
In VPlanPatternMatch.h I have changed the int_pred_ty code to look
through broadcasts in order to catch more cases, i.e. multiplying by a
splat of one, etc.
2026-01-07 10:35:08 +00:00
Pankaj Dwivedi
72f18a05d6
[VectorCombine] Fold scalar selects from bitcast into vector select (#173990) 2026-01-07 15:16:33 +05:30
Shih-Po Hung
39d6f10e33
[LV] Conservatively predicate SDiv/SRem (#170818)
Conservatively predicate sdiv/srem:
- RHS may carry poison in masked‑off lanes.
- RHS could be −1 while LHS has masked‑off lanes (risking INT_MIN/−1
overflow).

We’ll relax this once we can prove non‑wrap/non‑poison conditions.

Fixes #170775.
2026-01-07 04:25:38 +00:00
Aiden Grossman
c2d060c50e
[VPlan] Mark variable unused in release build [[maybe_unused]] (#174648)
To prevent compiler warnings when building without assertions turned on.
2026-01-06 21:27:55 +00:00
Ramkumar Ramachandra
d12e99376f
Reland [VPlan] Simplify pow-of-2 (mul|udiv) -> (shl|lshr) (#174581)
The original patch, landed as a2db31b0 ([VPlan] Simplify pow-of-2
(mul|udiv) -> (shl|lshr), #172477) had a critical commutative matcher
bug, which has now been fixed. An assert has also been strengthened,
following a post-commit review.
2026-01-06 20:36:26 +00:00
Florian Hahn
01d34eb38f
[VPlan] Only use isAddressSCEVForCost in legacy getAddressAccSCEV (NFCI)
Follow-up to https://github.com/llvm/llvm-project/pull/171204 and
1f331e453f to only rely on isAddressSCEVForCost in legacy isAddressSCEVForCost,
completely aligning the decisions of VPlan and legacy cost model.
2026-01-06 19:18:13 +00:00
Ramkumar Ramachandra
bdc7681d63
[VPlan] Restore all-operands-inv WidenGEP logic (#174416)
Restore the all-operands-invariant handling in WidenGEP::execute prior
to 37f7b31 (Reland [VPlan] Handle WidenGEP in narrowToSingleScalars), as
crashes have been reported.

Fixes #173761.
2026-01-06 13:05:37 +00:00
Alex Bradbury
5a456c17d9
Revert "[VPlan] Simplify pow-of-2 (mul|udiv) -> (shl|lshr)" (#174559)
Reverts llvm/llvm-project#172477

This is causing failures for RVA23 (including some tests running away in
their execution causing OOM, hence the builder dying). I will attempt to
follow up on the PR with a reproducer of some kind.
https://lab.llvm.org/buildbot/#/builders/210/builds/7243
2026-01-06 10:26:51 +00:00
Ramkumar Ramachandra
a2db31b06f
[VPlan] Simplify pow-of-2 (mul|udiv) -> (shl|lshr) (#172477) 2026-01-06 08:27:48 +00:00
Nikita Popov
707d18c8e7
[VPlan] Use getSigned() for index in VectorEndPointer recipe (#174426)
The stride can be negative here, so we should use getSigned().

This avoids an assertion failure with
https://github.com/llvm/llvm-project/pull/171456. It also avoids a
miscompile if the index is >64-bit, but I don't think that can happen in
practice.
2026-01-06 09:10:59 +01:00
Florian Hahn
16830b2164
[VPlan] Remove VPWidenSelectRecipe, use VPWidenRecipe instead (NFCI). (#174234)
All extra state has been removed from VPWidenSelectRecipe at this point.
There's no benefit of having a separate recipe and Select can easily be
handled by the existing VPWidenRecipe.

PR: https://github.com/llvm/llvm-project/pull/174234
2026-01-05 22:33:37 +00:00
Ryan Buchner
f180d4bb46
[SLP] Report the correct operand to getArithmeticInstrCost() when duplicated scalars (#174442)
Before, we were selecting the wrong operand in cases when Scalars
contained duplicate values. Stems from #135797.

Using:
`opt -passes=slp-vectorizer -mtriple=riscv64 -mattr=+v t.ll`
```
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64"

define void @foo(ptr noalias %A, ptr noalias %B) {
entry:
  %0 = load i32, ptr %B
  %add = add nsw i32 %0, 1
  store i32 %add, ptr %A
  %arrayidx.1 = getelementptr inbounds nuw i8, ptr %B, i64 4
  %1 = load i32, ptr %arrayidx.1
  %add.1 = add nsw i32 %1, 1
  %arrayidx2.1 = getelementptr inbounds nuw i8, ptr %A, i64 4
  store i32 %add.1, ptr %arrayidx2.1
  %arrayidx.2 = getelementptr inbounds nuw i8, ptr %B, i64 8
  %2 = load i32, ptr %arrayidx.2
  %add.2 = add nsw i32 %2, 1
  %arrayidx2.2 = getelementptr inbounds nuw i8, ptr %A, i64 8
  store i32 %add.2, ptr %arrayidx2.2
  %arrayidx.3 = getelementptr inbounds nuw i8, ptr %B, i64 12

  %arrayidx2.3 = getelementptr inbounds nuw i8, ptr %A, i64 12

  store i32 %add, ptr %arrayidx2.3
  %arrayidx.4 = getelementptr inbounds nuw i8, ptr %B, i64 16
  %4 = load i32, ptr %arrayidx.4
  %add.4 = add nsw i32 %4, 1
  %arrayidx2.4 = getelementptr inbounds nuw i8, ptr %A, i64 16
  store i32 %add.4, ptr %arrayidx2.4
  %arrayidx.5 = getelementptr inbounds nuw i8, ptr %B, i64 20
  %5 = load i32, ptr %arrayidx.5
  %add.5 = add nsw i32 %5, 1
  %arrayidx2.5 = getelementptr inbounds nuw i8, ptr %A, i64 20
  store i32 %add.5, ptr %arrayidx2.5
  %arrayidx.6 = getelementptr inbounds nuw i8, ptr %B, i64 24
  %6 = load i32, ptr %arrayidx.6
  %add.6 = add nsw i32 %6, 1
  %arrayidx2.6 = getelementptr inbounds nuw i8, ptr %A, i64 24
  store i32 %add.6, ptr %arrayidx2.6
  %arrayidx.7 = getelementptr inbounds nuw i8, ptr %B, i64 28
  %7 = load i32, ptr %arrayidx.7
  %add.7 = add nsw i32 %7, 1
  %arrayidx2.7 = getelementptr inbounds nuw i8, ptr %A, i64 28
  store i32 %add.7, ptr %arrayidx2.7
  ret void
}
```

The following trace is produced, note the wrong operand is used for `Idx
> 2`

Before:
```
GetScalarCost(), Idx=0
UniqueValues[Idx]:   %add = add nsw i32 %0, 1
Op1:   %0 = load i32, ptr %B, align 4
GetScalarCost(), Idx=1
UniqueValues[Idx]:   %add.1 = add nsw i32 %1, 1
Op1:   %1 = load i32, ptr %arrayidx.1, align 4
GetScalarCost(), Idx=2
UniqueValues[Idx]:   %add.2 = add nsw i32 %2, 1
Op1:   %2 = load i32, ptr %arrayidx.2, align 4
GetScalarCost(), Idx=3
UniqueValues[Idx]:   %add.4 = add nsw i32 %3, 1
Op1:   %0 = load i32, ptr %B, align 4
GetScalarCost(), Idx=4
UniqueValues[Idx]:   %add.5 = add nsw i32 %4, 1
Op1:   %3 = load i32, ptr %arrayidx.4, align 4
GetScalarCost(), Idx=5
UniqueValues[Idx]:   %add.6 = add nsw i32 %5, 1
Op1:   %4 = load i32, ptr %arrayidx.5, align 4
GetScalarCost(), Idx=6
UniqueValues[Idx]:   %add.7 = add nsw i32 %6, 1
Op1:   %5 = load i32, ptr %arrayidx.6, align 4
```

After:
```
GetScalarCost(), Idx=0
UniqueValues[Idx]:   %add = add nsw i32 %0, 1
Op1:   %0 = load i32, ptr %B, align 4
GetScalarCost(), Idx=1
UniqueValues[Idx]:   %add.1 = add nsw i32 %1, 1
Op1:   %1 = load i32, ptr %arrayidx.1, align 4
GetScalarCost(), Idx=2
UniqueValues[Idx]:   %add.2 = add nsw i32 %2, 1
Op1:   %2 = load i32, ptr %arrayidx.2, align 4
GetScalarCost(), Idx=3
UniqueValues[Idx]:   %add.4 = add nsw i32 %3, 1
Op1:   %3 = load i32, ptr %arrayidx.4, align 4
GetScalarCost(), Idx=4
UniqueValues[Idx]:   %add.5 = add nsw i32 %4, 1
Op1:   %4 = load i32, ptr %arrayidx.5, align 4
GetScalarCost(), Idx=5
UniqueValues[Idx]:   %add.6 = add nsw i32 %5, 1
Op1:   %5 = load i32, ptr %arrayidx.6, align 4
GetScalarCost(), Idx=6
UniqueValues[Idx]:   %add.7 = add nsw i32 %6, 1
Op1:   %6 = load i32, ptr %arrayidx.7, align 4
```
2026-01-05 22:25:25 +00:00