diff mbox

Cleaning up expand optabs code

Message ID g41v1qqcy5.fsf@linaro.org
State New
Headers show

Commit Message

Richard Sandiford March 29, 2011, 1:21 p.m. UTC
Mikael Pettersson <mikpe@it.uu.se> writes:
> Richard Sandiford writes:
>  > Andreas Krebbel <krebbel@linux.vnet.ibm.com> writes:
>  > > On 03/22/2011 06:48 PM, Richard Henderson wrote:
>  > >
>  > >> Ok.  Watch out for other target problems this week.
>  > >
>  > > This unfortunately broke bootstrap on s390.
>  > 
>  > This is PR 48263.  Since it seems to be affecting several targets,
>  > and since my bootstrap seems to be taking a looong time, I'll post
>  > the patch here before testing has finished.
>  > 
>  > > Just copying the pre-patch behaviour fixes the problem for me:
>  > 
>  > I think we need to undo more of the patch, and leave the conversion
>  > outside of the new interface.
>  > 
>  > Sorry for the breakage.
>  > 
>  > Richard
>  > 
>  > 
>  > gcc/
>  > 	PR rtl-optimization/48263
>  > 	* optabs.c (expand_binop_directly): Reinstate convert_modes code
>  > 	and original commutative_p handling.  Use maybe_gen_insn.
>
> Unfortunately this fix (r171418) broke m68k-linux, see
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48332

Please try the attached

Richard


gcc/
	PR rtl-optimization/48332
	* optabs.c (expand_binop_directly): Set xmodeN to the target-mandated
	mode of input operand N and modeN to its actual mode.

Comments

Mikael Pettersson March 29, 2011, 1:58 p.m. UTC | #1
Richard Sandiford writes:
 > Mikael Pettersson <mikpe@it.uu.se> writes:
 > > Richard Sandiford writes:
 > >  > Andreas Krebbel <krebbel@linux.vnet.ibm.com> writes:
 > >  > > On 03/22/2011 06:48 PM, Richard Henderson wrote:
 > >  > >
 > >  > >> Ok.  Watch out for other target problems this week.
 > >  > >
 > >  > > This unfortunately broke bootstrap on s390.
 > >  > 
 > >  > This is PR 48263.  Since it seems to be affecting several targets,
 > >  > and since my bootstrap seems to be taking a looong time, I'll post
 > >  > the patch here before testing has finished.
 > >  > 
 > >  > > Just copying the pre-patch behaviour fixes the problem for me:
 > >  > 
 > >  > I think we need to undo more of the patch, and leave the conversion
 > >  > outside of the new interface.
 > >  > 
 > >  > Sorry for the breakage.
 > >  > 
 > >  > Richard
 > >  > 
 > >  > 
 > >  > gcc/
 > >  > 	PR rtl-optimization/48263
 > >  > 	* optabs.c (expand_binop_directly): Reinstate convert_modes code
 > >  > 	and original commutative_p handling.  Use maybe_gen_insn.
 > >
 > > Unfortunately this fix (r171418) broke m68k-linux, see
 > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48332
 > 
 > Please try the attached
 > 
 > Richard
 > 
 > 
 > gcc/
 > 	PR rtl-optimization/48332
 > 	* optabs.c (expand_binop_directly): Set xmodeN to the target-mandated
 > 	mode of input operand N and modeN to its actual mode.

Thanks, this allowed me to build gcc-4.7 as a cross to m68k-linux again.

I'm starting a native bootstrap of gcc-4.7 head + this fix on m68k, but
that will take about 5 days to complete...

