This patch is a complete rework of the previous patch. Previously I used new
target hooks to provide IFmode (__ibm128) from being widened by default to
TFmode (long double) on power9 systems when long double is IEEE 128-bit.
This patch reorganizes the 3 128-bit floating point types, so that IFmode is
numerically higher than TFmode/KFmode. This means IFmode is considered the
widest type. Since we do not define arithmetic insns for IFmode, other than
negate/absolute value (that we define for the other types), we will not have
undesirable widening. I needed to change long double size so that lookup of
size would get the TFmode type and not the IFmode.
Since I reorganized the modes, the compiler now uses truncif{kf,tf}2 instead of
extend{tf,kf}if2. It turns out I had the argument modes backwards for trunc.
I have included a fix for this thinko.
I have built this on the following systems, and they bootstrapped and had no
regressions. Can I check this into the trunk, and after a burn-in period check
it into GCC 8.2, assuming the last build on power6 has no regressions?
1) Little endian power8 system (64-bit), --with-cpu=power8;
2) Big endian power8 system (64/32-bit), --with-cpu=power8;
3) Big endian power8 system (64/32-bit), no --with-cpu;
I'm currently building it on:
4) Big endian power6 system (64/32-bit), no --with-cpu.
2018-06-11 Michael Meissner <[email protected]>
PR target/85358
* config/rs6000/rs6000-modes.def (toplevel): Rework the 128-bit
floating point modes, so that IFmode is numerically greater than
TFmode, which is greater than KFmode using FRACTIONAL_FLOAT_MODE
to declare the ordering. This prevents IFmode from being
converted to TFmode when long double is IEEE 128-bit on an ISA 3.0
machine. Include rs6000-modes.h to share the fractional values
between genmodes* and the rest of the compiler.
(IFmode): Likewise.
(KFmode): Likewise.
(TFmode): Likewise.
* config/rs6000/rs6000-modes.h: New file.
* config/rs6000/rs6000.c (rs6000_debug_reg_global): Change the
meaning of rs6000_long_double_size so that 126..128 selects an
appropriate 128-bit floating point type.
(rs6000_option_override_internal): Likewise.
* config/rs6000/rs6000.h (toplevel): Include rs6000-modes.h.
(TARGET_LONG_DOUBLE_128): Change the meaning of
rs6000_long_double_size so that 126..128 selects an appropriate
128-bit floating point type.
(LONG_DOUBLE_TYPE_SIZE): Update comment.
* config/rs6000/rs6000.md (trunciftf2): Correct the modes of the
source and destination to match the standard usage.
(truncifkf2): Likewise.
--
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: [email protected], phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-modes.def
===================================================================
--- gcc/config/rs6000/rs6000-modes.def (revision 261349)
+++ gcc/config/rs6000/rs6000-modes.def (working copy)
@@ -18,16 +18,27 @@
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-/* IBM 128-bit floating point. IFmode and KFmode use the fractional float
- support in order to declare 3 128-bit floating point types. */
-FRACTIONAL_FLOAT_MODE (IF, 106, 16, ibm_extended_format);
+/* We order the 3 128-bit floating point types so that IFmode (IBM 128-bit
+ floating point) is the 128-bit floating point type with the highest
+ precision (128 bits). This so that machine independent parts of the
+ compiler do not try to widen IFmode to TFmode on ISA 3.0 (power9) that has
+ hardware support for IEEE 128-bit. We set TFmode (long double mode) in
+ between, and KFmode (explicit __float128) below it. */
+
+#ifndef RS6000_MODES_H
+#include "config/rs6000/rs6000-modes.h"
+#endif
+
+/* IBM 128-bit floating point. */
+FRACTIONAL_FLOAT_MODE (IF, FLOAT_PRECISION_IFmode, 16, ibm_extended_format);
/* Explicit IEEE 128-bit floating point. */
-FRACTIONAL_FLOAT_MODE (KF, 113, 16, ieee_quad_format);
+FRACTIONAL_FLOAT_MODE (KF, FLOAT_PRECISION_KFmode, 16, ieee_quad_format);
-/* 128-bit floating point. ABI_V4 uses IEEE quad, AIX/Darwin
- adjust this in rs6000_option_override_internal. */
-FLOAT_MODE (TF, 16, ieee_quad_format);
+/* 128-bit floating point, either IBM 128-bit or IEEE 128-bit. This is
+ adjusted in rs6000_option_override_internal to be the appropriate floating
+ point type. */
+FRACTIONAL_FLOAT_MODE (TF, FLOAT_PRECISION_TFmode, 16, ieee_quad_format);
/* Add any extra modes needed to represent the condition code.
Index: gcc/config/rs6000/rs6000-modes.h
===================================================================
--- gcc/config/rs6000/rs6000-modes.h (revision 0)
+++ gcc/config/rs6000/rs6000-modes.h (working copy)
@@ -0,0 +1,36 @@
+/* Definitions 128-bit floating point precisions used by PowerPC.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ Contributed by Michael Meissner ([email protected])
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* We order the 3 128-bit floating point types so that IFmode (IBM 128-bit
+ floating point) is the 128-bit floating point type with the highest
+ precision (128 bits). This so that machine independent parts of the
+ compiler do not try to widen IFmode to TFmode on ISA 3.0 (power9) that has
+ hardware support for IEEE 128-bit. We set TFmode (long double mode) in
+ between, and KFmode (explicit __float128) below it.
+
+ We won't encounter conversion from IEEE 128-bit to IBM 128-bit because we
+ don't have insns to support the IBM 128-bit aritmetic operations. */
+
+#ifndef RS6000_MODES_H
+#define RS6000_MODES_H 1
+#define FLOAT_PRECISION_IFmode 128
+#define FLOAT_PRECISION_TFmode 127
+#define FLOAT_PRECISION_KFmode 126
+#endif /* RS6000_MODES_H */
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 261350)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -2887,7 +2887,7 @@ rs6000_debug_reg_global (void)
fprintf (stderr, DEBUG_FMT_D, "tls_size", rs6000_tls_size);
fprintf (stderr, DEBUG_FMT_D, "long_double_size",
rs6000_long_double_type_size);
- if (rs6000_long_double_type_size == 128)
+ if (rs6000_long_double_type_size > 64)
{
fprintf (stderr, DEBUG_FMT_S, "long double type",
TARGET_IEEEQUAD ? "IEEE" : "IBM");
@@ -4558,16 +4558,25 @@ rs6000_option_override_internal (bool gl
}
}
+ /* Use long double size to select the appropriate long double. We use
+ TYPE_PRECISION to differentiate the 3 different long double types. We map
+ 128 into the precision used for TFmode. */
+ int default_long_double_size = (RS6000_DEFAULT_LONG_DOUBLE_SIZE == 64
+ ? 64
+ : FLOAT_PRECISION_TFmode);
+
/* Set long double size before the IEEE 128-bit tests. */
if (!global_options_set.x_rs6000_long_double_type_size)
{
if (main_target_opt != NULL
&& (main_target_opt->x_rs6000_long_double_type_size
- != RS6000_DEFAULT_LONG_DOUBLE_SIZE))
+ != default_long_double_size))
error ("target attribute or pragma changes long double size");
else
- rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
+ rs6000_long_double_type_size = default_long_double_size;
}
+ else if (rs6000_long_double_type_size == 128)
+ rs6000_long_double_type_size = FLOAT_PRECISION_TFmode;
/* Set -mabi=ieeelongdouble on some old targets. In the future, power server
systems will also set long double to be IEEE 128-bit. AIX and Darwin
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h (revision 261350)
+++ gcc/config/rs6000/rs6000.h (working copy)
@@ -30,6 +30,11 @@
#include "config/rs6000/rs6000-opts.h"
#endif
+/* 128-bit floating point precision values. */
+#ifndef RS6000_MODES_H
+#include "config/rs6000/rs6000-modes.h"
+#endif
+
/* Definitions for the object file format. These are set at
compile-time. */
@@ -539,7 +544,9 @@ extern int rs6000_vector_align[];
#define TARGET_ALIGN_NATURAL 0
#endif
-#define TARGET_LONG_DOUBLE_128 (rs6000_long_double_type_size == 128)
+/* We use values 126..128 to pick the appropriate long double type (IFmode,
+ KFmode, TFmode). */
+#define TARGET_LONG_DOUBLE_128 (rs6000_long_double_type_size > 64)
#define TARGET_IEEEQUAD rs6000_ieeequad
#define TARGET_ALTIVEC_ABI rs6000_altivec_abi
#define TARGET_LDBRX (TARGET_POPCNTD || rs6000_cpu == PROCESSOR_CELL)
@@ -865,9 +872,8 @@ extern unsigned char rs6000_recip_bits[]
words. */
#define DOUBLE_TYPE_SIZE 64
-/* A C expression for the size in bits of the type `long double' on
- the target machine. If you don't define this, the default is two
- words. */
+/* A C expression for the size in bits of the type `long double' on the target
+ machine. If you don't define this, the default is two words. */
#define LONG_DOUBLE_TYPE_SIZE rs6000_long_double_type_size
/* Work around rs6000_long_double_type_size dependency in ada/targtyps.c. */
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 261349)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -8159,8 +8159,8 @@ (define_expand "extendtfkf2"
})
(define_expand "trunciftf2"
- [(set (match_operand:IF 0 "gpc_reg_operand")
- (float_truncate:IF (match_operand:TF 1 "gpc_reg_operand")))]
+ [(set (match_operand:TF 0 "gpc_reg_operand")
+ (float_truncate:TF (match_operand:IF 1 "gpc_reg_operand")))]
"TARGET_FLOAT128_TYPE"
{
rs6000_expand_float128_convert (operands[0], operands[1], false);
@@ -8168,8 +8168,8 @@ (define_expand "trunciftf2"
})
(define_expand "truncifkf2"
- [(set (match_operand:IF 0 "gpc_reg_operand")
- (float_truncate:IF (match_operand:KF 1 "gpc_reg_operand")))]
+ [(set (match_operand:KF 0 "gpc_reg_operand")
+ (float_truncate:KF (match_operand:IF 1 "gpc_reg_operand")))]
"TARGET_FLOAT128_TYPE"
{
rs6000_expand_float128_convert (operands[0], operands[1], false);