On Sat, May 11, 2013 at 09:05:52AM +0200, Jakub Jelinek wrote:
> > Seems that we ought to have a testcase, even though it probably
> > means scanning the tree dumps to pick up the undefined behaviour.
> > Approved with a testcase.
> 
> I have added lots of testcases recently, for rotation by zero perhaps
> something similar to rotate-1a.c from above can be added as rotate-2b.c
> and rotate-4b.c, and test zero rotation.

Thanks for forcing me to do more testcases, I've actually found a serious
bug in my recent patch.  The (X << Y) OP (X >> ((-Y) & (B - 1))) style
patterns can only be recognized as rotates if OP is |, because
while they act as rotates for Y != 0, they act differently for Y == 0.
For (X << Y) OP (X >> (B - Y)) that is not an issue, because for Y == 0
they trigger undefined behavior.

Fixed thusly, plus added coverage for rotates by 0.  And rotate-5.c
testcase is to test the expmed.c change.

2013-05-10  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/45216
        PR tree-optimization/57157
        * tree-ssa-forwprop.c (simplify_rotate): Only recognize
        the (-Y) & (B - 1) variant if OP is |.
        * expmed.c (expand_shift_1): For rotations by const0_rtx just
        return shifted.  Use (-op1) & (prec - 1) as other_amount
        instead of prec - op1.

        * c-c++-common/rotate-1.c: Add 32 tests with +.
        * c-c++-common/rotate-1a.c: Adjust.
        * c-c++-common/rotate-2.c: Add 32 tests with +, expect
        only 48 rotates.
        * c-c++-common/rotate-2b.c: New test.
        * c-c++-common/rotate-3.c: Add 32 tests with +.
        * c-c++-common/rotate-4.c: Add 32 tests with +, expect
        only 48 rotates.
        * c-c++-common/rotate-4b.c: New test.
        * c-c++-common/rotate-5.c: New test.

--- gcc/tree-ssa-forwprop.c.jj  2013-05-10 10:39:13.000000000 +0200
+++ gcc/tree-ssa-forwprop.c     2013-05-11 09:57:39.627194037 +0200
@@ -2135,10 +2135,10 @@ simplify_bitwise_binary (gimple_stmt_ite
    (X << (int) Y) OP (X >> (int) (B - Y))
    ((T) ((T2) X << Y)) OP ((T) ((T2) X >> (B - Y)))
    ((T) ((T2) X << (int) Y)) OP ((T) ((T2) X >> (int) (B - Y)))
-   (X << Y) OP (X >> ((-Y) & (B - 1)))
-   (X << (int) Y) OP (X >> (int) ((-Y) & (B - 1)))
-   ((T) ((T2) X << Y)) OP ((T) ((T2) X >> ((-Y) & (B - 1))))
-   ((T) ((T2) X << (int) Y)) OP ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
+   (X << Y) | (X >> ((-Y) & (B - 1)))
+   (X << (int) Y) | (X >> (int) ((-Y) & (B - 1)))
+   ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1))))
+   ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
 
    and transform these into:
    X r<< CNT1
