aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fpu/softfloat.c6
-rw-r--r--tests/tcg/i386/test-i386-pseudo-denormal.c24
2 files changed, 30 insertions, 0 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index ac116c7..6094d26 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -5866,6 +5866,12 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
zSig1 = 0;
zSig0 = aSig + bSig;
if ( aExp == 0 ) {
+ if ((aSig | bSig) & UINT64_C(0x8000000000000000) && zSig0 < aSig) {
+ /* At least one of the values is a pseudo-denormal,
+ * and there is a carry out of the result. */
+ zExp = 1;
+ goto shiftRight1;
+ }
if (zSig0 == 0) {
return packFloatx80(zSign, 0, 0);
}
diff --git a/tests/tcg/i386/test-i386-pseudo-denormal.c b/tests/tcg/i386/test-i386-pseudo-denormal.c
new file mode 100644
index 0000000..cfa2a50
--- /dev/null
+++ b/tests/tcg/i386/test-i386-pseudo-denormal.c
@@ -0,0 +1,24 @@
+/* Test pseudo-denormal operations. */
+
+#include <stdint.h>
+#include <stdio.h>
+
+union u {
+ struct { uint64_t sig; uint16_t sign_exp; } s;
+ long double ld;
+};
+
+volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } };
+
+volatile long double ld_res;
+
+int main(void)
+{
+ int ret = 0;
+ ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld;
+ if (ld_res != 0x1p-16381L) {
+ printf("FAIL: pseudo-denormal add\n");
+ ret = 1;
+ }
+ return ret;
+}