/Mikael

 > 
 > Index: gcc/optabs.c
 > ===================================================================
 > --- gcc/optabs.c	2011-03-24 17:23:05.000000000 +0000
 > +++ gcc/optabs.c	2011-03-29 14:18:02.000000000 +0100
 > @@ -1243,9 +1243,9 @@ expand_binop_directly (enum machine_mode
 >  		       rtx last)
 >  {
 >    enum insn_code icode = optab_handler (binoptab, mode);
 > -  enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
 > -  enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
 > -  enum machine_mode tmp_mode;
 > +  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
 > +  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
 > +  enum machine_mode mode0, mode1, tmp_mode;
 >    struct expand_operand ops[3];
 >    bool commutative_p;
 >    rtx pat;
 > @@ -1256,8 +1256,8 @@ expand_binop_directly (enum machine_mode
 >       if we would swap the operands, we can save the conversions.  */
 >    commutative_p = commutative_optab_p (binoptab);
 >    if (commutative_p
 > -      && GET_MODE (xop0) != mode0 && GET_MODE (xop1) != mode1
 > -      && GET_MODE (xop0) == mode1 && GET_MODE (xop1) == mode1)
 > +      && GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1
 > +      && GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)
 >      {
 >        swap = xop0;
 >        xop0 = xop1;
 > @@ -1265,9 +1265,9 @@ expand_binop_directly (enum machine_mode
 >      }
 >  
 >    /* If we are optimizing, force expensive constants into a register.  */
 > -  xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp);
 > +  xop0 = avoid_expensive_constant (xmode0, binoptab, xop0, unsignedp);
 >    if (!shift_optab_p (binoptab))
 > -    xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp);
 > +    xop1 = avoid_expensive_constant (xmode1, binoptab, xop1, unsignedp);
 >  
 >    /* In case the insn wants input operands in modes different from
 >       those of the actual operands, convert the operands.  It would
 > @@ -1275,19 +1275,19 @@ expand_binop_directly (enum machine_mode
 >       that they're properly zero-extended, sign-extended or truncated
 >       for their mode.  */
 >  
 > -  if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
 > -    xop0 = convert_modes (mode0,
 > -			  GET_MODE (xop0) != VOIDmode
 > -			  ? GET_MODE (xop0)
 > -			  : mode,
 > -			  xop0, unsignedp);
 > -
 > -  if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
 > -    xop1 = convert_modes (mode1,
 > -			  GET_MODE (xop1) != VOIDmode
 > -			  ? GET_MODE (xop1)
 > -			  : mode,
 > -			  xop1, unsignedp);
 > +  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
 > +  if (xmode0 != VOIDmode && xmode0 != mode0)
 > +    {
 > +      xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
 > +      mode0 = xmode0;
 > +    }
 > +
 > +  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
 > +  if (xmode1 != VOIDmode && xmode1 != mode1)
 > +    {
 > +      xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
 > +      mode1 = xmode1;
 > +    }
 >  
 >    /* If operation is commutative,
 >       try to make the first operand a register.
 >
Richard Sandiford March 29, 2011, 9:34 p.m. UTC | #2
Mikael Pettersson <mikpe@it.uu.se> writes:
>  > gcc/
>  > 	PR rtl-optimization/48332
>  > 	* optabs.c (expand_binop_directly): Set xmodeN to the target-mandated
>  > 	mode of input operand N and modeN to its actual mode.
>
> Thanks, this allowed me to build gcc-4.7 as a cross to m68k-linux again.

Good to hear, thanks for testing.

> I'm starting a native bootstrap of gcc-4.7 head + this fix on m68k, but
> that will take about 5 days to complete...

Ouch.

Hopefully this time I've finally got it right.  Bootstrapped &
regression-tested on x86_64-linux-gnu.  OK to install?

Richard

>  > 
>  > Index: gcc/optabs.c
>  > ===================================================================
>  > --- gcc/optabs.c	2011-03-24 17:23:05.000000000 +0000
>  > +++ gcc/optabs.c	2011-03-29 14:18:02.000000000 +0100
>  > @@ -1243,9 +1243,9 @@ expand_binop_directly (enum machine_mode
>  >  		       rtx last)
>  >  {
>  >    enum insn_code icode = optab_handler (binoptab, mode);
>  > -  enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
>  > -  enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
>  > -  enum machine_mode tmp_mode;
>  > +  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
>  > +  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
>  > +  enum machine_mode mode0, mode1, tmp_mode;
>  >    struct expand_operand ops[3];
>  >    bool commutative_p;
>  >    rtx pat;
>  > @@ -1256,8 +1256,8 @@ expand_binop_directly (enum machine_mode
>  >       if we would swap the operands, we can save the conversions.  */
>  >    commutative_p = commutative_optab_p (binoptab);
>  >    if (commutative_p
>  > -      && GET_MODE (xop0) != mode0 && GET_MODE (xop1) != mode1
>  > -      && GET_MODE (xop0) == mode1 && GET_MODE (xop1) == mode1)
>  > +      && GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1
>  > +      && GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)
>  >      {
>  >        swap = xop0;
>  >        xop0 = xop1;
>  > @@ -1265,9 +1265,9 @@ expand_binop_directly (enum machine_mode
>  >      }
>  >  
>  >    /* If we are optimizing, force expensive constants into a register.  */
>  > -  xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp);
>  > +  xop0 = avoid_expensive_constant (xmode0, binoptab, xop0, unsignedp);
>  >    if (!shift_optab_p (binoptab))
>  > -    xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp);
>  > +    xop1 = avoid_expensive_constant (xmode1, binoptab, xop1, unsignedp);
>  >  
>  >    /* In case the insn wants input operands in modes different from
>  >       those of the actual operands, convert the operands.  It would
>  > @@ -1275,19 +1275,19 @@ expand_binop_directly (enum machine_mode
>  >       that they're properly zero-extended, sign-extended or truncated
>  >       for their mode.  */
>  >  
>  > -  if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
>  > -    xop0 = convert_modes (mode0,
>  > -			  GET_MODE (xop0) != VOIDmode
>  > -			  ? GET_MODE (xop0)
>  > -			  : mode,
>  > -			  xop0, unsignedp);
>  > -
>  > -  if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
>  > -    xop1 = convert_modes (mode1,
>  > -			  GET_MODE (xop1) != VOIDmode
>  > -			  ? GET_MODE (xop1)
>  > -			  : mode,
>  > -			  xop1, unsignedp);
>  > +  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
>  > +  if (xmode0 != VOIDmode && xmode0 != mode0)
>  > +    {
>  > +      xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
>  > +      mode0 = xmode0;
>  > +    }
>  > +
>  > +  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
>  > +  if (xmode1 != VOIDmode && xmode1 != mode1)
>  > +    {
>  > +      xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
>  > +      mode1 = xmode1;
>  > +    }
>  >  
>  >    /* If operation is commutative,
>  >       try to make the first operand a register.
>  >
Richard Henderson March 29, 2011, 10 p.m. UTC | #3
On 03/29/2011 06:21 AM, Richard Sandiford wrote:
> -  enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
> -  enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
> -  enum machine_mode tmp_mode;
> +  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
> +  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
> +  enum machine_mode mode0, mode1, tmp_mode;
...
> -  if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
> -    xop0 = convert_modes (mode0,
> -			  GET_MODE (xop0) != VOIDmode
> -			  ? GET_MODE (xop0)
> -			  : mode,
> -			  xop0, unsignedp);
> -
> -  if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
> -    xop1 = convert_modes (mode1,
> -			  GET_MODE (xop1) != VOIDmode
> -			  ? GET_MODE (xop1)
> -			  : mode,
> -			  xop1, unsignedp);
> +  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
> +  if (xmode0 != VOIDmode && xmode0 != mode0)
> +    {
> +      xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
> +      mode0 = xmode0;
> +    }
> +
> +  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
> +  if (xmode1 != VOIDmode && xmode1 != mode1)
> +    {
> +      xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
> +      mode1 = xmode1;
> +    }

This smells like a target bug, but I can't quite put my finger
on exactly what's wrong, and I haven't debugged the original.

The backend has said xmode[01] is what it expects.  The only
reason you wouldn't write xmode[01] in the create_input_operand
line is if xmode[01] are VOIDmode.

That seems like mistake number one, particularly for a binop,
but I'll accept that for the nonce.  Which pattern triggered
the problem in the target?

Then we've got the conditionalization in the init of mode[01],
which is presumably to handle CONST_INT as an input.

What about something like

	xmode0 = insn_data...
	if (xmode0 == VOIDmode)
	  xmode0 = mode;

	mode0 = GET_MODE (xop0);
	if (mode0 == VOIDmode)
	  mode0 = mode;

	if (xmode0 != mode0)
	  convert_modes

	create_input_operand(..., xmode0)

?  That seems more obvious than what you have.  And I *think*
it should produce the same results.  If it doesn't, then this
whole block of code needs a lot more explanation.


r~
Richard Sandiford March 30, 2011, 8:53 a.m. UTC | #4
Richard Henderson <rth@redhat.com> writes:
> On 03/29/2011 06:21 AM, Richard Sandiford wrote:
>> -  enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
>> -  enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
>> -  enum machine_mode tmp_mode;
>> +  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
>> +  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
>> +  enum machine_mode mode0, mode1, tmp_mode;
> ...
>> -  if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
>> -    xop0 = convert_modes (mode0,
>> -			  GET_MODE (xop0) != VOIDmode
>> -			  ? GET_MODE (xop0)
>> -			  : mode,
>> -			  xop0, unsignedp);
>> -
>> -  if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
>> -    xop1 = convert_modes (mode1,
>> -			  GET_MODE (xop1) != VOIDmode
>> -			  ? GET_MODE (xop1)
>> -			  : mode,
>> -			  xop1, unsignedp);
>> +  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
>> +  if (xmode0 != VOIDmode && xmode0 != mode0)
>> +    {
>> +      xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
>> +      mode0 = xmode0;
>> +    }
>> +
>> +  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
>> +  if (xmode1 != VOIDmode && xmode1 != mode1)
>> +    {
>> +      xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
>> +      mode1 = xmode1;
>> +    }
>
> This smells like a target bug, but I can't quite put my finger
> on exactly what's wrong, and I haven't debugged the original.
>
> The backend has said xmode[01] is what it expects.  The only
> reason you wouldn't write xmode[01] in the create_input_operand
> line is if xmode[01] are VOIDmode.

Right.  Sorry, I should have said, but the failure was actually from:

    case EXPAND_INPUT:
    input:
      gcc_assert (mode != VOIDmode);

expand_binop_direct passed the match_operand's mode to create_input_operand,
which was really the opposite of the intention.  The caller should be
passing the mode of the rtx, which it should always "know".

> That seems like mistake number one, particularly for a binop,
> but I'll accept that for the nonce.  Which pattern triggered
> the problem in the target?

It was ashrdi3:

(define_expand "ashrdi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (match_operand 2 "const_int_operand" "")))]
  "!TARGET_COLDFIRE"

Which seems reasonable in this context, since the shift count isn't
really DImode.

> Then we've got the conditionalization in the init of mode[01],
> which is presumably to handle CONST_INT as an input.
>
> What about something like
>
> 	xmode0 = insn_data...
> 	if (xmode0 == VOIDmode)
> 	  xmode0 = mode;
>
> 	mode0 = GET_MODE (xop0);
> 	if (mode0 == VOIDmode)
> 	  mode0 = mode;
>
> 	if (xmode0 != mode0)
> 	  convert_modes
>
> 	create_input_operand(..., xmode0)
>
> ?  That seems more obvious than what you have.  And I *think*
> it should produce the same results.  If it doesn't, then this
> whole block of code needs a lot more explanation.

The problem is that a VOIDmode match_operand doesn't necessary imply
that "mode" is the right mode.  VOIDmode register-accepting operands
are only a warning, not an error, and are sometimes needed for
flag-specific variations.  They've traditionally not forced a conversion
to "mode".  E.g. if you have something like this on a 32-bit target:

  unsigned long long foo (unsigned long long x, int y)
  {
    return x >>= y;
  }

then op1 will be (reg:SI y).  Having a VOIDmode match_operand shouldn't
force that to be converted to (reg:DI y), whereas I think the sequence
above would.

Or to put it another way: as things stand, "mode" is only trustworthy
for CONST_INT opNs.  A VOIDmode match_operand doesn't imply that the
opN argument to expand_binop_directly is a CONST_INT, or even that
only CONST_INTs are acceptable to the target.

This comes back to the point that we really should know up-front what
modes op0 and op1 actually have.  (The thing I left as a future clean-up.)
Until then, the process implemented by yesterday's patch was supposed to be:

   - work out what mode opN actually has at this point in time
   - see if the target has specifically asked for a different mode
   - if so, convert the operand

This is directly equivalent to what create_convert_operand_from does:

    case EXPAND_CONVERT_FROM:
      if (GET_MODE (op->value) != VOIDmode)
	mode = GET_MODE (op->value);
      else
	/* The caller must tell us what mode this value has.  */
	gcc_assert (mode != VOIDmode);

      imode = insn_data[(int) icode].operand[opno].mode;
      if (imode != VOIDmode && imode != mode)
	{
	  op->value = convert_modes (imode, mode, op->value, op->unsigned_p);
	  mode = imode;
	}

