[PATCH] Fix PR69771, bogus CONST_INT during shift expansion

Richard Biener rguenther@suse.de
Fri Feb 12 10:25:00 GMT 2016


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.

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;
+}



More information about the Gcc-patches mailing list