Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	2017-07-13 09:18:22.924279021 +0100
+++ gcc/coretypes.h	2017-07-13 09:18:23.795186280 +0100
@@ -55,6 +55,7 @@ typedef const struct simple_bitmap_def *
 struct rtx_def;
 typedef struct rtx_def *rtx;
 typedef const struct rtx_def *const_rtx;
+class scalar_float_mode;
 template<typename> class opt_mode;
 
 /* Subclasses of rtx_def, using indentation to show the class
@@ -311,6 +312,8 @@ #define rtx_insn struct _dont_use_rtx_in
 #define tree union _dont_use_tree_here_ *
 #define const_tree union _dont_use_tree_here_ *
 
+typedef struct scalar_float_mode scalar_float_mode;
+
 #endif
 
 /* Classes of functions that compiler needs to check
Index: gcc/machmode.h
===================================================================
--- gcc/machmode.h	2017-07-13 09:18:22.930278376 +0100
+++ gcc/machmode.h	2017-07-13 09:18:23.798185961 +0100
@@ -46,9 +46,15 @@ struct mode_traits
        res = T (typename mode_traits<T>::from_int (mode));
 
      when assigning to a value RES that must be assignment-compatible
-     with (but possibly not the same as) T.
-
-     Here we use an enum type distinct from machine_mode but with the
+     with (but possibly not the same as) T.  */
+#ifdef USE_ENUM_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.  */
+  typedef machine_mode from_int;
+#else
+  /* Here we use an enum type distinct from machine_mode but with the
      same range as machine_mode.  T should have a constructor that
      accepts this enum type; it should not have a constructor that
      accepts machine_mode.
@@ -58,6 +64,7 @@ struct mode_traits
      unoptimized code, the return statement above would construct the
      returned T directly from the numerical value of MODE.  */
   enum from_int { dummy = MAX_MACHINE_MODE };
+#endif
 };
 
 template<>
