alive2
alive2 copied to clipboard
bug in minnum and maxnum
I think these functions are incorrect in one corner case.
take this IR:
declare float @llvm.min.f32(float, float)
declare float @llvm.max.f32(float, float)
declare float @llvm.minnum.f32(float, float)
declare float @llvm.maxnum.f32(float, float)
declare float @llvm.minimum.f32(float, float)
declare float @llvm.maximum.f32(float, float)
declare float @llvm.minimumnum.f32(float, float)
declare float @llvm.maximumnum.f32(float, float)
define float @f() {
%2 = call float @llvm.maxnum.f32(float 0x0000000000000000, float 0x8000000000000000)
ret float %2
}
here's what alive-exec says:
~/svn/code/alive2/fp$ ~/alive2-regehr/build/alive-exec tmp.ll
----------------------------------------
define float @f() {
#0:
%#1 = fmax float 0.000000, -0.000000
ret float %#1
}
Executing %#0
%#1 = #x80000000
Returned #x80000000 / true
~/svn/code/alive2/fp$
but LangRef says that "-0.0 < +0.0 for the purposes of this intrinsic."
the analogous case for minnum is also wrong:
~/svn/code/alive2/fp$ ~/alive2-regehr/build/alive-exec tmp.ll
----------------------------------------
define float @f() {
#0:
%#1 = fmin float -0.000000, 0.000000
ret float %#1
}
Executing %#0
%#1 = #x00000000
Returned #x00000000 / true
This was a recent change in 363b05944f9212511ee6811d0eb1af841c177226
ah, thanks, I'll just put the text here
commit 363b05944f9212511ee6811d0eb1af841c177226
Author: YunQiang Su <[email protected]>
Date: Thu Feb 27 11:22:30 2025 +0800
LangRef: Clarify llvm.minnum and llvm.maxnum about sNaN and signed zero (#112852)
The documents claims that it ignores sNaN, while in the current code it
may be different.
- as the finally callback, it use libc call fmin(3)/fmax(3). while C23
clarifies that fmin(3)/fmax(3) should return NaN for sNaN vs NUM.
- on some architectures, such as aarch64, it converts to `fmaxnm`, which
returns qNaN for sNaN vs NUM.
- on RISC-V (SPEC 2019+), it converts to `fmax`, which returns NUM for
sNaN vs NUM.
Since we have introduced llvm.minimumnum and llvm.maximumnum, which
follow IEEE 754-2019's minimumNumber/maximumNumber.
So, it's time for us to clarify llvm.minnum and llvm.maxnum. Since the
final fallback of llvm.minnum and llvm.maxnum is
fmin(3)/fmax(3), so that it is reasonable to follow the behaviors of
fmin(3)/fmax(3).
Although C23 clarified the behavior about sNaN and +0.0/-0.0:
(NUM or NaN) vs sNaN -> qNaN
+0.0 vs -0.0 -> either one of +0.0/-0.0
It is the same the IEEE754-2008's maxNUM and minNUM.
Not all implementation work as expected.
Since some architectures such as aarch64/MIPSr6/LoongArch, have
instructions that implements +0.0>-0.0.
So Let's define llvm.minnum and llvm.maxnum to IEEE754-2008 with
+0.0>-0.0.
The architectures without such instructions can implements `NSZ` flavor
to speed up,
and the frontend, such as clang, can call them with `nsz` attribute.