[llvm] [InstCombine] Div ceil optimizations (PR #190175)
Takashi Idobe via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 11 13:27:04 PDT 2026
================
@@ -10361,6 +10361,10 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
SI->getFalseValue(), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
CR = CRTrue.unionWith(CRFalse);
CR = CR.intersectWith(getRangeForSelectPattern(*SI, IIQ));
+ } else if (auto *TI = dyn_cast<TruncInst>(V)) {
+ ConstantRange SrcCR = computeConstantRange(
+ TI->getOperand(0), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = SrcCR.truncate(BitWidth, TI->getNoWrapKind());
----------------
Takashiidobe wrote:
Good catch, I forgot to add this as a test case.
The case this is required for is the rust code case:
```rust
#[unsafe(no_mangle)]
pub fn div_ceil_with_range(x: u32) -> u32 {
x.count_zeros().div_ceil(7)
}
```
Which turns into this:
```llvm
define noundef range(i32 0, 6) i32 @div_ceil_with_range(i32 noundef %x) unnamed_addr {
start:
%self = xor i32 %x, -1
%0 = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 %self)
%d.lhs.trunc = trunc nuw nsw i32 %0 to i8
%d3 = udiv i8 %d.lhs.trunc, 7
%d.zext = zext nneg i8 %d3 to i32
%r4 = urem i8 %d.lhs.trunc, 7
%_6.not = icmp ne i8 %r4, 0
%1 = zext i1 %_6.not to i32
%_0.sroa.0.0 = add nuw nsw i32 %1, %d.zext
ret i32 %_0.sroa.0.0
}
```
I added a test case for this which gets optimized. Without the trunc change it doesn't optimize.
```llvm
; Trunc form: X comes from trunc nuw of an i32 with range info.
define i32 @divceil_trunc_nuw_range(i32 range(i32 0, 33) %x_wide) {
%x = trunc nuw i32 %x_wide to i8
%q = udiv i8 %x, 7
%r = urem i8 %x, 7
%cond = icmp ne i8 %r, 0
%q_ext = zext i8 %q to i32
%round = zext i1 %cond to i32
%result = add i32 %q_ext, %round
ret i32 %result
}
```
https://github.com/llvm/llvm-project/pull/190175
More information about the llvm-commits
mailing list