Index: gcc/doc/rtl.texi
===================================================================
--- gcc/doc/rtl.texi	2017-09-15 13:56:20.294149114 +0100
+++ gcc/doc/rtl.texi	2017-09-18 12:24:20.287485854 +0100
@@ -1921,19 +1921,32 @@ false.
 When @var{m1} is at least as narrow as @var{m2} the @code{subreg}
 expression is called @dfn{normal}.
 
+@findex REGMODE_NATURAL_SIZE
 Normal @code{subreg}s restrict consideration to certain bits of
-@var{reg}.  There are two cases.  If @var{m1} is smaller than a word,
-the @code{subreg} refers to the least-significant part (or
-@dfn{lowpart}) of one word of @var{reg}.  If @var{m1} is word-sized or
-greater, the @code{subreg} refers to one or more complete words.
-
-When used as an lvalue, @code{subreg} is a word-based accessor.
-Storing to a @code{subreg} modifies all the words of @var{reg} that
-overlap the @code{subreg}, but it leaves the other words of @var{reg}
+@var{reg}.  For this purpose, @var{reg} is divided into
+individually-addressable blocks in which each block has:
+
+@smallexample
+REGMODE_NATURAL_SIZE (@var{m2})
+@end smallexample
+
+bytes.  Usually the value is @code{UNITS_PER_WORD}; that is,
+most targets usually treat each word of a register as being
+independently addressable.
+
+There are two types of normal @code{subreg}.  If @var{m1} is known
+to be no bigger than a block, the @code{subreg} refers to the
+least-significant part (or @dfn{lowpart}) of one block of @var{reg}.
+If @var{m1} is known to be larger than a block, the @code{subreg} refers
+to two or more complete blocks.
+
+When used as an lvalue, @code{subreg} is a block-based accessor.
+Storing to a @code{subreg} modifies all the blocks of @var{reg} that
+overlap the @code{subreg}, but it leaves the other blocks of @var{reg}
 alone.
 
-When storing to a normal @code{subreg} that is smaller than a word,
-the other bits of the referenced word are usually left in an undefined
+When storing to a normal @code{subreg} that is smaller than a block,
+the other bits of the referenced block are usually left in an undefined
 state.  This laxity makes it easier to generate efficient code for
 such instructions.  To represent an instruction that preserves all the
 bits outside of those in the @code{subreg}, use @code{strict_low_part}
@@ -1991,10 +2004,11 @@ number of undefined bits.  For example:
 (subreg:PSI (reg:SI 0) 0)
 @end smallexample
 
+@findex REGMODE_NATURAL_SIZE
 accesses the whole of @samp{(reg:SI 0)}, but the exact relationship
 between the @code{PSImode} value and the @code{SImode} value is not
-defined.  If we assume @samp{UNITS_PER_WORD <= 4}, then the following
-two @code{subreg}s:
+defined.  If we assume @samp{REGMODE_NATURAL_SIZE (DImode) <= 4},
+then the following two @code{subreg}s:
 
 @smallexample
 (subreg:PSI (reg:DI 0) 0)
@@ -2005,7 +2019,7 @@ represent independent 4-byte accesses to
 @samp{(reg:DI 0)}.  Both @code{subreg}s have an unknown number
 of undefined bits.
 
-If @samp{UNITS_PER_WORD <= 2} then these two @code{subreg}s:
+If @samp{REGMODE_NATURAL_SIZE (PSImode) <= 2} then these two @code{subreg}s:
 
 @smallexample
 (subreg:HI (reg:PSI 0) 0)
@@ -2874,7 +2888,7 @@ The presence of @code{strict_low_part} s
 register which is meaningful in mode @var{n}, but is not part of
 mode @var{m}, is not to be altered.  Normally, an assignment to such
 a subreg is allowed to have undefined effects on the rest of the