@@ -287,6 +294,75 @@ 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 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 m)
+{
+  gcc_checking_assert (T::includes_p (m));
+  return typename mode_traits<T>::from_int (m);
+}
+
+/* Convert M to an opt_mode<T>.  */
+
+template<typename T>
+inline opt_mode<T>
+dyn_cast (machine_mode m)
+{
+  if (T::includes_p (m))
+    return T (typename mode_traits<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 m, U *result)
+{
+  if (T::includes_p (m))
+    {
+      *result = T (typename mode_traits<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:
+  typedef mode_traits<scalar_float_mode>::from_int from_int;
+
+  ALWAYS_INLINE scalar_float_mode () {}
+  ALWAYS_INLINE scalar_float_mode (from_int m) : m_mode (machine_mode (m)) {}
+  ALWAYS_INLINE operator machine_mode () const { return m_mode; }
+
+  static bool includes_p (machine_mode);
+
+protected:
+  machine_mode m_mode;
+};
+
+/* Return true if M is a scalar_float_mode.  */
+
+inline bool
+scalar_float_mode::includes_p (machine_mode m)
+{
+  return SCALAR_FLOAT_MODE_P (m);
+}
+
 /* Return the base GET_MODE_SIZE value for MODE.  */
 
 ALWAYS_INLINE unsigned short
@@ -548,6 +624,21 @@ struct int_n_data_t {
 extern bool int_n_enabled_p[NUM_INT_N_ENTS];
 extern const int_n_data_t int_n_data[NUM_INT_N_ENTS];
 
+/* Return true if MODE has class MODE_FLOAT, storing it as a
+   scalar_float_mode in *FLOAT_MODE if so.  */
+
+template<typename T>
+inline bool
+is_float_mode (machine_mode mode, T *float_mode)
+{
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      *float_mode = scalar_float_mode (scalar_float_mode::from_int (mode));
+      return true;
+    }
+  return false;
+}
+
 namespace mode_iterator
 {
   /* Start mode iterator *ITER at the first mode in class MCLASS, if any.  */
Index: gcc/gdbhooks.py
===================================================================
--- gcc/gdbhooks.py	2017-07-13 09:18:22.928278591 +0100
+++ gcc/gdbhooks.py	2017-07-13 09:18:23.798185961 +0100
@@ -422,6 +422,16 @@ class VecPrinter:
 
 ######################################################################
 
+class MachineModePrinter:
+    def __init__(self, gdbval):
+        self.gdbval = gdbval
+
+    def to_string (self):
+        name = str(self.gdbval['m_mode'])
+        return name[2:] if name.startswith('E_') else name
+
+######################################################################
+
 class OptMachineModePrinter:
     def __init__(self, gdbval):
         self.gdbval = gdbval
@@ -532,6 +542,8 @@ def build_pretty_printer():
 
     pp.add_printer_for_regex(r'opt_mode<(\S+)>',
                              'opt_mode', OptMachineModePrinter)
+    pp.add_printer_for_types(['scalar_float_mode'],
+                             'scalar_float_mode', MachineModePrinter)
 
     return pp
 
Index: gcc/real.h
===================================================================
--- gcc/real.h	2017-06-12 17:05:22.266750229 +0100
+++ gcc/real.h	2017-07-13 09:18:23.799185854 +0100
@@ -183,8 +183,7 @@ #define REAL_MODE_FORMAT(MODE)						\
 			: (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 @@ #define MODE_HAS_SIGN_DEPENDENT_ROUNDING
 {
 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 @@ #define MODE_HAS_SIGN_DEPENDENT_ROUNDING
   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))
 {}
 
Index: gcc/genmodes.c
===================================================================
--- gcc/genmodes.c	2017-07-13 09:18:20.866501621 +0100
+++ gcc/genmodes.c	2017-07-13 09:18:23.798185961 +0100
@@ -1129,6 +1129,23 @@ mode_unit_precision_inline (machine_mode
 }\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\n{");
 	printf ("#ifdef USE_ENUM_MODES\n");
 	printf ("#define %smode E_%smode\n", m->name, m->name);
 	printf ("#else\n");
-	printf ("#define %smode ((void) 0, E_%smode)\n",
-		m->name, m->name);
+	if (const char *mode_class = get_mode_class (m))
+	  printf ("#define %smode (%s ((%s::from_int) E_%smode))\n",
+		  m->name, mode_class, mode_class, m->name);
+	else
+	  printf ("#define %smode ((void) 0, E_%smode)\n",
+		  m->name, m->name);
 	printf ("#endif\n");
       }
 
Index: gcc/config/aarch64/aarch64.c
===================================================================
--- gcc/config/aarch64/aarch64.c	2017-07-13 09:18:19.014705954 +0100
+++ gcc/config/aarch64/aarch64.c	2017-07-13 09:18:23.795186280 +0100
@@ -11354,8 +11354,12 @@ #define CHECK(STRIDE, ELSIZE, CLASS, TES
 
       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;
 	}
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	2017-07-13 09:17:39.971572405 +0100
+++ gcc/dwarf2out.c	2017-07-13 09:18:23.797186067 +0100
@@ -15242,7 +15242,8 @@ mem_loc_descriptor (rtx rtl, machine_mod
 	  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);
@@ -18539,11 +18540,12 @@ insert_float (const_rtx rtl, unsigned ch
 {
   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;
@@ -18587,21 +18589,19 @@ add_const_value_attribute (dw_die_ref di
 	 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:
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	2017-07-05 16:29:19.600761904 +0100
+++ gcc/simplify-rtx.c	2017-07-13 09:18:23.800185748 +0100
@@ -5802,9 +5802,11 @@ simplify_immed_subreg (machine_mode oute
 	    {
 	      /* 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);
 
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2017-07-13 09:18:22.935277839 +0100
+++ gcc/optabs.c	2017-07-13 09:18:23.799185854 +0100
@@ -2551,7 +2551,7 @@ lowpart_subreg_maybe_copy (machine_mode
    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;
@@ -2697,6 +2697,7 @@ expand_unop (machine_mode mode, optab un
 {
   enum mode_class mclass = GET_MODE_CLASS (mode);
   machine_mode wider_mode;
+  scalar_float_mode float_mode;
   rtx temp;
   rtx libfunc;
 
@@ -2887,9 +2888,9 @@ expand_unop (machine_mode mode, optab un
   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;
 	}
@@ -3086,9 +3087,10 @@ expand_abs_nojump (machine_mode mode, rt
     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;
     }
@@ -3243,7 +3245,7 @@ expand_one_cmpl_abs_nojump (machine_mode
    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;
@@ -3327,7 +3329,7 @@ expand_copysign_absneg (machine_mode mod
    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;
@@ -3425,12 +3427,12 @@ expand_copysign_bit (machine_mode mode,
 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.  */
Index: gcc/ada/gcc-interface/utils.c
===================================================================
--- gcc/ada/gcc-interface/utils.c	2017-06-22 12:22:56.060377637 +0100
+++ gcc/ada/gcc-interface/utils.c	2017-07-13 09:18:23.793186493 +0100
@@ -3464,8 +3464,10 @@ gnat_type_for_mode (machine_mode mode, i
   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);
Index: gcc/go/go-lang.c
===================================================================
--- gcc/go/go-lang.c	2017-06-12 17:05:23.068757522 +0100
+++ gcc/go/go-lang.c	2017-07-13 09:18:23.798185961 +0100
@@ -382,12 +382,13 @@ go_langhook_type_for_mode (machine_mode
       return NULL_TREE;
     }
 
+  scalar_float_mode fmode;
   enum mode_class mc = GET_MODE_CLASS (mode);
   if (mc == MODE_INT)
     return go_langhook_type_for_size (GET_MODE_BITSIZE (mode), unsignedp);
-  else if (mc == MODE_FLOAT)
+  else if (is_float_mode (mode, &fmode))
     {
-      switch (GET_MODE_BITSIZE (mode))
+      switch (GET_MODE_BITSIZE (fmode))
 	{
 	case 32:
 	  return float_type_node;
@@ -396,7 +397,7 @@ go_langhook_type_for_mode (machine_mode
 	default:
 	  // We have to check for long double in order to support
 	  // i386 excess precision.
-	  if (mode == TYPE_MODE(long_double_type_node))
+	  if (fmode == TYPE_MODE(long_double_type_node))
 	    return long_double_type_node;
 	}
     }
