llvm / llvm/llvm-project

Inline `(int)float_value` if `-1.0 < float_value < +2.0`

Open
#221,108 1 comment 0 reactions 0 assignees View on GitHub
floating-point missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

It is possible to turn `(int)float_value`/`(unsigned)float_value` into an add and shift if `+0.0 <= float_value < +2.0` and the `float_value` is positive (not negative zero).

Additionally, if `-1.0 < float_value < +2.0`, then all you need to do is to clear the sign-bit to transform it into the `+0.0 <= float_value < +2.0` case.
```c++
int32_t src_a(float x) {
if (__builtin_signbit(x) || x >= 2.0f) {
__builtin_unreachable();
}
return (int32_t)x;
}

// similar trick is possible with bfloat/half/double
int32_t tgt_a(float x) {
if (__builtin_signbit(x) || x >= 2.0f) {
__builtin_unreachable();
}
uint32_t bin;
__builtin_memcpy(&bin, &x, sizeof(x));
bin += 0x00800000;
bin >>= 30;
return (int32_t)bin;
}

int32_t src_b(float x) {
if (x <= -1.0 || x >= 2.0f) {
__builtin_unreachable();
}
return (int32_t)x;
}

// A similar trick is possible with bfloat/half/double.
int32_t tgt_b(float x) {
if (x <= -1.0 || x >= 2.0f) {
__builtin_unreachable();
}
uint32_t bin;
__builtin_memcpy(&bin, &x, sizeof(x));
bin += 0x00800000;
bin &= 0x7FFFFFFF;
bin >>= 30;
return (int32_t)bin;
}

// same as tgt_b
int32_t tgt_c(float x) {
if (x <= -1.0 || x >= 2.0f) {
__builtin_unreachable();
}
uint32_t bin;
__builtin_memcpy(&bin, &x, sizeof(x));
bin += 0x00800000;
bin <<= 1;
bin >>= 31;
return (int32_t)bin;
}
```

Godbolt: https://godbolt.org/z/hs148WMrq
Alive2: https://alive2.llvm.org/ce/z/xBCrXN

This transformation is mostly useful for software floats.

Since this emits 2-3 instructions, I am not sure if it would also be useful for SIMD vectors.

I am not currently aware of real world uses.

Contributor guide

Open the contributing guide

Research direction

Start with the C++ examples and reproduce their current and target code on the linked Godbolt example. Use the Alive2 link to check the proposed transformations, including negative zero and the float, bfloat, half, and double cases. Done means the compiler recognizes the stated ranges and emits the add/shift form without changing semantics.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, performance
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.