aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorJames A. Morrison <phython@gcc.gnu.org>2005-06-12 08:03:23 +0000
committerJames A. Morrison <phython@gcc.gnu.org>2005-06-12 08:03:23 +0000
commit13d61949ea3014f28b9285218b1e5b096e06b321 (patch)
tree341f5a35ba0116afe7ce890b2b5c25eed5beff64 /gcc/fold-const.c
parent9401be5d1b5e97db751cf687deff5455d41cdb0b (diff)
2005-06-12 James A. Morrison <phython@gcc.gnu.org>
PR tree-optimization/14796 * fold-const.c (fold_binary): Transform (A >> C) << C into one BIT_AND_EXPR. <shift>: Transform (A OP c1) OP c2 into A OP (c1 + c2). git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@100853 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 96fffe995d4..1994410d4be 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -8742,6 +8742,59 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
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 >> c) << c into x & (-1<<c) */
+ 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;
+
+ if (low0 == low1)
+ {
+ 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);
+
+ 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)