clang++ miscompiles std::pow with mixed types when using -O3 -fno-math-errno -fveclib=libmvec
- 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
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