This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Move ((A & N) + B) & M -> (A + B) & M etc. optimization from fold-const.c to match.pd (PR tree-optimization/86401)


On Thu, 5 Jul 2018, Jakub Jelinek wrote:

> Hi!
> 
> I've encountered this while testing the rotate patterns in discussion
> with Jonathan for the std::__rot{l,r}, in the rotate-9.c test without
> this patch f1 is optimized into a rotate, but f2 is not.
> 
> Fixed by moving the optimization from fold-const.c to match.pd (well,
> leaving a helper in fold-const.c to avoid too much duplication).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2018-07-05  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/86401
> 	* fold-const.c (fold_binary_loc) <case BIT_AND_EXPR>: Move the
> 	((A & N) + B) & M -> (A + B) & M etc. optimization into ...
> 	(fold_bit_and_mask): ... here.  New helper function for match.pd.
> 	* fold-const.h (fold_bit_and_mask): Declare.
> 	* match.pd (((A & N) + B) & M -> (A + B) & M): New optimization.
> 
> 	* gcc.dg/tree-ssa/pr86401-1.c: New test.
> 	* gcc.dg/tree-ssa/pr86401-2.c: New test.
> 	* c-c++-common/rotate-9.c: New test.
> 
> --- gcc/fold-const.c.jj	2018-06-26 09:05:23.196346433 +0200
> +++ gcc/fold-const.c	2018-07-04 12:47:59.139981801 +0200
> @@ -10236,121 +10236,6 @@ fold_binary_loc (location_t loc, enum tr
>  	    }
>  	}
>  
> -      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
> -	 ((A & N) + B) & M -> (A + B) & M
> -	 Similarly if (N & M) == 0,
> -	 ((A | N) + B) & M -> (A + B) & M
> -	 and for - instead of + (or unary - instead of +)
> -	 and/or ^ instead of |.
> -	 If B is constant and (B & M) == 0, fold into A & M.  */
> -      if (TREE_CODE (arg1) == INTEGER_CST)
> -	{
> -	  wi::tree_to_wide_ref cst1 = wi::to_wide (arg1);
> -	  if ((~cst1 != 0) && (cst1 & (cst1 + 1)) == 0
> -	      && INTEGRAL_TYPE_P (TREE_TYPE (arg0))
> -	      && (TREE_CODE (arg0) == PLUS_EXPR
> -		  || TREE_CODE (arg0) == MINUS_EXPR
> -		  || TREE_CODE (arg0) == NEGATE_EXPR)
> -	      && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
> -		  || TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE))
> -	    {
> -	      tree pmop[2];
> -	      int which = 0;
> -	      wide_int cst0;
> -
> -	      /* Now we know that arg0 is (C + D) or (C - D) or
> -		 -C and arg1 (M) is == (1LL << cst) - 1.
> -		 Store C into PMOP[0] and D into PMOP[1].  */
> -	      pmop[0] = TREE_OPERAND (arg0, 0);
> -	      pmop[1] = NULL;
> -	      if (TREE_CODE (arg0) != NEGATE_EXPR)
> -		{
> -		  pmop[1] = TREE_OPERAND (arg0, 1);
> -		  which = 1;
> -		}
> -
> -	      if ((wi::max_value (TREE_TYPE (arg0)) & cst1) != cst1)
> -		which = -1;
> -
> -	      for (; which >= 0; which--)
> -		switch (TREE_CODE (pmop[which]))
> -		  {
> -		  case BIT_AND_EXPR:
> -		  case BIT_IOR_EXPR:
> -		  case BIT_XOR_EXPR:
> -		    if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
> -			!= INTEGER_CST)
> -		      break;
> -		    cst0 = wi::to_wide (TREE_OPERAND (pmop[which], 1)) & cst1;
> -		    if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
> -		      {
> -			if (cst0 != cst1)
> -			  break;
> -		      }
> -		    else if (cst0 != 0)
> -		      break;
> -		    /* If C or D is of the form (A & N) where
> -		       (N & M) == M, or of the form (A | N) or
> -		       (A ^ N) where (N & M) == 0, replace it with A.  */
> -		    pmop[which] = TREE_OPERAND (pmop[which], 0);
> -		    break;
> -		  case INTEGER_CST:
> -		    /* If C or D is a N where (N & M) == 0, it can be
> -		       omitted (assumed 0).  */
> -		    if ((TREE_CODE (arg0) == PLUS_EXPR
> -			 || (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
> -			&& (cst1 & wi::to_wide (pmop[which])) == 0)
> -		      pmop[which] = NULL;
> -		    break;
> -		  default:
> -		    break;
> -		  }
> -
> -	      /* Only build anything new if we optimized one or both arguments
> -		 above.  */
> -	      if (pmop[0] != TREE_OPERAND (arg0, 0)
> -		  || (TREE_CODE (arg0) != NEGATE_EXPR
> -		      && pmop[1] != TREE_OPERAND (arg0, 1)))
> -		{
> -		  tree utype = TREE_TYPE (arg0);
> -		  if (! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
> -		    {
> -		      /* Perform the operations in a type that has defined
> -			 overflow behavior.  */
> -		      utype = unsigned_type_for (TREE_TYPE (arg0));
> -		      if (pmop[0] != NULL)
> -			pmop[0] = fold_convert_loc (loc, utype, pmop[0]);
> -		      if (pmop[1] != NULL)
> -			pmop[1] = fold_convert_loc (loc, utype, pmop[1]);
> -		    }
> -
> -		  if (TREE_CODE (arg0) == NEGATE_EXPR)
> -		    tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[0]);
> -		  else if (TREE_CODE (arg0) == PLUS_EXPR)
> -		    {
> -		      if (pmop[0] != NULL && pmop[1] != NULL)
> -			tem = fold_build2_loc (loc, PLUS_EXPR, utype,
> -					       pmop[0], pmop[1]);
> -		      else if (pmop[0] != NULL)
> -			tem = pmop[0];
> -		      else if (pmop[1] != NULL)
> -			tem = pmop[1];
> -		      else
> -			return build_int_cst (type, 0);
> -		    }
> -		  else if (pmop[0] == NULL)
> -		    tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[1]);
> -		  else
> -		    tem = fold_build2_loc (loc, MINUS_EXPR, utype,
> -					   pmop[0], pmop[1]);
> -		  /* TEM is now the new binary +, - or unary - replacement.  */
> -		  tem = fold_build2_loc (loc, BIT_AND_EXPR, utype, tem,
> -					 fold_convert_loc (loc, utype, arg1));
> -		  return fold_convert_loc (loc, type, tem);
> -		}
> -	    }
> -	}
> -
>        /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
>        if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
>  	  && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
> @@ -11264,6 +11149,100 @@ fold_binary_loc (location_t loc, enum tr
>      } /* switch (code) */
>  }
>  
> +/* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
> +   ((A & N) + B) & M -> (A + B) & M
> +   Similarly if (N & M) == 0,
> +   ((A | N) + B) & M -> (A + B) & M
> +   and for - instead of + (or unary - instead of +)
> +   and/or ^ instead of |.
> +   If B is constant and (B & M) == 0, fold into A & M.
> +
> +   This function is a helper for match.pd patterns.  Return non-NULL
> +   type in which the simplified operation should be performed only
> +   if any optimization is possible.
> +
> +   ARG1 is M above, ARG00 is left operand of +/-, if CODE00 is BIT_*_EXPR,
> +   then ARG00{0,1} are operands of that bitop, otherwise CODE00 is ERROR_MARK.
> +   Similarly for ARG01, CODE01 and ARG01{0,1}, just for the right operand of
> +   +/-.  */
> +tree
> +fold_bit_and_mask (tree type, tree arg1, enum tree_code code,
> +		   tree arg00, enum tree_code code00, tree arg000, tree arg001,
> +		   tree arg01, enum tree_code code01, tree arg010, tree arg011,
> +		   tree *pmop)
> +{
> +  gcc_assert (TREE_CODE (arg1) == INTEGER_CST);
> +  gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR);
> +  wi::tree_to_wide_ref cst1 = wi::to_wide (arg1);
> +  if (~cst1 == 0
> +      || (cst1 & (cst1 + 1)) != 0
> +      || !INTEGRAL_TYPE_P (type)
> +      || (!TYPE_OVERFLOW_WRAPS (type)
> +	  && TREE_CODE (type) != INTEGER_TYPE)
> +      || (wi::max_value (type) & cst1) != cst1)
> +    return NULL_TREE;
> +
> +  enum tree_code codes[2] = { code00, code01 };
> +  tree arg0xx[4] = { arg000, arg001, arg010, arg011 };
> +  int which = 0;
> +  wide_int cst0;
> +
> +  /* Now we know that arg0 is (C + D) or (C - D) or -C and
> +     arg1 (M) is == (1LL << cst) - 1.
> +     Store C into PMOP[0] and D into PMOP[1].  */
> +  pmop[0] = arg00;
> +  pmop[1] = arg01;
> +  which = code != NEGATE_EXPR;
> +
> +  for (; which >= 0; which--)
> +    switch (codes[which])
> +      {
> +      case BIT_AND_EXPR:
> +      case BIT_IOR_EXPR:
> +      case BIT_XOR_EXPR:
> +	gcc_assert (TREE_CODE (arg0xx[2 * which + 1]) == INTEGER_CST);
> +	cst0 = wi::to_wide (arg0xx[2 * which + 1]) & cst1;
> +	if (codes[which] == BIT_AND_EXPR)
> +	  {
> +	    if (cst0 != cst1)
> +	      break;
> +	  }
> +	else if (cst0 != 0)
> +	  break;
> +	/* If C or D is of the form (A & N) where
> +	   (N & M) == M, or of the form (A | N) or
> +	   (A ^ N) where (N & M) == 0, replace it with A.  */
> +	pmop[which] = arg0xx[2 * which];
> +	break;
> +      case ERROR_MARK:
> +	if (TREE_CODE (pmop[which]) != INTEGER_CST)
> +	  break;
> +	/* If C or D is a N where (N & M) == 0, it can be
> +	   omitted (replaced with 0).  */
> +	if ((code == PLUS_EXPR
> +	     || (code == MINUS_EXPR && which == 0))
> +	    && (cst1 & wi::to_wide (pmop[which])) == 0)
> +	  pmop[which] = build_int_cst (type, 0);
> +	/* Similarly, with C - N where (-N & M) == 0.  */
> +	if (code == MINUS_EXPR
> +	    && which == 1
> +	    && (cst1 & -wi::to_wide (pmop[which])) == 0)
> +	  pmop[which] = build_int_cst (type, 0);
> +	break;
> +      default:
> +	gcc_unreachable ();
> +      }
> +
> +  /* Only build anything new if we optimized one or both arguments above.  */
> +  if (pmop[0] == arg00 && pmop[1] == arg01)
> +    return NULL_TREE;
> +
> +  if (TYPE_OVERFLOW_WRAPS (type))
> +    return type;
> +  else
> +    return unsigned_type_for (type);
> +}
> +
>  /* Used by contains_label_[p1].  */
>  
>  struct contains_label_data
> --- gcc/fold-const.h.jj	2018-05-25 14:34:36.871377394 +0200
> +++ gcc/fold-const.h	2018-07-04 12:34:18.072910936 +0200
> @@ -96,6 +96,9 @@ extern tree omit_two_operands_loc (locat
>  extern tree invert_truthvalue_loc (location_t, tree);
>  extern tree fold_unary_to_constant (enum tree_code, tree, tree);
>  extern tree fold_binary_to_constant (enum tree_code, tree, tree, tree);
> +extern tree fold_bit_and_mask (tree, tree, enum tree_code,
> +			       tree, enum tree_code, tree, tree,
> +			       tree, enum tree_code, tree, tree, tree *);
>  extern tree fold_read_from_constant_string (tree);
>  extern tree int_const_binop (enum tree_code, const_tree, const_tree);
>  #define build_fold_addr_expr(T)\
> --- gcc/match.pd.jj	2018-06-20 08:15:34.196862169 +0200
> +++ gcc/match.pd	2018-07-04 13:21:07.897317459 +0200
> @@ -779,6 +779,60 @@ (define_operator_list COND_BINARY
>    (bit_xor @0 @1)))
>  #endif
>  
> +/* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
> +   ((A & N) + B) & M -> (A + B) & M
> +   Similarly if (N & M) == 0,
> +   ((A | N) + B) & M -> (A + B) & M
> +   and for - instead of + (or unary - instead of +)
> +   and/or ^ instead of |.
> +   If B is constant and (B & M) == 0, fold into A & M.  */
> +(for op (plus minus)
> + (for bitop (bit_and bit_ior bit_xor)
> +  (simplify
> +   (bit_and (op:s (bitop:s@0 @3 INTEGER_CST@4) @1) INTEGER_CST@2)
> +    (with
> +     { tree pmop[2];
> +       tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, bitop,
> +				       @3, @4, @1, ERROR_MARK, NULL_TREE,
> +				       NULL_TREE, pmop); }
> +     (if (utype)
> +      (convert (bit_and (op (convert:utype { pmop[0]; })
> +			    (convert:utype { pmop[1]; }))
> +			(convert:utype @2))))))
> +  (simplify
> +   (bit_and (op:s @0 (bitop:s@1 @3 INTEGER_CST@4)) INTEGER_CST@2)
> +    (with
> +     { tree pmop[2];
> +       tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, ERROR_MARK,
> +				       NULL_TREE, NULL_TREE, @1, bitop, @3,
> +				       @4, pmop); }
> +     (if (utype)
> +      (convert (bit_and (op (convert:utype { pmop[0]; })
> +			    (convert:utype { pmop[1]; }))
> +			(convert:utype @2)))))))
> + (simplify
> +  (bit_and (op:s @0 @1) INTEGER_CST@2)
> +   (with
> +    { tree pmop[2];
> +      tree utype = fold_bit_and_mask (TREE_TYPE (@0), @2, op, @0, ERROR_MARK,
> +				      NULL_TREE, NULL_TREE, @1, ERROR_MARK,
> +				      NULL_TREE, NULL_TREE, pmop); }
> +    (if (utype)
> +     (convert (bit_and (op (convert:utype { pmop[0]; })
> +			   (convert:utype { pmop[1]; }))
> +		       (convert:utype @2)))))))
> +(for bitop (bit_and bit_ior bit_xor)
> + (simplify
> +  (bit_and (negate:s (bitop:s@0 @2 INTEGER_CST@3)) INTEGER_CST@1)
> +   (with
> +    { tree pmop[2];
> +      tree utype = fold_bit_and_mask (TREE_TYPE (@0), @1, NEGATE_EXPR, @0,
> +				      bitop, @2, @3, NULL_TREE, ERROR_MARK,
> +				      NULL_TREE, NULL_TREE, pmop); }
> +    (if (utype)
> +     (convert (bit_and (negate (convert:utype { pmop[0]; }))
> +		       (convert:utype @1)))))))
> +
>  /* X % Y is smaller than Y.  */
>  (for cmp (lt ge)
>   (simplify
> --- gcc/testsuite/gcc.dg/tree-ssa/pr86401-1.c.jj	2018-07-04 13:36:58.765324864 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr86401-1.c	2018-07-04 13:40:10.726523960 +0200
> @@ -0,0 +1,48 @@
> +/* PR tree-optimization/86401 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-not " \\+ 64" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "64 - " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\+ 4294967232" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " & 319" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\| 4294967168" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\^ 4294966912" "optimized" } } */
> +
> +unsigned f1 (unsigned x) { unsigned m = 64; return (m + x) & (m - 1); }
> +unsigned f2 (unsigned x) { return (64 + x) & 63; }
> +unsigned f3 (unsigned x) { unsigned m = 64; return (x + m) & (m - 1); }
> +unsigned f4 (unsigned x) { return (x + 64) & 63; }
> +unsigned f5 (unsigned x) { unsigned m = 64; return (m - x) & (m - 1); }
> +unsigned f6 (unsigned x) { return (64 - x) & 63; }
> +unsigned f7 (unsigned x) { unsigned m = 64; return (x - m) & (m - 1); }
> +unsigned f8 (unsigned x) { return (x - 64) & 63; }
> +unsigned f9 (unsigned x, unsigned y) { unsigned m = 64, n = 256 | (m - 1); return ((x & n) + y) & (m - 1); }
> +unsigned f10 (unsigned x, unsigned y) { return ((x & 319) + y) & 63; }
> +unsigned f11 (unsigned x, unsigned y) { unsigned m = 64, n = -128; return ((x | n) + y) & (m - 1); }
> +unsigned f12 (unsigned x, unsigned y) { return ((x | -128) + y) & 63; }
> +unsigned f13 (unsigned x, unsigned y) { unsigned m = 64, n = -384; return ((x ^ n) + y) & (m - 1); }
> +unsigned f14 (unsigned x, unsigned y) { return ((x ^ -384) + y) & 63; }
> +unsigned f15 (unsigned x, unsigned y) { unsigned m = 64, n = 256 | (m - 1); return (y + (x & n)) & (m - 1); }
> +unsigned f16 (unsigned x, unsigned y) { return (y + (x & 319)) & 63; }
> +unsigned f17 (unsigned x, unsigned y) { unsigned m = 64, n = -128; return (y + (x | n)) & (m - 1); }
> +unsigned f18 (unsigned x, unsigned y) { return (y + (x | -128)) & 63; }
> +unsigned f19 (unsigned x, unsigned y) { unsigned m = 64, n = -384; return (y + (x ^ n)) & (m - 1); }
> +unsigned f20 (unsigned x, unsigned y) { return (y + (x ^ -384)) & 63; }
> +unsigned f21 (unsigned x, unsigned y) { unsigned m = 64, n = 256 | (m - 1); return ((x & n) - y) & (m - 1); }
> +unsigned f22 (unsigned x, unsigned y) { return ((x & 319) - y) & 63; }
> +unsigned f23 (unsigned x, unsigned y) { unsigned m = 64, n = -128; return ((x | n) - y) & (m - 1); }
> +unsigned f24 (unsigned x, unsigned y) { return ((x | -128) - y) & 63; }
> +unsigned f25 (unsigned x, unsigned y) { unsigned m = 64, n = -384; return ((x ^ n) - y) & (m - 1); }
> +unsigned f26 (unsigned x, unsigned y) { return ((x ^ -384) - y) & 63; }
> +unsigned f27 (unsigned x, unsigned y) { unsigned m = 64, n = 256 | (m - 1); return (y - (x & n)) & (m - 1); }
> +unsigned f28 (unsigned x, unsigned y) { return (y - (x & 319)) & 63; }
> +unsigned f29 (unsigned x, unsigned y) { unsigned m = 64, n = -128; return (y - (x | n)) & (m - 1); }
> +unsigned f30 (unsigned x, unsigned y) { return (y - (x | -128)) & 63; }
> +unsigned f31 (unsigned x, unsigned y) { unsigned m = 64, n = -384; return (y - (x ^ n)) & (m - 1); }
> +unsigned f32 (unsigned x, unsigned y) { return (y - (x ^ -384)) & 63; }
> +unsigned f33 (unsigned x) { unsigned m = 64, n = 256 | (m - 1); return (-(x & n)) & (m - 1); }
> +unsigned f34 (unsigned x) { return (-(x & 319)) & 63; }
> +unsigned f35 (unsigned x) { unsigned m = 64, n = -128; return (-(x | n)) & (m - 1); }
> +unsigned f36 (unsigned x) { return (-(x | -128)) & 63; }
> +unsigned f37 (unsigned x) { unsigned m = 64, n = -384; return (-(x ^ n)) & (m - 1); }
> +unsigned f38 (unsigned x) { return (-(x ^ -384)) & 63; }
> --- gcc/testsuite/gcc.dg/tree-ssa/pr86401-2.c.jj	2018-07-04 13:47:52.371002780 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr86401-2.c	2018-07-04 13:48:21.267032753 +0200
> @@ -0,0 +1,48 @@
> +/* PR tree-optimization/86401 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-not " \\+ 64" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "64 - " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\+ -64" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " & 319" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\| -128" "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " \\^ -384" "optimized" } } */
> +
> +int f1 (int x) { int m = 64; return (m + x) & (m - 1); }
> +int f2 (int x) { return (64 + x) & 63; }
> +int f3 (int x) { int m = 64; return (x + m) & (m - 1); }
> +int f4 (int x) { return (x + 64) & 63; }
> +int f5 (int x) { int m = 64; return (m - x) & (m - 1); }
> +int f6 (int x) { return (64 - x) & 63; }
> +int f7 (int x) { int m = 64; return (x - m) & (m - 1); }
> +int f8 (int x) { return (x - 64) & 63; }
> +int f9 (int x, int y) { int m = 64, n = 256 | (m - 1); return ((x & n) + y) & (m - 1); }
> +int f10 (int x, int y) { return ((x & 319) + y) & 63; }
> +int f11 (int x, int y) { int m = 64, n = -128; return ((x | n) + y) & (m - 1); }
> +int f12 (int x, int y) { return ((x | -128) + y) & 63; }
> +int f13 (int x, int y) { int m = 64, n = -384; return ((x ^ n) + y) & (m - 1); }
> +int f14 (int x, int y) { return ((x ^ -384) + y) & 63; }
> +int f15 (int x, int y) { int m = 64, n = 256 | (m - 1); return (y + (x & n)) & (m - 1); }
> +int f16 (int x, int y) { return (y + (x & 319)) & 63; }
> +int f17 (int x, int y) { int m = 64, n = -128; return (y + (x | n)) & (m - 1); }
> +int f18 (int x, int y) { return (y + (x | -128)) & 63; }
> +int f19 (int x, int y) { int m = 64, n = -384; return (y + (x ^ n)) & (m - 1); }
> +int f20 (int x, int y) { return (y + (x ^ -384)) & 63; }
> +int f21 (int x, int y) { int m = 64, n = 256 | (m - 1); return ((x & n) - y) & (m - 1); }
> +int f22 (int x, int y) { return ((x & 319) - y) & 63; }
> +int f23 (int x, int y) { int m = 64, n = -128; return ((x | n) - y) & (m - 1); }
> +int f24 (int x, int y) { return ((x | -128) - y) & 63; }
> +int f25 (int x, int y) { int m = 64, n = -384; return ((x ^ n) - y) & (m - 1); }
> +int f26 (int x, int y) { return ((x ^ -384) - y) & 63; }
> +int f27 (int x, int y) { int m = 64, n = 256 | (m - 1); return (y - (x & n)) & (m - 1); }
> +int f28 (int x, int y) { return (y - (x & 319)) & 63; }
> +int f29 (int x, int y) { int m = 64, n = -128; return (y - (x | n)) & (m - 1); }
> +int f30 (int x, int y) { return (y - (x | -128)) & 63; }
> +int f31 (int x, int y) { int m = 64, n = -384; return (y - (x ^ n)) & (m - 1); }
> +int f32 (int x, int y) { return (y - (x ^ -384)) & 63; }
> +int f33 (int x) { int m = 64, n = 256 | (m - 1); return (-(x & n)) & (m - 1); }
> +int f34 (int x) { return (-(x & 319)) & 63; }
> +int f35 (int x) { int m = 64, n = -128; return (-(x | n)) & (m - 1); }
> +int f36 (int x) { return (-(x | -128)) & 63; }
> +int f37 (int x) { int m = 64, n = -384; return (-(x ^ n)) & (m - 1); }
> +int f38 (int x) { return (-(x ^ -384)) & 63; }
> --- gcc/testsuite/c-c++-common/rotate-9.c.jj	2018-07-04 13:53:08.810330994 +0200
> +++ gcc/testsuite/c-c++-common/rotate-9.c	2018-07-04 13:53:35.481358656 +0200
> @@ -0,0 +1,19 @@
> +/* PR tree-optimization/86401 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 2 "optimized" } } */
> +
> +unsigned int
> +f1 (unsigned int x, unsigned int s)
> +{
> +  unsigned int t = s % (__CHAR_BIT__ * __SIZEOF_INT__);
> +  return (x << t) | (x >> (((__CHAR_BIT__ * __SIZEOF_INT__) - t) % (__CHAR_BIT__ * __SIZEOF_INT__)));
> +}
> +
> +unsigned int
> +f2 (unsigned int x, unsigned int s)
> +{
> +  int n = __CHAR_BIT__ * __SIZEOF_INT__;
> +  unsigned int t = s % n;
> +  return (x << t) | (x >> ((n - t) % n));
> +}
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]