-register when @var{m} is less than a word.
+register when @var{m} is smaller than @samp{REGMODE_NATURAL_SIZE (@var{n})}.
 @end table
 
 @node Side Effects
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	2017-09-15 13:56:20.296149147 +0100
+++ gcc/emit-rtl.c	2017-09-18 12:24:20.289496494 +0100
@@ -816,6 +816,8 @@ validate_subreg (machine_mode omode, mac
   if (offset >= isize)
     return false;
 
+  unsigned int regsize = REGMODE_NATURAL_SIZE (imode);
+
   /* ??? This should not be here.  Temporarily continue to allow word_mode
      subregs of anything.  The most common offender is (subreg:SI (reg:DF)).
      Generally, backends are doing something sketchy but it'll take time to
@@ -824,7 +826,7 @@ validate_subreg (machine_mode omode, mac
     ;
   /* ??? Similarly, e.g. with (subreg:DF (reg:TI)).  Though store_bit_field
      is the culprit here, and not the backends.  */
-  else if (osize >= UNITS_PER_WORD && isize >= osize)
+  else if (osize >= regsize && isize >= osize)
     ;
   /* Allow component subregs of complex and vector.  Though given the below
      extraction rules, it's not always clear what that means.  */
@@ -876,17 +878,23 @@ validate_subreg (machine_mode omode, mac
     }
 
   /* For pseudo registers, we want most of the same checks.  Namely:
-     If the register no larger than a word, the subreg must be lowpart.
-     If the register is larger than a word, the subreg must be the lowpart
-     of a subword.  A subreg does *not* perform arbitrary bit extraction.
-     Given that we've already checked mode/offset alignment, we only have
-     to check subword subregs here.  */
-  if (osize < UNITS_PER_WORD
+
+     Assume that the pseudo register will be allocated to hard registers
+     that can hold REGSIZE bytes each.  If OSIZE is not a multiple of REGSIZE,
+     the remainder must correspond to the lowpart of the containing hard
+     register.  If BYTES_BIG_ENDIAN, the lowpart is at the highest offset,
+     otherwise it is at the lowest offset.
+
+     Given that we've already checked the mode and offset alignment,
+     we only have to check subblock subregs here.  */
+  if (osize < regsize
       && ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
     {
-      machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
-      unsigned int low_off = subreg_lowpart_offset (omode, wmode);
-      if (offset % UNITS_PER_WORD != low_off)
+      unsigned int block_size = MIN (isize, regsize);
+      unsigned int offset_within_block = offset % block_size;
+      if (BYTES_BIG_ENDIAN
+	  ? offset_within_block != block_size - osize
+	  : offset_within_block != 0)
 	return false;
     }
   return true;
@@ -1439,14 +1447,21 @@ gen_lowpart_common (machine_mode mode, r
   if (innermode == mode)
     return x;
 
-  /* MODE must occupy no more words than the mode of X.  */
-  if ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
-      > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
-    return 0;
-
-  /* Don't allow generating paradoxical FLOAT_MODE subregs.  */
-  if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize)
-    return 0;
+  if (SCALAR_FLOAT_MODE_P (mode))
+    {
+      /* Don't allow paradoxical FLOAT_MODE subregs.  */
+      if (msize > xsize)
+	return 0;
+    }
+  else
+    {
+      /* MODE must occupy no more of the underlying registers than X.  */
+      unsigned int regsize = REGMODE_NATURAL_SIZE (innermode);
+      unsigned int mregs = CEIL (msize, regsize);
+      unsigned int xregs = CEIL (xsize, regsize);
+      if (mregs > xregs)
+	return 0;
+    }
 
   scalar_int_mode int_mode, int_innermode, from_mode;
   if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	2017-09-14 16:25:43.862558497 +0100
+++ gcc/expr.c	2017-09-18 12:24:20.292512455 +0100
@@ -6190,7 +6190,8 @@ store_constructor (tree exp, rtx target,
 	   a constant.  But if more than one register is involved,
 	   this probably loses.  */
 	else if (REG_P (target) && TREE_STATIC (exp)
-		 && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
+		 && (GET_MODE_SIZE (GET_MODE (target))
+		     <= REGMODE_NATURAL_SIZE (GET_MODE (target))))
 	  {
 	    emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 	    cleared = 1;
