| Issue |
63895
|
| Summary |
APFloat's `addOrSubtractSignificand` still throws assert in subtler FMA cases.
|
| Labels |
|
| Assignees |
|
| Reporter |
eddyb
|
```c
#include <math.h>
float foo() {
return fmaf(
-0.000000000000000000000000000000000000014728589,
0.0000037105144,
0.000000000000000000000000000000000000000000055
);
}
```
results in (e.g. [via godbolt](https://godbolt.org/z/dE93eMobW)):
```
llvm/lib/Support/APFloat.cpp:1805:
llvm::lostFraction llvm::detail::IEEEFloat::addOrSubtractSignificand(const llvm::detail::IEEEFloat&, bool):
Assertion `!carry' failed.
```
However, that's not how the bug was found. I noticed 8-bit formats (like `Float8E5M2` and `Float8E4M3FN`) were added to `APFloat`, and decided to try brute-forcing all possible inputs for a few common operations (it only takes 8 seconds, and ~98% of that is FMA, because it uniquely has 3 inputs).
So the first example I found was for `Float8E4M3FN`, namely: `FMA(0.0254, 0.0781, -0.00195)` (the encoded byte values being `0x0d`, `0x1a`, `0x81`).
Then @solson helped me turn some formula sketches I made looking at the code, into Z3, which confirmed that the example I found was the only one across *all* possible 8-bit floats, but 16-bit and 32-bit have a lot more cases. (I'm only not including all that here because it's not really set up to generate ready to use examples, it's really finicky as-is)
---
My understanding is that https://github.com/llvm/llvm-project/commit/e62555c129d535d524354351791c5474c9929582 fixed most of the previously problematic cases, but not the ones where both significands are equal before subtraction, which will only work if `lost_fraction == lfExactlyZero`.
But if there is a lost fraction, neither direction will work to subtract equal significands - the code seems to rely on being able to assume that only equal exponents can result in equal significands, but we know that's not true w/ FMA.
(also, the lost fraction is always subtracted, regardless of the subtraction direction, but before https://github.com/llvm/llvm-project/commit/e62555c129d535d524354351791c5474c9929582 the source of the `lost_fraction` was tied to `reverse`, i.e. `a.subtractSignificand(b, lost_fraction != lfExactlyZero)` was always performed with `lost_fraction` coming from `lost_fraction = b.shiftSignificandRight(...);`, regardless of how `a` and `b` mapped to `*this` and `temp_rhs`, respectively - this seems significant as well, but I'm not sure how to tell or test this)
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs