Index: gcc/machmode.h
===================================================================
--- gcc/machmode.h	2017-09-04 12:18:47.820398622 +0100
+++ gcc/machmode.h	2017-09-04 12:18:50.674859598 +0100
@@ -20,6 +20,8 @@ Software Foundation; either version 3, o
 #ifndef HAVE_MACHINE_MODES
 #define HAVE_MACHINE_MODES
 
+typedef opt_mode<machine_mode> opt_machine_mode;
+
 extern CONST_MODE_SIZE unsigned short mode_size[NUM_MACHINE_MODES];
 extern const unsigned short mode_precision[NUM_MACHINE_MODES];
 extern const unsigned char mode_inner[NUM_MACHINE_MODES];
@@ -237,6 +239,8 @@ #define POINTER_BOUNDS_MODE_P(MODE)
 
   ALWAYS_INLINE opt_mode () : m_mode (E_VOIDmode) {}
   ALWAYS_INLINE opt_mode (const T &m) : m_mode (m) {}
+  template<typename U>
+  ALWAYS_INLINE opt_mode (const U &m) : m_mode (T (m)) {}
   ALWAYS_INLINE opt_mode (from_int m) : m_mode (machine_mode (m)) {}
 
   machine_mode else_void () const;
@@ -325,6 +329,13 @@ is_a (machine_mode m)
   return T::includes_p (m);
 }
 
+template<typename T, typename U>
+inline bool
+is_a (const opt_mode<U> &m)
+{
+  return T::includes_p (m.else_void ());
+}
+
 /* Assert that mode M has type T, and return it in that form.  */
 
 template<typename T>
@@ -335,6 +346,13 @@ as_a (machine_mode m)
   return typename mode_traits<T>::from_int (m);
 }
 
+template<typename T, typename U>
+inline T
+as_a (const opt_mode<U> &m)
+{
+  return as_a <T> (m.else_void ());
+}
+
 /* Convert M to an opt_mode<T>.  */
 
 template<typename T>
@@ -346,6 +364,13 @@ dyn_cast (machine_mode m)
   return opt_mode<T> ();
 }
 
+template<typename T, typename U>
+inline opt_mode<T>
+dyn_cast (const opt_mode<U> &m)
+{
+  return dyn_cast <T> (m.else_void ());
+}
+
 /* Return true if mode M has type T, storing it as a T in *RESULT
    if so.  */
 
@@ -627,11 +652,7 @@ GET_MODE_2XWIDER_MODE (const T &m)
 extern const unsigned char mode_complex[NUM_MACHINE_MODES];
 #define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
 
-/* Return the mode for data of a given size SIZE and mode class CLASS.
-   If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
-   The value is BLKmode if no other mode is found.  */
-
-extern machine_mode mode_for_size (unsigned int, enum mode_class, int);
+extern opt_machine_mode mode_for_size (unsigned int, enum mode_class, int);
 
 /* Return the machine mode to use for a MODE_INT of SIZE bits, if one
    exists.  If LIMIT is nonzero, modes wider than MAX_FIXED_MODE_SIZE
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	2017-09-04 12:18:44.944553324 +0100
+++ gcc/stor-layout.c	2017-09-04 12:18:50.675762071 +0100
@@ -291,19 +291,19 @@ finalize_size_functions (void)
   vec_free (size_functions);
 }
 
-/* Return the machine mode to use for a nonscalar of SIZE bits.  The
-   mode must be in class MCLASS, and have exactly that many value bits;
-   it may have padding as well.  If LIMIT is nonzero, modes of wider
-   than MAX_FIXED_MODE_SIZE will not be used.  */
+/* Return a machine mode of class MCLASS with SIZE bits of precision,
+   if one exists.  The mode may have padding bits as well the SIZE
+   value bits.  If LIMIT is nonzero, disregard modes wider than
+   MAX_FIXED_MODE_SIZE.  */
 
-machine_mode
+opt_machine_mode
 mode_for_size (unsigned int size, enum mode_class mclass, int limit)
 {
   machine_mode mode;
   int i;
 
   if (limit && size > MAX_FIXED_MODE_SIZE)
-    return BLKmode;
+    return opt_machine_mode ();
 
   /* Get the first mode which has this size, in the specified class.  */
   FOR_EACH_MODE_IN_CLASS (mode, mclass)
@@ -316,7 +316,7 @@ mode_for_size (unsigned int size, enum m
 	  && int_n_enabled_p[i])
 	return int_n_data[i].m;
 
-  return BLKmode;
+  return opt_machine_mode ();
 }
 
 /* Similar, except passed a tree node.  */
@@ -333,11 +333,11 @@ mode_for_size_tree (const_tree size, enu
   ui = uhwi;
   if (uhwi != ui)
     return BLKmode;
-  return mode_for_size (ui, mclass, limit);
+  return mode_for_size (ui, mclass, limit).else_blk ();
 }
 
-/* Similar, but never return BLKmode; return the narrowest mode that
-   contains at least the requested number of value bits.  */
+/* Return the narrowest mode of class MCLASS that contains at least
+   SIZE bits.  Abort if no such mode exists.  */
 
 machine_mode
 smallest_mode_for_size (unsigned int size, enum mode_class mclass)
@@ -426,9 +426,8 @@ bitwise_mode_for_mode (machine_mode mode
   if (COMPLEX_MODE_P (mode))
     {
       machine_mode trial = mode;
-      if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT)
-	trial = mode_for_size (bitsize, MODE_COMPLEX_INT, false);
-      if (trial != BLKmode
+      if ((GET_MODE_CLASS (trial) == MODE_COMPLEX_INT
+	   || mode_for_size (bitsize, MODE_COMPLEX_INT, false).exists (&trial))
 	  && have_regs_of_mode[GET_MODE_INNER (trial)])
 	return trial;
     }
@@ -438,16 +437,15 @@ bitwise_mode_for_mode (machine_mode mode
   if (VECTOR_MODE_P (mode) || bitsize > MAX_FIXED_MODE_SIZE)
     {
       machine_mode trial = mode;
-      if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
-	trial = mode_for_size (bitsize, MODE_VECTOR_INT, 0);
-      if (trial != BLKmode
+      if ((GET_MODE_CLASS (trial) == MODE_VECTOR_INT
+	   || mode_for_size (bitsize, MODE_VECTOR_INT, 0).exists (&trial))
 	  && have_regs_of_mode[trial]
 	  && targetm.vector_mode_supported_p (trial))
 	return trial;
     }
 
   /* Otherwise fall back on integers while honoring MAX_FIXED_MODE_SIZE.  */
-  return mode_for_size (bitsize, MODE_INT, true);
+  return mode_for_size (bitsize, MODE_INT, true).else_blk ();
 }
 
 /* Find a type that can be used for efficient bitwise operations on MODE.
@@ -2543,13 +2541,9 @@ make_fract_type (int precision, int unsi
     TYPE_SATURATING (type) = 1;
 
   /* Lay out the type: set its alignment, size, etc.  */
-  if (unsignedp)
-    {
-      TYPE_UNSIGNED (type) = 1;
-      SET_TYPE_MODE (type, mode_for_size (precision, MODE_UFRACT, 0));
-    }
-  else
-    SET_TYPE_MODE (type, mode_for_size (precision, MODE_FRACT, 0));
+  TYPE_UNSIGNED (type) = unsignedp;
+  enum mode_class mclass = unsignedp ? MODE_UFRACT : MODE_FRACT;
+  SET_TYPE_MODE (type, mode_for_size (precision, mclass, 0).require ());
   layout_type (type);
 
   return type;
@@ -2569,13 +2563,9 @@ make_accum_type (int precision, int unsi
     TYPE_SATURATING (type) = 1;
 
   /* Lay out the type: set its alignment, size, etc.  */
-  if (unsignedp)
-    {
-      TYPE_UNSIGNED (type) = 1;
-      SET_TYPE_MODE (type, mode_for_size (precision, MODE_UACCUM, 0));
-    }
-  else
-    SET_TYPE_MODE (type, mode_for_size (precision, MODE_ACCUM, 0));
+  TYPE_UNSIGNED (type) = unsignedp;
+  enum mode_class mclass = unsignedp ? MODE_UACCUM : MODE_ACCUM;
+  SET_TYPE_MODE (type, mode_for_size (precision, mclass, 0).require ());
   layout_type (type);
 
   return type;
Index: gcc/caller-save.c
===================================================================
--- gcc/caller-save.c	2017-09-04 11:49:42.884500727 +0100
+++ gcc/caller-save.c	2017-09-04 12:18:50.672152181 +0100
@@ -1161,7 +1161,7 @@ replace_reg_with_saved_mem (rtx *loc,
 	    gcc_assert (smode != VOIDmode);
 	    if (hard_regno_nregs [regno][smode] > 1)
 	      smode = mode_for_size (GET_MODE_SIZE (mode) / nregs,
-				     GET_MODE_CLASS (mode), 0);
+				     GET_MODE_CLASS (mode), 0).require ();
 	    XVECEXP (mem, 0, i) = gen_rtx_REG (smode, regno + i);
 	  }
     }
Index: gcc/config/alpha/alpha.h
===================================================================
--- gcc/config/alpha/alpha.h	2017-09-04 11:50:08.504926375 +0100
+++ gcc/config/alpha/alpha.h	2017-09-04 12:18:50.672152181 +0100
@@ -508,7 +508,7 @@ #define SECONDARY_MEMORY_NEEDED(CLASS1,C
 #define SECONDARY_MEMORY_NEEDED_MODE(MODE)		\
   (GET_MODE_CLASS (MODE) == MODE_FLOAT ? (MODE)		\
    : GET_MODE_SIZE (MODE) >= 4 ? (MODE)			\
-   : mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (MODE), 0))
+   : mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (MODE), 0).require ())
 
 /* Return the class of registers that cannot change mode from FROM to TO.  */
 
