diff mbox

[lra] patch to revert a code from previous patch.

Message ID 87pq4ijeoh.fsf@talisman.home
State New
Headers show

Commit Message

Richard Sandiford Oct. 16, 2012, 9:21 p.m. UTC
Vladimir Makarov <vmakarov@redhat.com> writes:
> On 10/16/2012 02:44 AM, Richard Sandiford wrote:
>> Vladimir Makarov <vmakarov@redhat.com> writes:
>>> On 12-10-15 4:25 PM, Richard Sandiford wrote:
>>>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>> Vladimir Makarov <vmakarov@redhat.com> writes:
>>>>>>      After committing a patch yesterday to implement proposals from a
>>>>>> review, I found that GCC crashes on SPEC2000 gap.  LRA is trying to find
>>>>>> a mode of operand (const_int 1) in *lea_general_1 insn and can not find
>>>>>> it as the operand and insn template operand has VOIDmode.
>>>>>>
>>>>>> There are still cases when context lookup is necessary to find a mode of
>>>>>> the operand.  So I am reversing the change I did yesterday.
>>>>>>
>>>>>> The patch is committed as rev. 192462.
>>>>>>
>>>>>> 2012-10-15  Vladimir Makarov  <vmakarov@redhat.com>
>>>>>>
>>>>>>            * lra-int.h (lra_get_mode): Remove.
>>>>>>            * lra-constraints.c (find_mode, get_op_mode): New functions.
>>>>>>            (match_reload): Use get_op_mode instead of lra_get_mode.
>>>>>>            (process_alt_operands, curr_insn_transform): Ditto.
>>>>> But my objection to this code still stands.  It's wrong to assume
>>>>> that an operand to an rtx has the same mode as the containing rtx.
>>>>>
>>>>> Please add a testcase that shows the problem.
>>>> (...because I was hoping to have a look myself).  But if that's too
>>>> difficult to reduce, then which operand to *lea_general_1 was the problem?
>>>> The pattern looks like:
>>>>
>>>> (define_insn_and_split "*lea_general_1"
>>>>     [(set (match_operand 0 "register_operand" "=r")
>>>> 	(plus (plus (match_operand 1 "index_register_operand" "l")
>>>> 		    (match_operand 2 "register_operand" "r"))
>>>> 	      (match_operand 3 "immediate_operand" "i")))]
>>>>
>>>> So operands 0, 1 and 2 should have been registers.  Operand 3 never
>>>> needs reloading, so its mode shouldn't matter.
>>>>
>>> In this case the const needs a reload as it was a pseudo substituted by
>>> equiv constant.
>> But in that case the operand modes we needed were there in the original
>> instruction operands.  If equiv substitution is causing us to lose track
>> of those operand modes, then that needs to be fixed.
>>
>> If the pattern had instead been:
>>
>>    (set (match_operand:SI 0 "register_operand" "=r")
>>         (unspec:SI [(match_operand 1 "register_operand" "r")] UNSPEC_FOO))
>>
>> and equiv substitution replaced operand 1 with a const_int without
>> the original mode being recorded anywhere, then we'd have no way
>> of recovering that mode from the pattern itself, because the modes
>> of unspec parameters are entirely target-specific.
>>
> I remember I thought about this.  The case is rare, it is better to 
> calculate than keep mode for each operand of each insn.  LRA speed is 
> achieved by minimizations of keeping data for each operand.  We keep 
> only locations. I believe it is a better approach.

I don't think we need to keep a _global_ tab on the operand modes.  The nice
thing about representing intermediate steps in rtl is that the substituted,
unreloaded operands only appear temporarily during curr_insn_transform.
Once that function has finished reloading the instruction, the instruction's
operands have the right form again.

This is the kind of thing I had in mind.  Tested on x86_64-linux-gnu
({,-m32}), no regressions.  Does it look OK?  And does it work with
the SPEC testcase?

I realise you probably have patches pending as well, so I'm happy to
wait until those have gone in and update.

Richard


gcc/
	* lra-int.h (lra_operand_data): Add is_address field.
	* lra.c (debug_operand_data): Initialize is_address field.
	(get_static_insn_data): Likewise.
	(setup_operand_alternative): Record is_address in operand data.
	(lra_set_insn_recog_data): Initialize is_address field.
	* lra-constraints.c (curr_operand_mode): New array.
	(init_curr_operand_mode): New function.
	(find_mode, get_op_mode): Delete.
	(match_reload): Use curr_operand_mode rather than get_op_mode.
	(process_alt_operands): Likewise.  Remove VOIDmode check from
	CONST_OK_POOL_P check.
	(curr_insn_transform): Likewise.  Swap the operand modes when
	swapping the operands.
	(lra_constraints): Call init_curr_operand_mode.

Comments

Vladimir Makarov Oct. 17, 2012, 1:17 a.m. UTC | #1
On 12-10-16 5:21 PM, Richard Sandiford wrote:
> Vladimir Makarov <vmakarov@redhat.com> writes:
>> On 10/16/2012 02:44 AM, Richard Sandiford wrote:
>>> Vladimir Makarov <vmakarov@redhat.com> writes:
>>>> On 12-10-15 4:25 PM, Richard Sandiford wrote:
>>>>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>>> Vladimir Makarov <vmakarov@redhat.com> writes:
>>>>>>>       After committing a patch yesterday to implement proposals from a
>>>>>>> review, I found that GCC crashes on SPEC2000 gap.  LRA is trying to find
>>>>>>> a mode of operand (const_int 1) in *lea_general_1 insn and can not find
>>>>>>> it as the operand and insn template operand has VOIDmode.
>>>>>>>
>>>>>>> There are still cases when context lookup is necessary to find a mode of
>>>>>>> the operand.  So I am reversing the change I did yesterday.
>>>>>>>
>>>>>>> The patch is committed as rev. 192462.
>>>>>>>
>>>>>>> 2012-10-15  Vladimir Makarov  <vmakarov@redhat.com>
>>>>>>>
>>>>>>>             * lra-int.h (lra_get_mode): Remove.
>>>>>>>             * lra-constraints.c (find_mode, get_op_mode): New functions.
>>>>>>>             (match_reload): Use get_op_mode instead of lra_get_mode.
>>>>>>>             (process_alt_operands, curr_insn_transform): Ditto.
>>>>>> But my objection to this code still stands.  It's wrong to assume
>>>>>> that an operand to an rtx has the same mode as the containing rtx.
>>>>>>
>>>>>> Please add a testcase that shows the problem.
>>>>> (...because I was hoping to have a look myself).  But if that's too
>>>>> difficult to reduce, then which operand to *lea_general_1 was the problem?
>>>>> The pattern looks like:
>>>>>
>>>>> (define_insn_and_split "*lea_general_1"
>>>>>      [(set (match_operand 0 "register_operand" "=r")
>>>>> 	(plus (plus (match_operand 1 "index_register_operand" "l")
>>>>> 		    (match_operand 2 "register_operand" "r"))
>>>>> 	      (match_operand 3 "immediate_operand" "i")))]
>>>>>
>>>>> So operands 0, 1 and 2 should have been registers.  Operand 3 never
>>>>> needs reloading, so its mode shouldn't matter.
>>>>>
>>>> In this case the const needs a reload as it was a pseudo substituted by
>>>> equiv constant.
>>> But in that case the operand modes we needed were there in the original
>>> instruction operands.  If equiv substitution is causing us to lose track
>>> of those operand modes, then that needs to be fixed.
>>>
>>> If the pattern had instead been:
>>>
>>>     (set (match_operand:SI 0 "register_operand" "=r")
>>>          (unspec:SI [(match_operand 1 "register_operand" "r")] UNSPEC_FOO))
>>>
>>> and equiv substitution replaced operand 1 with a const_int without
>>> the original mode being recorded anywhere, then we'd have no way
>>> of recovering that mode from the pattern itself, because the modes
>>> of unspec parameters are entirely target-specific.
>>>
>> I remember I thought about this.  The case is rare, it is better to
>> calculate than keep mode for each operand of each insn.  LRA speed is
>> achieved by minimizations of keeping data for each operand.  We keep
>> only locations. I believe it is a better approach.
> I don't think we need to keep a _global_ tab on the operand modes.  The nice
> thing about representing intermediate steps in rtl is that the substituted,
> unreloaded operands only appear temporarily during curr_insn_transform.
> Once that function has finished reloading the instruction, the instruction's
> operands have the right form again.
>
> This is the kind of thing I had in mind.  Tested on x86_64-linux-gnu
> ({,-m32}), no regressions.  Does it look OK?  And does it work with
> the SPEC testcase?
Although, I believe that it will work for all cases.  And I like it more 
than my solution.
So the patch is ok.  Thanks for working on this, Richard.
> I realise you probably have patches pending as well, so I'm happy to
> wait until those have gone in and update.
>
You can commit it into the branch.  You have to do some work for 
conflict resolution (I added new helper function in 
curr_insn_transformation for swapping operands) as the code was changed 
a lot today.
>
>
> gcc/
> 	* lra-int.h (lra_operand_data): Add is_address field.
> 	* lra.c (debug_operand_data): Initialize is_address field.
> 	(get_static_insn_data): Likewise.
> 	(setup_operand_alternative): Record is_address in operand data.
> 	(lra_set_insn_recog_data): Initialize is_address field.
> 	* lra-constraints.c (curr_operand_mode): New array.
> 	(init_curr_operand_mode): New function.
> 	(find_mode, get_op_mode): Delete.
> 	(match_reload): Use curr_operand_mode rather than get_op_mode.
> 	(process_alt_operands): Likewise.  Remove VOIDmode check from
> 	CONST_OK_POOL_P check.
> 	(curr_insn_transform): Likewise.  Swap the operand modes when
> 	swapping the operands.
> 	(lra_constraints): Call init_curr_operand_mode.
>
> Index: gcc/lra-int.h
> ===================================================================
> --- gcc/lra-int.h	2012-10-16 19:32:48.000000000 +0100
> +++ gcc/lra-int.h	2012-10-16 20:35:53.272728031 +0100
> @@ -157,6 +157,8 @@ struct lra_operand_data
>        This field is set up every time when corresponding
>        operand_alternative in lra_static_insn_data is set up.  */
>     unsigned int early_clobber : 1;
> +  /* True if the operand is an address.  */
> +  unsigned int is_address : 1;
>   };
>   
>   /* Info about register in an insn.  */
> Index: gcc/lra.c
> ===================================================================
> --- gcc/lra.c	2012-10-16 19:32:48.000000000 +0100
> +++ gcc/lra.c	2012-10-16 20:36:19.042726596 +0100
> @@ -518,7 +518,7 @@ static struct lra_operand_data debug_ope
>       NULL, /* alternative  */
>       VOIDmode, /* We are not interesting in the operand mode.  */
>       OP_IN,
> -    0, 0, 0
> +    0, 0, 0, 0
>     };
>   
>   /* The following data are used as static insn data for all debug
> @@ -619,6 +619,7 @@ get_static_insn_data (int icode, int nop
>   	    = (data->operand[i].constraint[0] == '=' ? OP_OUT
>   	       : data->operand[i].constraint[0] == '+' ? OP_INOUT
>   	       : OP_IN);
> +	  data->operand[i].is_address = false;
>   	}
>         for (i = 0; i < ndup; i++)
>   	data->dup_num[i] = recog_data.dup_num[i];
> @@ -824,6 +825,7 @@ setup_operand_alternative (lra_insn_reco
>   		  break;
>   
>   		case 'p':
> +		  static_data->operand[i].is_address = true;
>   		  op_alt->is_address = 1;
>   		  op_alt->cl = (reg_class_subunion[(int) op_alt->cl]
>   				[(int) base_reg_class (VOIDmode,
> @@ -845,6 +847,7 @@ setup_operand_alternative (lra_insn_reco
>   		    }
>   		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
>   		    {
> +		      static_data->operand[i].is_address = true;
>   		      op_alt->is_address = 1;
>   		      op_alt->cl
>   			= (reg_class_subunion
> @@ -1063,6 +1066,7 @@ lra_set_insn_recog_data (rtx insn)
>   	      insn_static_data->operand[i].constraint = constraints[i];
>   	      insn_static_data->operand[i].strict_low = false;
>   	      insn_static_data->operand[i].is_operator = false;
> +	      insn_static_data->operand[i].is_address = false;
>   	    }
>   	}
>         for (i = 0; i < insn_static_data->n_operands; i++)
> Index: gcc/lra-constraints.c
> ===================================================================
> --- gcc/lra-constraints.c	2012-10-16 19:32:48.000000000 +0100
> +++ gcc/lra-constraints.c	2012-10-16 20:49:42.717681827 +0100
> @@ -138,11 +138,13 @@
>   static int bb_reload_num;
>   
>   /* The current insn being processed and corresponding its data (basic
> -   block, the insn data, and the insn static data.  */
> +   block, the insn data, the insn static data, and the mode of each
> +   operand).  */
>   static rtx curr_insn;
>   static basic_block curr_bb;
>   static lra_insn_recog_data_t curr_id;
>   static struct lra_static_insn_data *curr_static_id;
> +static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
>   
>   
>   
> @@ -298,6 +300,27 @@ get_equiv_substitution (rtx x)
>     gcc_unreachable ();
>   }
>   
> +/* Set up curr_operand_mode.  */
> +static void
> +init_curr_operand_mode (void)
> +{
> +  int nop = curr_static_id->n_operands;
> +  for (int i = 0; i < nop; i++)
> +    {
> +      enum machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
> +      if (mode == VOIDmode)
> +	{
> +	  /* The .md mode for address operands is the mode of the
> +	     addressed value rather than the mode of the address itself.  */
> +	  if (curr_id->icode >= 0 && curr_static_id->operand[i].is_address)
> +	    mode = Pmode;
> +	  else
> +	    mode = curr_static_id->operand[i].mode;
> +	}
> +      curr_operand_mode[i] = mode;
> +    }
> +}
> +
>   
>   
>   /* The page contains code to reuse input reloads.  */
> @@ -876,65 +899,6 @@ #define SMALL_REGISTER_CLASS_P(C)					\
>     (reg_class_size [(C)] == 1						\
>      || (reg_class_size [(C)] >= 1 && targetm.class_likely_spilled_p (C)))
>   
> -/* Return mode of WHAT inside of WHERE whose mode of the context is
> -   OUTER_MODE.	If WHERE does not contain WHAT, return VOIDmode.  */
> -static enum machine_mode
> -find_mode (rtx *where, enum machine_mode outer_mode, rtx *what)
> -{
> -  int i, j;
> -  enum machine_mode mode;
> -  rtx x;
> -  const char *fmt;
> -  enum rtx_code code;
> -
> -  if (where == what)
> -    return outer_mode;
> -  if (*where == NULL_RTX)
> -    return VOIDmode;
> -  x = *where;
> -  code = GET_CODE (x);
> -  outer_mode = GET_MODE (x);
> -  fmt = GET_RTX_FORMAT (code);
> -  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
> -    {
> -      if (fmt[i] == 'e')
> -	{
> -	  if ((mode = find_mode (&XEXP (x, i), outer_mode, what)) != VOIDmode)
> -	    return mode;
> -	}
> -      else if (fmt[i] == 'E')
> -	{
> -	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
> -	  if ((mode = find_mode (&XVECEXP (x, i, j), outer_mode, what))
> -	      != VOIDmode)
> -	    return mode;
> -	}
> -    }
> -  return VOIDmode;
> -}
> -
> -/* Return mode for operand NOP of the current insn.  */
> -static inline enum machine_mode
> -get_op_mode (int nop)
> -{
> -  rtx *loc;
> -  enum machine_mode mode;
> -  bool md_first_p = asm_noperands (PATTERN (curr_insn)) < 0;
> -
> -  /* Take mode from the machine description first.  */
> -  if (md_first_p && (mode = curr_static_id->operand[nop].mode) != VOIDmode)
> -    return mode;
> -  loc = curr_id->operand_loc[nop];
> -  /* Take mode from the operand second.	 */
> -  mode = GET_MODE (*loc);
> -  if (mode != VOIDmode)
> -    return mode;
> -  if (! md_first_p && (mode = curr_static_id->operand[nop].mode) != VOIDmode)
> -    return mode;
> -  /* Here is a very rare case.	Take mode from the context.  */
> -  return find_mode (&PATTERN (curr_insn), VOIDmode, loc);
> -}
> -
>   /* If REG is a reload pseudo, try to make its class satisfying CL.  */
>   static void
>   narrow_reload_pseudo_class (rtx reg, enum reg_class cl)
> @@ -969,8 +933,8 @@ match_reload (signed char out, signed ch
>     rtx in_rtx = *curr_id->operand_loc[ins[0]];
>     rtx out_rtx = *curr_id->operand_loc[out];
>   
> -  outmode = get_op_mode (out);
> -  inmode = get_op_mode (ins[0]);
> +  outmode = curr_operand_mode[out];
> +  inmode = curr_operand_mode[ins[0]];
>     if (inmode != outmode)
>       {
>         if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
> @@ -1698,7 +1662,7 @@ process_alt_operands (int only_alternati
>   	    }
>         
>   	  op = no_subreg_reg_operand[nop];
> -	  mode = get_op_mode (nop);
> +	  mode = curr_operand_mode[nop];
>   
>   	  win = did_match = winreg = offmemok = constmemok = false;
>   	  badop = true;
> @@ -2170,8 +2134,7 @@ process_alt_operands (int only_alternati
>   	      if (CONST_POOL_OK_P (mode, op)
>   		  && ((targetm.preferred_reload_class
>   		       (op, this_alternative) == NO_REGS)
> -		      || no_input_reloads_p)
> -		  && get_op_mode (nop) != VOIDmode)
> +		      || no_input_reloads_p))
>   		{
>   		  const_to_mem = 1;
>   		  if (! no_regs_p)
> @@ -2976,6 +2939,9 @@ curr_insn_transform (void)
>         curr_swapped = !curr_swapped;
>         if (curr_swapped)
>   	{
> +	  enum machine_mode mode = curr_operand_mode[commutative];
> +	  curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
> +	  curr_operand_mode[commutative + 1] = mode;
>   	  x = *curr_id->operand_loc[commutative];
>   	  *curr_id->operand_loc[commutative]
>   	    = *curr_id->operand_loc[commutative + 1];
> @@ -2987,6 +2953,9 @@ curr_insn_transform (void)
>   	}
>         else
>   	{
> +	  enum machine_mode mode = curr_operand_mode[commutative];
> +	  curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
> +	  curr_operand_mode[commutative + 1] = mode;
>   	  x = *curr_id->operand_loc[commutative];
>   	  *curr_id->operand_loc[commutative]
>   	    = *curr_id->operand_loc[commutative + 1];
> @@ -3025,6 +2994,9 @@ curr_insn_transform (void)
>   	fprintf (lra_dump_file, "  Commutative operand exchange in insn %u\n",
>   		 INSN_UID (curr_insn));
>   
> +      enum machine_mode mode = curr_operand_mode[commutative];
> +      curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
> +      curr_operand_mode[commutative + 1] = mode;
>         tem = *curr_id->operand_loc[commutative];
>         *curr_id->operand_loc[commutative]
>   	= *curr_id->operand_loc[commutative + 1];
> @@ -3156,7 +3128,7 @@ curr_insn_transform (void)
>   	rtx op = *curr_id->operand_loc[i];
>   	rtx subreg = NULL_RTX;
>   	rtx plus = NULL_RTX;
> -	enum machine_mode mode = get_op_mode (i);
> +	enum machine_mode mode = curr_operand_mode[i];
>   	
>   	if (GET_CODE (op) == SUBREG)
>   	  {
> @@ -3174,8 +3146,7 @@ curr_insn_transform (void)
>   	if (CONST_POOL_OK_P (mode, op)
>   	    && ((targetm.preferred_reload_class
>   		 (op, (enum reg_class) goal_alt[i]) == NO_REGS)
> -		|| no_input_reloads_p)
> -	    && mode != VOIDmode)
> +		|| no_input_reloads_p))
>   	  {
>   	    rtx tem = force_const_mem (mode, op);
>   	
> @@ -3270,7 +3241,7 @@ curr_insn_transform (void)
>   	  enum op_type type = curr_static_id->operand[i].type;
>   
>   	  loc = curr_id->operand_loc[i];
> -	  mode = get_op_mode (i);
> +	  mode = curr_operand_mode[i];
>   	  if (GET_CODE (*loc) == SUBREG)
>   	    {
>   	      reg = SUBREG_REG (*loc);
> @@ -3730,6 +3701,7 @@ lra_constraints (bool first_p)
>   	  curr_id = lra_get_insn_recog_data (curr_insn);
>   	  curr_static_id = curr_id->insn_static_data;
>   	  init_curr_insn_input_reloads ();
> +	  init_curr_operand_mode ();
>   	  if (curr_insn_transform ())
>   	    changed_p = true;
>   	}
diff mbox

Patch

Index: gcc/lra-int.h
===================================================================
--- gcc/lra-int.h	2012-10-16 19:32:48.000000000 +0100
+++ gcc/lra-int.h	2012-10-16 20:35:53.272728031 +0100
@@ -157,6 +157,8 @@  struct lra_operand_data
      This field is set up every time when corresponding
      operand_alternative in lra_static_insn_data is set up.  */
   unsigned int early_clobber : 1;
+  /* True if the operand is an address.  */
+  unsigned int is_address : 1;
 };
 
 /* Info about register in an insn.  */
Index: gcc/lra.c
===================================================================
--- gcc/lra.c	2012-10-16 19:32:48.000000000 +0100
+++ gcc/lra.c	2012-10-16 20:36:19.042726596 +0100
@@ -518,7 +518,7 @@  static struct lra_operand_data debug_ope
     NULL, /* alternative  */
     VOIDmode, /* We are not interesting in the operand mode.  */
     OP_IN,
-    0, 0, 0 
+    0, 0, 0, 0
   };
 
 /* The following data are used as static insn data for all debug
@@ -619,6 +619,7 @@  get_static_insn_data (int icode, int nop
 	    = (data->operand[i].constraint[0] == '=' ? OP_OUT
 	       : data->operand[i].constraint[0] == '+' ? OP_INOUT
 	       : OP_IN);
+	  data->operand[i].is_address = false;
 	}
       for (i = 0; i < ndup; i++)
 	data->dup_num[i] = recog_data.dup_num[i];
@@ -824,6 +825,7 @@  setup_operand_alternative (lra_insn_reco
 		  break;
 
 		case 'p':
+		  static_data->operand[i].is_address = true;
 		  op_alt->is_address = 1;
 		  op_alt->cl = (reg_class_subunion[(int) op_alt->cl]
 				[(int) base_reg_class (VOIDmode,
@@ -845,6 +847,7 @@  setup_operand_alternative (lra_insn_reco
 		    }
 		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		    {
+		      static_data->operand[i].is_address = true;
 		      op_alt->is_address = 1;
 		      op_alt->cl
 			= (reg_class_subunion
@@ -1063,6 +1066,7 @@  lra_set_insn_recog_data (rtx insn)
 	      insn_static_data->operand[i].constraint = constraints[i];
 	      insn_static_data->operand[i].strict_low = false;
 	      insn_static_data->operand[i].is_operator = false;
+	      insn_static_data->operand[i].is_address = false;
 	    }
 	}
       for (i = 0; i < insn_static_data->n_operands; i++)
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2012-10-16 19:32:48.000000000 +0100
+++ gcc/lra-constraints.c	2012-10-16 20:49:42.717681827 +0100
@@ -138,11 +138,13 @@ 
 static int bb_reload_num;
 
 /* The current insn being processed and corresponding its data (basic
-   block, the insn data, and the insn static data.  */
+   block, the insn data, the insn static data, and the mode of each
+   operand).  */
 static rtx curr_insn;
 static basic_block curr_bb;
 static lra_insn_recog_data_t curr_id;
 static struct lra_static_insn_data *curr_static_id;
