Issue |
134024
|
Summary |
Remove common `add`s when `icmp eq`ing two `select`s [InstCombine]
|
Labels |
new issue
|
Assignees |
|
Reporter |
scottmcm
|
Take the following IR, extracted from part of how Rust generates `==` on enums:
```llvm
define noundef i64 @get_discr(i8 noundef %x) unnamed_addr {
start:
%_4 = icmp ule i8 %x, 1
%small = select i1 %_4, i8 3, i8 %x
%_5 = sub i8 %small, 2
%_0 = zext i8 %_5 to i64
ret i64 %_0
}
define noundef zeroext i1 @discr_eq(i8 noundef %a, i8 noundef %b) unnamed_addr {
start:
%_3 = call noundef i64 @get_discr(i8 noundef %a)
%_4 = call noundef i64 @get_discr(i8 noundef %b)
%_0 = icmp eq i64 %_3, %_4
ret i1 %_0
}
```
Today, when optimizing `get_discr` InstCombine will change the <https://llvm.godbolt.org/z/6Eq87h6h7>
```c
(x <= 1 ? 3 : x) - 2
```
to
```c
(x <= 1 ? 1 : x - 2)
```
which is reasonable on its own.
The problem, though, is that that makes things worse later in `discr_eq`.
It's unable to undo that transformation after the inlining, and thus ends up as <https://llvm.godbolt.org/z/31MdEhfcv>
```llvm
define noundef zeroext i1 @discr_eq(i8 noundef %a, i8 noundef %b) unnamed_addr #0 {
%0 = add i8 %a, -2
%_4.inv.i = icmp ugt i8 %a, 1
%_5.i = select i1 %_4.inv.i, i8 %0, i8 1
%1 = add i8 %b, -2
%_4.inv.i1 = icmp ugt i8 %b, 1
%_5.i2 = select i1 %_4.inv.i1, i8 %1, i8 1
%_0 = icmp eq i8 %_5.i, %_5.i2
ret i1 %_0
}
```
But there's no reason to do those `add`s any more -- they could be pulled outside the `select`s where they'd cancel out.
Phrased as C, it's doing
```c
(x <= 1 ? 1 : x - 2) == (y <= 1 ? 1 : y - 2)
```
when instead it could be doing
```c
(x <= 1 ? 3 : x) == (y <= 1 ? 3 : y)
```
So InstCombine should be able to detect this case, and rewrite it back to
```llvm
define noundef zeroext i1 @discr_eq(i8 noundef %a, i8 noundef %b) unnamed_addr #0 {
%_4.inv.i = icmp ugt i8 %a, 1
%_5.i = select i1 %_4.inv.i, i8 %a, i8 3
%_4.inv.i1 = icmp ugt i8 %b, 1
%_5.i2 = select i1 %_4.inv.i1, i8 %b, i8 3
%_0 = icmp eq i8 %_5.i, %_5.i2
ret i1 %_0
}
```
Alive2 proof of correctness for that: <https://alive2.llvm.org/ce/z/AWCmDs>
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs