]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/45216 (Rotate expressions not recognized at tree level)
authorJakub Jelinek <jakub@redhat.com>
Fri, 10 May 2013 08:40:10 +0000 (10:40 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 10 May 2013 08:40:10 +0000 (10:40 +0200)
PR tree-optimization/45216
PR tree-optimization/57157
* tree-ssa-forwprop.c (simplify_rotate): New function.
(ssa_forward_propagate_and_combine): Call it.

* c-c++-common/rotate-1.c: New test.
* c-c++-common/rotate-1a.c: New test.
* c-c++-common/rotate-2.c: New test.
* c-c++-common/rotate-2a.c: New test.
* c-c++-common/rotate-3.c: New test.
* c-c++-common/rotate-3a.c: New test.
* c-c++-common/rotate-4.c: New test.
* c-c++-common/rotate-4a.c: New test.

From-SVN: r198769

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/rotate-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-1a.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-2a.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-3a.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/rotate-4a.c [new file with mode: 0644]
gcc/tree-ssa-forwprop.c

index c7d6db9a744d5169e420745c60d51c69d63b47a7..82b35a1e601fc9760185e6888cbd39f577171588 100644 (file)
@@ -1,3 +1,10 @@
+2013-05-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/45216
+       PR tree-optimization/57157
+       * tree-ssa-forwprop.c (simplify_rotate): New function.
+       (ssa_forward_propagate_and_combine): Call it.
+
 2013-05-10  Richard Biener  <rguenther@suse.de>
 
        * tree-vect-data-refs.c (vect_enhance_data_refs_alignment): Do not
index 7656de9b0ab574aeca17cb93b81f3bc1417f970d..19e0a5b54011ad287619807a5c8f9f537e46b809 100644 (file)
@@ -1,3 +1,16 @@
+2013-05-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/45216
+       PR tree-optimization/57157
+       * c-c++-common/rotate-1.c: New test.
+       * c-c++-common/rotate-1a.c: New test.
+       * c-c++-common/rotate-2.c: New test.
+       * c-c++-common/rotate-2a.c: New test.
+       * c-c++-common/rotate-3.c: New test.
+       * c-c++-common/rotate-3a.c: New test.
+       * c-c++-common/rotate-4.c: New test.
+       * c-c++-common/rotate-4a.c: New test.
+
 2013-05-10  Richard Biener  <rguenther@suse.de>
 
        * gcc.target/i386/avx256-unaligned-load-2.c: Make well-defined.
diff --git a/gcc/testsuite/c-c++-common/rotate-1.c b/gcc/testsuite/c-c++-common/rotate-1.c
new file mode 100644 (file)
index 0000000..ec3e90b
--- /dev/null
@@ -0,0 +1,389 @@
+/* Check rotate pattern detection.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f2 (unsigned int x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f6 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f7 (unsigned char x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f8 (unsigned char x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f9 (unsigned int x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f10 (unsigned int x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f14 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f15 (unsigned char x, unsigned int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f16 (unsigned char x, unsigned long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f17 (unsigned int x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f18 (unsigned int x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f21 (unsigned short int x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x << y);
+}
+
+unsigned short int
+f22 (unsigned short int x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x << y);
+}
+
+unsigned char
+f23 (unsigned char x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ - y)) ^ (x << y);
+}
+
+unsigned char
+f24 (unsigned char x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f25 (unsigned int x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x << y);
+}
+
+unsigned int
+f26 (unsigned int x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x << y);
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1)) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f29 (unsigned short int x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x << y);
+}
+
+unsigned short int
+f30 (unsigned short int x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x << y);
+}
+
+unsigned char
+f31 (unsigned char x, unsigned int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x << y);
+}
+
+unsigned char
+f32 (unsigned char x, unsigned long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x << y);
+}
+
+unsigned int
+f33 (unsigned int x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f34 (unsigned int x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f38 (unsigned short int x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f39 (unsigned char x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f40 (unsigned char x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f41 (unsigned int x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f42 (unsigned int x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1)) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f46 (unsigned short int x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f47 (unsigned char x, unsigned int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f48 (unsigned char x, unsigned long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f49 (unsigned int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f50 (unsigned int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f53 (unsigned short int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x >> y);
+}
+
+unsigned short int
+f54 (unsigned short int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x >> y);
+}
+
+unsigned char
+f55 (unsigned char x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ - y)) ^ (x >> y);
+}
+
+unsigned char
+f56 (unsigned char x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f57 (unsigned int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x >> y);
+}
+
+unsigned int
+f58 (unsigned int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x >> y);
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f61 (unsigned short int x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x >> y);
+}
+
+unsigned short int
+f62 (unsigned short int x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x >> y);
+}
+
+unsigned char
+f63 (unsigned char x, unsigned int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
+}
+
+unsigned char
+f64 (unsigned char x, unsigned long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-1a.c b/gcc/testsuite/c-c++-common/rotate-1a.c
new file mode 100644 (file)
index 0000000..fc838a8
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+
+#ifndef ROTATE_N
+#define ROTATE_N "rotate-1.c"
+#endif
+
+#include ROTATE_N
+
+unsigned int expected[] = {
+0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
+0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
+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,
+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)
+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, 3) != expected[n - 1]) abort ();
+  ALL
+  return 0;
+#endif
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-2.c b/gcc/testsuite/c-c++-common/rotate-2.c
new file mode 100644 (file)
index 0000000..d853866
--- /dev/null
@@ -0,0 +1,389 @@
+/* Check rotate pattern detection.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f2 (unsigned int x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f6 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f7 (unsigned char x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f8 (unsigned char x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f9 (unsigned int x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f10 (unsigned int x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f14 (unsigned short int x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f15 (unsigned char x, unsigned int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f16 (unsigned char x, unsigned long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f17 (unsigned int x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f18 (unsigned int x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f21 (unsigned short int x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << y);
+}
+
+unsigned short int
+f22 (unsigned short int x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << y);
+}
+
+unsigned char
+f23 (unsigned char x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << y);
+}
+
+unsigned char
+f24 (unsigned char x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f25 (unsigned int x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << y);
+}
+
+unsigned int
+f26 (unsigned int x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << y);
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f29 (unsigned short int x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << y);
+}
+
+unsigned short int
+f30 (unsigned short int x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << y);
+}
+
+unsigned char
+f31 (unsigned char x, unsigned int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << y);
+}
+
+unsigned char
+f32 (unsigned char x, unsigned long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << y);
+}
+
+unsigned int
+f33 (unsigned int x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f34 (unsigned int x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f38 (unsigned short int x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f39 (unsigned char x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f40 (unsigned char x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f41 (unsigned int x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f42 (unsigned int x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f46 (unsigned short int x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f47 (unsigned char x, unsigned int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f48 (unsigned char x, unsigned long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f49 (unsigned int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f50 (unsigned int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f53 (unsigned short int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> y);
+}
+
+unsigned short int
+f54 (unsigned short int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> y);
+}
+
+unsigned char
+f55 (unsigned char x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> y);
+}
+
+unsigned char
+f56 (unsigned char x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f57 (unsigned int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> y);
+}
+
+unsigned int
+f58 (unsigned int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> y);
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f61 (unsigned short int x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> y);
+}
+
+unsigned short int
+f62 (unsigned short int x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> y);
+}
+
+unsigned char
+f63 (unsigned char x, unsigned int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> y);
+}
+
+unsigned char
+f64 (unsigned char x, unsigned long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> y);
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-2a.c b/gcc/testsuite/c-c++-common/rotate-2a.c
new file mode 100644 (file)
index 0000000..d709c0d
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-2.c"
+
+#include "rotate-1a.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-3.c b/gcc/testsuite/c-c++-common/rotate-3.c
new file mode 100644 (file)
index 0000000..a7d138f
--- /dev/null
@@ -0,0 +1,389 @@
+/* Check rotate pattern detection.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f2 (unsigned int x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f6 (unsigned short int x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f7 (unsigned char x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f8 (unsigned char x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f9 (unsigned int x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f10 (unsigned int x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f14 (unsigned short int x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f15 (unsigned char x, int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f16 (unsigned char x, long int y)
+{
+  return (x << y) | (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f17 (unsigned int x, int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f18 (unsigned int x, long int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f21 (unsigned short int x, int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x << y);
+}
+
+unsigned short int
+f22 (unsigned short int x, long int y)
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x << y);
+}
+
+unsigned char
+f23 (unsigned char x, int y)
+{
+  return (x >> (__CHAR_BIT__ - y)) ^ (x << y);
+}
+
+unsigned char
+f24 (unsigned char x, long int y)
+{
+  return (x >> (__CHAR_BIT__ - y)) ^ (x << y);
+}
+
+unsigned int
+f25 (unsigned int x, int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x << y);
+}
+
+unsigned int
+f26 (unsigned int x, long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x << y);
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1)) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f29 (unsigned short int x, int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x << y);
+}
+
+unsigned short int
+f30 (unsigned short int x, long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x << y);
+}
+
+unsigned char
+f31 (unsigned char x, int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x << y);
+}
+
+unsigned char
+f32 (unsigned char x, long int y)
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x << y);
+}
+
+unsigned int
+f33 (unsigned int x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f34 (unsigned int x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned short int
+f38 (unsigned short int x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y));
+}
+
+unsigned char
+f39 (unsigned char x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ - y));
+}
+
+unsigned char
+f40 (unsigned char x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ - y));
+}
+
+unsigned int
+f41 (unsigned int x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f42 (unsigned int x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - y));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1)) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned short int
+f46 (unsigned short int x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned short) - y));
+}
+
+unsigned char
+f47 (unsigned char x, int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned char
+f48 (unsigned char x, long int y)
+{
+  return (x >> y) | (x << (__CHAR_BIT__ * sizeof (unsigned char) - y));
+}
+
+unsigned int
+f49 (unsigned int x, int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f50 (unsigned int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - 1)) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - 1));
+}
+
+unsigned short int
+f53 (unsigned short int x, int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x >> y);
+}
+
+unsigned short int
+f54 (unsigned short int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * __SIZEOF_SHORT__ - y)) ^ (x >> y);
+}
+
+unsigned char
+f55 (unsigned char x, int y)
+{
+  return (x << (__CHAR_BIT__ - y)) ^ (x >> y);
+}
+
+unsigned char
+f56 (unsigned char x, long int y)
+{
+  return (x << (__CHAR_BIT__ - y)) ^ (x >> y);
+}
+
+unsigned int
+f57 (unsigned int x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x >> y);
+}
+
+unsigned int
+f58 (unsigned int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - y)) ^ (x >> y);
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned int) - 1)) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> (__CHAR_BIT__ * sizeof (unsigned int) - 1));
+}
+
+unsigned short int
+f61 (unsigned short int x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x >> y);
+}
+
+unsigned short int
+f62 (unsigned short int x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned short) - y)) ^ (x >> y);
+}
+
+unsigned char
+f63 (unsigned char x, int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
+}
+
+unsigned char
+f64 (unsigned char x, long int y)
+{
+  return (x << (__CHAR_BIT__ * sizeof (unsigned char) - y)) ^ (x >> y);
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-3a.c b/gcc/testsuite/c-c++-common/rotate-3a.c
new file mode 100644 (file)
index 0000000..450fc22
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-4.c"
+
+#include "rotate-1a.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-4.c b/gcc/testsuite/c-c++-common/rotate-4.c
new file mode 100644 (file)
index 0000000..705fece
--- /dev/null
@@ -0,0 +1,389 @@
+/* Check rotate pattern detection.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 64 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f2 (unsigned int x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f6 (unsigned short int x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f7 (unsigned char x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f8 (unsigned char x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f9 (unsigned int x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f10 (unsigned int x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f14 (unsigned short int x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f15 (unsigned char x, int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f16 (unsigned char x, long int y)
+{
+  return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f17 (unsigned int x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f18 (unsigned int x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f21 (unsigned short int x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << y);
+}
+
+unsigned short int
+f22 (unsigned short int x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << y);
+}
+
+unsigned char
+f23 (unsigned char x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << y);
+}
+
+unsigned char
+f24 (unsigned char x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << y);
+}
+
+unsigned int
+f25 (unsigned int x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << y);
+}
+
+unsigned int
+f26 (unsigned int x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << y);
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f29 (unsigned short int x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << y);
+}
+
+unsigned short int
+f30 (unsigned short int x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << y);
+}
+
+unsigned char
+f31 (unsigned char x, int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << y);
+}
+
+unsigned char
+f32 (unsigned char x, long int y)
+{
+  return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << y);
+}
+
+unsigned int
+f33 (unsigned int x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f34 (unsigned int x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f38 (unsigned short int x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f39 (unsigned char x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f40 (unsigned char x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f41 (unsigned int x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f42 (unsigned int x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f46 (unsigned short int x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f47 (unsigned char x, int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f48 (unsigned char x, long int y)
+{
+  return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f49 (unsigned int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f50 (unsigned int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f53 (unsigned short int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> y);
+}
+
+unsigned short int
+f54 (unsigned short int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> y);
+}
+
+unsigned char
+f55 (unsigned char x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> y);
+}
+
+unsigned char
+f56 (unsigned char x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> y);
+}
+
+unsigned int
+f57 (unsigned int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> y);
+}
+
+unsigned int
+f58 (unsigned int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> y);
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+  return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f61 (unsigned short int x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> y);
+}
+
+unsigned short int
+f62 (unsigned short int x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> y);
+}
+
+unsigned char
+f63 (unsigned char x, int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> y);
+}
+
+unsigned char
+f64 (unsigned char x, long int y)
+{
+  return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> y);
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-4a.c b/gcc/testsuite/c-c++-common/rotate-4a.c
new file mode 100644 (file)
index 0000000..450fc22
--- /dev/null
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-4.c"
+
+#include "rotate-1a.c"
index 715082ceefb6fda38ac06a091db5f196cfe33e77..e714a5ef24490442f4f63b1bc34ada0486bf4be5 100644 (file)
@@ -2124,6 +2124,242 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
 }
 
 
+/* Recognize rotation patterns.  Return true if a transformation
+   applied, otherwise return false.
+
+   We are looking for X with unsigned type T with bitsize B, OP being
+   +, | or ^, some type T2 wider than T and
+   (X << CNT1) OP (X >> CNT2)                          iff CNT1 + CNT2 == B
+   ((T) ((T2) X << CNT1)) OP ((T) ((T2) X >> CNT2))    iff CNT1 + CNT2 == B
+   (X << Y) OP (X >> (B - Y))
+   (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))))
+
+   and transform these into:
+   X r<< CNT1
+   X r<< Y
+
+   Note, in the patterns with T2 type, the type of OP operands
+   might be even a signed type, but should have precision B.  */
+
+static bool
+simplify_rotate (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree arg[2], rtype, rotcnt = NULL_TREE;
+  tree def_arg1[2], def_arg2[2];
+  enum tree_code def_code[2];
+  tree lhs;
+  int i;
+  bool swapped_p = false;
+  gimple g;
+
+  arg[0] = gimple_assign_rhs1 (stmt);
+  arg[1] = gimple_assign_rhs2 (stmt);
+  rtype = TREE_TYPE (arg[0]);
+
+  /* Only create rotates in complete modes.  Other cases are not
+     expanded properly.  */
+  if (!INTEGRAL_TYPE_P (rtype)
+      || TYPE_PRECISION (rtype) != GET_MODE_PRECISION (TYPE_MODE (rtype)))
+    return false;
+
+  for (i = 0; i < 2; i++)
+    defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]);
+
+  /* Look through narrowing conversions.  */
+  if (CONVERT_EXPR_CODE_P (def_code[0])
+      && CONVERT_EXPR_CODE_P (def_code[1])
+      && INTEGRAL_TYPE_P (TREE_TYPE (def_arg1[0]))
+      && INTEGRAL_TYPE_P (TREE_TYPE (def_arg1[1]))
+      && TYPE_PRECISION (TREE_TYPE (def_arg1[0]))
+        == TYPE_PRECISION (TREE_TYPE (def_arg1[1]))
+      && TYPE_PRECISION (TREE_TYPE (def_arg1[0])) > TYPE_PRECISION (rtype)
+      && has_single_use (arg[0])
+      && has_single_use (arg[1]))
+    {
+      for (i = 0; i < 2; i++)
+       {
+         arg[i] = def_arg1[i];
+         defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]);
+       }
+    }
+
+  /* One operand has to be LSHIFT_EXPR and one RSHIFT_EXPR.  */
+  for (i = 0; i < 2; i++)
+    if (def_code[i] != LSHIFT_EXPR && def_code[i] != RSHIFT_EXPR)
+      return false;
+    else if (!has_single_use (arg[i]))
+      return false;
+  if (def_code[0] == def_code[1])
+    return false;
+
+  /* If we've looked through narrowing conversions before, look through
+     widening conversions from unsigned type with the same precision
+     as rtype here.  */
+  if (TYPE_PRECISION (TREE_TYPE (def_arg1[0])) != TYPE_PRECISION (rtype))
+    for (i = 0; i < 2; i++)
+      {
+       tree tem;
+       enum tree_code code;
+       defcodefor_name (def_arg1[i], &code, &tem, NULL);
+       if (!CONVERT_EXPR_CODE_P (code)
+           || !INTEGRAL_TYPE_P (TREE_TYPE (tem))
+           || TYPE_PRECISION (TREE_TYPE (tem)) != TYPE_PRECISION (rtype))
+         return false;
+       def_arg1[i] = tem;
+      }
+  /* Both shifts have to use the same first operand.  */
+  if (TREE_CODE (def_arg1[0]) != SSA_NAME || def_arg1[0] != def_arg1[1])
+    return false;
+  if (!TYPE_UNSIGNED (TREE_TYPE (def_arg1[0])))
+    return false;
+
+  /* CNT1 + CNT2 == B case above.  */
+  if (host_integerp (def_arg2[0], 1)
+      && host_integerp (def_arg2[1], 1)
+      && (unsigned HOST_WIDE_INT) tree_low_cst (def_arg2[0], 1)
+        + tree_low_cst (def_arg2[1], 1) == TYPE_PRECISION (rtype))
+    rotcnt = def_arg2[0];
+  else if (TREE_CODE (def_arg2[0]) != SSA_NAME
+          || TREE_CODE (def_arg2[1]) != SSA_NAME)
+    return false;
+  else
+    {
+      tree cdef_arg1[2], cdef_arg2[2], def_arg2_alt[2];
+      enum tree_code cdef_code[2];
+      /* Look through conversion of the shift count argument.
+        The C/C++ FE cast any shift count argument to integer_type_node.
+        The only problem might be if the shift count type maximum value
+        is equal or smaller than number of bits in rtype.  */
+      for (i = 0; i < 2; i++)
+       {
+         def_arg2_alt[i] = def_arg2[i];
+         defcodefor_name (def_arg2[i], &cdef_code[i],
+                          &cdef_arg1[i], &cdef_arg2[i]);
+         if (CONVERT_EXPR_CODE_P (cdef_code[i])
+             && INTEGRAL_TYPE_P (TREE_TYPE (cdef_arg1[i]))
+             && TYPE_PRECISION (TREE_TYPE (cdef_arg1[i]))
+                > floor_log2 (TYPE_PRECISION (rtype))
+             && TYPE_PRECISION (TREE_TYPE (cdef_arg1[i]))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (cdef_arg1[i]))))
+           {
+             def_arg2_alt[i] = cdef_arg1[i];
+             defcodefor_name (def_arg2_alt[i], &cdef_code[i],
+                              &cdef_arg1[i], &cdef_arg2[i]);
+           }
+       }
+      for (i = 0; i < 2; i++)
+       /* Check for one shift count being Y and the other B - Y,
+          with optional casts.  */
+       if (cdef_code[i] == MINUS_EXPR
+           && host_integerp (cdef_arg1[i], 0)
+           && tree_low_cst (cdef_arg1[i], 0) == TYPE_PRECISION (rtype)
+           && TREE_CODE (cdef_arg2[i]) == SSA_NAME)
+         {
+           tree tem;
+           enum tree_code code;
+
+           if (cdef_arg2[i] == def_arg2[1 - i]
+               || cdef_arg2[i] == def_arg2_alt[1 - i])
+             {
+               rotcnt = cdef_arg2[i];
+               break;
+             }
+           defcodefor_name (cdef_arg2[i], &code, &tem, NULL);
+           if (CONVERT_EXPR_CODE_P (code)
+               && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                > floor_log2 (TYPE_PRECISION (rtype))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem)))
+               && (tem == def_arg2[1 - i]
+                   || tem == def_arg2_alt[1 - i]))
+             {
+               rotcnt = tem;
+               break;
+             }
+         }
+       /* The above sequence isn't safe for Y being 0,
+          because then one of the shifts triggers undefined behavior.
+          This alternative is safe even for rotation count of 0.
+          One shift count is Y and the other (-Y) & (B - 1).  */
+       else if (cdef_code[i] == BIT_AND_EXPR
+                && 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 tem;
+           enum tree_code code;
+
+           defcodefor_name (cdef_arg1[i], &code, &tem, NULL);
+           if (CONVERT_EXPR_CODE_P (code)
+               && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                > floor_log2 (TYPE_PRECISION (rtype))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem))))
+             defcodefor_name (tem, &code, &tem, NULL);
+
+           if (code == NEGATE_EXPR)
+             {
+               if (tem == def_arg2[1 - i] || tem == def_arg2_alt[1 - i])
+                 {
+                   rotcnt = tem;
+                   break;
+                 }
+               defcodefor_name (tem, &code, &tem, NULL);
+               if (CONVERT_EXPR_CODE_P (code)
+                   && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+                   && TYPE_PRECISION (TREE_TYPE (tem))
+                      > floor_log2 (TYPE_PRECISION (rtype))
+                   && TYPE_PRECISION (TREE_TYPE (tem))
+                      == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem)))
+                   && (tem == def_arg2[1 - i]
+                       || tem == def_arg2_alt[1 - i]))
+                 {
+                   rotcnt = tem;
+                   break;
+                 }
+             }
+         }
+      if (rotcnt == NULL_TREE)
+       return false;
+      swapped_p = i != 1;
+    }
+
+  if (!useless_type_conversion_p (TREE_TYPE (def_arg2[0]),
+                                 TREE_TYPE (rotcnt)))
+    {
+      g = gimple_build_assign_with_ops (NOP_EXPR,
+                                       make_ssa_name (TREE_TYPE (def_arg2[0]),
+                                                      NULL),
+                                       rotcnt, NULL_TREE);
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      rotcnt = gimple_assign_lhs (g);
+    }
+  lhs = gimple_assign_lhs (stmt);
+  if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
+    lhs = make_ssa_name (TREE_TYPE (def_arg1[0]), NULL);
+  g = gimple_build_assign_with_ops (((def_code[0] == LSHIFT_EXPR) ^ swapped_p)
+                                   ? LROTATE_EXPR : RROTATE_EXPR,
+                                   lhs, def_arg1[0], rotcnt);
+  if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
+    {
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign_with_ops (NOP_EXPR, gimple_assign_lhs (stmt),
+                                       lhs, NULL_TREE);
+    }
+  gsi_replace (gsi, g, false);
+  return true;
+}
+
 /* Perform re-associations of the plus or minus statement STMT that are
    always permitted.  Returns true if the CFG was changed.  */
 
@@ -3114,6 +3350,11 @@ ssa_forward_propagate_and_combine (void)
                      cfg_changed = true;
                    changed = did_something != 0;
                  }
+               else if ((code == PLUS_EXPR
+                         || code == BIT_IOR_EXPR
+                         || code == BIT_XOR_EXPR)
+                        && simplify_rotate (&gsi))
+                 changed = true;
                else if (code == BIT_AND_EXPR
                         || code == BIT_IOR_EXPR
                         || code == BIT_XOR_EXPR)