Open Quuxplusone opened 4 years ago
Bugzilla Link | PR45101 |
Status | NEW |
Importance | P enhancement |
Reported by | Alexander Cherepanov (ch3root@openwall.com) |
Reported on | 2020-03-04 09:50:49 -0800 |
Last modified on | 2020-03-10 09:50:14 -0700 |
Version | trunk |
Hardware | PC Linux |
CC | efriedma@quicinc.com, htmldeveloper@gmail.com, listmail@philipreames.com, llvm-bugs@lists.llvm.org |
Fixed by commit(s) | |
Attachments | |
Blocks | |
Blocked by | |
See also |
I guess this is specifically an issue with x87 long double? I'm pretty sure that for all IEEE float formats, given two non-zero, non-NaN values, x==y implies that x and y are bit-wise identical.
I'm not exactly sure. I would expect IBM double-double and IEEE 754 decimal floating-point formats to exhibit the same behavior. But I haven't checked this, plus I'm not sure about their support in LLVM.
This is controlled by impliesEquivalanceIfTrue in llvm/lib/Transforms/Scalar/GVN.cpp .
clang doesn't support decimal floating-point formats. For an example of potential future problems please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94035#c5 .
x86 extended precision format (x86_fp80): gcc devs seems to consider pseudo-denormals (and other pseudo-*, unnormals etc.) as trap representations -- please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94035#c2 .
IBM extended double (double-double) (ppc_fp128): affected but please see what gcc devs say -- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94035#c4 .
attribute((noipa,optnone)) // imagine it in a separate TU static long double opaque(long double d) { return d; }
int main() { union { long double d; unsigned long l[2]; } x = {opaque(-(long double)-1)};
if (x.d == 1)
printf("%016lx %016lx\n", x.l[0], x.l[1]);
printf("%016lx %016lx\n", x.l[0], x.l[1]);
For comparison:
Here, x has long double value 1. which is represented as the pair (1., -0.) of ordinary doubles, the constant 1 in the if
is converted to the pair (1., 0.). They are the same value (and are necessarily equal) but have different (non-trap) representations.
There are 3 issues here:
1) the sign of the low part of -(long double)-1 differs from gcc -- AIUI both variants are fine so not sure if anybody cares; 2) high and low parts of ppc_fp128 computed at compile-time are interchanged -- I remember seeing a discussion of it somewhere but I cannot find it right now; 3) after we swap high and low parts, the low part computed at compile-time (0000000000000000, i.e. 0.) differs from run-time (8000000000000000, i.e. -0.) -- that's what this PR is about.
(In reply to Alexander Cherepanov from comment #4)
> 2) high and low parts of ppc_fp128 computed at compile-time are interchanged
> -- I remember seeing a discussion of it somewhere but I cannot find it right
> now;
I've searched the bugzilla a little bit more and still cannot find it. Filed as
bug 45137.
At the IR level, I'd be happy to say that arithmetic on unnormal/pseudo-denormal long double produces poison, sure. Which would imply that the arithmetic is UB at the C level. It simplifies our reasoning without affecting any legitimate use cases. Someone would need to write that up in LangRef, though.
For double-double, yes, it's sort of on its way out, but people who are using it care that it doesn't break in weird ways.