Index: gcc/config/i386/i386.h
===================================================================
--- gcc/config/i386/i386.h	2017-09-04 11:50:08.515731048 +0100
+++ gcc/config/i386/i386.h	2017-09-04 12:18:50.672152181 +0100
@@ -1548,7 +1548,7 @@ #define SECONDARY_MEMORY_NEEDED(CLASS1,
    for integral modes that can be moved using 32 bit move.  */
 #define SECONDARY_MEMORY_NEEDED_MODE(MODE)			\
   (GET_MODE_BITSIZE (MODE) < 32 && INTEGRAL_MODE_P (MODE)	\
-   ? mode_for_size (32, GET_MODE_CLASS (MODE), 0)		\
+   ? mode_for_size (32, GET_MODE_CLASS (MODE), 0).require ()	\
    : MODE)
 
 /* Return a class of registers that cannot change FROM mode to TO mode.  */
Index: gcc/config/s390/s390.h
===================================================================
--- gcc/config/s390/s390.h	2017-09-04 11:50:24.561571751 +0100
+++ gcc/config/s390/s390.h	2017-09-04 12:18:50.673054653 +0100
@@ -624,9 +624,9 @@ #define SECONDARY_MEMORY_NEEDED(CLASS1,
 
 /* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on 64bit
    because the movsi and movsf patterns don't handle r/f moves.  */
