These patches are the machine independent changes needed to add IEEE 128-bit floating point to the PowerPC. The change is to add a new mode macro, SPECIAL_FLOATING_MODE, that is similar to FRACTIONAL_FLOATING_MODE, except that the normal widening functions skip SPECIAL_FLOATING_MODE's modes. In particular, on the PowerPC, the existing long double functions are faster, than the IEEE 128-bit emulation functions, so it is desirable that double widens to long double instead of __float128.
As a consequence of the way I implemented SPECIAL_FLOATING_MODE, some of the changes involved code that starts at the narrowest type, and goes up by widening types, until an appropriate mode is found, or we find the mode itself. I needed to check whether the wider mode was VOIDmode as well as the original type. 2014-07-15 Michael Meissner <meiss...@linux.vnet.ibm.com> * cse.c (cse_insn): When going through the list of smaller types, exit the loop if the type is VOIDmode in addition to the type we are looking at, to allow special modes that aren't normally considered when widening types. This is used by the PowerPC, so that floating point is widened from double to long double, and does not get converted to the slower __float128 (IEEE 128-bit floating point). * dse.c (find_shift_sequence): Likewise. * combine.c (simplify_comparison): Likewise. * rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise. * machmode.h (GET_MODE_WIDER_MODE_SPECIAL): New macro to get the wider types, including special modes that are normally skipped in looking for a wider type. * machmode.def (SPECIAL_FLOAT_MODE): Document the use of SPECIAL_FLOAT_MODE in comments. * expr.c (init_expr_target): Use the GET_MODE_WIDER_MODE_SPECIAL macro to include special modes in doing the initialization. (compress_float_constant): Likewise. * genmodes.c (struct mode_data): Add support for SPECIAL_FLOAT_MODE that creates floating point modes that are normally skipped in widening types, but are available if the user explicitly uses the type. (complete_mode): Likewise. (FLOAT_MODE): Likewise. (FRACTIONAL_FLOAT_MODE): Likewise. (SPECIAL_FLOAT_MODE): Likewise. (FLOAT_MODE_INTERNAL): Likewise. (make_float_mode): Likewise. (emit_mode_wider): Likewise. * emit-rtl.c (init_derived_machine_modes): Use the GET_MODE_WIDER_MODE_SPECIAL macro to include special modes in doing the initialization. (init_emit_once): Likewise. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/cse.c =================================================================== --- gcc/cse.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/cse.c (working copy) @@ -4823,7 +4823,7 @@ cse_insn (rtx insn) rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1)); for (tmode = GET_MODE_WIDER_MODE (mode); - GET_MODE_SIZE (tmode) <= UNITS_PER_WORD; + GET_MODE_SIZE (tmode) <= UNITS_PER_WORD && tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode)) { rtx inner = gen_lowpart (tmode, XEXP (src, 0)); @@ -4875,7 +4875,7 @@ cse_insn (rtx insn) XEXP (memory_extend_rtx, 0) = src; for (tmode = GET_MODE_WIDER_MODE (mode); - GET_MODE_SIZE (tmode) <= UNITS_PER_WORD; + GET_MODE_SIZE (tmode) <= UNITS_PER_WORD && tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode)) { struct table_elt *larger_elt; Index: gcc/dse.c =================================================================== --- gcc/dse.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/dse.c (working copy) @@ -1738,7 +1738,7 @@ find_shift_sequence (int access_size, for (new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT, MODE_INT); - GET_MODE_BITSIZE (new_mode) <= BITS_PER_WORD; + GET_MODE_BITSIZE (new_mode) <= BITS_PER_WORD && new_mode != VOIDmode; new_mode = GET_MODE_WIDER_MODE (new_mode)) { rtx target, new_reg, shift_seq, insn, new_lhs; Index: gcc/combine.c =================================================================== --- gcc/combine.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/combine.c (working copy) @@ -11118,7 +11118,8 @@ simplify_comparison (enum rtx_code code, else if (c0 == c1) for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (GET_MODE (op0))); - tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode)) + tmode != GET_MODE (op0) && tmode != VOIDmode; + tmode = GET_MODE_WIDER_MODE (tmode)) if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode)) { op0 = gen_lowpart (tmode, inner_op0); Index: gcc/machmode.h =================================================================== --- gcc/machmode.h (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/machmode.h (working copy) @@ -249,6 +249,12 @@ extern const unsigned char mode_nunits[N extern const unsigned char mode_wider[NUM_MACHINE_MODES]; #define GET_MODE_WIDER_MODE(MODE) ((enum machine_mode) mode_wider[MODE]) +/* Special modes are not listed in the normal widening tables, but they are + listed in the widening tables used for initialization, etc. */ +extern const unsigned char mode_wider_special[NUM_MACHINE_MODES]; +#define GET_MODE_WIDER_MODE_SPECIAL(MODE) \ + ((enum machine_mode) mode_wider_special[MODE]) + /* For scalars, this is a mode with twice the precision. For vectors, this is a mode with the same inner mode but with twice the elements. */ extern const unsigned char mode_2xwider[NUM_MACHINE_MODES]; Index: gcc/rtlanal.c =================================================================== --- gcc/rtlanal.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/rtlanal.c (working copy) @@ -5278,7 +5278,8 @@ init_num_sign_bit_copies_in_rep (void) for (in_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); in_mode != VOIDmode; in_mode = GET_MODE_WIDER_MODE (mode)) - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != in_mode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != in_mode && mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { enum machine_mode i; Index: gcc/machmode.def =================================================================== --- gcc/machmode.def (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/machmode.def (working copy) @@ -90,6 +90,15 @@ along with GCC; see the file COPYING3. storage, but with only PRECISION significant bits, using floating point format FORMAT. + SPECIAL_FLOAT_MODE (MODE, BYTESIZE, FORMAT); + declares MODE to be of class FLOAT and BYTESIZE bytes wide, using + floating point format FORMAT. MODE is arranged so that other scalar + floating point mode's of the same size are preferred when the compiler + is trying to widen the floating point. The intention is to support the + PowerPC which has 2 128-bit floating point types (IEEE 128-bit and the + IBM extended double format), and have DFmode widen to TFmode (IBM + format) instead of KFmode (IEEE 128-bit). + DECIMAL_FLOAT_MODE (MODE, BYTESIZE, FORMAT); declares MODE to be of class DECIMAL_FLOAT and BYTESIZE bytes wide. All of the bits of its representation are significant. Index: gcc/expr.c =================================================================== --- gcc/expr.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/expr.c (working copy) @@ -264,11 +264,11 @@ init_expr_target (void) mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000)); for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { enum machine_mode srcmode; for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode; - srcmode = GET_MODE_WIDER_MODE (srcmode)) + srcmode = GET_MODE_WIDER_MODE_SPECIAL (srcmode)) { enum insn_code ic; @@ -3645,7 +3645,7 @@ compress_float_constant (rtx x, rtx y) oldcost = set_src_cost (force_const_mem (dstmode, y), speed); for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode)); - srcmode != orig_srcmode; + srcmode != orig_srcmode && srcmode != VOIDmode; srcmode = GET_MODE_WIDER_MODE (srcmode)) { enum insn_code ic; Index: gcc/genmodes.c =================================================================== --- gcc/genmodes.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/genmodes.c (working copy) @@ -74,6 +74,8 @@ struct mode_data unsigned int fbit; /* the number of fractional bits */ bool need_bytesize_adj; /* true if this mode need dynamic size adjustment */ + bool special; /* true if this mode is special and should be + skipped with the normal widening rules. */ }; static struct mode_data *modes[MAX_MODE_CLASS]; @@ -84,7 +86,7 @@ static const struct mode_data blank_mode 0, "<unknown>", MAX_MODE_CLASS, -1U, -1U, -1U, -1U, 0, 0, 0, 0, 0, - "<unknown>", 0, 0, 0, 0, false + "<unknown>", 0, 0, 0, 0, false, false }; static htab_t modes_by_name; @@ -368,6 +370,7 @@ complete_mode (struct mode_data *m) /* Complex modes should have a component indicated, but no more. */ validate_mode (m, UNSET, UNSET, SET, UNSET, UNSET); m->ncomponents = 2; + m->special = m->component->special; if (m->component->precision != (unsigned int)-1) m->precision = 2 * m->component->precision; m->bytesize = 2 * m->component->bytesize; @@ -384,6 +387,7 @@ complete_mode (struct mode_data *m) if (m->component->precision != (unsigned int)-1) m->precision = m->ncomponents * m->component->precision; m->bytesize = m->ncomponents * m->component->bytesize; + m->special = m->component->special; break; default: @@ -579,20 +583,29 @@ make_fixed_point_mode (enum mode_class c m->fbit = fbit; } -#define FLOAT_MODE(N, Y, F) FRACTIONAL_FLOAT_MODE (N, -1U, Y, F) -#define FRACTIONAL_FLOAT_MODE(N, B, Y, F) \ - make_float_mode (#N, B, Y, #F, __FILE__, __LINE__) +#define FLOAT_MODE(N, Y, F) \ + FLOAT_MODE_INTERNAL (N, -1U, Y, F, false) + +#define FRACTIONAL_FLOAT_MODE(N, B, Y, F) \ + FLOAT_MODE_INTERNAL (N, B, Y, F, false) + +#define SPECIAL_FLOAT_MODE(N, B, Y, F) \ + FLOAT_MODE_INTERNAL (N, B, Y, F, true) + +#define FLOAT_MODE_INTERNAL(N, B, Y, F, SPECIAL) \ + make_float_mode (#N, B, Y, #F, SPECIAL, __FILE__, __LINE__) static void make_float_mode (const char *name, unsigned int precision, unsigned int bytesize, - const char *format, + const char *format, bool special, const char *file, unsigned int line) { struct mode_data *m = new_mode (MODE_FLOAT, name, file, line); m->bytesize = bytesize; m->precision = precision; m->format = format; + m->special = special; } #define DECIMAL_FLOAT_MODE(N, Y, F) \ @@ -1194,7 +1207,9 @@ emit_mode_wider (void) int c; struct mode_data *m; - print_decl ("unsigned char", "mode_wider", "NUM_MACHINE_MODES"); + /* Special modes are not listed in the normal widening tables, but they are + listed in the widening tables used for initialization, etc. */ + print_decl ("unsigned char", "mode_wider_special", "NUM_MACHINE_MODES"); for_all_modes (c, m) tagged_printf ("%smode", @@ -1202,6 +1217,37 @@ emit_mode_wider (void) m->name); print_closer (); + print_decl ("unsigned char", "mode_wider", "NUM_MACHINE_MODES"); + + for_all_modes (c, m) + { + const char *name; + + if (!m->wider) + name = void_mode->name; + else if (!m->wider->special || m->special) + name = m->wider->name; + else + { + struct mode_data * m2; + + name = void_mode->name; + for (m2 = m->wider->wider; + m2 && m2 != void_mode; + m2 = m2->wider) + { + if (!m2->special) + { + name = m2->name; + break; + } + } + } + + tagged_printf ("%smode", name, m->name); + } + + print_closer (); print_decl ("unsigned char", "mode_2xwider", "NUM_MACHINE_MODES"); for_all_modes (c, m) @@ -1212,6 +1258,8 @@ emit_mode_wider (void) m2 && m2 != void_mode; m2 = m2->wider) { + if (m2->special && !m->special) + continue; if (m2->bytesize < 2 * m->bytesize) continue; if (m->precision != (unsigned int) -1) @@ -1242,8 +1290,10 @@ emit_mode_wider (void) break; } + if (m2 == void_mode) m2 = 0; + tagged_printf ("%smode", m2 ? m2->name : void_mode->name, m->name); Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk) (revision 212529) +++ gcc/emit-rtl.c (working copy) @@ -5786,7 +5786,7 @@ init_derived_machine_modes (void) for (enum machine_mode mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT && byte_mode == VOIDmode) @@ -5868,13 +5868,13 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) const_tiny_rtx[i][(int) mode] = CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); for (mode = GET_CLASS_NARROWEST_MODE (MODE_DECIMAL_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) const_tiny_rtx[i][(int) mode] = CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); @@ -5882,7 +5882,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) const_tiny_rtx[i][(int) mode] = GEN_INT (i); for (mode = MIN_MODE_PARTIAL_INT; @@ -5895,7 +5895,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) const_tiny_rtx[3][(int) mode] = constm1_rtx; for (mode = MIN_MODE_PARTIAL_INT; @@ -5905,7 +5905,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)]; const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner); @@ -5913,7 +5913,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)]; const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner); @@ -5921,7 +5921,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); @@ -5930,7 +5930,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); @@ -5938,7 +5938,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_FRACT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { FCONST0 (mode).data.high = 0; FCONST0 (mode).data.low = 0; @@ -5949,7 +5949,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_UFRACT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { FCONST0 (mode).data.high = 0; FCONST0 (mode).data.low = 0; @@ -5960,7 +5960,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_ACCUM); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { FCONST0 (mode).data.high = 0; FCONST0 (mode).data.low = 0; @@ -5982,7 +5982,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_UACCUM); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { FCONST0 (mode).data.high = 0; FCONST0 (mode).data.low = 0; @@ -6004,21 +6004,21 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FRACT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); } for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UFRACT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); } for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_ACCUM); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1); @@ -6026,7 +6026,7 @@ init_emit_once (void) for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UACCUM); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + mode = GET_MODE_WIDER_MODE_SPECIAL (mode)) { const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0); const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);