This patch adds a scalar_float_mode class, which wraps a mode enum
that is known to satisfy SCALAR_FLOAT_MODE_P.  Things like "SFmode"
now give a scalar_float_mode object instead of a machine_mode.
This in turn needs a change to the real.h format_helper, so that
it can accept both machine_modes and scalar_float_modes.

gcc/
2016-11-30  Richard Sandiford  <richard.sandif...@arm.com>
            Alan Hayward  <alan.hayw...@arm.com>
            David Sherwood  <david.sherw...@arm.com>

        * coretypes.h (scalar_float_mode): New type.
        * machmode.h (PROTECT_ENUM_CONVERSION): New macro.
        (is_a): New function.
        (as_a): Likewise.
        (dyn_cast): Likewise.
        (scalar_float_mode): New class.
        (scalar_float_mode::includes_p): New function.
        (scalar_float_mode::from_int): Likewise.
        * real.h (FLOAT_MODE_FORMAT): Use as_a <scalar_float_mode>.
        (format_helper::format_helper): Turn into a template.
        * genmodes.c (get_mode_class): New function.
        (emit_insn_modes_h): Give modes the class returned by get_mode_class,
        or machine_mode if none.
        * config/aarch64/aarch64.c (aarch64_simd_valid_immediate): Use
        as_a <scalar_float_mode>.
        * dwarf2out.c (mem_loc_descriptor): Likewise.
        (insert_float): Likewise.
        (add_const_value_attribute): Likewise.
        * simplify-rtx.c (simplify_immed_subreg): Likewise.
        * optabs.c (expand_absneg_bit): Take a scalar_float_mode.
        (expand_unop): Update accordingly.
        (expand_abs_nojump): Likewise.
        (expand_copysign_absneg): Take a scalar_float_mode.
        (expand_copysign_bit): Likewise.
        (expand_copysign): Update accordingly.

gcc/ada/
2016-11-24  Richard Sandiford  <richard.sandif...@arm.com>
            Alan Hayward  <alan.hayw...@arm.com>
            David Sherwood  <david.sherw...@arm.com>

        * gcc-interface/utils.c (gnat_type_for_mode): Use is_a
        <scalar_float_mode> instead of SCALAR_FLOAT_MODE_P.

diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 0ae381f..29e5203 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -3411,8 +3411,10 @@ gnat_type_for_mode (machine_mode mode, int unsignedp)
   if (COMPLEX_MODE_P (mode))
     return NULL_TREE;
 
