I will try my best to describe what's this issue.
I only could reproduce this problem with Rust.
The original report to rust project: rust-lang/rust#151286
I tested it with llvm-project:main and found same issue remains.
I wrote a patch fix this problem #176625
This is what I am guessing.
On AArch64 in release builds, this code returns wrong result (only in complex code):
let snan: f64 = f64::from_bits(0x7FF0_0000_0000_0001);
let max = if snan > 0.0 { snan } else { 0.0 };
// Expected: 0.0 (because fcmp ogt returns false for SNAN)
// Got: QNAN 0x7FF8000000000001
Only happens at opt-level >= 1. Debug builds work fine.
LLVM generates this IR: https://godbolt.org/z/dnjYPrsKa
%cmp = fcmp ogt double %snan, 0.0
%max = select i1 %cmp, double %snan, double 0.0
DAGCombiner combines it to:
%max = fmaxnum double %snan, 0.0
AArch64 backend selects:
The fmaxnm instruction converts SNAN to QNAN. But fcmp ogt returns false for SNAN, so the original code should return 0.0.
I will try my best to describe what's this issue.
I only could reproduce this problem with Rust.
The original report to rust project: rust-lang/rust#151286
I tested it with llvm-project:main and found same issue remains.
I wrote a patch fix this problem #176625
This is what I am guessing.
On AArch64 in release builds, this code returns wrong result (only in complex code):
Only happens at opt-level >= 1. Debug builds work fine.
LLVM generates this IR: https://godbolt.org/z/dnjYPrsKa
DAGCombiner combines it to:
AArch64 backend selects:
The
fmaxnminstruction converts SNAN to QNAN. Butfcmp ogtreturns false for SNAN, so the original code should return0.0.