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]

[patch] Fix pr14796


 Hi,

  This patch adds some transformations for shifts and rotates such as
(a << c1) << c2 to a << (c1+c2).  This patch has been bootstrapped and
regtested on ia64-linux with no new regressions.  Ok for mainline?

-- 
Thanks,
Jim

http://www.csclub.uwaterloo.ca/~ja2morri/
http://phython.blogspot.com
http://open.nit.ca/wiki/?page=jim
2005-06-09  James A. Morrison  <phython@gcc.gnu.org>

	* fold-const.c (fold_binary): Transform (A >> C1) << C2 into
	one BIT_AND_EXPR and a SHIFT_EXPR, if needed.
	<shift>: Transform (A OP c1) OP c2 into A OP (c1 + c2).

Index: fold-const.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.592
diff -u -p -r1.592 fold-const.c
--- fold-const.c	6 Jun 2005 19:25:45 -0000	1.592
+++ fold-const.c	9 Jun 2005 12:48:57 -0000
@@ -8742,6 +8765,69 @@ fold_binary (enum tree_code code, tree t
 	 don't try to compute it in the compiler.  */
       if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
 	return NULL_TREE;
+
+      /* Turn (a OP c1) OP c2 into a OP (c1+c2).  */
+      if (TREE_CODE (arg0) == code && host_integerp (arg1, false)
+	  && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+	  && host_integerp (TREE_OPERAND (arg0, 1), false)
+	  && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+	{
+	  HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
+			       + TREE_INT_CST_LOW (arg1));
+
+	  /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
+	     being well defined.  */
+	  if (low >= TYPE_PRECISION (type))
+	    {
+	      if (code == LROTATE_EXPR || code == RROTATE_EXPR)
+	        low = low % TYPE_PRECISION (type);
+	      else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
+	        return build_int_cst (type, 0);
+	      else
+		low = TYPE_PRECISION (type) - 1;
+	    }
+
+	  return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+			      build_int_cst (type, low));
+	}
+
+      /* Transform (x >> c1) << c2...  */
+      if (code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR
+	  && host_integerp (arg1, false)
+	  && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+	  && host_integerp (TREE_OPERAND (arg0, 1), false)
+	  && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+	{
+	  HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
+	  HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
+	  unsigned HOST_WIDE_INT low;
+	  HOST_WIDE_INT high;
+	  tree lshift;
+	  tree arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
+
+	  lshift_double (-1, -1, low0 < low1 ? low0 : low1,
+			 TYPE_PRECISION (type), &low, &high, 1);
+	  lshift = build_int_cst_wide (type, low, high);
+
+	  if (low0 > low1)
+	    /*  ...into (x >> (c1 - c2)) & (-1<<c2).  */
+	    return fold_build2 (BIT_AND_EXPR, type,
+				fold_build2 (RSHIFT_EXPR, type, arg00,
+					     build_int_cst (type,
+							    low0 - low1)),
+				lshift);
+	  else if (low0 < low1)
+	    /*  ...into (x & (-1<<c1)) << (c2 - c1).  */
+	    return fold_build2 (LSHIFT_EXPR, type,
+				fold_build2 (BIT_AND_EXPR, type, arg00,
+					     lshift),
+				build_int_cst (type, low1 - low0));
+	  else
+	    /*  ...into x & (-1 << c), since c1 == c2.  */
+	    return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
+	} 
+
+
       /* Rewrite an LROTATE_EXPR by a constant into an
 	 RROTATE_EXPR by a new constant.  */
       if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f (int a) {
	return (a << 3) << 6;
}

int g (int b) {
	return (b >> 5) << 5;
}

int h (int c) {
	return (c >> 3) << 2;
}

int j (int d) {
	return (d >> 2) << 3;
}
/* { dg-final { scan-tree-dump "a << 9" "gimple" } } */
/* { dg-final { scan-tree-dump "b & -32" "gimple" } } */
/* { dg-final { scan-tree-dump "c >> 1" "gimple" } } */
/* { dg-final { scan-tree-dump "d & -4" "gimple" } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f (int a) {
	return (a << 31) << 6;
}

unsigned int g (unsigned int a) {
	return (a >> 7) >> 25;
}

int h (int b) {
	return (b >> 30) >> 30;
}

long long j (long long c) {
	return (c >> 35) << 35;
}
/* { dg-final { scan-tree-dump-times "= 0" 2 "gimple" } } */
/* { dg-final { scan-tree-dump "b >> 31" "gimple" } } */
/* { dg-final { scan-tree-dump "c & -34359738368" "gimple" } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */

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