Inline `ilogb` when `x` is `normal`.
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
If `x` is normal, (or if `x` is subnormal with the MSB of the mantissa set), then `ilogb` can be implemented by clearing the sign bit, right shifting the exponent, and subtracting a constant.
Converting a call to `ilogb` to a bitwise-and, right-shift, subtract may be profitable for some platforms without an FPU.
This transformation might not be profitable if the above operations take up more space than a call to `ilogb`, or if the above operations are slower than an assembly implementation of `ilogb`.
This transformation is invalid if the result of `ilogb(normal)` is outside the range of `int` (which should generally be false where `int` is 32 bits).
Currently, Clang does not perform this optimization, and Alive2 is unable to prove it. https://alive2.llvm.org/ce/z/v4eQZt
https://godbolt.org/z/dGGa6ebqP
```c++
int src_f32(float x) {
if (!__builtin_isnormal(x)) {
__builtin_unreachable();
}
return __builtin_ilogbf(x);
}
int tgt_f32(float x) {
if (!__builtin_isnormal(x)) {
__builtin_unreachable();
}
uint32_t bin;
__builtin_memcpy(&bin, &x, sizeof(x));
bin &= ~(UINT32_C(1) << 31);
bin >>= 23;
int ret = (int)bin;
return ret - 127;
}
int src_f64(double x) {
if (!__builtin_isnormal(x)) {
__builtin_unreachable();
}
return __builtin_ilogb(x);
}
int tgt_f64(double x) {
if (!__builtin_isnormal(x)) {
__builtin_unreachable();
}
uint64_t bin;
__builtin_memcpy(&bin, &x, sizeof(x));
bin &= ~(UINT64_C(1) << 63);
bin >>= 52;
int ret = (int)bin;
return ret - 1023;
}
```
***
Next steps:
- This can be generalized to `frexp(x, &exponent)` if only the exponent is needed.
- A similar transformation for `ilogb` exists if `x` is always subnormal (or has the smallest normal exponent) which turns `ilogb` into `__builtin_clz(x) - constant`.
Contributor guide
Assessment
This issue has not been assessed yet.