1116 Commits

Author SHA1 Message Date
Kiva
03ab85cb87
[InstCombine] fold gepi _, (srem x, y) to gepi _, (urem x, y) if y is power-of-2 (#180148)
This PR adds a small, targeted InstCombine fold for the pattern:
```
%idx = srem i64 %x, 2^k
%p   = getelementptr inbounds nuw i8, ptr %base, i64 %idx
```

When the GEP is inbounds + nuw, and the divisor is a non-zero
power-of-two constant, the signed remainder cannot produce a negative
offset without violating the inbounds/nuw constraints. In that case we
can canonicalize the index to a non-negative form and expose the common
power-of-two rewrite:

- Rewrite the GEP index from `srem %x, 2^k` to `urem %x, 2^k`
- Create a new GEP with the new index and replace the original GEP
- the `urem %x, 2^k` will further folds to `and %x (2^k-1)`

resulting the following pattern

```
%idx = and i64 %x, (2^k-1)
%p   = getelementptr inbounds nuw i8, ptr %base, i64 %idx
```

Fixes #180097.
generalized alive2 proof: https://alive2.llvm.org/ce/z/8EBxug
2026-02-09 22:26:07 +08:00
Rahul Joshi
017ca73917
[NFC][LLVM] Remove pass initialization from pass constructors (#180158) 2026-02-06 09:06:32 -08:00
Luke Lau
d8073d9b4b
[InstCombine] Bubble splices of binop operands to their result (#179432)
In #172961 we are trying to remove llvm.experimental.vp.reverse now that
llvm.vector.splice.right supports variable offsets.

A VP reverse reverses the first EVL elements of the vector, e.g.
01234567 -> 210xxxxx when EVL=3, where x=poison.

This can now be represented by splice.right(reverse(V), poison, EVL):

       01234567
    -> 76543210 (reverse)
    -> 210xxxxx (splice.right)

This PR implements the vp.reverse combines that pull through binops, but
generalized to vector.splice. Specifically, this implements the
following combines:

    Op(splice(V1, poison, offset), splice(V2, poison, offset)) -> splice(Op(V1, V2), poison, offset)
    Op(splice(V1, poison, offset), RHSSplat) -> splice(Op(V1, RHSSplat), poison, offset)
    Op(LHSSplat, splice(V2, poison, offset)) -> splice(Op(LHSSplat, V2), poison, offset)

We can then remove the vp.reverse intrinsic and its related combines
soon after, once we migrate the loop vectorizer over.
2026-02-04 06:09:49 +00:00
Snehasish Kumar
fc7ad8127a
[InstCombine][profcheck] Preserve !prof metadata when folding select. (#177707)
The new select `InstCombinerImpl::foldBinOpSelectBinOp` reuses the same
condition in the same BB as the original so the profile info can be
trivially copied over.
2026-01-27 23:21:00 -08:00
Snehasish Kumar
da3f2934c3
[InstCombine][profcheck] Propogate profile metadata when transforming br (X && !Y) to br (!X || Y) (#175939)
Updated visitBranchInst to propagate and swap !prof metadata when transforming br (X && !Y) to br (!X || Y).
2026-01-27 23:18:53 -08:00
Alan Zhao
e47e51a30a
[profcheck][InstCombine] Fix missing profile data identified by not.ll test (#176497)
Tracking issue: #147390
2026-01-21 10:06:29 -08:00
Mircea Trofin
071bd59bd4
[profcheck][instcombine] Propagate branch weigths in folded GEP (#176247)
Patch following #170439. The branch weigths of the new select are the same as of the original's.

Issue #147390
2026-01-15 22:08:31 +00:00
Jianjian Guan
b153f17b8a
[InstCombine] Fold chained GEP with constant base into single GEP (#170439)
Fixes https://github.com/llvm/llvm-project/issues/167014.
2026-01-15 17:25:05 +08:00
Antonio Frighetto
bf5975e2ba
[InstCombine] Restrain folding switch condition operation into case to one-use
It may be profitable to simplify the switch condition operation into
their cases if such a condition is used only by the switch.
2026-01-13 14:41:37 +01:00
Sayan Sivakumaran
9e1a185be4
[InstCombine] Fold intrinsics over multi-use selects when the intrinsic is the only user (#172723)
Closes #172176.

Previously, `FoldOpIntoSelect` wouldn't fold multi-use selects if
`MultiUse` wasn't explicitly true. This prevents useful folding when the
select is used multiple times in the same intrinsic call. Similar to
what is done in `foldOpIntoPhi`, we'll now check that all of the uses
come from a single user, rather than checking that there is only one
use.
2026-01-09 17:25:43 +01:00
Matt Arsenault
1f2663e1f2
InstCombine: Prepare to handle multiple uses in SimplifyDemandedFPClass (#174863)
Follow the structure of SimplifyDemandedBits. Doesn't handle anything
in the multiple use case for now, and continues just calling
computeKnownFPClass.
2026-01-08 17:35:23 +01:00
Antonio Frighetto
2d050f0143
[InstCombine] Canonicalize switch(X^C) expressions to switch(X)
`switch(X^C)` expressions can be folded to `switch(X)`. Minor
opportunity to generalize simplifications in `visitSwitchInst`
via an inverse function helper as well.

Proof: https://alive2.llvm.org/ce/z/TMRy_3.

Fixes: https://github.com/llvm/llvm-project/issues/174255.
Fixes: https://github.com/llvm/llvm-project/issues/143368.
2026-01-05 21:23:14 +01:00
Gábor Spaits
58822a6933
[InstCombine] Fold (select C, (x bin_op a), x) bin_op b into x bin_op select C, (a bin_op b), b (#173511)
Fixes #154246.

The original pattern in the issue was the following:
```llvm
define i8 @src(i8 %arg0, i8 %arg1) {
  %v0 = icmp eq i8 %arg1, -1
  %v1 = or i8 %arg0, 4
  %v2 = select i1 %v0, i8 %v1, i8 %arg0
  %v3 = or i8 %v2, 1
  ret i8 %v3
}
```
to
```llvm
define i8 @tgt(i8 %arg0, i8 %arg1) {
  %v0 = icmp eq i8 %arg1, -1
  %v3.v = select i1 %v0, i8 5, i8 1
  %v3 = or i8 %arg0, %v3.v
  ret i8 %v3
}
```
(Alive2: https://alive2.llvm.org/ce/z/Nq6b4)

This PR works with other binary operators too like `add` and `mul`.
2026-01-04 20:45:25 +01:00
Matt Arsenault
cbb2aa9b2d
InstCombine: Replace some isa<FPMathOperator> with dyn_cast (#172356)
This isa and get flag pattern is essentially an abstracted
isa and dyn_cast, so make this more direct.
2025-12-15 20:10:29 +00:00
Nikita Popov
09b0885569
[LangRef] Specify icmp on pointers to only compare address (#163936)
This changes LangRef to specify that pointer icmp only compares the
address bits of the pointers. That is, `icmp pred %a, %b` is equivalent
to `icmp pred ptrtoaddr(%a), ptrtoaddr(%b)`.

Similarly, it specifies that the `nonnull` attribute requires that the
address bits are non-zero.

There are a couple of motivations for this:

* For inequality comparisons, this is really the only sensible
semantics. Relational comparison of address and metadata bits as a
single integer is generally meaningless (unless the metadata bits are
equal).
* This matches (as far as I understand) the behavior of existing CHERI
implementations.
* LLVM can only reason about the address bits. These semantics allow
pointers with non-address bits to receive essentially the same
comparison optimization support as ordinary pointers.

In terms of implementation, this PR adjusts:
 * The AMDGPULowerBufferFatPointers pass.
* An InstCombine fold that may replace pointers with different
non-address bits.
 * The fold that replaces pointers based on dominating pointer equality.

It does not adjust:
* ISel, because we don't have in-tree targets where we can show a
difference.
* Various icmp+ptrtoint transforms, because we'll have to change this
code for ptrtoaddr optimization support anyway, and these changes are
tightly related.

Related discussion starting from:
https://discourse.llvm.org/t/clarifiying-the-semantics-of-ptrtoint/83987/60?u=nikic
2025-12-04 15:24:23 +00:00
Florian Hahn
700b77b5e5
[InstCombine] Don't sink if it would require dropping deref assumptions. (#166945)
Currently sinking assumes in instcombine drops assumes if they would
prevent sinking. Removing dereferenceable assumptions earlier on can
inhibit vectorization of early-exit loops in practice.

Special-case deferenceable assumptions so that they block sinking. This
can be combined with a separate change to drop dereferencebale
assumptions after vectorization: https://clang.godbolt.org/z/jGqcx3sbs

PR: https://github.com/llvm/llvm-project/pull/166945
2025-11-09 21:08:46 +00:00
Andreas Jonson
b9ea93cd5c
[InstCombine] Fold operation into select, when one operand is zext of select's condition (#166816)
Proof https://alive2.llvm.org/ce/z/oCQyTG
2025-11-08 15:22:32 +01:00
Gábor Spaits
628d53aba5
[InstCombine] Enable FoldOpIntoSelect and foldOpIntoPhi when the Op's other parameter is non-const (#166102)
This patch enables `FoldOpIntoSelect` and `foldOpIntoPhi` for the cases
when Op's second parameter is a non-constant.
It doesn't seem to bring significant improvements, but the compile
time impact is neglegable.
2025-11-05 10:04:32 +01:00
Nikita Popov
de9e18dc75
[InstCombine] Handle ptrtoaddr in gep of pointer sub fold (#164818)
This extends the `ptradd x, ptrtoint(y) - ptrtoint(x)` to `y`
InstCombine fold to support ptrtoaddr. In the case where x and y have
the same underlying object, this is handled by InstSimplify already. If
the underlying object may differ, the replacement can only be performed
if provenance does not matter.

For pointers with non-address bits we need to be careful here, because
the pattern will return a pointer with the non-address bits of x and the
address bits of y. As such, uses in ptrtoaddr are safe to replace, but
uses in ptrtoint are not. Whether uses in icmp are safe to replace
depends on the outcome of the pending discussion on icmp semantics (I'll
adjust this in https://github.com/llvm/llvm-project/pull/163936 if/when
that lands).
2025-10-27 09:16:48 +01:00
Benjamin Maxwell
8ebec3d551
[InstCombine] Constant fold binops through vector.insert (#164624)
This patch improves constant folding through `llvm.vector.insert`. It
does not change anything for fixed-length vectors (which can already be
folded to ConstantVectors for these cases), but folds scalable vectors
that otherwise would not be folded.

These folds preserve the destination vector (which could be undef or
poison), giving targets more freedom in lowering the operations.
2025-10-24 09:03:40 +01:00
Benjamin Maxwell
c80495c1b0
[InstCombine] Allow folding cross-lane operations into PHIs/selects (#164388)
Previously, cross-lane operations were disallowed here, but they are
only problematic if the `select` condition is a vector, as the input of
the operation is not simply one of the arms of the phi/select.
2025-10-23 09:27:57 +01:00
Nikita Popov
af4367a6db
[InstCombine] Skip foldFBinOpOfIntCastsFromSign for vector ops (#162804)
Converting a vector float op into a vector int op may be non-profitable,
especially for targets where the float op for a given type is legal, but
the integer op is not.

We could of course also try to address this via a reverse transform in
the backend, but I don't think it's worth the bother, given that vectors
were never the intended use case for this transform in the first place.

Fixes https://github.com/llvm/llvm-project/issues/162749.
2025-10-13 10:13:34 +02:00
Mircea Trofin
8aa49974df
[NFC][InstCombine] Make use of unknown profile info clear in the API name (#162766)
Making the choice more clear from the API name, otherwise it'd be very easy for one to just "not bother" with the `MDFrom`​, especially since it is optional and follows the optional `Name`​ - but this time we'd have a harder time detecting it's effectivelly dropped metadata.
2025-10-10 09:33:45 -07:00
Cullen Rhodes
100db53856
[InstCombine][nfc] Remove dead invoke inst check in foldOpIntoPhi (#161871)
There's a check above the pred block is terminated with an unconditional
branch, so this code is unreachable.
2025-10-08 09:44:57 +01:00
Rahul Joshi
9ebf1e9175
[NFC][InstCombine] Fix namespace usage in InstCombine (#161902) 2025-10-04 05:28:24 -07:00
Nicolai Hähnle
11a4b2d950
Cleanup the LLVM exported symbols namespace (#161240)
There's a pattern throughout LLVM of cl::opts being exported. That in
itself is probably a bit unfortunate, but what's especially bad about it
is that a lot of those symbols are in the global namespace. Move them
into the llvm namespace.

While doing this, I noticed some other variables in the global namespace
and moved them as well.
2025-10-01 15:32:07 -07:00
Yingwei Zheng
73d9974c91
[InstCombine] Avoid self-replacing in getUndefReplacement (#161500)
Self-replacing has a different meaning in InstCombine. It will replace
all uses with poison.
Closes https://github.com/llvm/llvm-project/issues/161492.
2025-10-01 22:02:30 +08:00
mikael-nilsson-arm
69586331e8
[InstCombine] Opt phi(freeze(undef), C) -> phi(C, C) (#161181)
Try to choose a value for freeze that enables the PHI to be replaced
with its input constants if they are equal.
2025-10-01 10:13:42 +02:00
Alan Zhao
045e09f22b
[InstCombine] Set !prof metadata on Selects identified by add.ll test (#158743)
These select instructions are created from non-branching instructions,
so their branch weights are unknown.

Tracking issue: #147390
2025-09-29 20:37:06 +00:00
Alan Zhao
b5afe416c7
[InstCombine] Preserve profile data with select instructions and binary operators (#158375)
Tracking issue: #147390
2025-09-15 20:12:08 +00:00
Nikita Popov
a301e1a895
[InstCombine] Split GEPs with multiple non-zero offsets (#151333)
Split GEPs that have more than one non-zero offset into two GEPs. This
is in preparation for the ptradd migration, which can only represent
such GEPs.

This also enables CSE and LICM of the common base.
2025-09-10 16:51:58 +02:00
Hongyu Chen
75b0c89e62
[InstCombine][VectorCombine][NFC] Unify uses of lossless inverse cast (#156597)
This patch addresses
https://github.com/llvm/llvm-project/pull/155216#discussion_r2297724663.
This patch adds a helper function to put the inverse cast on constants,
with cast flags preserved(optional).
Follow-up patches will add trunc/ext handling on VectorCombine and flags
preservation on InstCombine.
2025-09-08 13:30:06 +00:00
Nikita Popov
349523e26b
[InstCombine] Merge constant offset geps across variable geps (#156326)
Fold:

    %gep1 = ptradd %p, C1
    %gep2 = ptradd %gep1, %x
    %res = ptradd %gep2, C2

To:

    %gep = ptradd %gep, %x
    %res = ptradd %gep, C1+C2

An alternative to this would be to generally canonicalize constant
offset GEPs to the right. I found the results of doing that somewhat
mixed, so I'm going for this more obviously beneficial change for now.

Proof for flag preservation on reassociation:
https://alive2.llvm.org/ce/z/gmpAMg
2025-09-03 10:47:32 +02:00
Kazu Hirata
a36a4019d3
[InstCombine] Remove unnecessary casts (NFC) (#156394)
These variables are already non const.
2025-09-01 23:12:07 -07:00
Nikita Popov
055bfc0271
[InstCombine] Strip leading zero indices from GEP (#155415)
GEPs are often in the form `gep [N x %T], ptr %p, i64 0, i64 %idx`.
Canonicalize these to `gep %T, ptr %p, i64 %idx`.

This enables transforms that only support one GEP index to work and
improves CSE.

Various transforms were recently hardened to make sure they still work
without the leading index.
2025-09-01 09:58:11 +02:00
Nikita Popov
f8f6965cee
[InstCombine] Allow freezing multiple operands (#154336)
InstCombine tries to convert `freeze(inst(op))` to `inst(freeze(op))`.
Currently, this is limited to the case where a single operand needs to
be frozen, and all other operands are guaranteed non-poison.

This patch allows the transform even if multiple operands need to be
frozen. The existing limitation makes sure that we do not increase the
total number of freezes, but it also means that that we may fail to
eliminate freezes (via poison flag dropping) and may prevent
optimizations (as analysis generally can't look past freeze). Overall, I
believe that aggressively pushing freezes upwards is more beneficial
than harmful.

This is the middle-end version of #145939 in DAGCombine (which is
currently reverted for SDAG-specific reasons).
2025-08-25 12:58:39 +02:00
Nikita Popov
09dc08b707 [InstCombine] Handle repeated users in foldOpIntoPhi()
If the phi is used multiple times in the same user, it will appear
multiple times in users(), in which case make_early_inc_range()
is insufficient to prevent iterator invalidation.

Fixes the issue reported at:
https://github.com/llvm/llvm-project/pull/151115#issuecomment-3141542852
2025-08-01 11:07:06 +02:00
Nikita Popov
d4d2d7d785
[InstCombine] Preserve nuw in canonicalizeGEPOfConstGEPI8() (#151533)
Proof: https://alive2.llvm.org/ce/z/4j8U3f
2025-08-01 09:40:03 +02:00
Nikita Popov
a71909156e
[InstCombine] Set flags when canonicalizing GEP indices (#151516)
When truncating set nsw/nuw based on nusw/nuw. When extending, use zext
nneg if nusw+nuw.

Proof: https://alive2.llvm.org/ce/z/JA2Yzr
2025-07-31 15:58:04 +02:00
Nikita Popov
16d73839b1
[InstCombine] Support folding intrinsics into phis (#151115)
Call foldOpIntoPhi() for speculatable intrinsics. We already do this for
FoldOpIntoSelect().

Among other things, this partially subsumes
https://github.com/llvm/llvm-project/pull/149858.
2025-07-31 12:32:37 +02:00
Nikita Popov
385fe30ee0
[InstCombine] Strip trailing zero GEP indices (#151338)
Zero indices at the end do not change the GEP offset and can be removed.

(Doing the same at the start requires adjusting the source element
type.)
2025-07-30 17:55:00 +02:00
Nikita Popov
8a09adc22a
[InstCombine] Split GEPs with multiple variable indices (#137297)
Split GEPs that have more than one variable index into two. This is in
preparation for the ptradd migration, which will not support multi-index
GEPs.

This also enables the split off part to be CSEd and LICMed.
2025-07-30 12:54:06 +02:00
Jeremy Morse
c9ceb9b75f
[DebugInfo] Remove intrinsic-flavours of findDbgUsers (#149816)
This is one of the final remaining debug-intrinsic specific codepaths
out there, and pieces of cross-LLVM infrastructure to do with debug
intrinsics.
2025-07-21 17:49:25 +01:00
Nikita Popov
a216702406
[InstCombine] Merge one-use GEP offsets during expansion (#147263)
When expanding a GEP chain, if there is a chain of one-use GEPs followed
by a multi-use GEP, rewrite the multi-use GEP to include the one-use
GEPs offsets.

This means the offsets from the one-use GEPs can be reused by the offset
expansion without additional cost (from computing them again with a
different reassociation).
2025-07-21 10:49:38 +02:00
Jeremy Morse
c9d8b68676
[DebugInfo] Suppress lots of users of DbgValueInst (#149476)
This is another prune of dead code -- we never generate debug intrinsics
nowadays, therefore there's no need for these codepaths to run.

---------

Co-authored-by: Nikita Popov <github@npopov.com>
2025-07-18 11:31:52 +01:00
Jeremy Morse
2a1869b981
[DebugInfo] Shave even more users of DbgVariableIntrinsic from LLVM (#149136)
At this stage I'm just opportunistically deleting any code using
debug-intrinsic types, largely adjacent to calls to findDbgUsers. I'll
get to deleting that in probably one or more two commits.
2025-07-18 08:25:10 +01:00
Jeremy Morse
5328c732a4
[DebugInfo] Strip more debug-intrinsic code from local utils (#149037)
SROA and a few other facilities use generic-lambdas and some overloaded
functions to deal with both intrinsics and debug-records at the same time.
As part of stripping out intrinsic support, delete a swathe of this code
from things in the Utils directory.

This is a large diff, but is mostly about removing functions that were
duplicated during the migration to debug records. I've taken a few
opportunities to replace comments about "intrinsics" with "records",
and replace generic lambdas with plain lambdas (I believe this makes
it more readable).

All of this is chipping away at intrinsic-specific code until we get to
removing parts of findDbgUsers, which is the final boss -- we can't
remove that until almost everything else is gone.
2025-07-16 14:13:53 +01:00
Cullen Rhodes
7392a546bb
[InstCombine] Treat identical operands as one in pushFreezeToPreventPoisonFromPropagating (#145348)
To push a freeze through an instruction, only one operand may produce
poison. However, this currently fails for identical operands which are
treated as separate. This patch fixes this by treating them as a single
operand.
2025-07-16 13:35:40 +01:00
Jeremy Morse
5b8c15c6e7
[DebugInfo] Remove getPrevNonDebugInstruction (#148859)
With the advent of intrinsic-less debug-info, we no longer need to
scatter calls to getPrevNonDebugInstruction around the codebase. Remove
most of them -- there are one or two that have the "SkipPseudoOp" flag
turned on, however they don't seem to be in positions where skipping
anything would be reasonable.
2025-07-16 11:41:32 +01:00
Nikita Popov
2dc44b3a7b
[InstCombine] Fix multi-use handling for multi-GEP rewrite (#146689)
If we're expanding offsets for a chain of GEPs in RewriteGEPs mode, we
should also rewrite GEPs that have one-use themselves, but are kept
alive by a multi-use GEP later in the chain.

For the sake of simplicity, I've changed this to just skip the one-use
condition entirely (which will perform an unnecessary rewrite of a no
longer used GEP, but shouldn't otherwise matter).
2025-07-02 16:45:27 +02:00