llvm/llvm-project

Take advantage of `assume`s on `x * x` (with `nuw`)

Open

#122.412 aperta il 10 gen 2025

Vedi su GitHub
 (9 commenti) (0 reazioni) (1 assegnatario)C++ (10.782 fork)batch import
good first issuellvm:optimizationsmissed-optimization

Metriche repository

Star
 (26.378 star)
Metriche merge PR
 (Merge medio 1g 2h) (1000 PR mergiate in 30 g)

Descrizione

Rust stabilized its isqrt method today, so I was looking at its codegen.

The output for

let root = u16::isqrt(num);

currently has a manual

assume(root <= 255)

I was thinking that it'd be nice to give LLVM a bit more specific information, like

assume(root * root <= num)

since that's (a partial) definition of what isqrt does, and strictly more specific.

Sadly, that assume today doesn't seem to be worth bothering adding, since opt seems like it doesn't take advantage of it even in a "simple" situation that doesn't need to know anything about num: https://llvm.godbolt.org/z/zoq4T5fKr

But Alive2 confirms that it would be allowed to https://alive2.llvm.org/ce/z/ko8HYR

define i1 @src(i16 noundef %num, i16 noundef %s) noundef zeroext {
start:
  %_4 = mul nuw i16 noundef %s, noundef %s
  %cond = icmp ule i16 %_4, noundef %num
  assume i1 %cond
  %_0 = icmp ult i16 noundef %s, 256
  ret i1 %_0
}
=>
define i1 @tgt(i16 noundef %num, i16 noundef %s) noundef zeroext {
start:
  ret i1 1
}
Transformation seems to be correct!

Original Rust code I used to get the LLVM IR: https://rust.godbolt.org/z/vM8qj4xjf

pub unsafe fn isqrt_facts(num: u16, s: u16) -> bool {
    std::hint::assert_unchecked(u16::unchecked_mul(s, s) <= num);
    s <= 255
}

cc https://github.com/rust-lang/rust/issues/116226

Guida contributor