rs6000: Don't use TFmode for 128 bits fp constant in toc [PR110011]

As PR110011 shows, when encoding 128 bits fp constant into
toc, we adopts REAL_VALUE_TO_TARGET_LONG_DOUBLE which is
to find the first float mode with LONG_DOUBLE_TYPE_SIZE
bits of precision, it would be TFmode here.  But the 128
bits fp constant can be with mode IFmode or KFmode, which
doesn't necessarily have the same underlying float format
as the one of TFmode, like this PR exposes, with option
-mabi=ibmlongdouble TFmode has ibm_extended_format while
KFmode has ieee_quad_format, mixing up the formats (the
encoding/decoding ways) would cause unexpected results.

This patch is to make it use constant's own mode instead
of TFmode for real_to_target call.

	PR target/110011

gcc/ChangeLog:

	* config/rs6000/rs6000.cc (output_toc): Use the mode of the 128-bit
	floating constant itself for real_to_target call.

gcc/testsuite/ChangeLog:

	* gcc.target/powerpc/pr110011.c: New test.

(cherry picked from commit 388809f2afde874180da0669c669e241037eeba0)
This commit is contained in:
Kewen Lin
2023-06-12 01:07:52 -05:00
parent 8bed12134d
commit cefe925fe4
2 changed files with 43 additions and 1 deletions
+1 -1
View File
@@ -17300,7 +17300,7 @@ output_toc (FILE *file, rtx x, int labelno, machine_mode mode)
if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
REAL_VALUE_TO_TARGET_DECIMAL128 (*CONST_DOUBLE_REAL_VALUE (x), k);
else
REAL_VALUE_TO_TARGET_LONG_DOUBLE (*CONST_DOUBLE_REAL_VALUE (x), k);
real_to_target (k, CONST_DOUBLE_REAL_VALUE (x), GET_MODE (x));
if (TARGET_64BIT)
{
@@ -0,0 +1,42 @@
/* { dg-do run } */
/* { dg-require-effective-target float128_runtime } */
/* Force long double to be with IBM format here, to verify
_Float128 constant still uses its own format (IEEE) for
encoding rather than IBM format. */
/* { dg-options "-mfp-in-toc -mabi=ibmlongdouble" } */
/* { dg-add-options float128 } */
#define MPFR_FLOAT128_MAX 0x1.ffffffffffffffffffffffffffffp+16383f128
__attribute__ ((noipa))
_Float128 f128_max ()
{
return MPFR_FLOAT128_MAX;
}
typedef union
{
int w[4];
_Float128 f128;
} U;
int main ()
{
U umax;
umax.f128 = f128_max ();
/* ieee float128 max:
7ffeffff ffffffff ffffffff ffffffff. */
if (umax.w[1] != 0xffffffff || umax.w[2] != 0xffffffff)
__builtin_abort ();
#ifdef __LITTLE_ENDIAN__
if (umax.w[0] != 0xffffffff || umax.w[3] != 0x7ffeffff)
__builtin_abort ();
#else
if (umax.w[3] != 0xffffffff || umax.w[0] != 0x7ffeffff)
__builtin_abort ();
#endif
return 0;
}