diff mbox

Fix PR69771, bogus CONST_INT during shift expansion

Message ID alpine.LSU.2.11.1602121119020.31122@t29.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Feb. 12, 2016, 10:23 a.m. UTC
I am testing the following patch which fixes PR69771 where the code
doesn't match the comment before it.  We get to expand a QImode << QImode
shift but the shift amount was of type int and thus it was expanded
as SImode constant.  Then

  /* In case the insn wants input operands in modes different from
     those of the actual operands, convert the operands.  It would
     seem that we don't need to convert CONST_INTs, but we do, so
     that they're properly zero-extended, sign-extended or truncated
     for their mode.  */

has to apply as we need to re-extend the VOIDmode CONST_INT for
QImode.  But then mode1 is computed as 'mode' (QImode) which happens
to match what is expected even though the constant isn't valid.

The fix is IMHO to always call convert_modes for VOIDmode ops
(if the target doesn't expect VOIDmode itself).

Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk?

Thanks,
Richard.

2016-02-12  Richard Biener  <rguenther@suse.de>

	PR rtl-optimization/69771
	* optabs.c (expand_binop_directly): Properly zero-/sign-extend
	VOIDmode operands.

	* gcc.dg/torture/pr69771.c: New testcase.

Comments

Jakub Jelinek Feb. 12, 2016, 10:32 a.m. UTC | #1
On Fri, Feb 12, 2016 at 11:23:26AM +0100, Richard Biener wrote:
> 
> I am testing the following patch which fixes PR69771 where the code
> doesn't match the comment before it.  We get to expand a QImode << QImode
> shift but the shift amount was of type int and thus it was expanded
> as SImode constant.  Then
> 
>   /* In case the insn wants input operands in modes different from
>      those of the actual operands, convert the operands.  It would
>      seem that we don't need to convert CONST_INTs, but we do, so
>      that they're properly zero-extended, sign-extended or truncated
>      for their mode.  */
> 
> has to apply as we need to re-extend the VOIDmode CONST_INT for
> QImode.  But then mode1 is computed as 'mode' (QImode) which happens
> to match what is expected even though the constant isn't valid.
> 
> The fix is IMHO to always call convert_modes for VOIDmode ops
> (if the target doesn't expect VOIDmode itself).
> 
> Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk?

This looks like the PR69764 fix I've sent last night (and updated patch
this morning).
BTW, I wouldn't use a runtime test with clearly undefined behavior,
especially not if it tests what the outcome of that UB is.

> 2016-02-12  Richard Biener  <rguenther@suse.de>
> 
> 	PR rtl-optimization/69771
> 	* optabs.c (expand_binop_directly): Properly zero-/sign-extend
> 	VOIDmode operands.
> 
> 	* gcc.dg/torture/pr69771.c: New testcase.

	Jakub
Richard Biener Feb. 12, 2016, 10:46 a.m. UTC | #2
On Fri, 12 Feb 2016, Jakub Jelinek wrote:

> On Fri, Feb 12, 2016 at 11:23:26AM +0100, Richard Biener wrote:
> > 
> > I am testing the following patch which fixes PR69771 where the code
> > doesn't match the comment before it.  We get to expand a QImode << QImode
> > shift but the shift amount was of type int and thus it was expanded
> > as SImode constant.  Then
> > 
> >   /* In case the insn wants input operands in modes different from
> >      those of the actual operands, convert the operands.  It would
> >      seem that we don't need to convert CONST_INTs, but we do, so
> >      that they're properly zero-extended, sign-extended or truncated
> >      for their mode.  */
> > 
> > has to apply as we need to re-extend the VOIDmode CONST_INT for
> > QImode.  But then mode1 is computed as 'mode' (QImode) which happens
> > to match what is expected even though the constant isn't valid.
> > 
> > The fix is IMHO to always call convert_modes for VOIDmode ops
> > (if the target doesn't expect VOIDmode itself).
> > 
> > Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk?
> 
> This looks like the PR69764 fix I've sent last night (and updated patch
> this morning).
> BTW, I wouldn't use a runtime test with clearly undefined behavior,
> especially not if it tests what the outcome of that UB is.

Ah, indeed looks like a dup.  Let's go with your version which had
feedback from Bernd already.  Might want to add my testcase (w/o the
runtime outcome test).

Richard.

> > 2016-02-12  Richard Biener  <rguenther@suse.de>
> > 
> > 	PR rtl-optimization/69771
> > 	* optabs.c (expand_binop_directly): Properly zero-/sign-extend
> > 	VOIDmode operands.
> > 
> > 	* gcc.dg/torture/pr69771.c: New testcase.
> 
> 	Jakub
Bernd Schmidt Feb. 12, 2016, 12:15 p.m. UTC | #3
On 02/12/2016 11:46 AM, Richard Biener wrote:
> On Fri, 12 Feb 2016, Jakub Jelinek wrote:
>
>> On Fri, Feb 12, 2016 at 11:23:26AM +0100, Richard Biener wrote:
>>>
>>> I am testing the following patch which fixes PR69771 where the code
>>> doesn't match the comment before it.  We get to expand a QImode << QImode
>>> shift but the shift amount was of type int and thus it was expanded
>>> as SImode constant.  Then
>>>
>>>    /* In case the insn wants input operands in modes different from
>>>       those of the actual operands, convert the operands.  It would
>>>       seem that we don't need to convert CONST_INTs, but we do, so
>>>       that they're properly zero-extended, sign-extended or truncated
>>>       for their mode.  */
>>>
>>> has to apply as we need to re-extend the VOIDmode CONST_INT for
>>> QImode.  But then mode1 is computed as 'mode' (QImode) which happens
>>> to match what is expected even though the constant isn't valid.
>>>
>>> The fix is IMHO to always call convert_modes for VOIDmode ops
>>> (if the target doesn't expect VOIDmode itself).
>>>
>>> Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk?
>>
>> This looks like the PR69764 fix I've sent last night (and updated patch
>> this morning).
>> BTW, I wouldn't use a runtime test with clearly undefined behavior,
>> especially not if it tests what the outcome of that UB is.
>
> Ah, indeed looks like a dup.  Let's go with your version which had
> feedback from Bernd already.  Might want to add my testcase (w/o the
> runtime outcome test).

Actually, Richard I was just looking at Jakub's second patch and I think 
yours is better - on the first round of review I didn't notice that the 
convert_modes code is there and is documented to deal with the CONST_INT 
problem. If it completed testing I think you should commit it.


Bernd
Jakub Jelinek Feb. 12, 2016, 12:24 p.m. UTC | #4
On Fri, Feb 12, 2016 at 01:15:11PM +0100, Bernd Schmidt wrote:
> >Ah, indeed looks like a dup.  Let's go with your version which had
> >feedback from Bernd already.  Might want to add my testcase (w/o the
> >runtime outcome test).
> 
> Actually, Richard I was just looking at Jakub's second patch and I think
> yours is better - on the first round of review I didn't notice that the
> convert_modes code is there and is documented to deal with the CONST_INT
> problem. If it completed testing I think you should commit it.

That patch doesn't look right to me.  The code is there not just for shifts,
but also for non-shifts, and for non-shifts, we know the arguments are in
mode, we also know unsignedp, so if needed convert_modes can perform
zero or sign extension.  IMHO it is just shifts/rotates that are
problematical, because what the second operand mode is and whether it is unsigned
or signed is just less well defined, and then various backends have various
requirements on it.  Also, on some target for shift/rotate xmode1 might be
already equal to mode, and in that case convert_modes would not be called,
but still the CONST_INT might be originally from yet another mode and we'd
still ICE.

	Jakub
Richard Biener Feb. 12, 2016, 12:48 p.m. UTC | #5
On Fri, 12 Feb 2016, Jakub Jelinek wrote:

> On Fri, Feb 12, 2016 at 01:15:11PM +0100, Bernd Schmidt wrote:
> > >Ah, indeed looks like a dup.  Let's go with your version which had
> > >feedback from Bernd already.  Might want to add my testcase (w/o the
> > >runtime outcome test).
> > 
> > Actually, Richard I was just looking at Jakub's second patch and I think
> > yours is better - on the first round of review I didn't notice that the
> > convert_modes code is there and is documented to deal with the CONST_INT
> > problem. If it completed testing I think you should commit it.
> 
> That patch doesn't look right to me.  The code is there not just for shifts,
> but also for non-shifts, and for non-shifts, we know the arguments are in
> mode, we also know unsignedp, so if needed convert_modes can perform
> zero or sign extension.  IMHO it is just shifts/rotates that are
> problematical, because what the second operand mode is and whether it is unsigned
> or signed is just less well defined, and then various backends have various
> requirements on it.  Also, on some target for shift/rotate xmode1 might be
> already equal to mode, and in that case convert_modes would not be called,
> but still the CONST_INT might be originally from yet another mode and we'd
> still ICE.

But my patch should deal with all this.

-  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
-  if (xmode1 != VOIDmode && xmode1 != mode1)
+  mode1 = GET_MODE (xop1);
+  if (xmode1 != mode1)
     {
       xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
       mode1 = xmode1;

so if xop1 is not VOIDmode and already of xmode1 we won't do anything.
But if it is VOIDmode (and xmode1 is not VOIDmode) we'll always
do convert_modes.

The only thing that can (hopefully not) happen is that xmode1
is VOIDmode but mode1 is not (maybe removing the xmode1 != VOIDmode
check is a bit too optimistic here).  Not sure if there can be
valid patterns requesting a VOIDmode op ... (and not only accept
CONST_INTs).

Richard.
Richard Biener Feb. 12, 2016, 12:50 p.m. UTC | #6
On Fri, 12 Feb 2016, Richard Biener wrote:

> On Fri, 12 Feb 2016, Jakub Jelinek wrote:
> 
> > On Fri, Feb 12, 2016 at 01:15:11PM +0100, Bernd Schmidt wrote:
> > > >Ah, indeed looks like a dup.  Let's go with your version which had
> > > >feedback from Bernd already.  Might want to add my testcase (w/o the
> > > >runtime outcome test).
> > > 
> > > Actually, Richard I was just looking at Jakub's second patch and I think
> > > yours is better - on the first round of review I didn't notice that the
> > > convert_modes code is there and is documented to deal with the CONST_INT
> > > problem. If it completed testing I think you should commit it.
> > 
> > That patch doesn't look right to me.  The code is there not just for shifts,
> > but also for non-shifts, and for non-shifts, we know the arguments are in
> > mode, we also know unsignedp, so if needed convert_modes can perform
> > zero or sign extension.  IMHO it is just shifts/rotates that are
> > problematical, because what the second operand mode is and whether it is unsigned
> > or signed is just less well defined, and then various backends have various
> > requirements on it.  Also, on some target for shift/rotate xmode1 might be
> > already equal to mode, and in that case convert_modes would not be called,
> > but still the CONST_INT might be originally from yet another mode and we'd
> > still ICE.
> 
> But my patch should deal with all this.
> 
> -  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
> -  if (xmode1 != VOIDmode && xmode1 != mode1)
> +  mode1 = GET_MODE (xop1);
> +  if (xmode1 != mode1)
>      {
>        xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
>        mode1 = xmode1;
> 
> so if xop1 is not VOIDmode and already of xmode1 we won't do anything.
> But if it is VOIDmode (and xmode1 is not VOIDmode) we'll always
> do convert_modes.
> 
> The only thing that can (hopefully not) happen is that xmode1
> is VOIDmode but mode1 is not (maybe removing the xmode1 != VOIDmode
> check is a bit too optimistic here).  Not sure if there can be
> valid patterns requesting a VOIDmode op ... (and not only accept
> CONST_INTs).

Oh, bootstrap & testing went fine on x86_64-unknown-linux-gnu.

If we can agree on the patch then I'll pick up the testcase from
your patch (and adjust mine).

Richard.
Jakub Jelinek Feb. 12, 2016, 12:57 p.m. UTC | #7
On Fri, Feb 12, 2016 at 01:48:36PM +0100, Richard Biener wrote:
> But my patch should deal with all this.
> 
> -  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
> -  if (xmode1 != VOIDmode && xmode1 != mode1)
> +  mode1 = GET_MODE (xop1);
> +  if (xmode1 != mode1)
>      {
>        xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
>        mode1 = xmode1;
> 
> so if xop1 is not VOIDmode and already of xmode1 we won't do anything.
> But if it is VOIDmode (and xmode1 is not VOIDmode) we'll always
> do convert_modes.

The case I'm worried about is if xop1 is a constant in narrower
mode (let's say QImode), e.g. -15, unsignedp is 1, and xmode1 is
wider.  Then previously we'd zero extend it, thus get
0xf1, but with your patch we'll end up with -15 instead,
because convert_modes will be called e.g. with (SImode, VOIDmode, xop1, 1)
instead of (SImode, QImode, xop1, 1).
Dunno if it is just hypothetical or real.

	Jakub
Richard Biener Feb. 12, 2016, 1:45 p.m. UTC | #8
On Fri, 12 Feb 2016, Jakub Jelinek wrote:

> On Fri, Feb 12, 2016 at 01:48:36PM +0100, Richard Biener wrote:
> > But my patch should deal with all this.
> > 
> > -  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
> > -  if (xmode1 != VOIDmode && xmode1 != mode1)
> > +  mode1 = GET_MODE (xop1);
> > +  if (xmode1 != mode1)
> >      {
> >        xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
> >        mode1 = xmode1;
> > 
> > so if xop1 is not VOIDmode and already of xmode1 we won't do anything.
> > But if it is VOIDmode (and xmode1 is not VOIDmode) we'll always
> > do convert_modes.
> 
> The case I'm worried about is if xop1 is a constant in narrower
> mode (let's say QImode), e.g. -15, unsignedp is 1, and xmode1 is
> wider.  Then previously we'd zero extend it, thus get
> 0xf1, but with your patch we'll end up with -15 instead,
> because convert_modes will be called e.g. with (SImode, VOIDmode, xop1, 1)
> instead of (SImode, QImode, xop1, 1).
> Dunno if it is just hypothetical or real.

But we don't know which mode xop1 was expanded with here.  The only
way to know would be passing down its original type (or its mode).

That's the general issue with our modeless CONST_INTs.

So yes, that case is sth to worry about (for all operations that
can arrive in expand_binop_directly which can have different mode
operands).

Also note that unsignedp doesn't apply to op1 for shifts, only to op0.
So eventually we shouldn't (ab-)use expand_binop for expanding shifts
at all...

Richard.
Jakub Jelinek Feb. 12, 2016, 1:49 p.m. UTC | #9
On Fri, Feb 12, 2016 at 02:45:40PM +0100, Richard Biener wrote:
> > The case I'm worried about is if xop1 is a constant in narrower
> > mode (let's say QImode), e.g. -15, unsignedp is 1, and xmode1 is
> > wider.  Then previously we'd zero extend it, thus get
> > 0xf1, but with your patch we'll end up with -15 instead,
> > because convert_modes will be called e.g. with (SImode, VOIDmode, xop1, 1)
> > instead of (SImode, QImode, xop1, 1).
> > Dunno if it is just hypothetical or real.
> 
> But we don't know which mode xop1 was expanded with here.  The only
> way to know would be passing down its original type (or its mode).

Well, most binary ops have the requirement that both modes are the same,
which is why most of the expansion APIs for them pass around just a single
mode, not two modes (or 3, if even the result could have different mode).
And in that case we better have expanded the CONST_INTs with the right mode
already.  Just shifts are special.

> So yes, that case is sth to worry about (for all operations that
> can arrive in expand_binop_directly which can have different mode
> operands).
> 
> Also note that unsignedp doesn't apply to op1 for shifts, only to op0.
> So eventually we shouldn't (ab-)use expand_binop for expanding shifts
> at all...

Perhaps; but please look at the latest patch I've posted, which IMHO does
what your patch does for shift/rorate xop1 only, and keeps doing what it
used to do otherwise.

	Jakub
diff mbox

Patch

Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(revision 233369)
+++ gcc/optabs.c	(working copy)
@@ -1013,15 +1013,15 @@  expand_binop_directly (machine_mode mode
      that they're properly zero-extended, sign-extended or truncated
      for their mode.  */
 
-  mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode;
-  if (xmode0 != VOIDmode && xmode0 != mode0)
+  mode0 = GET_MODE (xop0);
+  if (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)
+  mode1 = GET_MODE (xop1);
+  if (xmode1 != mode1)
     {
       xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
       mode1 = xmode1;
Index: gcc/testsuite/gcc.dg/torture/pr69771.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr69771.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr69771.c	(working copy)
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+
+unsigned char a = 5, c;
+unsigned short b = 0;
+unsigned d = 0x76543210;
+void __attribute__((noinline))
+fn1() { c = d >> ~(a || ~b); } /* { dg-warning "shift count is negative" } */
+
+int main()
+{
+  fn1();
+  if (c != 1)
+    __builtin_abort ();
+  return 0;
+}