Collapse `icmp`s due to `nuw`+`noundef`
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Today, the following doesn't optimize further:
```llvm
define noundef { i16, i1 } @src(i16 noundef %num) unnamed_addr {
start:
%r = shl nuw i16 %num, 8
%_3 = icmp ult i16 %num, 256
%0 = insertvalue { i16, i1 } poison, i16 %r, 0
%1 = insertvalue { i16, i1 } %0, i1 %_3, 1
ret { i16, i1 } %1
}
```
But since shifting the `num` left by 8 didn't overflow, that means it's definitely below 256, and the `icmp` is always true:
```
define {i16, i1, i8} @src(i16 noundef %num) noundef {
start:
%r = shl nuw i16 noundef %num, 8
%_3 = icmp ult i16 noundef %num, 256
%#0 = insertvalue {i16, i1, i8} poison, i16 %r, 0
%#1 = insertvalue {i16, i1, i8} %#0, i1 %_3, 1
ret {i16, i1, i8} %#1
}
=>
define {i16, i1, i8} @tgt(i16 noundef %num) noundef {
start:
%r = shl nuw i16 noundef %num, 8
%#0 = insertvalue {i16, i1, i8} poison, i16 %r, 0
%#1 = insertvalue {i16, i1, i8} %#0, i1 1, 1
ret {i16, i1, i8} %#1
}
Transformation seems to be correct!
```
Inspired by https://github.com/rust-lang/rust/pull/157560 where I was adding some `nuw` and was surprised things didn't optimize out.
---
Note that the `noundef`s are load-bearing here: `nuw` is just poison-generating, not UB, so without the `noundef` on the return then the optimization is *not* legal () since someone might just never look at the product.
Contributor guide
Assessment
This issue has not been assessed yet.