[backport from gcc-4.7/trunk r173659, fixes parts of PR15256, depends on pr15256-2-pr18041 patch ] Date: Wed, 11 May 2011 16:12:33 +0200 (CEST) From: Richard Guenther Subject: [PATCH] Fix parts of PR15256 List-Archive: This fixes parts of PR15256 - optimization of manual bitfield manipulation on the tree level. The patch extends the previous forwprop patch for this and adds two additional patterns we can easily match. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. gcc/ 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/testsuite/ 2011-05-11 Richard Guenther PR tree-optimization/15256 * gcc.dg/tree-ssa/forwprop-14.c: New testcase. --- gcc-4.6.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.6.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-14.c 2011-12-17 16:57:58.000000000 +0100 @@ -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" } } */ --- gcc-4.6.2/gcc/tree-ssa-forwprop.c.~1~ 2011-12-17 16:52:13.000000000 +0100 +++ gcc-4.6.2/gcc/tree-ssa-forwprop.c 2011-12-17 16:57:58.000000000 +0100 @@ -1623,6 +1623,9 @@ simplify_bitwise_binary (gimple_stmt_ite 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_ite } } + 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))) - { - 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 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)) + { + 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; @@ -2173,7 +2234,8 @@ tree_ssa_forward_propagate_single_use_va 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;