Add a partial_subreg_p predicate

Message ID 87tw11caeo.fsf@linaro.org
State New
Headers show

Commit Message

Richard Sandiford Aug. 21, 2017, 1:34 p.m.
This patch adds a partial_subreg_p predicate to go alongside
paradoxical_subreg_p.

The first two changes to cse_insn preserve the current behaviour,
but the condition seems strange.  Shouldn't we be able to continue
to cse if the inner modes of the two subregs have the same size?

The patch also preserves the existing condition in
simplify_operand_subreg, but perhaps it should be using
a df_read_modify_subreg_p-style check instead.  We don't
need to reload the inner value first if the inner value
is no bigger than a word, for example.

The use in curr_insn_transform also seemed strange.  Surely the
modes of the SET_DEST and SET_SRC will be the same, given that
this code isn't meant for constants?

Like the paradoxical_subreg_p patch, this one replaces some tests that
were based on GET_MODE_SIZE rather than GET_MODE_PRECISION.  In each
case the change should be a no-op or an improvement.

Doing this in regcprop.c prevents some replacements of the 82-bit RFmode
with the 80-bit XFmode on ia64.  I don't understand the target details
here particularly well, but from the way the modes are described in
ia64-modes.def, it isn't valid to assume that an XFmode can carry an
RFmode payload.  A comparison of the testsuite assembly output for one
target per CPU showed no other differences.

Some of the places changed here are tracking the widest access mode
found for a register.  The series tries to standardise on:

  if (partial_subreg_p (widest_seen, new_mode))
    widest_seen = new_mode;

rather than:

  if (paradoxical_subreg_p (new_mode, widest_seen))
    widest_seen = new_mode;

Either would have been OK.

Tested on aarch64-linux-gnu and x86_64-linux-gnu in addition to the above.
OK to install?

Richard


2017-08-21  Richard Sandiford  <richard.sandiford@linaro.org>
	    Alan Hayward  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

gcc/
	* rtl.h (partial_subreg_p): New function.
	* caller-save.c (save_call_clobbered_regs): Use it.
	* calls.c (expand_call): Likewise.
	* combine.c (combinable_i3pat): Likewise.
	(simplify_set): Likewise.
	(make_extraction): Likewise.
	(make_compound_operation_int): Likewise.
	(gen_lowpart_or_truncate): Likewise.
	(force_to_mode): Likewise.
	(make_field_assignment): Likewise.
	(reg_truncated_to_mode): Likewise.
	(record_truncated_value): Likewise.
	(move_deaths): Likewise.
	* cse.c (record_jump_cond): Likewise.
	(cse_insn): Likewise.
	* cselib.c (cselib_lookup_1): Likewise.
	* df-scan.c (df_read_modify_subreg_p): Likewise.
	* expmed.c (extract_bit_field_using_extv): Likewise.
	* function.c (assign_parm_setup_reg): Likewise.
	* ifcvt.c (noce_convert_multiple_sets): Likewise.
	* ira-build.c (create_insn_allocnos): Likewise.
	* lra-coalesce.c (merge_pseudos): Likewise.
	* lra-constraints.c (match_reload): Likewise.
	(simplify_operand_subreg): Likewise.
	(curr_insn_transform): Likewise.
	* lra-lives.c (process_bb_lives): Likewise.
	* lra.c (new_insn_reg): Likewise.
	(lra_substitute_pseudo): Likewise.
	* regcprop.c (mode_change_ok): Likewise.
	(maybe_mode_change): Likewise.
	(copyprop_hardreg_forward_1): Likewise.
	* reload.c (push_reload): Likewise.
	(find_reloads): Likewise.
	(find_reloads_subreg_address): Likewise.
	* reload1.c (alter_reg): Likewise.
	(eliminate_regs_1): Likewise.
	* simplify-rtx.c (simplify_unary_operation_1): Likewise.

Comments

Jeff Law Aug. 29, 2017, 9:49 p.m. | #1
On 08/21/2017 07:34 AM, Richard Sandiford wrote:
> This patch adds a partial_subreg_p predicate to go alongside

> paradoxical_subreg_p.

> 

> The first two changes to cse_insn preserve the current behaviour,

> but the condition seems strange.  Shouldn't we be able to continue

> to cse if the inner modes of the two subregs have the same size?

I would think so.  It could well be a simple oversight.  We're talking
about very old code -- this stuff is virtually unchanged in 25 years.

This specific chunk of code is something I would like to look more
deeply into its utility -- most of what it's doing should be handled by
DOM these days.  It'd be an interesting exercise to see if this code is
important at all anymore.

If you wanted to handle that case, I wouldn't object as a follow-up if
you can come up with a testcase that shows when its useful.


> The patch also preserves the existing condition in

> simplify_operand_subreg, but perhaps it should be using

> a df_read_modify_subreg_p-style check instead.  We don't

> need to reload the inner value first if the inner value

> is no bigger than a word, for example.

Not sure on this one.  We could try to change it as a follow-up though.
Vlad may have a better sense of how this might interact with other parts
of LRA than I would

> 

> The use in curr_insn_transform also seemed strange.  Surely the

> modes of the SET_DEST and SET_SRC will be the same, given that

> this code isn't meant for constants?

Is it possible this is for the zero/sign extension support?

> 

> Like the paradoxical_subreg_p patch, this one replaces some tests that

> were based on GET_MODE_SIZE rather than GET_MODE_PRECISION.  In each

> case the change should be a no-op or an improvement.

> 

> Doing this in regcprop.c prevents some replacements of the 82-bit RFmode

> with the 80-bit XFmode on ia64.  I don't understand the target details

> here particularly well, but from the way the values are described in

> ia64-modes.def, it isn't valid to assume that an XFmode can carry an

> RFmode payload.  A comparison of the testsuite assembly output for one

> target per CPU showed no other differences.

> 

> Some of the places changed here are tracking the widest access mode

> found for a register.  The series tries to standardise on:

> 

>   if (partial_subreg_p (widest_seen, new_mode))