But we have to break the flow there (rather than go on to coerce the operands)
because of the commutative thing.

Richard
Richard Henderson March 30, 2011, 3:13 p.m. UTC | #5
On 03/30/2011 01:53 AM, Richard Sandiford wrote:
> This comes back to the point that we really should know up-front what
> modes op0 and op1 actually have.  (The thing I left as a future clean-up.)
> Until then, the process implemented by yesterday's patch was supposed to be:
> 
>    - work out what mode opN actually has at this point in time
>    - see if the target has specifically asked for a different mode
>    - if so, convert the operand

Ok, I get it.  The patch is ok as-is.


r~
diff mbox

Patch

Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2011-03-24 17:23:05.000000000 +0000
+++ gcc/optabs.c	2011-03-29 14:18:02.000000000 +0100
@@ -1243,9 +1243,9 @@  expand_binop_directly (enum machine_mode
 		       rtx last)
 {
   enum insn_code icode = optab_handler (binoptab, mode);
-  enum machine_mode mode0 = insn_data[(int) icode].operand[1].mode;
-  enum machine_mode mode1 = insn_data[(int) icode].operand[2].mode;
-  enum machine_mode tmp_mode;
+  enum machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
+  enum machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
+  enum machine_mode mode0, mode1, tmp_mode;
   struct expand_operand ops[3];
   bool commutative_p;
   rtx pat;
@@ -1256,8 +1256,8 @@  expand_binop_directly (enum machine_mode
      if we would swap the operands, we can save the conversions.  */
   commutative_p = commutative_optab_p (binoptab);
   if (commutative_p
-      && GET_MODE (xop0) != mode0 && GET_MODE (xop1) != mode1
-      && GET_MODE (xop0) == mode1 && GET_MODE (xop1) == mode1)
+      && GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1
+      && GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)
     {
       swap = xop0;
       xop0 = xop1;
@@ -1265,9 +1265,9 @@  expand_binop_directly (enum machine_mode
     }
 
   /* If we are optimizing, force expensive constants into a register.  */
-  xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp);
+  xop0 = avoid_expensive_constant (xmode0, binoptab, xop0, unsignedp);
   if (!shift_optab_p (binoptab))
-    xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp);
+    xop1 = avoid_expensive_constant (xmode1, binoptab, xop1, unsignedp);
 
   /* In case the insn wants input operands in modes different from
      those of the actual operands, convert the operands.  It would
@@ -1275,19 +1275,19 @@  expand_binop_directly (enum machine_mode
      that they're properly zero-extended, sign-extended or truncated
      for their mode.  */
 
-  if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
-    xop0 = convert_modes (mode0,
-			  GET_MODE (xop0) != VOIDmode
-			  ? GET_MODE (xop0)
-			  : mode,
-			  xop0, unsignedp);
-
-  if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
-    xop1 = convert_modes (mode1,
-			  GET_MODE (xop1) != VOIDmode
-			  ? GET_MODE (xop1)
-			  : mode,
-			  xop1, unsignedp);
+  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
+  if (xmode0 != VOIDmode && xmode0 != mode0)
+    {
+      xop0 = convert_modes (xmode0, mode0, xop0, unsignedp);
+      mode0 = xmode0;
+    }
+
+  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
+  if (xmode1 != VOIDmode && xmode1 != mode1)
+    {
+      xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
+      mode1 = xmode1;
+    }
 
   /* If operation is commutative,
      try to make the first operand a register.