On Sat, 11 May 2013, Jakub Jelinek wrote:

> 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.

Ok.

Thanks,
Richard.

> 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
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend

Reply via email to