This patch contains the machine independent changes that I will need to add
IEEE 128-bit floating point to the GCC compiler for PowerPC.

It adds a new mode defintion macro: SPECIAL_FLOAT_MODE that is similar to
FLOAT_MODE.  The difference is the conversion system will skip
SPECIAL_FLOAT_MODE types when it is looking for a larger type.

The problem is the PowerPC will have 2 128-bit floating point types, one using
the IBM double-double format (a pair of doubles to give the user more mantissa
bits, but no greater exponent range), and IEEE 128-bit floating point.  I don't
want DFmode to automatically convert to KFmode (IEEE 128-bit floating point),
but to TFmode (IBM double-double).

With these patches applied, in the places where we are setting up types, we
include the special floating point types, but for the normal
GET_MODE_WIDER_MODE usage we do not want to use the special floating point
mode.

I found some of the GET_MODE_WIDER_MODE loops needed to add a check for running
out of modes if the mode type was special.  For those loops, I added a test for
mode not being VOIDmode.


2015-05-05  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        * machmode.h (GET_MODE_WIDER_MODE_SPECIAL): New macro to get the
        wider modes that are normally skipped by default.

        * rtlanal.c (init_num_sign_bit_copies_in_rep): In going from
        narrow to wider modes, check whether we receive VOIDmode, since
        special floating point types are not listed in the normal widening
        tables.  When doing initializations, go through all modes in a
        class, even special modes, that are normally skipped by default
        widening.
        * cse.c (cse_insn): Likewise.
        * expr.c (init_expr_target): Likewise.
        (compress_float_constant): Likewise.
        * dse.c (find_shift_sequence): Likewise.
        * emit-rtl.c (init_derived_machine_modes): Likewise.
        (init_emit_once): Likewise.
        * combine.c (simplify_comparison): Likewise.

        * machmode.def (SPECIAL_FLOAT_MODE): New type of floating point
        that is special, and is not automatically part of the normal
        widening rules.

        * genmodes.c (struct mode_data): Add special field.
        (blank_mode): Initialize special.
        (complete_mode): Complex and vector types inherit the special mode
        class.
        (FLOAT_MODE): Add special field for floating point to sort special
        nodes higher than normal nodes for the same size.  The intention
        is to allow __float128 on PowerPC (KFmode) to be higher than long
        double (TFmode), so that automatic widening uses the long double
        type.
        (FRACTIONAL_FLOAT_MODE): Likewise.
        (SPECIAL_FLOAT_MODE): Likewise.
        (FLOAT_MODE_INTERNAL): Likewise.
        (make_float_mode): Likewise.
        (emit_mode_wider): Likewise.

These patches have been part of my IEEE 128-bit floating point branch for some
time, and I have bootstrapped that branch many times.  At present, I am just
submitting these patches to add the necessary infrastructure for the patches I
will be contributing later.  I have done an x86 bootstrap on the IEEE 128-bit
floating point branch to make sure it does not cause problems for ports that do
not define SPECIAL_FLOAT_MODE types.

Are these patches ok to commit to the trunk?

I would also be open to alternative ways of creating a mode that is not part of
the normal wider conversion methods or in adding options to control the order
the widening types are searched.

-- 
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/gcc/cse.c)    
(revision 222823)
+++ gcc/cse.c   (.../gcc/cse.c) (working copy)
@@ -4856,7 +4856,7 @@ cse_insn (rtx_insn *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));
@@ -4908,7 +4908,7 @@ cse_insn (rtx_insn *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/expr.c
===================================================================
--- gcc/expr.c  (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/expr.c)   
(revision 222823)
+++ gcc/expr.c  (.../gcc/expr.c)        (working copy)
@@ -261,11 +261,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))
     {
       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;
 
@@ -3686,7 +3686,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/machmode.h
===================================================================
--- gcc/machmode.h      
(.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/machmode.h)       
(revision 222823)
+++ gcc/machmode.h      (.../gcc/machmode.h)    (working copy)
@@ -252,6 +252,12 @@ extern const unsigned char mode_nunits[N
 extern const unsigned char mode_wider[NUM_MACHINE_MODES];
 #define GET_MODE_WIDER_MODE(MODE) ((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) \
+  ((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/gcc/rtlanal.c)        
(revision 222823)
+++ gcc/rtlanal.c       (.../gcc/rtlanal.c)     (working copy)
@@ -5305,7 +5305,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))
       {
        machine_mode i;
Index: gcc/machmode.def
===================================================================
--- gcc/machmode.def    
(.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/machmode.def)     
(revision 222823)
+++ gcc/machmode.def    (.../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/dse.c
===================================================================
--- gcc/dse.c   (.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/dse.c)    
(revision 222823)
+++ gcc/dse.c   (.../gcc/dse.c) (working copy)
@@ -1773,7 +1773,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, new_lhs;
Index: gcc/genmodes.c
===================================================================
--- gcc/genmodes.c      
(.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/genmodes.c)       
(revision 222823)
+++ gcc/genmodes.c      (.../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.  */
   unsigned int int_n;          /* If nonzero, then __int<INT_N> will be 
defined */
 };
 
@@ -85,7 +87,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, 0
+  "<unknown>", 0, 0, 0, 0, false, false, 0
 };
 
 static htab_t modes_by_name;
@@ -370,6 +372,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;
@@ -386,6 +389,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:
@@ -594,20 +598,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)    \
@@ -1246,7 +1259,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",
@@ -1254,6 +1269,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)
@@ -1264,6 +1310,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)
@@ -1294,8 +1342,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/gcc/emit-rtl.c)       
(revision 222823)
+++ gcc/emit-rtl.c      (.../gcc/emit-rtl.c)    (working copy)
@@ -5876,7 +5876,7 @@ init_derived_machine_modes (void)
 
   for (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)
@@ -5953,13 +5953,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);
 
@@ -5967,7 +5967,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;
@@ -5980,7 +5980,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;
@@ -5990,7 +5990,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);
@@ -5998,7 +5998,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);
@@ -6006,7 +6006,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);
@@ -6015,7 +6015,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);
@@ -6023,7 +6023,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;
@@ -6034,7 +6034,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;
@@ -6045,7 +6045,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;
@@ -6067,7 +6067,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;
@@ -6089,21 +6089,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);
@@ -6111,7 +6111,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);
Index: gcc/combine.c
===================================================================
--- gcc/combine.c       
(.../svn+ssh://meiss...@gcc.gnu.org/svn/gcc/trunk/gcc/combine.c)        
(revision 222823)
+++ gcc/combine.c       (.../gcc/combine.c)     (working copy)
@@ -11419,7 +11419,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);

Reply via email to