Forward-over-reverse Hessian is NaN at `-O2`, correct at `-O0`/`-O1`/`-O3` and with `-fno-slp-vectorize`
- Dominant language
- LLVM
- Stars
- 1.7k
- Forks
- 188
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 26
Description
Enzyme produces NaN at `-O2` at the forward-over-reverse hessian, while the other flags `-O0`, `-O1`, `-O3` produce the correct Hessian results. However, with `-O2 -fno-slp-vectorize`, it produces the correct results.
Minimal reproducible example:
```cpp
#include
#include
using namespace std;
void f(float *x, float *out) {
float t3[5] = {0.6f, 0.6f, 0.6f, 0.6f, 0.6f};
float s0 = exp(atan2(acos(exp(x[0])) - atan2(sin(x[0]), x[0]),
atan2(x[0], -2.0f) + x[0]));
for (int i = 0; i < 5; i++) {
float t0 = s0 + x[i];
float t2 = s0 + cos(asinh(sqrt(s0) / x[i])) + t0;
t3[i] = t3[i] * log(pow(s0, atan2(pow(s0, s0), pow(s0, t3[i])))) + t2;
out[i] = acosh(t0) * t2 + t3[i];
}
}
extern int enzyme_dup;
extern int enzyme_const;
template RT __enzyme_autodiff(void *, T...);
template RT __enzyme_fwddiff(void *, T...);
void grad(float *x, float *dx, float *y, float *dy) {
__enzyme_autodiff((void *)f, enzyme_dup, x, dx, enzyme_dup, y, dy);
}
int main() {
float x[5] = {-0.9383832812309265f, -0.45288288593292236f,
-0.24080416560173035f, -0.6241748332977295f,
-0.4739071726799011f};
float dx[5] = {1, 0, 0, 0, 0};
float y[5] = {0}, dy[5] = {1, 0, 0, 0, 0};
float g[5] = {0}, h[5] = {0};
__enzyme_fwddiff((void *)grad, enzyme_dup, x, dx, enzyme_dup, g, h,
enzyme_const, y, enzyme_const, dy);
for (int i = 0; i < 5; i++)
printf("%.9g ", h[i]);
printf("\n");
}
```
Build and run:
```bash
clang++ -std=c++17 -O2 repro.cpp -I $ENZYME_INC -fplugin=$ENZYME -o repro
./repro
```
Output:
```
-O0 3.91245604 0 0 0 0
-O1 3.91245651 0 0 0 0
-O2 -nan 0 0 0 0 <-- wrong
-O3 3.91245627 0 0 0 0
-O2 -fno-slp-vectorize 3.91245651 0 0 0 0
```
Environment: clang 16.0.6, Enzyme `main` at `a9975371`, x86-64 (AMD EPYC 9654, AVX-512).
Contributor guide
Research direction
Start with the repro.cpp entry points, __enzyme_fwddiff and __enzyme_autodiff, and build it with clang++ 16.0.6 at -O2; compare the output with -O1, -O3, and -fno-slp-vectorize. Investigate the SLP-vectorization interaction with forward-over-reverse Hessian generation. Done means the -O2 run produces the correct Hessian instead of NaN while the other configurations remain correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100