>     widest_seen = new_mode;

> 

> rather than:

> 

>   if (paradoxical_subreg_p (new_mode, widest_seen))

>     widest_seen = new_mode;

> 

> Either would have been OK.

> 

> Tested on aarch64-linux-gnu and x86_64-linux-gnu in addition to the above.

> OK to install?

> 

> Richard

> 

> 

> 2017-08-21  Richard Sandiford  <richard.sandiford@linaro.org>

> 	    Alan Hayward  <alan.hayward@arm.com>

> 	    David Sherwood  <david.sherwood@arm.com>

> 

> gcc/

> 	* rtl.h (partial_subreg_p): New function.

> 	* caller-save.c (save_call_clobbered_regs): Use it.

> 	* calls.c (expand_call): Likewise.

> 	* combine.c (combinable_i3pat): Likewise.

> 	(simplify_set): Likewise.

> 	(make_extraction): Likewise.

> 	(make_compound_operation_int): Likewise.

> 	(gen_lowpart_or_truncate): Likewise.

> 	(force_to_mode): Likewise.

> 	(make_field_assignment): Likewise.

> 	(reg_truncated_to_mode): Likewise.

> 	(record_truncated_value): Likewise.

> 	(move_deaths): Likewise.

> 	* cse.c (record_jump_cond): Likewise.

> 	(cse_insn): Likewise.

> 	* cselib.c (cselib_lookup_1): Likewise.

> 	* df-scan.c (df_read_modify_subreg_p): Likewise.

> 	* expmed.c (extract_bit_field_using_extv): Likewise.

> 	* function.c (assign_parm_setup_reg): Likewise.

> 	* ifcvt.c (noce_convert_multiple_sets): Likewise.

> 	* ira-build.c (create_insn_allocnos): Likewise.

> 	* lra-coalesce.c (merge_pseudos): Likewise.

> 	* lra-constraints.c (match_reload): Likewise.

> 	(simplify_operand_subreg): Likewise.

> 	(curr_insn_transform): Likewise.

> 	* lra-lives.c (process_bb_lives): Likewise.

> 	* lra.c (new_insn_reg): Likewise.

> 	(lra_substitute_pseudo): Likewise.

> 	* regcprop.c (mode_change_ok): Likewise.

> 	(maybe_mode_change): Likewise.

> 	(copyprop_hardreg_forward_1): Likewise.

> 	* reload.c (push_reload): Likewise.

> 	(find_reloads): Likewise.

> 	(find_reloads_subreg_address): Likewise.

> 	* reload1.c (alter_reg): Likewise.

> 	(eliminate_regs_1): Likewise.

> 	* simplify-rtx.c (simplify_unary_operation_1): Likewise.

Any thought on whether or not a same size subreg predicate would be
useful.  ie, (subreg:SI (reg:SF)) and the like.  Certainly not something
you have to do to go forward, just something to ponder.

The patch is OK for the trunk.  The issues noted above all seem like
potentially follow-up items if we want to tackle them at all.

jeff
Richard Sandiford Aug. 30, 2017, 3:41 p.m. | #2
Jeff Law <law@redhat.com> writes:
> On 08/21/2017 07:34 AM, Richard Sandiford wrote:

>> This patch adds a partial_subreg_p predicate to go alongside

>> paradoxical_subreg_p.

>> 

>> The first two changes to cse_insn preserve the current behaviour,

>> but the condition seems strange.  Shouldn't we be able to continue

>> to cse if the inner modes of the two subregs have the same size?

> I would think so.  It could well be a simple oversight.  We're talking

> about very old code -- this stuff is virtually unchanged in 25 years.

>

> This specific chunk of code is something I would like to look more

> deeply into its utility -- most of what it's doing should be handled by

> DOM these days.  It'd be an interesting exercise to see if this code is

> important at all anymore.


OK.  When I get some spare machine time, I might try putting a
gcc_unreachable () there and doing the usual multi-target testing,
just to see if or when it fires.

> If you wanted to handle that case, I wouldn't object as a follow-up if

> you can come up with a testcase that shows when its useful.

>

>

>> The patch also preserves the existing condition in

>> simplify_operand_subreg, but perhaps it should be using

>> a df_read_modify_subreg_p-style check instead.  We don't

>> need to reload the inner value first if the inner value

>> is no bigger than a word, for example.

> Not sure on this one.  We could try to change it as a follow-up though.

> Vlad may have a better sense of how this might interact with other parts

> of LRA than I would


I'll give this one a go too.

>> The use in curr_insn_transform also seemed strange.  Surely the

>> modes of the SET_DEST and SET_SRC will be the same, given that

>> this code isn't meant for constants?

> Is it possible this is for the zero/sign extension support?


Even then I don't think we could ever have SET_SRC and SET_DEST being
different.  The extension has to be explicit in the source.

>> Like the paradoxical_subreg_p patch, this one replaces some tests that

>> were based on GET_MODE_SIZE rather than GET_MODE_PRECISION.  In each

>> case the change should be a no-op or an improvement.

>> 

>> Doing this in regcprop.c prevents some replacements of the 82-bit RFmode

>> with the 80-bit XFmode on ia64.  I don't understand the target details

>> here particularly well, but from the way the values are described in

>> ia64-modes.def, it isn't valid to assume that an XFmode can carry an

>> RFmode payload.  A comparison of the testsuite assembly output for one

>> target per CPU showed no other differences.

>> 

>> Some of the places changed here are tracking the widest access mode

>> found for a register.  The series tries to standardise on:

>> 

>>   if (partial_subreg_p (widest_seen, new_mode))

>>     widest_seen = new_mode;

>> 

>> rather than:

>> 

>>   if (paradoxical_subreg_p (new_mode, widest_seen))

>>     widest_seen = new_mode;

>> 

>> Either would have been OK.

>> 

>> Tested on aarch64-linux-gnu and x86_64-linux-gnu in addition to the above.

>> OK to install?

>> 

>> Richard

>> 

>> 

