Issue 92074
Summary [ValueTracking] Missed optimization of modulo power-of-two
Labels new issue
Assignees
Reporter YanWQ-monad
    Recently I found a missed optimization related to modulo power-of-two. It's

https://github.com/dtcxzyw/llvm-opt-benchmark/blob/b79d63cb8adea5949cc449d4186e342d3dbdd871/bench/wasmtime-rs/optimized/1ham0fg2czw77e66.ll#L235

and it's compiled from [something](https://github.com/bytecodealliance/wasmtime/blob/a6f27eeb7e9ada3f1e10d75630f733b204e2c1ba/cranelift/codegen/meta/src/constant_hash.rs#L12-L42) like

``` rust
let modulo = if size.is_power_of_two() {  // i.e. ctpop(size) == 1
    size * 2
} else {
 size.next_power_of_two()
};

let result = xxx % modulo;
```

where `urem xxx, modulo` could be optimized to `and xxx, (modulo - 1)`.

To solve it, I have created a PR #91171 that enables the recognization of `.next_power_of_two()`, and I also have a draft patch that could recognize power-of-two from dom conditions.

However, the key problem in this case is that LLVM currently only search 2 levels beyond `phi` nodes, so the resursion of `isKnownToBeAPowerOfTwo` stops at `size * 2`, and fails to know `size` is a power-of-two from the condition.
https://github.com/llvm/llvm-project/blob/37ffbbb19576a884c5bb93b9ac0ae97f89523b6b/llvm/lib/Analysis/ValueTracking.cpp#L2197-L2199

Though changing `- 1` to `- 3` could make it work in this case, it's obviously not a proper way to solve the problem.

I am not sure if there is a way to handle this complex context across multiple basic blocks, or should we instead patch `wasmtime` to use `let modulo = (size + 1).next_power_of_two()`?

cc @nikic @dtcxzyw 
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to