llvm / llvm/llvm-project

clang++ miscompiles std::pow with mixed types when using -O3 -fno-math-errno -fveclib=libmvec

Open
#164,642 0 comments 0 reactions 0 assignees View on GitHub
floating-point llvm:optimizations miscompilation
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

I am using the `Linux x64_64` release of [LLVM 21.1.4](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.4).

Reduced test case (also in [godbolt](https://godbolt.org/z/bWbe4Y54e)):
`test.cpp`
```cpp
#include
#include

using T = double;
using U = float;

void __attribute__((noinline)) computePow(T *dst, T *base, U *exponent, int n)
{
for (int i = 0; i < n; ++i) {
dst[i] = static_cast(std::pow(base[i], exponent[i]));
}
}

int main()
{
constexpr int N = 4;

T x[N] = {2, 4, 6, 8};
U y[N] = {7, 5, 3, 1};

T z[N];
computePow(z, x, y, N);

for (int i = 0; i < N; ++i) {
std::cout << "pow(" << x[i] << ", " << y[i] << ") = " << z[i]
<< std::endl;
}
}
```
```text
$ clang++ test.cpp -o test -O3 -fveclib=libmvec -fno-math-errno
./test
pow(2, 7) = 64
pow(4, 5) = 65536
pow(6, 3) = 0
pow(8, 1) = 0
```

However, the result should be
```text
pow(2, 7) = 128
pow(4, 5) = 1024
pow(6, 3) = 216
pow(8, 1) = 8
```

The same wrong result happens for other combinations of types for `T` and `U`, where `T != U`, for example `T = double` and `U = int`. The result is instead correct for `T = U = double` and `T = U = float`.

---

From what I have investigated, it seems like the issue is that the compiled program uses the [libmvec function](https://sourceware.org/glibc/wiki/libmvec?action=AttachFile&do=view&target=VectorABI.txt) `_ZGVdN4vv_pow` for computing 4 powers at once, but the values are not placed properly in the registers.

In the assembly generated (see godbolt), the registers xmm0 and xmm1 are used for the base and the registers xmm2 and xmm3 for the exponent. I think that ymm0 should instead be used for the base and ymm1 for the exponent.

Contributor guide

Open the contributing guide

Research direction

Start by compiling and running the reduced test.cpp with -O3 -fveclib=libmvec -fno-math-errno, then inspect the generated assembly around _ZGVdN4vv_pow and compare its argument registers with the linked libmvec Vector ABI. The fix is complete when mixed-type std::pow calls produce the expected values and the reported double/float case is verified.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.