>> 2017-08-21  Richard Sandiford  <richard.sandiford@linaro.org>

>> 	    Alan Hayward  <alan.hayward@arm.com>

>> 	    David Sherwood  <david.sherwood@arm.com>

>> 

>> gcc/

>> 	* rtl.h (partial_subreg_p): New function.

>> 	* caller-save.c (save_call_clobbered_regs): Use it.

>> 	* calls.c (expand_call): Likewise.

>> 	* combine.c (combinable_i3pat): Likewise.

>> 	(simplify_set): Likewise.

>> 	(make_extraction): Likewise.

>> 	(make_compound_operation_int): Likewise.

>> 	(gen_lowpart_or_truncate): Likewise.

>> 	(force_to_mode): Likewise.

>> 	(make_field_assignment): Likewise.

>> 	(reg_truncated_to_mode): Likewise.

>> 	(record_truncated_value): Likewise.

>> 	(move_deaths): Likewise.

>> 	* cse.c (record_jump_cond): Likewise.

>> 	(cse_insn): Likewise.

>> 	* cselib.c (cselib_lookup_1): Likewise.

>> 	* df-scan.c (df_read_modify_subreg_p): Likewise.

>> 	* expmed.c (extract_bit_field_using_extv): Likewise.

>> 	* function.c (assign_parm_setup_reg): Likewise.

>> 	* ifcvt.c (noce_convert_multiple_sets): Likewise.

>> 	* ira-build.c (create_insn_allocnos): Likewise.

>> 	* lra-coalesce.c (merge_pseudos): Likewise.

>> 	* lra-constraints.c (match_reload): Likewise.

>> 	(simplify_operand_subreg): Likewise.

>> 	(curr_insn_transform): Likewise.

>> 	* lra-lives.c (process_bb_lives): Likewise.

>> 	* lra.c (new_insn_reg): Likewise.

>> 	(lra_substitute_pseudo): Likewise.

>> 	* regcprop.c (mode_change_ok): Likewise.

>> 	(maybe_mode_change): Likewise.

>> 	(copyprop_hardreg_forward_1): Likewise.

>> 	* reload.c (push_reload): Likewise.

>> 	(find_reloads): Likewise.

>> 	(find_reloads_subreg_address): Likewise.

>> 	* reload1.c (alter_reg): Likewise.

>> 	(eliminate_regs_1): Likewise.

>> 	* simplify-rtx.c (simplify_unary_operation_1): Likewise.

> Any thought on whether or not a same size subreg predicate would be

> useful.  ie, (subreg:SI (reg:SF)) and the like.  Certainly not something

> you have to do to go forward, just something to ponder.


Yeah, it might be worth having that too if there are a few instances
of it.  I'll keep an eye out.

> The patch is OK for the trunk.  The issues noted above all seem like

> potentially follow-up items if we want to tackle them at all.


Thanks,
Richard

>

> jeff
Jeff Law Aug. 30, 2017, 7:29 p.m. | #3
On 08/30/2017 09:41 AM, Richard Sandiford wrote:
> 

> Even then I don't think we could ever have SET_SRC and SET_DEST being

> different.  The extension has to be explicit in the source.

Yea, you should still have the same mode for the SET_SRC and SET_DEST.
It's just that the operands underneath may have different modes.

ie