-  if (SCALAR_FLOAT_MODE_P (mode))
-    return float_type_for_precision (GET_MODE_PRECISION (mode), mode);
+  scalar_float_mode float_mode;
+  if (is_a <scalar_float_mode> (mode, &float_mode))
+    return float_type_for_precision (GET_MODE_PRECISION (float_mode),
+                                    float_mode);
 
   if (SCALAR_INT_MODE_P (mode))
     return gnat_type_for_size (GET_MODE_BITSIZE (mode), unsignedp);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 944577d..cc97b7a 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -11035,8 +11035,12 @@ aarch64_simd_valid_immediate (rtx op, machine_mode 
mode, bool inverse,
 
       if (info)
        {
-         info->value = CONST_VECTOR_ELT (op, 0);
-         info->element_width = GET_MODE_BITSIZE (GET_MODE (info->value));
+         rtx elt = CONST_VECTOR_ELT (op, 0);
+         scalar_float_mode elt_mode
+           = as_a <scalar_float_mode> (GET_MODE (elt));
+
+         info->value = elt;
+         info->element_width = GET_MODE_BITSIZE (elt_mode);
          info->mvn = false;
          info->shift = 0;
        }
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 9f81995..f4c1859 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -56,6 +56,7 @@ struct rtx_def;
 typedef struct rtx_def *rtx;
 typedef const struct rtx_def *const_rtx;
 class machine_mode;
+class scalar_float_mode;
 template<typename> class opt_mode;
 
 /* Subclasses of rtx_def, using indentation to show the class
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8dc8523..5130b64 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -15121,7 +15121,8 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
          else
 #endif
            {
-             unsigned int length = GET_MODE_SIZE (mode);
+             scalar_float_mode float_mode = as_a <scalar_float_mode> (mode);
+             unsigned int length = GET_MODE_SIZE (float_mode);
              unsigned char *array = ggc_vec_alloc<unsigned char> (length);
 
              insert_float (rtl, array);
@@ -18343,11 +18344,12 @@ insert_float (const_rtx rtl, unsigned char *array)
 {
   long val[4];
   int i;
+  scalar_float_mode mode = as_a <scalar_float_mode> (GET_MODE (rtl));
 
-  real_to_target (val, CONST_DOUBLE_REAL_VALUE (rtl), GET_MODE (rtl));
+  real_to_target (val, CONST_DOUBLE_REAL_VALUE (rtl), mode);
 
   /* real_to_target puts 32-bit pieces in each long.  Pack them.  */
-  for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
+  for (i = 0; i < GET_MODE_SIZE (mode) / 4; i++)
     {
       insert_int (val[i], 4, array);
       array += 4;
@@ -18391,21 +18393,19 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
         floating-point constant.  A CONST_DOUBLE is used whenever the
         constant requires more than one word in order to be adequately
         represented.  */
-      {
-       machine_mode mode = GET_MODE (rtl);
-
-       if (TARGET_SUPPORTS_WIDE_INT == 0 && !SCALAR_FLOAT_MODE_P (mode))
-         add_AT_double (die, DW_AT_const_value,
-                        CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
-       else
-         {
-           unsigned int length = GET_MODE_SIZE (mode);
-           unsigned char *array = ggc_vec_alloc<unsigned char> (length);
+      if (TARGET_SUPPORTS_WIDE_INT == 0
+         && !SCALAR_FLOAT_MODE_P (GET_MODE (rtl)))
+       add_AT_double (die, DW_AT_const_value,
+                      CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+      else
+       {
+         scalar_float_mode mode = as_a <scalar_float_mode> (GET_MODE (rtl));
+         unsigned int length = GET_MODE_SIZE (mode);
+         unsigned char *array = ggc_vec_alloc<unsigned char> (length);
 
-           insert_float (rtl, array);
-           add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
-         }
-      }
+         insert_float (rtl, array);
+         add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
+       }
       return true;
 
     case CONST_VECTOR:
diff --git a/gcc/genmodes.c b/gcc/genmodes.c
index 4dbced2..3cc426e 100644
--- a/gcc/genmodes.c
+++ b/gcc/genmodes.c
@@ -1129,6 +1129,23 @@ mode_unit_precision_inline (machine_mode_enum mode)\n\
 }\n");
 }
 
+/* Return the best machine mode class for MODE, or null if machine_mode
+   should be used.  */
+
+static const char *
+get_mode_class (struct mode_data *mode)
+{
+  switch (mode->cl)
+    {
+    case MODE_FLOAT:
+    case MODE_DECIMAL_FLOAT:
+      return "scalar_float_mode";
+
+    default:
+      return NULL;
+    }
+}
+
 static void
 emit_insn_modes_h (void)
 {
@@ -1158,8 +1175,12 @@ enum machine_mode_enum\n{");
        printf ("#ifdef USE_ENUM_MODES\n");
        printf ("#define %smode E_%smode\n", m->name, m->name);
        printf ("#else\n");
-       printf ("#define %smode (machine_mode (E_%smode))\n",
-               m->name, m->name);
+       if (const char *mode_class = get_mode_class (m))
+         printf ("#define %smode (%s::from_int (E_%smode))\n",
+                 m->name, mode_class, m->name);
+       else
+         printf ("#define %smode (machine_mode (E_%smode))\n",
+                 m->name, m->name);
        printf ("#endif\n");
       }
 
diff --git a/gcc/machmode.h b/gcc/machmode.h
index 44a8ad4..996f991 100644
--- a/gcc/machmode.h
+++ b/gcc/machmode.h
@@ -29,6 +29,16 @@ extern const unsigned short 
mode_unit_precision[NUM_MACHINE_MODES];
 extern const unsigned char mode_wider[NUM_MACHINE_MODES];
 extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
 
+/* Allow direct conversion of enums to specific mode classes only
+   when USE_ENUM_MODES is defined.  This is only intended for use
+   by gencondmd, so that it can tell more easily when .md conditions
+   are always false.  */
+#ifdef USE_ENUM_MODES
+#define PROTECT_ENUM_CONVERSION public
+#else
+#define PROTECT_ENUM_CONVERSION protected
+#endif
+
 /* Get the name of mode MODE as a string.  */
 
 extern const char * const mode_name[NUM_MACHINE_MODES];
@@ -237,6 +247,85 @@ opt_mode<T>::exists (U *mode) const
   return false;
 }
 
+/* Return true if mode M has type T.  */
+
+template<typename T>
+inline bool
+is_a (machine_mode_enum m)
+{
+  return T::includes_p (m);
+}
+
+/* Assert that mode M has type T, and return it in that form.  */
+
+template<typename T>
+inline T
+as_a (machine_mode_enum m)
+{
+  gcc_checking_assert (T::includes_p (m));
+  return T::from_int (m);
+}
+
+/* Convert M to an opt_mode<T>.  */
+
+template<typename T>
+inline opt_mode<T>
+dyn_cast (machine_mode_enum m)
+{
+  if (T::includes_p (m))
+    return T::from_int (m);
+  return opt_mode<T> ();
+}
+
+/* Return true if mode M has type T, storing it as a T in *RESULT
+   if so.  */
+
+template<typename T, typename U>
+inline bool
+is_a (machine_mode_enum m, U *result)
+{
+  if (T::includes_p (m))
+    {
+      *result = T::from_int (m);
+      return true;
+    }
+  return false;
+}
+
+/* Represents a machine mode that is known to be a SCALAR_FLOAT_MODE_P.  */
+class scalar_float_mode
+{
+public:
+  ALWAYS_INLINE scalar_float_mode () {}
+  ALWAYS_INLINE operator machine_mode_enum () const { return m_mode; }
+
+  static bool includes_p (machine_mode_enum);
+  static scalar_float_mode from_int (int i);
+
+PROTECT_ENUM_CONVERSION:
+  ALWAYS_INLINE scalar_float_mode (machine_mode_enum m) : m_mode (m) {}
+
+protected:
+  machine_mode_enum m_mode;
+};
+
+/* Return true if M is a scalar_float_mode.  */
+
+inline bool
+scalar_float_mode::includes_p (machine_mode_enum m)
+{
+  return SCALAR_FLOAT_MODE_P (m);
+}
+
+/* Return M as a scalar_float_mode.  This function should only be used by
+   utility functions; general code should use as_a<T> instead.  */
+
+ALWAYS_INLINE scalar_float_mode
+scalar_float_mode::from_int (int i)
+{
+  return machine_mode_enum (i);
+}
+
 /* Represents a general machine mode (scalar or non-scalar).  */
 class machine_mode
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 5dab1b4..58c26e4 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -2550,7 +2550,7 @@ lowpart_subreg_maybe_copy (machine_mode omode, rtx val,
    logical operation on the sign bit.  */
 
 static rtx
-expand_absneg_bit (enum rtx_code code, machine_mode mode,
+expand_absneg_bit (enum rtx_code code, scalar_float_mode mode,
                   rtx op0, rtx target)
 {
   const struct real_format *fmt;
@@ -2696,6 +2696,7 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, 
rtx target,
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
   machine_mode wider_mode;
+  scalar_float_mode float_mode;
   rtx temp;
   rtx libfunc;
 
@@ -2886,9 +2887,9 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, 
rtx target,
   if (optab_to_code (unoptab) == NEG)
     {
       /* Try negating floating point values by flipping the sign bit.  */
-      if (SCALAR_FLOAT_MODE_P (mode))
+      if (is_a <scalar_float_mode> (mode, &float_mode))
        {
-         temp = expand_absneg_bit (NEG, mode, op0, target);
+         temp = expand_absneg_bit (NEG, float_mode, op0, target);
          if (temp)
            return temp;
        }
@@ -3085,9 +3086,10 @@ expand_abs_nojump (machine_mode mode, rtx op0, rtx 
target,
     return temp;
 
   /* For floating point modes, try clearing the sign bit.  */
-  if (SCALAR_FLOAT_MODE_P (mode))
+  scalar_float_mode float_mode;
+  if (is_a <scalar_float_mode> (mode, &float_mode))
     {
-      temp = expand_absneg_bit (ABS, mode, op0, target);
+      temp = expand_absneg_bit (ABS, float_mode, op0, target);
       if (temp)
        return temp;
     }
@@ -3241,7 +3243,7 @@ expand_one_cmpl_abs_nojump (machine_mode mode, rtx op0, 
rtx target)
    and not playing with subregs so much, will help the register allocator.  */
 
 static rtx
-expand_copysign_absneg (machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_absneg (scalar_float_mode mode, rtx op0, rtx op1, rtx target,
                        int bitpos, bool op0_is_abs)
 {
   machine_mode imode;
@@ -3325,7 +3327,7 @@ expand_copysign_absneg (machine_mode mode, rtx op0, rtx 
op1, rtx target,
    is true if op0 is known to have its sign bit clear.  */
 
 static rtx
-expand_copysign_bit (machine_mode mode, rtx op0, rtx op1, rtx target,
+expand_copysign_bit (scalar_float_mode mode, rtx op0, rtx op1, rtx target,
                     int bitpos, bool op0_is_abs)
 {
   machine_mode imode;
@@ -3423,12 +3425,12 @@ expand_copysign_bit (machine_mode mode, rtx op0, rtx 
op1, rtx target,
 rtx
 expand_copysign (rtx op0, rtx op1, rtx target)
 {
-  machine_mode mode = GET_MODE (op0);
+  scalar_float_mode mode;
   const struct real_format *fmt;
   bool op0_is_abs;
   rtx temp;
 
-  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
+  mode = as_a <scalar_float_mode> (GET_MODE (op0));
   gcc_assert (GET_MODE (op1) == mode);
 
   /* First try to do it with a special instruction.  */
diff --git a/gcc/real.h b/gcc/real.h
index 59af580..e861b03 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -183,8 +183,7 @@ extern const struct real_format *
                        : (gcc_unreachable (), 0)])
 
 #define FLOAT_MODE_FORMAT(MODE) \
-  (REAL_MODE_FORMAT (SCALAR_FLOAT_MODE_P (MODE)? (MODE) \
-                                              : GET_MODE_INNER (MODE)))
+  (REAL_MODE_FORMAT (as_a <scalar_float_mode> (GET_MODE_INNER (MODE))))
 
 /* The following macro determines whether the floating point format is
    composite, i.e. may contain non-consecutive mantissa bits, in which
@@ -212,7 +211,7 @@ class format_helper
 {
 public:
   format_helper (const real_format *format) : m_format (format) {}
-  format_helper (machine_mode m);
+  template<typename T> format_helper (const T &);
   const real_format *operator-> () const { return m_format; }
   operator const real_format *() const { return m_format; }
 
@@ -222,7 +221,8 @@ private:
   const real_format *m_format;
 };
 
-inline format_helper::format_helper (machine_mode m)
+template<typename T>
+inline format_helper::format_helper (const T &m)
   : m_format (m == VOIDmode ? 0 : REAL_MODE_FORMAT (m))
 {}
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 0251bd4..907c1e7 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -5816,9 +5816,11 @@ simplify_immed_subreg (machine_mode outermode, rtx op,
            {
              /* This is big enough for anything on the platform.  */
              long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
-             int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
+             scalar_float_mode el_mode;
+
+             el_mode = as_a <scalar_float_mode> (GET_MODE (el));
+             int bitsize = GET_MODE_BITSIZE (el_mode);
 
-             gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
              gcc_assert (bitsize <= elem_bitsize);
              gcc_assert (bitsize % value_bit == 0);
 

Reply via email to