llvm / llvm/llvm-project

Collapse `icmp`s due to `nuw`+`noundef`

Open
#202,240 1 comment 0 reactions 0 assignees View on GitHub
llvm:optimizations missed-optimization
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.