From 51e020fc08daf1c62eb4d78cee4e8d2d0172c7e6 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Wed, 11 May 2011 14:13:38 +0000 Subject: [PATCH] re PR tree-optimization/15256 ([tree-ssa] Optimize manual bitfield manipilation.) 2011-05-11 Richard Guenther PR tree-optimization/15256 * tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize (A & B) | C, combine (A op CST1) op CST2. (tree_ssa_forward_propagate_single_use_vars): Only bother to visit assigns that have uses. * gcc.dg/tree-ssa/forwprop-14.c: New testcase. From-SVN: r173659 --- gcc/ChangeLog | 8 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c | 18 +++ gcc/tree-ssa-forwprop.c | 128 +++++++++++++++----- 4 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d4db4ef00a8..09654faf15d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2011-05-11 Richard Guenther + + PR tree-optimization/15256 + * tree-ssa-forwprop.c (simplify_bitwise_binary): Canonicalize + (A & B) | C, combine (A op CST1) op CST2. + (tree_ssa_forward_propagate_single_use_vars): Only bother to + visit assigns that have uses. + 2011-05-11 Nathan Froyd * ggc-page.c (extra_order_size_table): Use struct diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5fde36e00a3..a7e2261fa19 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-05-11 Richard Guenther + + PR tree-optimization/15256 + * gcc.dg/tree-ssa/forwprop-14.c: New testcase. + 2011-05-11 Jakub Jelinek PR debug/48159 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c new file mode 100644 index 00000000000..7432e0d5405 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +unsigned int +foo (unsigned int eax) +{ + eax |= 4; + eax &= 247; + eax |= 16; + eax &= 223; + eax |= 64; + eax &= 127; + return eax; +} + +/* { dg-final { scan-tree-dump-times " & " 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\\| " 1 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 02d95238866..605547081e4 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1623,6 +1623,9 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi) tree arg2 = gimple_assign_rhs2 (stmt); enum tree_code code = gimple_assign_rhs_code (stmt); tree res; + gimple def1 = NULL, def2 = NULL; + tree def1_arg1, def2_arg1; + enum tree_code def1_code, def2_code; /* If the first argument is an SSA name that is itself a result of a typecast of an ADDR_EXPR to an integer, feed the ADDR_EXPR to the @@ -1655,44 +1658,102 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi) } } + def1_code = TREE_CODE (arg1); + def1_arg1 = arg1; + if (TREE_CODE (arg1) == SSA_NAME) + { + def1 = SSA_NAME_DEF_STMT (arg1); + if (is_gimple_assign (def1)) + { + def1_code = gimple_assign_rhs_code (def1); + def1_arg1 = gimple_assign_rhs1 (def1); + } + } + + def2_code = TREE_CODE (arg2); + def2_arg1 = arg2; + if (TREE_CODE (arg2) == SSA_NAME) + { + def2 = SSA_NAME_DEF_STMT (arg2); + if (is_gimple_assign (def2)) + { + def2_code = gimple_assign_rhs_code (def2); + def2_arg1 = gimple_assign_rhs1 (def2); + } + } + /* For bitwise binary operations apply operand conversions to the binary operation result instead of to the operands. This allows to combine successive conversions and bitwise binary operations. */ - if (TREE_CODE (arg1) == SSA_NAME - && TREE_CODE (arg2) == SSA_NAME) + if (CONVERT_EXPR_CODE_P (def1_code) + && CONVERT_EXPR_CODE_P (def2_code) + && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1)) + /* Make sure that the conversion widens the operands or that it + changes the operation to a bitfield precision. */ + && ((TYPE_PRECISION (TREE_TYPE (def1_arg1)) + < TYPE_PRECISION (TREE_TYPE (arg1))) + || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1))) + != MODE_INT) + || (TYPE_PRECISION (TREE_TYPE (arg1)) + != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1)))))) { - gimple def_stmt1 = SSA_NAME_DEF_STMT (arg1); - gimple def_stmt2 = SSA_NAME_DEF_STMT (arg2); - if (is_gimple_assign (def_stmt1) - && is_gimple_assign (def_stmt2) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt1)) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2))) + gimple newop; + tree tem = create_tmp_reg (TREE_TYPE (def1_arg1), + NULL); + newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1); + tem = make_ssa_name (tem, newop); + gimple_assign_set_lhs (newop, tem); + gsi_insert_before (gsi, newop, GSI_SAME_STMT); + gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR, + tem, NULL_TREE, NULL_TREE); + update_stmt (gsi_stmt (*gsi)); + return true; + } + + /* (a | CST1) & CST2 -> (a & CST2) | (CST1 & CST2). */ + if (code == BIT_AND_EXPR + && def1_code == BIT_IOR_EXPR + && TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST) + { + tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2), + arg2, gimple_assign_rhs2 (def1)); + tree tem; + gimple newop; + if (integer_zerop (cst)) { - tree darg1 = gimple_assign_rhs1 (def_stmt1); - tree darg2 = gimple_assign_rhs1 (def_stmt2); - /* Make sure that the conversion widens the operands or that it - changes the operation to a bitfield precision. */ - if (types_compatible_p (TREE_TYPE (darg1), TREE_TYPE (darg2)) - && ((TYPE_PRECISION (TREE_TYPE (darg1)) - < TYPE_PRECISION (TREE_TYPE (arg1))) - || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1))) - != MODE_INT) - || (TYPE_PRECISION (TREE_TYPE (arg1)) - != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1)))))) - { - gimple newop; - tree tem = create_tmp_reg (TREE_TYPE (darg1), - NULL); - newop = gimple_build_assign_with_ops (code, tem, darg1, darg2); - tem = make_ssa_name (tem, newop); - gimple_assign_set_lhs (newop, tem); - gsi_insert_before (gsi, newop, GSI_SAME_STMT); - gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR, - tem, NULL_TREE, NULL_TREE); - update_stmt (gsi_stmt (*gsi)); - return true; - } + gimple_assign_set_rhs1 (stmt, def1_arg1); + update_stmt (stmt); + return true; } + tem = create_tmp_reg (TREE_TYPE (arg2), NULL); + newop = gimple_build_assign_with_ops (BIT_AND_EXPR, + tem, def1_arg1, arg2); + tem = make_ssa_name (tem, newop); + gimple_assign_set_lhs (newop, tem); + /* Make sure to re-process the new stmt as it's walking upwards. */ + gsi_insert_before (gsi, newop, GSI_NEW_STMT); + gimple_assign_set_rhs1 (stmt, tem); + gimple_assign_set_rhs2 (stmt, cst); + gimple_assign_set_rhs_code (stmt, BIT_IOR_EXPR); + update_stmt (stmt); + return true; + } + + /* Combine successive equal operations with constants. */ + if ((code == BIT_AND_EXPR + || code == BIT_IOR_EXPR + || code == BIT_XOR_EXPR) + && def1_code == code + && TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST) + { + tree cst = fold_build2 (code, TREE_TYPE (arg2), + arg2, gimple_assign_rhs2 (def1)); + gimple_assign_set_rhs1 (stmt, def1_arg1); + gimple_assign_set_rhs2 (stmt, cst); + update_stmt (stmt); + return true; } return false; @@ -2171,7 +2232,8 @@ tree_ssa_forward_propagate_single_use_vars (void) tree rhs = gimple_assign_rhs1 (stmt); enum tree_code code = gimple_assign_rhs_code (stmt); - if (TREE_CODE (lhs) != SSA_NAME) + if (TREE_CODE (lhs) != SSA_NAME + || has_zero_uses (lhs)) { gsi_next (&gsi); continue;