@@ -2293,7 +2293,8 @@ simplify_rotate (gimple_stmt_iterator *g
                 && host_integerp (cdef_arg2[i], 0)
                 && tree_low_cst (cdef_arg2[i], 0)
                    == TYPE_PRECISION (rtype) - 1
-                && TREE_CODE (cdef_arg1[i]) == SSA_NAME)
+                && TREE_CODE (cdef_arg1[i]) == SSA_NAME
+                && gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR)
          {
            tree tem;
            enum tree_code code;
--- gcc/expmed.c.jj     2013-05-07 10:26:46.000000000 +0200
+++ gcc/expmed.c        2013-05-11 09:11:54.087412982 +0200
@@ -2166,7 +2166,8 @@ expand_shift_1 (enum tree_code code, enu
            {
              /* If we have been unable to open-code this by a rotation,
                 do it as the IOR of two shifts.  I.e., to rotate A
-                by N bits, compute (A << N) | ((unsigned) A >> (C - N))
+                by N bits, compute
+                (A << N) | ((unsigned) A >> ((-N) & (C - 1)))
                 where C is the bitsize of A.
 
                 It is theoretically possible that the target machine might
@@ -2181,14 +2182,22 @@ expand_shift_1 (enum tree_code code, enu
              rtx temp1;
 
              new_amount = op1;
-             if (CONST_INT_P (op1))
+             if (op1 == const0_rtx)
+               return shifted;
+             else if (CONST_INT_P (op1))
                other_amount = GEN_INT (GET_MODE_BITSIZE (mode)
                                        - INTVAL (op1));
              else
-               other_amount
-                 = simplify_gen_binary (MINUS, GET_MODE (op1),
-                                        GEN_INT (GET_MODE_PRECISION (mode)),
-                                        op1);
+               {
+                 other_amount
+                   = simplify_gen_unary (NEG, GET_MODE (op1),
+                                         op1, GET_MODE (op1));
+                 other_amount
+                   = simplify_gen_binary (AND, GET_MODE (op1),
+                                          other_amount,
+                                          GEN_INT (GET_MODE_PRECISION (mode)
+                                                   - 1));
+               }
 
              shifted = force_reg (mode, shifted);
 
--- gcc/testsuite/c-c++-common/rotate-1.c.jj    2013-05-10 10:39:13.000000000 
+0200
+++ gcc/testsuite/c-c++-common/rotate-1.c       2013-05-11 10:11:22.725252954 
+0200
@@ -1,7 +1,7 @@
 /* Check rotate pattern detection.  */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
-/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 96 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
 
 unsigned int
@@ -387,3 +387,195 @@ f64 (unsigned char x, unsigned long int
 {
   return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
 }
+
+unsigned int
+f65 (unsigned int x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f66 (unsigned int x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f70 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f71 (unsigned char x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f72 (unsigned char x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f73 (unsigned int x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f74 (unsigned int x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f78 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f79 (unsigned char x, unsigned int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f80 (unsigned char x, unsigned long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f81 (unsigned int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) + (x >> y);
+}
+
+unsigned int
+f82 (unsigned int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) + (x >> y);
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f85 (unsigned short int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) + (x >> y);
+}
+
+unsigned short int
+f86 (unsigned short int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) + (x >> y);
+}
+
+unsigned char
+f87 (unsigned char x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ - y)) + (x >> y);
+}
+
+unsigned char
+f88 (unsigned char x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ - y)) + (x >> y);
+}
+
+unsigned int
+f89 (unsigned int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) + (x >> y);
+}
+
+unsigned int
+f90 (unsigned int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) + (x >> y);
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f93 (unsigned short int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) + (x >> y);
+}
+
+unsigned short int
+f94 (unsigned short int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) + (x >> y);
+}
+
+unsigned char
+f95 (unsigned char x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) + (x >> y);
+}
+
+unsigned char
+f96 (unsigned char x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) + (x >> y);
+}
--- gcc/testsuite/c-c++-common/rotate-1a.c.jj   2013-05-10 10:39:13.000000000 
+0200
+++ gcc/testsuite/c-c++-common/rotate-1a.c      2013-05-11 10:16:15.702552070 
+0200
@@ -21,13 +21,18 @@ unsigned int expected[] = {
 0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf,
 0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf,
 0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf,
+0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf,
+0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
+0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
+0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf,
 0x2468acf, 0x2468acf, 0x91a2b3c, 0x2468acf0, 0xacf, 0xacf, 0xf, 0xf };
 
 #define F(n) __typeof (f##n) f##n __attribute__((noinline, noclone));
 #define D(n) F(n##0) F(n##1) F(n##2) F(n##3) F(n##4) F(n##5) F(n##6) F(n##7) 
