Hi!

As mentioned in the PR, e.g. wide-int is very unhappy if the shift second
operand doesn't fit into the shift mode.
Generally, the backend shift patterns ensure that, but in debug insns
nothing enforces that.

This patch fixes that by making sure e.g. QImode shifts have always at
QImode shift amount, HImode shifts have QImode or HImode shift amount etc.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2015-03-09  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/65321
        * cfgexpand.c (expand_debug_expr): Ensure shift amount isn't wider
        than shift mode.
        * var-tracking.c (use_narrower_mode): Likewise.

        * gcc.dg/pr65321.c: New test.

--- gcc/cfgexpand.c.jj  2015-03-09 08:05:13.000000000 +0100
+++ gcc/cfgexpand.c     2015-03-09 09:15:38.139652882 +0100
@@ -3921,6 +3921,31 @@ expand_debug_expr (tree exp)
       op1 = expand_debug_expr (TREE_OPERAND (exp, 1));
       if (!op1)
        return NULL_RTX;
+      switch (TREE_CODE (exp))
+       {
+       case LSHIFT_EXPR:
+       case RSHIFT_EXPR:
+       case LROTATE_EXPR:
+       case RROTATE_EXPR:
+       case WIDEN_LSHIFT_EXPR:
+         /* Ensure second operand isn't wider than the first one.  */
+         inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
+         if (SCALAR_INT_MODE_P (inner_mode))
+           {
+             machine_mode opmode = mode;
+             if (VECTOR_MODE_P (mode))
+               opmode = GET_MODE_INNER (mode);
+             if (SCALAR_INT_MODE_P (opmode)
+                 && (GET_MODE_PRECISION (opmode)
+                     < GET_MODE_PRECISION (inner_mode)))
+               op1 = simplify_gen_subreg (opmode, op1, inner_mode,
+                                          subreg_lowpart_offset (opmode,
+                                                                 inner_mode));
+           }
+         break;
+       default:
+         break;
+       }
       /* Fall through.  */
 
     unary:
--- gcc/var-tracking.c.jj       2015-01-15 20:25:40.000000000 +0100
+++ gcc/var-tracking.c  2015-03-09 09:07:00.042127704 +0100
@@ -1011,7 +1011,13 @@ use_narrower_mode (rtx x, machine_mode m
       return simplify_gen_binary (GET_CODE (x), mode, op0, op1);
     case ASHIFT:
       op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
-      return simplify_gen_binary (ASHIFT, mode, op0, XEXP (x, 1));
+      op1 = XEXP (x, 1);
+      /* Ensure shift amount is not wider than mode.  */
+      if (GET_MODE (op1) == VOIDmode)
+       op1 = lowpart_subreg (mode, op1, wmode);
+      else if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (op1)))
+       op1 = lowpart_subreg (mode, op1, GET_MODE (op1));
+      return simplify_gen_binary (ASHIFT, mode, op0, op1);
     default:
       gcc_unreachable ();
     }
--- gcc/testsuite/gcc.dg/pr65321.c.jj   2015-03-09 09:10:32.110658776 +0100
+++ gcc/testsuite/gcc.dg/pr65321.c      2015-03-09 09:10:19.000000000 +0100
@@ -0,0 +1,31 @@
+/* PR rtl-optimization/65321 */
+/* { dg-do compile } */
+/* { dg-options "-O3 -g" } */
+
+int a, b, c, d, e;
+
+int
+foo (void)
+{
+  int h;
+  char i;
+  for (; c > 0;)
+    {
+      for (d = 0; d < 2; d++)
+       {
+         i = 1 << d;
+         if (i - a)
+           {
+             e = b = 0;
+             for (; c; c--)
+               d = 127;
+           }
+       }
+      h = ~d;
+      if (h > c)
+       for (;;)
+         ;
+      return 0;
+    }
+  return 0;
+}

        Jakub

Reply via email to