diff mbox

Fix PR69771, bogus CONST_INT during shift expansion

Message ID 20160212132813.GR3017@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Feb. 12, 2016, 1:28 p.m. UTC
On Fri, Feb 12, 2016 at 01:50:08PM +0100, Richard Biener wrote:
> > -  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).

Another possibility, only do the convert_modes from VOIDmode for
shift_optab_p's xop1, and keep doing what we've done before otherwise.

2016-02-12  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/69764
	PR rtl-optimization/69771
	* optabs.c (expand_binop_directly): For shift_optab_p, force
	convert_modes with VOIDmode if xop1 has VOIDmode.

	* c-c++-common/pr69764.c: New test.
	* gcc.dg/torture/pr69771.c: New testcase.


	Jakub

Comments

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

> On Fri, Feb 12, 2016 at 01:50:08PM +0100, Richard Biener wrote:
> > > -  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).
> 
> Another possibility, only do the convert_modes from VOIDmode for
> shift_optab_p's xop1, and keep doing what we've done before otherwise.

That looks like a very targeted and safe fix indeed.

Richard.

> 2016-02-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR rtl-optimization/69764
> 	PR rtl-optimization/69771
> 	* optabs.c (expand_binop_directly): For shift_optab_p, force
> 	convert_modes with VOIDmode if xop1 has VOIDmode.
> 
> 	* c-c++-common/pr69764.c: New test.
> 	* gcc.dg/torture/pr69771.c: New testcase.
> 
> --- gcc/optabs.c.jj	2016-02-12 00:50:30.410240366 +0100
> +++ gcc/optabs.c	2016-02-12 10:33:32.743492532 +0100
> @@ -988,7 +988,7 @@ expand_binop_directly (machine_mode mode
>  						      from_mode, 1);
>    machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
>    machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
> -  machine_mode mode0, mode1, tmp_mode;
> +  machine_mode mode0, mode1 = mode, tmp_mode;
>    struct expand_operand ops[3];
>    bool commutative_p;
>    rtx_insn *pat;
> @@ -1006,6 +1006,8 @@ expand_binop_directly (machine_mode mode
>    xop0 = avoid_expensive_constant (xmode0, binoptab, 0, xop0, unsignedp);
>    if (!shift_optab_p (binoptab))
>      xop1 = avoid_expensive_constant (xmode1, binoptab, 1, xop1, unsignedp);
> +  else
> +    mode1 = VOIDmode;
>  
>    /* In case the insn wants input operands in modes different from
>       those of the actual operands, convert the operands.  It would
> @@ -1020,7 +1020,7 @@ expand_binop_directly (machine_mode mode
>        mode0 = xmode0;
>      }
>  
> -  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
> +  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode1;
>    if (xmode1 != VOIDmode && xmode1 != mode1)
>      {
>        xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
> --- gcc/testsuite/c-c++-common/pr69764.c.jj	2016-02-12 10:27:34.522587995 +0100
> +++ gcc/testsuite/c-c++-common/pr69764.c	2016-02-12 10:27:34.522587995 +0100
> @@ -0,0 +1,38 @@
> +/* PR rtl-optimization/69764 */
> +/* { dg-do compile { target int32plus } } */
> +
> +unsigned char
> +fn1 (unsigned char a)
> +{
> +  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
> +}
> +
> +unsigned short
> +fn2 (unsigned short a)
> +{
> +  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
> +}
> +
> +unsigned int
> +fn3 (unsigned int a)
> +{
> +  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
> +}
> +
> +unsigned char
> +fn4 (unsigned char a)
> +{
> +  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
> +}
> +
> +unsigned short
> +fn5 (unsigned short a)
> +{
> +  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
> +}
> +
> +unsigned int
> +fn6 (unsigned int a)
> +{
> +  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
> +}
> --- gcc/testsuite/gcc.dg/torture/pr69771.c.jj	2016-02-12 10:27:34.522587995 +0100
> +++ gcc/testsuite/gcc.dg/torture/pr69771.c	2016-02-12 10:27:34.522587995 +0100
> @@ -0,0 +1,12 @@
> +/* PR rtl-optimization/69771 */
> +/* { dg-do compile } */
> +
> +unsigned char a = 5, c;
> +unsigned short b = 0;
> +unsigned d = 0x76543210;
> +
> +void
> +foo (void)
> +{
> +  c = d >> ~(a || ~b);	/* { dg-warning "shift count is negative" } */
> +}
> 
> 	Jakub
> 
>
Bernd Schmidt Feb. 12, 2016, 2:20 p.m. UTC | #2
On 02/12/2016 02:47 PM, Richard Biener wrote:
>> Another possibility, only do the convert_modes from VOIDmode for
>> shift_optab_p's xop1, and keep doing what we've done before otherwise.
>
> That looks like a very targeted and safe fix indeed.

You two can obviously go ahead and sort this out, I'll just make one 
more comment. What attracted me to Richard's patch was its clarity and 
lack of potential to confuse readers.

>> -  machine_mode mode0, mode1, tmp_mode;
>> +  machine_mode mode0, mode1 = mode, tmp_mode;

>>     if (!shift_optab_p (binoptab))
>>       xop1 = avoid_expensive_constant (xmode1, binoptab, 1, xop1, unsignedp);
>> +  else
>> +    mode1 = VOIDmode;

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

Here, things aren't so clear, and the fact that the mode1 calculation 
now differs from the mode0 one may be overlooked by someone in the future.

Rather than use codes like "mode variable is VOIDmode", I'd prefer to 
use booleans with descriptive names, like "op1_may_need_conversion".


Bernd
diff mbox

Patch

--- gcc/optabs.c.jj	2016-02-12 00:50:30.410240366 +0100
+++ gcc/optabs.c	2016-02-12 10:33:32.743492532 +0100
@@ -988,7 +988,7 @@  expand_binop_directly (machine_mode mode
 						      from_mode, 1);
   machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
   machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
-  machine_mode mode0, mode1, tmp_mode;
+  machine_mode mode0, mode1 = mode, tmp_mode;
   struct expand_operand ops[3];
   bool commutative_p;
   rtx_insn *pat;
@@ -1006,6 +1006,8 @@  expand_binop_directly (machine_mode mode
   xop0 = avoid_expensive_constant (xmode0, binoptab, 0, xop0, unsignedp);
   if (!shift_optab_p (binoptab))
     xop1 = avoid_expensive_constant (xmode1, binoptab, 1, xop1, unsignedp);
+  else
+    mode1 = VOIDmode;
 
   /* In case the insn wants input operands in modes different from
      those of the actual operands, convert the operands.  It would
@@ -1020,7 +1020,7 @@  expand_binop_directly (machine_mode mode
       mode0 = xmode0;
     }
 
-  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode;
+  mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode1;
   if (xmode1 != VOIDmode && xmode1 != mode1)
     {
       xop1 = convert_modes (xmode1, mode1, xop1, unsignedp);
--- gcc/testsuite/c-c++-common/pr69764.c.jj	2016-02-12 10:27:34.522587995 +0100
+++ gcc/testsuite/c-c++-common/pr69764.c	2016-02-12 10:27:34.522587995 +0100
@@ -0,0 +1,38 @@ 
+/* PR rtl-optimization/69764 */
+/* { dg-do compile { target int32plus } } */
+
+unsigned char
+fn1 (unsigned char a)
+{
+  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
+}
+
+unsigned short
+fn2 (unsigned short a)
+{
+  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
+}
+
+unsigned int
+fn3 (unsigned int a)
+{
+  return a >> ~6;	/* { dg-warning "right shift count is negative" } */
+}
+
+unsigned char
+fn4 (unsigned char a)
+{
+  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
+}
+
+unsigned short
+fn5 (unsigned short a)
+{
+  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
+}
+
+unsigned int
+fn6 (unsigned int a)
+{
+  return a >> 0xff03;	/* { dg-warning "right shift count >= width of type" } */
+}
--- gcc/testsuite/gcc.dg/torture/pr69771.c.jj	2016-02-12 10:27:34.522587995 +0100
+++ gcc/testsuite/gcc.dg/torture/pr69771.c	2016-02-12 10:27:34.522587995 +0100
@@ -0,0 +1,12 @@ 
+/* PR rtl-optimization/69771 */
+/* { dg-do compile } */
+
+unsigned char a = 5, c;
+unsigned short b = 0;
+unsigned d = 0x76543210;
+
+void
+foo (void)
+{
+  c = d >> ~(a || ~b);	/* { dg-warning "shift count is negative" } */
+}