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 <meiss...@linux.ibm.com> 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: meiss...@linux.ibm.com, 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 (meiss...@linux.ibm.com) + + 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);