F(n##8) F(n##9)
 #define ALL \
 F(1) F(2) F(3) F(4) F(5) F(6) F(7) F(8) F(9) \
-D(1) D(2) D(3) D(4) D(5) F(60) F(61) F(62) F(63) F(64)
+D(1) D(2) D(3) D(4) D(5) D(6) D(7) D(8) \
+F(90) F(91) F(92) F(93) F(94) F(95) F(96)
 ALL
 
 int
--- gcc/testsuite/c-c++-common/rotate-2.c.jj    2013-05-10 10:39:13.000000000 
+0200
+++ gcc/testsuite/c-c++-common/rotate-2.c       2013-05-11 10:35:38.127716820 
+0200
@@ -1,7 +1,9 @@
 /* Check rotate pattern detection.  */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
-/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* Rotates should be recognized only in functions with | instead of + or ^,
+   or in functions that have constant shift counts (unused attribute on y).  */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 48 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
 
 unsigned int
@@ -387,3 +389,195 @@ f64 (unsigned char x, unsigned long int
 {
   return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> 
y);
 }
+
+unsigned int
+f65 (unsigned int x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f66 (unsigned int x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f70 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f71 (unsigned char x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f72 (unsigned char x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f73 (unsigned int x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f74 (unsigned int x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 
1)));
+}
+
+unsigned short int
+f78 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 
1)));
+}
+
+unsigned char
+f79 (unsigned char x, unsigned int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 
1)));
+}
+
+unsigned char
+f80 (unsigned char x, unsigned long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 
1)));
+}
+
+unsigned int
+f81 (unsigned int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f82 (unsigned int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f85 (unsigned short int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> y);
+}
+
+unsigned short int
+f86 (unsigned short int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> y);
+}
+
+unsigned char
+f87 (unsigned char x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> y);
+}
+
+unsigned char
+f88 (unsigned char x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f89 (unsigned int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> y);
+}
+
+unsigned int
+f90 (unsigned int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> y);
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f93 (unsigned short int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> 
y);
+}
+
+unsigned short int
+f94 (unsigned short int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> 
y);
+}
+
+unsigned char
+f95 (unsigned char x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> 
y);
+}
+
+unsigned char
+f96 (unsigned char x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> 
y);
+}
--- gcc/testsuite/c-c++-common/rotate-2b.c.jj   2013-05-11 09:46:48.588912339 
+0200
+++ gcc/testsuite/c-c++-common/rotate-2b.c      2013-05-11 10:19:22.767376497 
+0200
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+#ifndef ROTATE_N
+#define ROTATE_N "rotate-2.c"
+#endif
+
+#include ROTATE_N
+
+unsigned int expected[] = {
+0x12345678, 0x12345678, 0x2468acf0, 0x91a2b3c, 0x5678, 0x5678, 0x78, 0x78,
+0x12345678, 0x12345678, 0x2468acf0, 0x91a2b3c, 0x5678, 0x5678, 0x78, 0x78,
+0x0, 0x0, 0x2468acf0, 0x91a2b3c, 0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x2468acf0, 0x91a2b3c, 0x0, 0x0, 0x0, 0x0,
+0x12345678, 0x12345678, 0x91a2b3c, 0x2468acf0, 0x5678, 0x5678, 0x78, 0x78,
+0x12345678, 0x12345678, 0x91a2b3c, 0x2468acf0, 0x5678, 0x5678, 0x78, 0x78,
+0x0, 0x0, 0x91a2b3c, 0x2468acf0, 0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x91a2b3c, 0x2468acf0, 0x0, 0x0, 0x0, 0x0,
+0x2468acf0, 0x2468acf0, 0x2468acf0, 0x91a2b3c, 0xacf0, 0xacf0, 0xf0, 0xf0,
+0x2468acf0, 0x2468acf0, 0x2468acf0, 0x91a2b3c, 0xacf0, 0xacf0, 0xf0, 0xf0,
+0x2468acf0, 0x2468acf0, 0x91a2b3c, 0x2468acf0, 0xacf0, 0xacf0, 0xf0, 0xf0,
+0x2468acf0, 0x2468acf0, 0x91a2b3c, 0x2468acf0, 0xacf0, 0xacf0, 0xf0, 0xf0 };
+
+#define F(n) __typeof (f##n) f##n __attribute__((noinline, noclone));
+#define D(n) F(n##0) F(n##1) F(n##2) F(n##3) F(n##4) F(n##5) F(n##6) F(n##7) 
F(n##8) F(n##9)
+#define ALL \
+F(1) F(2) F(3) F(4) F(5) F(6) F(7) F(8) F(9) \
+D(1) D(2) D(3) D(4) D(5) D(6) D(7) D(8) \
+F(90) F(91) F(92) F(93) F(94) F(95) F(96)
+ALL
+
+int
+main ()
+{
+#if __CHAR_BIT__ != 8 || __SIZEOF_SHORT__ != 2 || __SIZEOF_INT__ != 4
+  return 0;
+#else
+#undef F
+#define F(n) if ((unsigned int) f##n (0x12345678U, 0) != expected[n - 1]) 
abort ();
+  ALL
+  return 0;
+#endif
+}
--- gcc/testsuite/c-c++-common/rotate-3.c.jj    2013-05-10 10:39:13.000000000 
+0200
+++ gcc/testsuite/c-c++-common/rotate-3.c       2013-05-11 10:14:41.003101647 
+0200
@@ -1,7 +1,7 @@
 /* Check rotate pattern detection.  */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
-/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 96 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
 
 unsigned int
@@ -387,3 +387,195 @@ f64 (unsigned char x, long int y)
 {
   return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
 }
+
+unsigned int
+f65 (unsigned int x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f66 (unsigned int x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f70 (unsigned short int x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f71 (unsigned char x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f72 (unsigned char x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f73 (unsigned int x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f74 (unsigned int x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f78 (unsigned short int x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f79 (unsigned char x, int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f80 (unsigned char x, long int y)
+{
+  return (x << y) + (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f81 (unsigned int x, int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) + (x >> y);
+}
+
+unsigned int
+f82 (unsigned int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) + (x >> y);
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f85 (unsigned short int x, int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) + (x >> y);
+}
+
+unsigned short int
+f86 (unsigned short int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) + (x >> y);
+}
+
+unsigned char
+f87 (unsigned char x, int y)
+{
+  return (x << (__CHAR_BIT__ - y)) + (x >> y);
+}
+
+unsigned char
+f88 (unsigned char x, long int y)
+{
+  return (x << (__CHAR_BIT__ - y)) + (x >> y);
+}
+
+unsigned int
+f89 (unsigned int x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) + (x >> y);
+}
+
+unsigned int
+f90 (unsigned int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) + (x >> y);
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f93 (unsigned short int x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) + (x >> y);
+}
+
+unsigned short int
+f94 (unsigned short int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) + (x >> y);
+}
+
+unsigned char
+f95 (unsigned char x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) + (x >> y);
+}
+
+unsigned char
+f96 (unsigned char x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) + (x >> y);
+}
--- gcc/testsuite/c-c++-common/rotate-4.c.jj    2013-05-10 10:39:13.000000000 
+0200
+++ gcc/testsuite/c-c++-common/rotate-4.c       2013-05-11 10:35:56.784601368 
+0200
@@ -1,7 +1,9 @@
 /* Check rotate pattern detection.  */
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
-/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* Rotates should be recognized only in functions with | instead of + or ^,
+   or in functions that have constant shift counts (unused attribute on y).  */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 48 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
 
 unsigned int
@@ -387,3 +389,195 @@ f64 (unsigned char x, long int y)
 {
   return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> 
y);
 }
+
+unsigned int
+f65 (unsigned int x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f66 (unsigned int x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f70 (unsigned short int x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f71 (unsigned char x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f72 (unsigned char x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f73 (unsigned int x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f74 (unsigned int x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 
1)));
+}
+
+unsigned short int
+f78 (unsigned short int x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 
1)));
+}
+
+unsigned char
+f79 (unsigned char x, int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 
1)));
+}
+
+unsigned char
+f80 (unsigned char x, long int y)
+{
+  return (x << y) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 
1)));
+}
+
+unsigned int
+f81 (unsigned int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f82 (unsigned int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f85 (unsigned short int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> y);
+}
+
+unsigned short int
+f86 (unsigned short int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> y);
+}
+
+unsigned char
+f87 (unsigned char x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> y);
+}
+
+unsigned char
+f88 (unsigned char x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> y);
+}
+
+unsigned int
+f89 (unsigned int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> y);
+}
+
+unsigned int
+f90 (unsigned int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> y);
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f93 (unsigned short int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> 
y);
+}
+
+unsigned short int
+f94 (unsigned short int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> 
y);
+}
+
+unsigned char
+f95 (unsigned char x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> 
y);
+}
+
+unsigned char
+f96 (unsigned char x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> 
y);
+}
--- gcc/testsuite/c-c++-common/rotate-4b.c.jj   2013-05-11 10:19:37.190287705 
+0200
+++ gcc/testsuite/c-c++-common/rotate-4b.c      2013-05-11 10:31:46.249115585 
+0200
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-4.c"
+
+#include "rotate-2b.c"
--- gcc/testsuite/c-c++-common/rotate-5.c.jj    2013-05-11 10:20:17.094179336 
+0200
+++ gcc/testsuite/c-c++-common/rotate-5.c       2013-05-11 10:29:06.360066035 
+0200
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+#if __CHAR_BIT__ * __SIZEOF_LONG_LONG__ == 64
+__attribute__((noinline, noclone))
+unsigned long long
+f1 (unsigned long long x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & 63));
+}
+
+#if __CHAR_BIT__ * __SIZEOF_INT128__ == 128
+__attribute__((noinline, noclone))
+unsigned __int128
+f2 (unsigned __int128 x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & 128));
+}
+#endif
+#endif
+
+int
+main ()
+{
+#if __CHAR_BIT__ * __SIZEOF_LONG_LONG__ == 64
+  if (f1 (0x123456789abcdef0ULL, 0) != 0x123456789abcdef0ULL)
+    abort ();
+#if __CHAR_BIT__ * __SIZEOF_INT128__ == 128
+  if (f2 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+         | 0x0fedcba987654321ULL, 0)
+      != ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+          | 0x0fedcba987654321ULL))
+    abort ();
+#endif
+#endif
+  return 0;
+}


        Jakub

Reply via email to