+static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
 
 
 
@@ -298,6 +300,27 @@  get_equiv_substitution (rtx x)
   gcc_unreachable ();
 }
 
+/* Set up curr_operand_mode.  */
+static void
+init_curr_operand_mode (void)
+{
+  int nop = curr_static_id->n_operands;
+  for (int i = 0; i < nop; i++)
+    {
+      enum machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
+      if (mode == VOIDmode)
+	{
+	  /* The .md mode for address operands is the mode of the
+	     addressed value rather than the mode of the address itself.  */
+	  if (curr_id->icode >= 0 && curr_static_id->operand[i].is_address)
+	    mode = Pmode;
+	  else
+	    mode = curr_static_id->operand[i].mode;
+	}
+      curr_operand_mode[i] = mode;
+    }
+}
+
 
 
 /* The page contains code to reuse input reloads.  */
@@ -876,65 +899,6 @@  #define SMALL_REGISTER_CLASS_P(C)					\
   (reg_class_size [(C)] == 1						\
    || (reg_class_size [(C)] >= 1 && targetm.class_likely_spilled_p (C)))
 
-/* Return mode of WHAT inside of WHERE whose mode of the context is
-   OUTER_MODE.	If WHERE does not contain WHAT, return VOIDmode.  */
-static enum machine_mode
-find_mode (rtx *where, enum machine_mode outer_mode, rtx *what)
-{
-  int i, j;
-  enum machine_mode mode;
-  rtx x;
-  const char *fmt;
-  enum rtx_code code;
-
-  if (where == what)
-    return outer_mode;
-  if (*where == NULL_RTX)
-    return VOIDmode;
-  x = *where;
-  code = GET_CODE (x);
-  outer_mode = GET_MODE (x);
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-	{
-	  if ((mode = find_mode (&XEXP (x, i), outer_mode, what)) != VOIDmode)
-	    return mode;
-	}
-      else if (fmt[i] == 'E')
-	{
-	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-	  if ((mode = find_mode (&XVECEXP (x, i, j), outer_mode, what))
-	      != VOIDmode)
-	    return mode;
-	}
-    }
-  return VOIDmode;
-}
-
-/* Return mode for operand NOP of the current insn.  */
-static inline enum machine_mode
-get_op_mode (int nop)
-{
-  rtx *loc;
-  enum machine_mode mode;
-  bool md_first_p = asm_noperands (PATTERN (curr_insn)) < 0;
-
-  /* Take mode from the machine description first.  */
-  if (md_first_p && (mode = curr_static_id->operand[nop].mode) != VOIDmode)
-    return mode;
-  loc = curr_id->operand_loc[nop];
-  /* Take mode from the operand second.	 */
-  mode = GET_MODE (*loc);
-  if (mode != VOIDmode)
-    return mode;
-  if (! md_first_p && (mode = curr_static_id->operand[nop].mode) != VOIDmode)
-    return mode;
-  /* Here is a very rare case.	Take mode from the context.  */
-  return find_mode (&PATTERN (curr_insn), VOIDmode, loc);
-}
-
 /* If REG is a reload pseudo, try to make its class satisfying CL.  */
 static void
 narrow_reload_pseudo_class (rtx reg, enum reg_class cl)
