[LoopVectorize] `-vector-library` selects a 512-bit veclib call (`amd_vrd8_log`) on an AVX2-only target
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Disclaimer: AI generated. Found during other work and manually prompted. No auto-discovery / bounty /karma seeking entreprise here (pinky swear).
## Summary
With `-vector-library=AMDLIBM` on a target whose maximum legal vector width is 256-bit (e.g. `znver1`, `-march=x86-64-v3`), a loop over `float` whose body computes `log` in `double` is vectorized at VF=8. The resulting `<8 x double>` `log` is lowered to `amd_vrd8_log` — an 8-wide-double (512-bit) routine that executes AVX-512 instructions — so the binary SIGILLs at runtime on a CPU without AVX-512. A pure-`double` loop in the same translation unit is correctly capped at `amd_vrd4_log` (256-bit), so the width gate exists but is not applied to a wider-element library call that arises inside a narrower-element loop.
## Reproducer
`repro.c`:
```c
#include
// float loop, but log() runs in double -> <8 x double> at VF=8.
void f(float *out, const float *in, long n) {
for (long i = 0; i < n; i++)
out[i] = (float) log((double) in[i]);
}
// Control: pure-double loop.
void g(double *out, const double *in, long n) {
for (long i = 0; i < n; i++)
out[i] = log(in[i]);
}
```
Compile to asm:
```
clang -O3 -march=znver1 -fno-math-errno -fveclib=AMDLIBM -S repro.c -o repro.s
grep -oE 'callq\s+amd_vr[a-z0-9_]+' repro.s | sort -u
```
Or via `opt` on the IR:
```
clang -O0 -Xclang -disable-O0-optnone -march=znver1 -fno-math-errno -emit-llvm -S repro.c -o repro.ll
opt -passes='default' -vector-library=AMDLIBM repro.ll -S | grep -oE 'amd_vr[a-z0-9_]+'
```
## Expected vs actual
| function | expected on AVX2 (max 256-bit) | actual |
|---|---|---|
| `g` (pure double) | `amd_vrd4_log` (256-bit) | `amd_vrd4_log` — OK |
| `f` (float loop, double log) | `amd_vrd4_log` / native split | `amd_vrd8_log` (512-bit, AVX-512 only) — BUG |
## Confirmed crash on real hardware
On an AMD Ryzen 5 2400G (znver1, AVX2, no AVX-512), the binary above SIGILLs in an AVX-512 instruction:
```
Program received signal SIGILL, Illegal instruction.
0x00007ffff7db94ea in amd_vrd8_log_zn4 () from libalm.so
=> 0x7ffff7db94ea : vmovapd %zmm0,%zmm6
#0 amd_vrd8_log_zn4 ()
#1 f ()
```
`amd_vrd8_log` is a real AMDLIBM symbol; it dispatches only to AVX-512 implementations (`_avx512`/`_zn4`/`_zn5`) — there is no 256-bit variant of an 8-wide-double routine, so any call to it on a sub-AVX-512 target is unconditionally illegal.
## Notes
Reproduced with clang/LLVM 22.1.8 (current release) via the `-fveclib=AMDLIBM` driver flag; not yet checked against trunk.
Contributor guide
Research direction
Start by running the repro.c clang and opt commands with -vector-library=AMDLIBM, then inspect the LoopVectorize vector-library width handling for the float loop whose log call becomes <8 x double>. Done means an AVX2-only target no longer emits amd_vrd8_log for f, while the pure-double control remains capped at amd_vrd4_log.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100