~sext(A) & Op1 --> A ? 0 : Op1
With no extra uses, this pattern is already reduced,
but we would miss it in examples such as issue #59773.
https://alive2.llvm.org/ce/z/WGLcSR
As per post-commit feedback - we generally do not like Constant Expressions,
and trying to deal with them leads to inconsistent results
that may very well be non-optimal. So just don't.
`canFreelyInvertAllUsersOf()`, in general, does not make sense
for constants, and constant expressions are likely even more problematic.
For those, we just want to create a simple constant expression and be done.
Fixes https://github.com/llvm/llvm-project/issues/59613
and (fcmp ord x, 0), (fcmp u* x, inf) -> fcmp o* x, inf
and (fcmp ord x, 0), (fcmp u* fabs(x), inf) -> fcmp o* x, inf
Clang emits this peculiar pattern as an isfinite check in
__builtin_isnormal which can be simplified. We should fix clang to
emit this in the first place, but should also fold it here.
The important bit here is that we gracefully handle other uses,
iff they can be adapted to inversion.
I'll note, the previous logic was actively bad,
it increased instruction count since it didn't actually ensure
that the inversions happened.
Matches what we do for binary operations, but a special care needs
is needed to preserve operand order, as the logical operations
are not strictly commutative!
This reverts commit 492c471839a66e354ebe696bd3e15f7477c63613.
As pointed out by nloped, the transform in f2 is not correct: If
%shr is poison, then freeze may result in a negative value. The
transform is correct in the case where the freeze is pushed through
the operation in a way that guarantees the result is non-negative,
which is the case I had tested.
Move logical operators on pairs of llvm.is.fpclass on the same value
into the test mask of a single is_fpclass.
or (class x, mask0), (class x, mask1) -> class x, (mask0 | mask1)
and (class x, mask0), (class x, mask1) -> class x, (mask0 & mask1)
xor (class x, mask0), (class x, mask1) -> class x, (mask0 ^ mask1)
The and/or cases should appear frequently in the builtin math
libraries; haven't seen the xor case but handle it for completeness.
This is largely just for the sake of completeness. For logical ops,
this is mostly subsumed by foldSelectValueEquivalence() in a more
generic way. The only exception is vector support, as select
value equivalence folding currently doesn't support this for the
case where the replacement does not simplify.
This patch mechanically replaces None with std::nullopt where the
compiler would warn if None were deprecated. The intent is to reduce
the amount of manual work required in migrating from Optional to
std::optional.
This is part of an effort to migrate from llvm::Optional to
std::optional:
https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
~(A & ?) | (A ^ B) --> ~((A & ?) & B)
https://alive2.llvm.org/ce/z/mxex6V
This is similar to 9d218b61cc50 where we peeked through
another logic op to find a common operand.
When X is a power-of-two or zero and zero input is poison:
ctlz(i32 X) ^ 31 --> cttz(X)
cttz(i32 X) ^ 31 --> ctlz(X)
https://alive2.llvm.org/ce/z/Cs7sFE
For (X op Y) op Z --> (Y op Z) op X
we can still do transform when Y is multi-use. In D131356 limit it to one-use,
this patch remove this limit.
This is still not a complete solution, I add a todo test to show it.
In this case, X and Y are both multi use, we can't differentiate how to convert based on this.
But at least we don't make the code worse,and it can solve half the scenarios.
If the shift constant has undefined lanes, we can assume those
are the same as the defined lanes in these transforms:
https://alive2.llvm.org/ce/z/t6TTJ2
Replace undef with poison in the test while here to support
the transition away from undef.
Canonicalize ((x + C1) & C2) --> ((x & C2) + C1) for suitable constants
C1 and C2, instead of the other way round. This should allow more
constant ADDs to be matched as part of addressing modes for loads and
stores.
Differential Revision: https://reviews.llvm.org/D130080
(X op Y) op Z --> (Y op Z) op X
This isn't a complete solution (see TODO tests for possible refinements),
but it shows some nice wins and doesn't seem to cause any harm. I think
the most potential danger is from conflicting with other folds and causing
an infinite loop - that's the reason for avoiding patterns with constant
operands.
Alternatively, we could try this in the reassociate pass, but we would not
immediately see all of the logic folds that instcombine provides. I also
looked at improving ValueTracking's isImpliedCondition() (and we should
still add some enhancements there), but that would not work in general for
bitwise logic reduction.
The tests that reduce completely to 0/-1 are motivated by issue #56653.
Differential Revision: https://reviews.llvm.org/D131356
(~A | C) | (A ^ B) --> ~(A & B) | C
https://alive2.llvm.org/ce/z/Qw3aiJ
This extends the existing fold (just above the new match)
to peek through another 'or' instruction.
This should let the motivating case from issue #57174
simplify completely.
(A | ?) | (A ^ B) --> (A | ?) | B
https://alive2.llvm.org/ce/z/dbNQw4
This extends the existing transform to peek through
another 'or' instruction for the common operand.
This is the underlying missing fold that should allow
issue #56711 and issue #57120 to reduce even more.
This works with any logic + extend:
https://alive2.llvm.org/ce/z/vzsqQD
The motivating case is from issue #56294, but that's still not optimal
(it should simplify completely).
The 'and (sext (ashr X, ShiftC)), C' --> 'lshr (sext X), ShiftC'
transformation would access out of bounds bits in APInt::getLowBitsSet
if the shift count was larger than X's bit width or if it was negative.
Fixes#56424
(-(X & 1)) & Y --> (X & 1) == 0 ? 0 : Y
https://alive2.llvm.org/ce/z/rhpH3i
This is noted as a missing IR canonicalization in issue #55618.
We already managed to fix codegen to the expected form.
When the mask is a power-of-2 constant and op0 is a shifted-power-of-2
constant, test if the shift amount equals the offset bit index:
(ShiftC << X) & C --> X == (log2(C) - log2(ShiftC)) ? C : 0
(ShiftC >> X) & C --> X == (log2(ShiftC) - log2(C)) ? C : 0
This is an alternate to D127610 with a more general pattern.
We match only shift+and instead of the trailing xor, so we see a few
more tests diffs. I think we discussed this initially in D126617.
Here are proofs for shifts in both directions:
https://alive2.llvm.org/ce/z/CFrLs4
The test diffs look equal or better for IR, and this makes the
patterns more uniform in IR. The backend can partially invert this
in both cases if that is profitable. It is not trivially reversible,
however, so if we find perf regressions that are not easy to undo,
then we may want to revert this.
Differential Revision: https://reviews.llvm.org/D127801
This shows narrowing improvements on the logic tests
(transforms recently added with e247b0e5c921).
This is not a complete fix. That would require adding
folds to visitOr/visitXor. But it enables the expected
transforms for the basic patterns in the affected tests.
The 1st try ( afa192cfb6049a15c55 ) was reverted because it could
cause an infinite loop with constant expressions.
A test for that and an extra condition to enable the transform
are added now. I also added code comments to better describe
the transform and the existing, related transform.
Original commit message:
https://alive2.llvm.org/ce/z/hRy3rE
As shown in D123408, we can produce this pattern when moving
casts around, and we already have a related fold for a binop
with a constant operand.