@@ -969,8 +933,8 @@  match_reload (signed char out, signed ch
   rtx in_rtx = *curr_id->operand_loc[ins[0]];
   rtx out_rtx = *curr_id->operand_loc[out];
 
-  outmode = get_op_mode (out);
-  inmode = get_op_mode (ins[0]);
+  outmode = curr_operand_mode[out];
+  inmode = curr_operand_mode[ins[0]];
   if (inmode != outmode)
     {
       if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
@@ -1698,7 +1662,7 @@  process_alt_operands (int only_alternati
 	    }
       
 	  op = no_subreg_reg_operand[nop];
-	  mode = get_op_mode (nop);
+	  mode = curr_operand_mode[nop];
 
 	  win = did_match = winreg = offmemok = constmemok = false;
 	  badop = true;
@@ -2170,8 +2134,7 @@  process_alt_operands (int only_alternati
 	      if (CONST_POOL_OK_P (mode, op)
 		  && ((targetm.preferred_reload_class
 		       (op, this_alternative) == NO_REGS)
-		      || no_input_reloads_p)
-		  && get_op_mode (nop) != VOIDmode)
+		      || no_input_reloads_p))
 		{
 		  const_to_mem = 1;
 		  if (! no_regs_p)
@@ -2976,6 +2939,9 @@  curr_insn_transform (void)
       curr_swapped = !curr_swapped;
       if (curr_swapped)
 	{
+	  enum machine_mode mode = curr_operand_mode[commutative];
+	  curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
+	  curr_operand_mode[commutative + 1] = mode;
 	  x = *curr_id->operand_loc[commutative];
 	  *curr_id->operand_loc[commutative]
 	    = *curr_id->operand_loc[commutative + 1];
@@ -2987,6 +2953,9 @@  curr_insn_transform (void)
 	}
       else
 	{
+	  enum machine_mode mode = curr_operand_mode[commutative];
+	  curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
+	  curr_operand_mode[commutative + 1] = mode;
 	  x = *curr_id->operand_loc[commutative];
 	  *curr_id->operand_loc[commutative]
 	    = *curr_id->operand_loc[commutative + 1];
@@ -3025,6 +2994,9 @@  curr_insn_transform (void)
 	fprintf (lra_dump_file, "  Commutative operand exchange in insn %u\n",
 		 INSN_UID (curr_insn));
 
+      enum machine_mode mode = curr_operand_mode[commutative];
+      curr_operand_mode[commutative] = curr_operand_mode[commutative + 1];
+      curr_operand_mode[commutative + 1] = mode;
       tem = *curr_id->operand_loc[commutative];
       *curr_id->operand_loc[commutative]
 	= *curr_id->operand_loc[commutative + 1];
@@ -3156,7 +3128,7 @@  curr_insn_transform (void)
 	rtx op = *curr_id->operand_loc[i];
 	rtx subreg = NULL_RTX;
 	rtx plus = NULL_RTX;
-	enum machine_mode mode = get_op_mode (i);
+	enum machine_mode mode = curr_operand_mode[i];
 	
 	if (GET_CODE (op) == SUBREG)
 	  {
@@ -3174,8 +3146,7 @@  curr_insn_transform (void)
 	if (CONST_POOL_OK_P (mode, op)
 	    && ((targetm.preferred_reload_class
 		 (op, (enum reg_class) goal_alt[i]) == NO_REGS)
-		|| no_input_reloads_p)
-	    && mode != VOIDmode)
+		|| no_input_reloads_p))
 	  {
 	    rtx tem = force_const_mem (mode, op);
 	    
@@ -3270,7 +3241,7 @@  curr_insn_transform (void)
 	  enum op_type type = curr_static_id->operand[i].type;
 
 	  loc = curr_id->operand_loc[i];
-	  mode = get_op_mode (i);
+	  mode = curr_operand_mode[i];
 	  if (GET_CODE (*loc) == SUBREG)
 	    {
 	      reg = SUBREG_REG (*loc);
@@ -3730,6 +3701,7 @@  lra_constraints (bool first_p)
 	  curr_id = lra_get_insn_recog_data (curr_insn);
 	  curr_static_id = curr_id->insn_static_data;
 	  init_curr_insn_input_reloads ();
+	  init_curr_operand_mode ();
 	  if (curr_insn_transform ())
 	    changed_p = true;
 	}