-#define SECONDARY_MEMORY_NEEDED_MODE(MODE)		\
- (GET_MODE_BITSIZE (MODE) < 32				\
-  ? mode_for_size (32, GET_MODE_CLASS (MODE), 0)	\
+#define SECONDARY_MEMORY_NEEDED_MODE(MODE)			\
+ (GET_MODE_BITSIZE (MODE) < 32					\
+  ? mode_for_size (32, GET_MODE_CLASS (MODE), 0).require ()	\
   : (MODE))
 
 
Index: gcc/config/sparc/sparc.h
===================================================================
--- gcc/config/sparc/sparc.h	2017-09-04 11:50:24.563372530 +0100
+++ gcc/config/sparc/sparc.h	2017-09-04 12:18:50.673054653 +0100
@@ -1077,13 +1077,13 @@ #define SECONDARY_MEMORY_NEEDED(CLASS1,
 /* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on v9
    because the movsi and movsf patterns don't handle r/f moves.
    For v8 we copy the default definition.  */
-#define SECONDARY_MEMORY_NEEDED_MODE(MODE) \
-  (TARGET_ARCH64						\
-   ? (GET_MODE_BITSIZE (MODE) < 32				\
-      ? mode_for_size (32, GET_MODE_CLASS (MODE), 0)		\
-      : MODE)							\
-   : (GET_MODE_BITSIZE (MODE) < BITS_PER_WORD			\
-      ? mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (MODE), 0)	\
+#define SECONDARY_MEMORY_NEEDED_MODE(MODE)				   \
+  (TARGET_ARCH64							   \
+   ? (GET_MODE_BITSIZE (MODE) < 32					   \
+      ? mode_for_size (32, GET_MODE_CLASS (MODE), 0).require ()		   \
+      : MODE)								   \
+   : (GET_MODE_BITSIZE (MODE) < BITS_PER_WORD				   \
+      ? mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (MODE), 0).require () \
       : MODE))
 
 /* Return the maximum number of consecutive registers
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	2017-09-04 11:50:08.544543511 +0100
+++ gcc/expmed.c	2017-09-04 12:18:50.673054653 +0100
@@ -1711,14 +1711,9 @@ extract_bit_field_1 (rtx str_rtx, unsign
 
   /* Get the mode of the field to use for atomic access or subreg
      conversion.  */
-  mode1 = mode;
-  if (SCALAR_INT_MODE_P (tmode))
-    {
-      machine_mode try_mode = mode_for_size (bitsize,
-						  GET_MODE_CLASS (tmode), 0);
-      if (try_mode != BLKmode)
-	mode1 = try_mode;
-    }
+  if (!SCALAR_INT_MODE_P (tmode)
+      || !mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0).exists (&mode1))
+    mode1 = mode;
   gcc_assert (mode1 != BLKmode);
 
   /* Extraction of a full MODE1 value can be done with a subreg as long
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2017-09-04 11:49:42.941500722 +0100
+++ gcc/reload.c	2017-09-04 12:18:50.675762071 +0100
@@ -578,7 +578,8 @@ get_secondary_mem (rtx x ATTRIBUTE_UNUSE
   mode = SECONDARY_MEMORY_NEEDED_MODE (mode);
 #else
   if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD && INTEGRAL_MODE_P (mode))
-    mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);
+    mode = mode_for_size (BITS_PER_WORD,
+			  GET_MODE_CLASS (mode), 0).require ();
 #endif
 
   /* If we already have made a MEM for this operand in MODE, return it.  */
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	2017-09-04 11:49:42.944500722 +0100
+++ gcc/varasm.c	2017-09-04 12:18:50.676664544 +0100
@@ -2780,8 +2780,8 @@ assemble_integer (rtx x, unsigned int si
       else
 	mclass = MODE_INT;
 
-      omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0);
-      imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0);
+      omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0).require ();
+      imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0).require ();
 
       for (i = 0; i < size; i += subsize)
 	{
Index: gcc/lower-subreg.c
===================================================================
--- gcc/lower-subreg.c	2017-09-04 12:18:41.572976650 +0100
+++ gcc/lower-subreg.c	2017-09-04 12:18:50.674859598 +0100
@@ -616,20 +616,18 @@ simplify_subreg_concatn (machine_mode ou
   part = XVECEXP (op, 0, byte / inner_size);
   partmode = GET_MODE (part);
 
+  final_offset = byte % inner_size;
+  if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
+    return NULL_RTX;
+
   /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
      regular CONST_VECTORs.  They have vector or integer modes, depending
      on the capabilities of the target.  Cope with them.  */
   if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
     partmode = GET_MODE_INNER (innermode);
   else if (partmode == VOIDmode)
-    {
-      enum mode_class mclass = GET_MODE_CLASS (innermode);
-      partmode = mode_for_size (inner_size * BITS_PER_UNIT, mclass, 0);
-    }
-
-  final_offset = byte % inner_size;
-  if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
-    return NULL_RTX;
+    partmode = mode_for_size (inner_size * BITS_PER_UNIT,
+			      GET_MODE_CLASS (innermode), 0).require ();
 
   return simplify_gen_subreg (outermode, part, partmode, final_offset);
 }