(set (reg:SI) (zero_extend:SI (reg:HI))

So the SET_SRC/SET_DEST have the same modes, but the operands presented
to the allocators and reloaders have different modes.

The only reason I remember this being an "interesting" case is because
in the old allocator (pre-IRA) we were not good at tying objects of
different sizes.

Jeff

Patch

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2017-08-21 14:20:43.099964655 +0100
+++ gcc/rtl.h	2017-08-21 14:21:03.728890033 +0100
@@ -2787,6 +2787,30 @@  extern rtx operand_subword_force (rtx, u
 extern int subreg_lowpart_p (const_rtx);
 extern unsigned int subreg_size_lowpart_offset (unsigned int, unsigned int);
 
+/* Return true if a subreg of mode OUTERMODE would only access part of
+   an inner register with mode INNERMODE.  The other bits of the inner
+   register would then be "don't care" on read.  The behavior for writes
+   depends on REGMODE_NATURAL_SIZE; bits in the same REGMODE_NATURAL_SIZE-d
+   chunk would be clobbered but other bits would be preserved.  */
+
+inline bool
+partial_subreg_p (machine_mode outermode, machine_mode innermode)
+{
+  return GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode);
+}
+
+/* Likewise return true if X is a subreg that is smaller than the inner
+   register.  Use df_read_modify_subreg_p to test whether writing to such
+   a subreg preserves any part of the inner register.  */
+
+inline bool
+partial_subreg_p (const_rtx x)
+{
+  if (GET_CODE (x) != SUBREG)
+    return false;
+  return partial_subreg_p (GET_MODE (x), GET_MODE (SUBREG_REG (x)));
+}
+
 /* Return true if a subreg with the given outer and inner modes is
    paradoxical.  */
 
Index: gcc/caller-save.c
===================================================================
--- gcc/caller-save.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/caller-save.c	2017-08-21 14:21:03.716860701 +0100
@@ -837,8 +837,7 @@  save_call_clobbered_regs (void)
 		  nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
 		  mode = HARD_REGNO_CALLER_SAVE_MODE
 		    (r, nregs, PSEUDO_REGNO_MODE (regno));
-		  if (GET_MODE_BITSIZE (mode)
-		      > GET_MODE_BITSIZE (save_mode[r]))
+		  if (partial_subreg_p (save_mode[r], mode))
 		    save_mode[r] = mode;
 		  while (nregs-- > 0)
 		    SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
Index: gcc/calls.c
===================================================================
--- gcc/calls.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/calls.c	2017-08-21 14:21:03.716860701 +0100
@@ -3354,8 +3354,7 @@  expand_call (tree exp, rtx target, int i
 	      || ((caller_mode != caller_promoted_mode
 		   || callee_mode != callee_promoted_mode)
 		  && (caller_unsignedp != callee_unsignedp
-		      || GET_MODE_BITSIZE (caller_mode)
-			 < GET_MODE_BITSIZE (callee_mode)))))
+		      || partial_subreg_p (caller_mode, callee_mode)))))
 	{
 	  try_tail_call = 0;
 	  maybe_complain_about_tail_call (exp,
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	2017-08-21 14:20:43.092940547 +0100
+++ gcc/combine.c	2017-08-21 14:21:03.718865590 +0100
@@ -2220,9 +2220,7 @@  combinable_i3pat (rtx_insn *i3, rtx *loc
 	 STACK_POINTER_REGNUM, since these are always considered to be
 	 live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
       subdest = dest;
-      if (GET_CODE (subdest) == SUBREG
-	  && (GET_MODE_SIZE (GET_MODE (subdest))
-	      >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
+      if (GET_CODE (subdest) == SUBREG && !partial_subreg_p (subdest))
 	subdest = SUBREG_REG (subdest);
       if (pi3dest_killed
 	  && REG_P (subdest)
@@ -6831,10 +6829,8 @@  simplify_set (rtx x)
   /* If we have (set (cc0) (subreg ...)), we try to remove the subreg
      in SRC.  */
   if (dest == cc0_rtx
-      && GET_CODE (src) == SUBREG
-      && subreg_lowpart_p (src)
-      && (GET_MODE_PRECISION (GET_MODE (src))
-	  < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (src)))))
+      && partial_subreg_p (src)
+      && subreg_lowpart_p (src))
     {
       rtx inner = SUBREG_REG (src);
       machine_mode inner_mode = GET_MODE (inner);
@@ -7603,7 +7599,7 @@  make_extraction (machine_mode mode, rtx
   /* Never narrow an object, since that might not be safe.  */
 
   if (mode != VOIDmode
-      && GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode))
+      && partial_subreg_p (extraction_mode, mode))
     extraction_mode = mode;
 
   if (!MEM_P (inner))
@@ -7653,7 +7649,7 @@  make_extraction (machine_mode mode, rtx
   if (wanted_inner_mode != VOIDmode
       && inner_mode != wanted_inner_mode
       && ! pos_rtx
-      && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
+      && partial_subreg_p (wanted_inner_mode, is_mode)
       && MEM_P (inner)
       && ! mode_dependent_address_p (XEXP (inner, 0), MEM_ADDR_SPACE (inner))
       && ! MEM_VOLATILE_P (inner))
@@ -8167,7 +8163,7 @@  make_compound_operation_int (machine_mod
 		   to (subreg:QI (lshiftrt:SI (reg:SI) (const_int 7)) 0).  */
 		|| (GET_CODE (inner) == AND
 		    && CONST_INT_P (XEXP (inner, 1))
-		    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
+		    && partial_subreg_p (x)
 		    && exact_log2 (UINTVAL (XEXP (inner, 1)))
 		       >= GET_MODE_BITSIZE (mode) - 1)))
 	  subreg_code = SET;
@@ -8180,7 +8176,7 @@  make_compound_operation_int (machine_mod
 	  tem = simplified;
 
 	if (GET_CODE (tem) != GET_CODE (inner)
-	    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner))
+	    && partial_subreg_p (x)
 	    && subreg_lowpart_p (x))
 	  {
 	    rtx newer
@@ -8191,8 +8187,9 @@  make_compound_operation_int (machine_mod
 	    if (GET_CODE (newer) != SUBREG)
 	      newer = make_compound_operation (newer, in_code);
 
-	    /* force_to_mode can expand compounds.  If it just re-expanded the
-	       compound, use gen_lowpart to convert to the desired mode.  */
+	    /* force_to_mode can expand compounds.  If it just re-expanded
+	       the compound, use gen_lowpart to convert to the desired
+	       mode.  */
 	    if (rtx_equal_p (newer, x)
 		/* Likewise if it re-expanded the compound only partially.
 		   This happens for SUBREG of ZERO_EXTRACT if they extract
@@ -8433,7 +8430,7 @@  canon_reg_for_combine (rtx x, rtx reg)
 gen_lowpart_or_truncate (machine_mode mode, rtx x)
 {
   if (!CONST_INT_P (x)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+      && partial_subreg_p (mode, GET_MODE (x))
       && !TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x))
       && !(REG_P (x) && reg_truncated_to_mode (mode, x)))
     {
@@ -8489,7 +8486,7 @@  force_to_mode (rtx x, machine_mode mode,
   /* It is not valid to do a right-shift in a narrower mode
      than the one it came in with.  */
   if ((code == LSHIFTRT || code == ASHIFTRT)
-      && GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (x)))
+      && partial_subreg_p (mode, GET_MODE (x)))
     op_mode = GET_MODE (x);
 
   /* Truncate MASK to fit OP_MODE.  */
@@ -8535,8 +8532,7 @@  force_to_mode (rtx x, machine_mode mode,
      if the constant masks to zero all the bits the mode doesn't have.  */
   if (GET_CODE (x) == SUBREG
       && subreg_lowpart_p (x)
-      && ((GET_MODE_SIZE (GET_MODE (x))
-	   < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+      && (partial_subreg_p (x)
 	  || (0 == (mask
 		    & GET_MODE_MASK (GET_MODE (x))
 		    & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
@@ -9485,8 +9481,7 @@  make_field_assignment (rtx x)
 
   if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
       && subreg_lowpart_p (XEXP (src, 0))
-      && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
+      && partial_subreg_p (XEXP (src, 0))
       && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
       && CONST_INT_P (XEXP (SUBREG_REG (XEXP (src, 0)), 0))
       && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
@@ -13207,7 +13202,7 @@  reg_truncated_to_mode (machine_mode mode
   if (truncated == 0
       || rsp->truncation_label < label_tick_ebb_start)
     return false;
-  if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
+  if (!partial_subreg_p (mode, truncated))
     return true;
   if (TRULY_NOOP_TRUNCATION_MODES_P (mode, truncated))
     return true;
@@ -13230,9 +13225,10 @@  record_truncated_value (rtx x)
       machine_mode original_mode = GET_MODE (SUBREG_REG (x));
       truncated_mode = GET_MODE (x);
 
-      if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
+      if (!partial_subreg_p (truncated_mode, original_mode))
 	return true;
 
+      truncated_mode = GET_MODE (x);
       if (TRULY_NOOP_TRUNCATION_MODES_P (truncated_mode, original_mode))
 	return true;
 
@@ -13248,8 +13244,7 @@  record_truncated_value (rtx x)
   rsp = &reg_stat[REGNO (x)];
   if (rsp->truncated_to_mode == 0
       || rsp->truncation_label < label_tick_ebb_start
-      || (GET_MODE_SIZE (truncated_mode)
-	  < GET_MODE_SIZE (rsp->truncated_to_mode)))
+      || partial_subreg_p (truncated_mode, rsp->truncated_to_mode))
     {
       rsp->truncated_to_mode = truncated_mode;
       rsp->truncation_label = label_tick;
@@ -13773,8 +13768,7 @@  move_deaths (rtx x, rtx maybe_kill_insn,
 	     the remaining registers in place of NOTE.  */
 
 	  if (note != 0 && regno < FIRST_PSEUDO_REGISTER
-	      && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-		  > GET_MODE_SIZE (GET_MODE (x))))
+	      && partial_subreg_p (GET_MODE (x), GET_MODE (XEXP (note, 0))))
 	    {
 	      unsigned int deadregno = REGNO (XEXP (note, 0));
 	      unsigned int deadend = END_REGNO (XEXP (note, 0));
@@ -13793,8 +13787,8 @@  move_deaths (rtx x, rtx maybe_kill_insn,
 	     their own REG_DEAD notes lying around.  */
 	  else if ((note == 0
 		    || (note != 0
-			&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-			    < GET_MODE_SIZE (GET_MODE (x)))))
+			&& partial_subreg_p (GET_MODE (XEXP (note, 0)),
+					     GET_MODE (x))))
 		   && regno < FIRST_PSEUDO_REGISTER
 		   && REG_NREGS (x) > 1)
 	    {
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	2017-08-21 14:20:43.093943991 +0100
+++ gcc/cse.c	2017-08-21 14:21:03.719868034 +0100
@@ -3952,10 +3952,9 @@  record_jump_cond (enum rtx_code code, ma
      if we test MODE instead, we can get an infinite recursion
      alternating between two modes each wider than MODE.  */
 
-  if (code == NE && GET_CODE (op0) == SUBREG
-      && subreg_lowpart_p (op0)
-      && (GET_MODE_SIZE (GET_MODE (op0))
-	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+  if (code == NE
+      && partial_subreg_p (op0)
+      && subreg_lowpart_p (op0))
     {
       machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
@@ -3964,10 +3963,9 @@  record_jump_cond (enum rtx_code code, ma
 			  reversed_nonequality);
     }
 
-  if (code == NE && GET_CODE (op1) == SUBREG
-      && subreg_lowpart_p (op1)
-      && (GET_MODE_SIZE (GET_MODE (op1))
-	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+  if (code == NE
+      && partial_subreg_p (op1)
+      && subreg_lowpart_p (op1))
     {
       machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
@@ -5000,8 +4998,8 @@  cse_insn (rtx_insn *insn)
 	      && ! (src != 0
 		    && GET_CODE (src) == SUBREG
 		    && GET_MODE (src) == GET_MODE (p->exp)
-		    && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-			< GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+		    && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+					 GET_MODE (SUBREG_REG (p->exp)))))
 	    continue;
 
 	  if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
@@ -5111,8 +5109,8 @@  cse_insn (rtx_insn *insn)
 	      && ! (src != 0
 		    && GET_CODE (src) == SUBREG
 		    && GET_MODE (src) == GET_MODE (elt->exp)
-		    && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-			< GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+		    && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+					 GET_MODE (SUBREG_REG (elt->exp)))))
 	    {
 	      elt = elt->next_same_value;
 	      continue;
@@ -5951,8 +5949,7 @@  cse_insn (rtx_insn *insn)
 	    && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
 		 / UNITS_PER_WORD)
 		== (GET_MODE_SIZE (GET_MODE (dest)) - 1) / UNITS_PER_WORD)
-	    && (GET_MODE_SIZE (GET_MODE (dest))
-		>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+	    && !partial_subreg_p (dest)
 	    && sets[i].src_elt != 0)
 	  {
 	    machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/cselib.c	2017-08-21 14:21:03.719868034 +0100
@@ -2033,8 +2033,8 @@  cselib_lookup_1 (rtx x, machine_mode mod
 		&& GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
 		   > GET_MODE_SIZE (mode)
 		&& (lwider == NULL
-		    || GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
-		       < GET_MODE_SIZE (GET_MODE (lwider->elt->val_rtx))))
+		    || partial_subreg_p (GET_MODE (l->elt->val_rtx),
+					 GET_MODE (lwider->elt->val_rtx))))
 	      {
 		struct elt_loc_list *el;
 		if (i < FIRST_PSEUDO_REGISTER
Index: gcc/df-scan.c
===================================================================
--- gcc/df-scan.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/df-scan.c	2017-08-21 14:21:03.719868034 +0100
@@ -2631,13 +2631,12 @@  df_ref_record (enum df_ref_class cl,
 bool
 df_read_modify_subreg_p (rtx x)
 {
-  unsigned int isize, osize;
-  if (GET_CODE (x) != SUBREG)
+  unsigned int isize;
+
+  if (!partial_subreg_p (x))
     return false;
   isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
-  osize = GET_MODE_SIZE (GET_MODE (x));
-  return isize > osize
-	 && isize > REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+  return isize > REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
 }
 
 
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	2017-08-21 14:20:43.095950879 +0100
+++ gcc/expmed.c	2017-08-21 14:21:03.720870478 +0100
@@ -1501,8 +1501,7 @@  extract_bit_field_using_extv (const extr
 	  && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (target), ext_mode))
 	{
 	  target = gen_lowpart (ext_mode, target);
-	  if (GET_MODE_PRECISION (ext_mode)
-	      > GET_MODE_PRECISION (GET_MODE (spec_target)))
+	  if (partial_subreg_p (GET_MODE (spec_target), ext_mode))
 	    spec_target_subreg = target;
 	}
       else
Index: gcc/function.c
===================================================================
--- gcc/function.c	2017-08-21 12:09:48.345623608 +0100
+++ gcc/function.c	2017-08-21 14:21:03.721872923 +0100
@@ -3262,13 +3262,11 @@  assign_parm_setup_reg (struct assign_par
       push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
       tempreg = convert_to_mode (data->nominal_mode, tempreg, unsignedp);
 
-      if (GET_CODE (tempreg) == SUBREG
+      if (partial_subreg_p (tempreg)
 	  && GET_MODE (tempreg) == data->nominal_mode
 	  && REG_P (SUBREG_REG (tempreg))
 	  && data->nominal_mode == data->passed_mode
-	  && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (data->entry_parm)
-	  && GET_MODE_SIZE (GET_MODE (tempreg))
-	     < GET_MODE_SIZE (GET_MODE (data->entry_parm)))
+	  && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (data->entry_parm))
 	{
 	  /* The argument is already sign/zero extended, so note it
 	     into the subreg.  */
Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/ifcvt.c	2017-08-21 14:21:03.721872923 +0100
@@ -3195,7 +3195,7 @@  noce_convert_multiple_sets (struct noce_
 	{
 	  machine_mode src_mode = GET_MODE (new_val);
 	  machine_mode dst_mode = GET_MODE (temp);
-	  if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+	  if (!partial_subreg_p (dst_mode, src_mode))
 	    {
 	      end_sequence ();
 	      return FALSE;
@@ -3206,7 +3206,7 @@  noce_convert_multiple_sets (struct noce_
 	{
 	  machine_mode src_mode = GET_MODE (old_val);
 	  machine_mode dst_mode = GET_MODE (temp);
-	  if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+	  if (!partial_subreg_p (dst_mode, src_mode))
 	    {
 	      end_sequence ();
 	      return FALSE;
Index: gcc/ira-build.c
===================================================================
--- gcc/ira-build.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/ira-build.c	2017-08-21 14:21:03.722875367 +0100
@@ -1853,7 +1853,7 @@  create_insn_allocnos (rtx x, rtx outer,
 	      if (outer != NULL && GET_CODE (outer) == SUBREG)
 		{
 		  machine_mode wmode = GET_MODE (outer);
-		  if (GET_MODE_SIZE (wmode) > GET_MODE_SIZE (ALLOCNO_WMODE (a)))
+		  if (partial_subreg_p (ALLOCNO_WMODE (a), wmode))
 		    ALLOCNO_WMODE (a) = wmode;
 		}
 	    }
Index: gcc/lra-coalesce.c
===================================================================
--- gcc/lra-coalesce.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/lra-coalesce.c	2017-08-21 14:21:03.722875367 +0100
@@ -112,8 +112,8 @@  merge_pseudos (int regno1, int regno2)
     = (lra_merge_live_ranges
        (lra_reg_info[first].live_ranges,
 	lra_copy_live_range_list (lra_reg_info[first2].live_ranges)));
-  if (GET_MODE_SIZE (lra_reg_info[first].biggest_mode)
-      < GET_MODE_SIZE (lra_reg_info[first2].biggest_mode))
+  if (partial_subreg_p (lra_reg_info[first].biggest_mode,
+			lra_reg_info[first2].biggest_mode))
     lra_reg_info[first].biggest_mode = lra_reg_info[first2].biggest_mode;
 }
 
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2017-08-21 14:20:43.096954323 +0100
+++ gcc/lra-constraints.c	2017-08-21 14:21:03.722875367 +0100
@@ -925,7 +925,7 @@  match_reload (signed char out, signed ch
   push_to_sequence (*before);
   if (inmode != outmode)
     {
-      if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
+      if (partial_subreg_p (outmode, inmode))
 	{
 	  reg = new_in_reg
 	    = lra_create_new_reg_with_unique_value (inmode, in_rtx,
@@ -1576,8 +1576,7 @@  simplify_operand_subreg (int nop, machin
 	      bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
 
 	      insert_before = (type != OP_OUT
-			       || GET_MODE_SIZE (innermode)
-				    > GET_MODE_SIZE (mode));
+			       || partial_subreg_p (mode, innermode));
 	      insert_after = type != OP_IN;
 	      insert_move_for_subreg (insert_before ? &before : NULL,
 				      insert_after ? &after : NULL,
@@ -3936,8 +3935,7 @@  curr_insn_transform (bool check_only_p)
       lra_assert (out >= 0 && in >= 0
 		  && curr_static_id->operand[out].type == OP_OUT
 		  && curr_static_id->operand[in].type == OP_IN);
-      rld = (GET_MODE_SIZE (GET_MODE (dest)) <= GET_MODE_SIZE (GET_MODE (src))
-	     ? dest : src);
+      rld = partial_subreg_p (GET_MODE (src), GET_MODE (dest)) ? src : dest;
       rld_mode = GET_MODE (rld);
 #ifdef SECONDARY_MEMORY_NEEDED_MODE
       sec_mode = SECONDARY_MEMORY_NEEDED_MODE (rld_mode);
@@ -3947,7 +3945,7 @@  curr_insn_transform (bool check_only_p)
       new_reg = lra_create_new_reg (sec_mode, NULL_RTX,
 				    NO_REGS, "secondary");
       /* If the mode is changed, it should be wider.  */
-      lra_assert (GET_MODE_SIZE (sec_mode) >= GET_MODE_SIZE (rld_mode));
+      lra_assert (!partial_subreg_p (sec_mode, rld_mode));
       if (sec_mode != rld_mode)
         {
 	  /* If the target says specifically to use another mode for
Index: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/lra-lives.c	2017-08-21 14:21:03.723877811 +0100
@@ -717,9 +717,9 @@  process_bb_lives (basic_block bb, int &c
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
 	{
 	  int i, regno = reg->regno;
-	  
-	  if (GET_MODE_SIZE (reg->biggest_mode)
-	      > GET_MODE_SIZE (lra_reg_info[regno].biggest_mode))
+
+	  if (partial_subreg_p (lra_reg_info[regno].biggest_mode,
+				reg->biggest_mode))
 	    lra_reg_info[regno].biggest_mode = reg->biggest_mode;
 	  if (regno < FIRST_PSEUDO_REGISTER)
 	    {
@@ -729,8 +729,8 @@  process_bb_lives (basic_block bb, int &c
 		 part of multi-register group.  Process this case
 		 here.  */
 	      for (i = 1; i < hard_regno_nregs[regno][reg->biggest_mode]; i++)
-		if (GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno + i]))
-		    > GET_MODE_SIZE (lra_reg_info[regno + i].biggest_mode))
+		if (partial_subreg_p (lra_reg_info[regno + i].biggest_mode,
+				      GET_MODE (regno_reg_rtx[regno + i])))
 		  lra_reg_info[regno + i].biggest_mode
 		    = GET_MODE (regno_reg_rtx[regno + i]);
 	    }
Index: gcc/lra.c
===================================================================
--- gcc/lra.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/lra.c	2017-08-21 14:21:03.723877811 +0100
@@ -546,8 +546,8 @@  new_insn_reg (rtx_insn *insn, int regno,
   lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
   ir->type = type;
   ir->biggest_mode = mode;
-  if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (lra_reg_info[regno].biggest_mode)
-      && NONDEBUG_INSN_P (insn))
+  if (NONDEBUG_INSN_P (insn)
+      && partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
     lra_reg_info[regno].biggest_mode = mode;
   ir->subreg_p = subreg_p;
   ir->early_clobber = early_clobber;
@@ -1913,7 +1913,7 @@  lra_substitute_pseudo (rtx *loc, int old
       if (mode != inner_mode
 	  && ! (CONST_INT_P (new_reg) && SCALAR_INT_MODE_P (mode)))
 	{
-	  if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (inner_mode)
+	  if (!partial_subreg_p (mode, inner_mode)
 	      || ! SCALAR_INT_MODE_P (inner_mode))
 	    new_reg = gen_rtx_SUBREG (mode, new_reg, 0);
 	  else
Index: gcc/regcprop.c
===================================================================
--- gcc/regcprop.c	2017-08-21 10:42:34.185530464 +0100
+++ gcc/regcprop.c	2017-08-21 14:21:03.726885145 +0100
@@ -372,7 +372,7 @@  copy_value (rtx dest, rtx src, struct va
 mode_change_ok (machine_mode orig_mode, machine_mode new_mode,
 		unsigned int regno ATTRIBUTE_UNUSED)
 {
-  if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode))
+  if (partial_subreg_p (orig_mode, new_mode))
     return false;
 
 #ifdef CANNOT_CHANGE_MODE_CLASS
@@ -392,8 +392,8 @@  maybe_mode_change (machine_mode orig_mod
 		   machine_mode new_mode, unsigned int regno,
 		   unsigned int copy_regno ATTRIBUTE_UNUSED)
 {
-  if (GET_MODE_SIZE (copy_mode) < GET_MODE_SIZE (orig_mode)
-      && GET_MODE_SIZE (copy_mode) < GET_MODE_SIZE (new_mode))
+  if (partial_subreg_p (copy_mode, orig_mode)
+      && partial_subreg_p (copy_mode, new_mode))
     return NULL_RTX;
 
   /* Avoid creating multiple copies of the stack pointer.  Some ports
@@ -1076,8 +1076,8 @@  copyprop_hardreg_forward_1 (basic_block
       /* If a noop move is using narrower mode than we have recorded,
 	 we need to either remove the noop move, or kill_set_value.  */
       if (noop_p
-	  && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set)))
-	      < GET_MODE_BITSIZE (vd->e[REGNO (SET_DEST (set))].mode)))
+	  && partial_subreg_p (GET_MODE (SET_DEST (set)),
+			       vd->e[REGNO (SET_DEST (set))].mode))
 	{
 	  if (noop_move_p (insn))
 	    {
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2017-08-21 14:20:43.098961211 +0100
+++ gcc/reload.c	2017-08-21 14:21:03.727887589 +0100
@@ -1071,8 +1071,7 @@  push_reload (rtx in, rtx out, rtx *inloc
 		      && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
 		      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != UNKNOWN)
 		  || (WORD_REGISTER_OPERATIONS
-		      && (GET_MODE_PRECISION (inmode)
-			  < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in))))
+		      && partial_subreg_p (inmode, GET_MODE (SUBREG_REG (in)))
 		      && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
 			  ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1)
 			   / UNITS_PER_WORD)))))
@@ -1171,8 +1170,7 @@  push_reload (rtx in, rtx out, rtx *inloc
 	       || MEM_P (SUBREG_REG (out)))
 	      && (paradoxical_subreg_p (outmode, GET_MODE (SUBREG_REG (out)))
 		  || (WORD_REGISTER_OPERATIONS
-		      && (GET_MODE_PRECISION (outmode)
-			  < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out))))
+		      && partial_subreg_p (outmode, GET_MODE (SUBREG_REG (out)))
 		      && ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
 			  ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
 			   / UNITS_PER_WORD)))))
@@ -1417,10 +1415,10 @@  push_reload (rtx in, rtx out, rtx *inloc
       /* The modes can be different.  If they are, we want to reload in
 	 the larger mode, so that the value is valid for both modes.  */
       if (inmode != VOIDmode
-	  && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (rld[i].inmode))
+	  && partial_subreg_p (rld[i].inmode, inmode))
 	rld[i].inmode = inmode;
       if (outmode != VOIDmode
-	  && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (rld[i].outmode))
+	  && partial_subreg_p (rld[i].outmode, outmode))
 	rld[i].outmode = outmode;
       if (in != 0)
 	{
@@ -1462,26 +1460,25 @@  push_reload (rtx in, rtx out, rtx *inloc
 	     overwrite the operands only when the new mode is larger.
 	     See also PR33613.  */
 	  if (!rld[i].in
-	      || GET_MODE_SIZE (GET_MODE (in))
-	           > GET_MODE_SIZE (GET_MODE (rld[i].in)))
+	      || partial_subreg_p (GET_MODE (rld[i].in), GET_MODE (in)))
 	    rld[i].in = in;
 	  if (!rld[i].in_reg
 	      || (in_reg
-		  && GET_MODE_SIZE (GET_MODE (in_reg))
-	             > GET_MODE_SIZE (GET_MODE (rld[i].in_reg))))
+		  && partial_subreg_p (GET_MODE (rld[i].in_reg),
+				       GET_MODE (in_reg))))
 	    rld[i].in_reg = in_reg;
 	}
       if (out != 0)
 	{
 	  if (!rld[i].out
 	      || (out
-		  && GET_MODE_SIZE (GET_MODE (out))
-	             > GET_MODE_SIZE (GET_MODE (rld[i].out))))
+		  && partial_subreg_p (GET_MODE (rld[i].out),
+				       GET_MODE (out))))
 	    rld[i].out = out;
 	  if (outloc
 	      && (!rld[i].out_reg
-		  || GET_MODE_SIZE (GET_MODE (*outloc))
-		     > GET_MODE_SIZE (GET_MODE (rld[i].out_reg))))
+		  || partial_subreg_p (GET_MODE (rld[i].out_reg),
+				       GET_MODE (*outloc))))
 	    rld[i].out_reg = *outloc;
 	}
       if (reg_class_subset_p (rclass, rld[i].rclass))
@@ -1587,7 +1584,7 @@  push_reload (rtx in, rtx out, rtx *inloc
       int regno;
       machine_mode rel_mode = inmode;
 
-      if (out && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (inmode))
+      if (out && partial_subreg_p (rel_mode, outmode))
 	rel_mode = outmode;
 
       for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
@@ -4549,11 +4546,10 @@  find_reloads (rtx_insn *insn, int replac
   /* Compute reload_mode and reload_nregs.  */
   for (i = 0; i < n_reloads; i++)
     {
-      rld[i].mode
-	= (rld[i].inmode == VOIDmode
-	   || (GET_MODE_SIZE (rld[i].outmode)
-	       > GET_MODE_SIZE (rld[i].inmode)))
-	  ? rld[i].outmode : rld[i].inmode;
+      rld[i].mode = rld[i].inmode;
+      if (rld[i].mode == VOIDmode
+	  || partial_subreg_p (rld[i].mode, rld[i].outmode))
+	rld[i].mode = rld[i].outmode;
 
       rld[i].nregs = ira_reg_class_max_nregs [rld[i].rclass][rld[i].mode];
     }
@@ -6157,7 +6153,7 @@  find_reloads_subreg_address (rtx x, int
     return NULL;
 
   if (WORD_REGISTER_OPERATIONS
-      && GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode)
+      && partial_subreg_p (outer_mode, inner_mode)
       && ((GET_MODE_SIZE (outer_mode) - 1) / UNITS_PER_WORD
           == (GET_MODE_SIZE (inner_mode) - 1) / UNITS_PER_WORD))
     return NULL;
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	2017-08-21 14:20:43.099964655 +0100
+++ gcc/reload1.c	2017-08-21 14:21:03.728890033 +0100
@@ -2218,8 +2218,8 @@  alter_reg (int i, int from_reg, bool don
 
 	  if (spill_stack_slot[from_reg])
 	    {
-	      if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
-		  > inherent_size)
+	      if (partial_subreg_p (mode,
+				    GET_MODE (spill_stack_slot[from_reg])))
 		mode = GET_MODE (spill_stack_slot[from_reg]);
 	      if (spill_stack_slot_width[from_reg] > total_size)
 		total_size = spill_stack_slot_width[from_reg];
@@ -2817,7 +2817,7 @@  eliminate_regs_1 (rtx x, machine_mode me
 	  int new_size = GET_MODE_SIZE (GET_MODE (new_rtx));
 
 	  if (MEM_P (new_rtx)
-	      && ((x_size < new_size
+	      && ((partial_subreg_p (GET_MODE (x), GET_MODE (new_rtx))
 		   /* On RISC machines, combine can create rtl of the form
 		      (set (subreg:m1 (reg:m2 R) 0) ...)
 		      where m1 < m2, and expects something interesting to
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	2017-08-21 14:20:43.102974987 +0100
+++ gcc/simplify-rtx.c	2017-08-21 14:21:03.728890033 +0100
@@ -987,10 +987,8 @@  simplify_unary_operation_1 (enum rtx_cod
 					XEXP (op, 0), const0_rtx);
 
 
-      if (GET_CODE (op) == SUBREG
+      if (partial_subreg_p (op)
 	  && subreg_lowpart_p (op)
-	  && (GET_MODE_SIZE (GET_MODE (op))
-	      < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
 	  && GET_CODE (SUBREG_REG (op)) == ASHIFT
 	  && XEXP (SUBREG_REG (op), 0) == const1_rtx)
 	{
@@ -1627,9 +1625,7 @@  simplify_unary_operation_1 (enum rtx_cod
 	 of mode N.  E.g.
 	 (zero_extend:SI (subreg:QI (and:SI (reg:SI) (const_int 63)) 0)) is
 	 (and:SI (reg:SI) (const_int 63)).  */
-      if (GET_CODE (op) == SUBREG
-	  && GET_MODE_PRECISION (GET_MODE (op))
-	     < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op)))
+      if (partial_subreg_p (op)
 	  && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op)))
 	     <= HOST_BITS_PER_WIDE_INT
 	  && GET_MODE_PRECISION (mode)