[InstCombine] fold (sext(ucmp/scmp(X, Y)) -> ucmp/scmp(X, Y) (#191182)
relates: https://github.com/llvm/llvm-project/issues/190538
related PR: https://github.com/llvm/llvm-project/pull/190787
This PR folds (sext(ucmp/scmp(X, Y)) -> ucmp/scmp(X, Y). Since ucmp/scmp
return -1, 0, 1, if you see the sequence:
```llvm
%_3 = tail call i8 @llvm.ucmp.i8.i64(i64 %a, i64 %b)
%_0 = sext i8 %_3 to i64
```
It's fine to turn this into:
```llvm
%_0 = tail call i64 @llvm.ucmp.i64.i64(i64 %a, i64 %b)
```
[Alive Proof](https://alive2.llvm.org/ce/z/VmeKM2)
Likewise for scmp:
```llvm
%_3 = tail call i8 @llvm.scmp.i8.i64(i64 %a, i64 %b)
%_0 = sext i8 %_3 to i64
```
```llvm
%_0 = tail call i64 @llvm.scmp.i64.i64(i64 %a, i64 %b)
```
[Alive Proof](https://alive2.llvm.org/ce/z/WSm7YS)
For ucmp, a simple way to get this is to cmp two rust unsigned integers:
```rust
pub fn compare(a: u64, b: u64) -> i64 {
a.cmp(&b) as i64
}
```
Which gets this:
```llvm
define noundef range(i64 -1, 2) i64 @compare(i64 noundef %a, i64 noundef %b) unnamed_addr {
start:
%_3 = tail call i8 @llvm.ucmp.i8.i64(i64 %a, i64 %b)
%_0 = sext i8 %_3 to i64
ret i64 %_0
}
declare range(i8 -1, 2) i8 @llvm.ucmp.i8.i64(i64, i64)
```
For scmp, swapping to i64s will suffice:
```rust
pub fn compare(a: i64, b: i64) -> i64 {
a.cmp(&b) as i64
}
```
```llvm
define noundef range(i64 -1, 2) i64 @compare(i64 noundef %a, i64 noundef %b) unnamed_addr {
start:
%_3 = tail call i8 @llvm.scmp.i8.i64(i64 %a, i64 %b)
%_0 = sext i8 %_3 to i64
ret i64 %_0
}
declare range(i8 -1, 2) i8 @llvm.scmp.i8.i64(i64, i64)
```