Bladeren bron

gcc: fix inf * NaN in m68k's soft-float double multiplication

__muldf3 in libgcc/config/m68k/lb1sf68.S returns infinity for inf * NaN, where
IEEE 754 asks for NaN.  When a's high word equals 0x7ff00000 the code branches to
Lmuldf$a$nf, decides there whether a is a NaN, and if a turns out to be infinity
signals overflow -- without ever examining b.  The comment two lines above says
"we still have to check d1 and b", but b never gets checked.  The float path next
to it does it right: Lmulsf$inf exists precisely to look at b first.

Measured on the ColdFire toolchain, over all 64 combinations of {+0, -0, 1, -2.5,
1e300, +inf, -inf, NaN}: two are wrong without this patch, +inf * NaN and
-inf * NaN, and none with it.  Only double multiplication is affected; float
multiplication, both divisions and subtraction already return NaN as they should.

Verified by assembling the patched file and linking it ahead of libgcc, so no
toolchain rebuild was needed to see it.

It surfaced through uClibc-ng's scalb, which propagates a NaN argument with
x * fn and therefore returned inf for scalb(inf, NaN).  musl carries the same
line from the same fdlibm ancestor, so it is affected too.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
ramin 1 week geleden
bovenliggende
commit
f2d32bb5a4
1 gewijzigde bestanden met toevoegingen van 22 en 0 verwijderingen
  1. 22 0
      toolchain/gcc/patches/15.3.0/0011-m68k-muldf3-check-b-for-nan-when-a-is-inf.patch

+ 22 - 0
toolchain/gcc/patches/15.3.0/0011-m68k-muldf3-check-b-for-nan-when-a-is-inf.patch

@@ -0,0 +1,22 @@
+--- a/libgcc/config/m68k/lb1sf68.S
++++ libgcc/config/m68k/lb1sf68.S
+@@ -1742,9 +1742,18 @@
+ 
+ Lmuldf$a$nf:
+ 	moveq	IMM (MULTIPLY),d5
+-	movel	a0,d7		| get sign bit back into d7
+ 	tstl	d1		| we know d0 == 0x7ff00000, so check d1
+ 	bne	Ld$inop		| if d1 <> 0 a is NaN
++| a is INFINITY, but b has not been looked at yet, and INFINITY * NaN is NaN.
++| d7 still holds the +INFINITY pattern needed for that test, so the sign is
++| restored only on the overflow path; Ld$inop builds its own result.
++	cmpl	d7,d2		| compare b with INFINITY
++	bhi	Ld$inop		| b's fraction has a high bit set: b is NaN
++	bne	Lmuldf$a$inf	| b is below INFINITY, hence finite
++	tstl	d3		| b's high word is INFINITY's: check the low one
++	bne	Ld$inop		| if that is nonzero b is NaN
++Lmuldf$a$inf:
++	movel	a0,d7		| get sign bit back into d7
+ 	bra	Ld$overflow	| else signal overflow
+ 
+ | If either number is zero return zero, unless the other is +/-INFINITY or