[backport from gcc-4.7/trunk r173650, fixes parts of PR18041, depends on pr15256-1 patch, depends on PR50213 patch ] Date: Tue, 10 May 2011 13:25:40 +0200 (CEST) From: Richard Guenther Subject: [PATCH] Fix tree parts of PR18041 List-Archive: This patch makes us apply operand conversions of bitwise binary operations to the operation result instead, which in turn allows us to combine those conversions which helps bitfield related operations. For struct B { unsigned bit0 : 1; unsigned bit1 : 1; }; void foo (struct B *b) { b->bit0 = b->bit0 | b->bit1; } we with this patch generate D.2686_2 = b_1(D)->bit0; D.2688_4 = b_1(D)->bit1; D.2693_10 = D.2688_4 ^ D.2686_2; b_1(D)->bit0 = D.2693_10; instead of D.2686_2 = b_1(D)->bit0; D.2687_3 = (unsigned char) D.2686_2; D.2688_4 = b_1(D)->bit1; D.2689_5 = (unsigned char) D.2688_4; D.2690_6 = D.2687_3 | D.2689_5; D.2691_7 = () D.2690_6; b_1(D)->bit0 = D.2691_7; which is shorter and easier to analyze. The generated code is the same though, and still contains too many masking operations. Bitfield lowering will expose more conversion combining opportunities similar to the above. Bootstrap and regtest pending on x86_64-unknown-linux-gnu. Richard. gcc/ 2011-05-11 Richard Guenther PR tree-optimization/18041 * tree-ssa-forwprop.c (simplify_bitwise_and): Rename to ... (simplify_bitwise_binary): ... this. Handle operand conversions by applying them to the result instead. (tree_ssa_forward_propagate_single_use_vars): Adjust. CSE tree code. gcc/testsuite/ 2011-05-11 Richard Guenther PR tree-optimization/18041 * gcc.dg/tree-ssa/forwprop-13.c: New testcase. --- gcc-4.6.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-13.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.6.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-13.c 2011-12-17 18:29:35.000000000 +0100 @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +struct B { + unsigned bit0 : 1; + unsigned bit1 : 1; +}; + +void +foo (struct B *b) +{ + b->bit0 = b->bit0 | b->bit1; +} + +/* { dg-final { scan-tree-dump-not "\\\(unsigned" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ --- gcc-4.6.2/gcc/tree-ssa-forwprop.c.~1~ 2011-12-17 18:27:47.000000000 +0100 +++ gcc-4.6.2/gcc/tree-ssa-forwprop.c 2011-12-17 18:31:00.000000000 +0100 @@ -1612,44 +1612,90 @@ simplify_builtin_call (gimple_stmt_itera return false; } -/* Run bitwise and assignments throug the folder. 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 folder rather than the ssa name. -*/ +/* Simplify bitwise binary operations. + Return true if a transformation applied, otherwise return false. */ -static void -simplify_bitwise_and (gimple_stmt_iterator *gsi, gimple stmt) +static bool +simplify_bitwise_binary (gimple_stmt_iterator *gsi) { - tree res; + gimple stmt = gsi_stmt (*gsi); tree arg1 = gimple_assign_rhs1 (stmt); tree arg2 = gimple_assign_rhs2 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); + tree res; - if (TREE_CODE (arg2) != INTEGER_CST) - return; - - if (TREE_CODE (arg1) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (arg1)) + /* 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 + folder rather than the ssa name. */ + if (code == BIT_AND_EXPR + && TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (arg1) == SSA_NAME) { gimple def = SSA_NAME_DEF_STMT (arg1); + tree op = arg1; - if (gimple_assign_cast_p (def) - && INTEGRAL_TYPE_P (gimple_expr_type (def))) + /* ??? This looks bogus - the conversion could be truncating. */ + if (is_gimple_assign (def) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def)) + && INTEGRAL_TYPE_P (TREE_TYPE (arg1))) { - tree op = gimple_assign_rhs1 (def); + tree opp = gimple_assign_rhs1 (def); + if (TREE_CODE (opp) == ADDR_EXPR) + op = opp; + } - if (TREE_CODE (op) == ADDR_EXPR) - arg1 = op; + res = fold_binary_loc (gimple_location (stmt), + BIT_AND_EXPR, TREE_TYPE (gimple_assign_lhs (stmt)), + op, arg2); + if (res && is_gimple_min_invariant (res)) + { + gimple_assign_set_rhs_from_tree (gsi, res); + update_stmt (stmt); + return true; } } - res = fold_binary_loc (gimple_location (stmt), - BIT_AND_EXPR, TREE_TYPE (gimple_assign_lhs (stmt)), - arg1, arg2); - if (res && is_gimple_min_invariant (res)) + /* 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) { - gimple_assign_set_rhs_from_tree (gsi, res); - update_stmt (stmt); + 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; + } + } } - return; + + return false; } @@ -2125,6 +2171,7 @@ tree_ssa_forward_propagate_single_use_va { tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); if (TREE_CODE (lhs) != SSA_NAME) { @@ -2132,10 +2179,10 @@ tree_ssa_forward_propagate_single_use_va continue; } - if (gimple_assign_rhs_code (stmt) == ADDR_EXPR + if (code == ADDR_EXPR /* Handle pointer conversions on invariant addresses as well, as this is valid gimple. */ - || (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) + || (CONVERT_EXPR_CODE_P (code) && TREE_CODE (rhs) == ADDR_EXPR && POINTER_TYPE_P (TREE_TYPE (lhs)))) { @@ -2153,7 +2200,7 @@ tree_ssa_forward_propagate_single_use_va else gsi_next (&gsi); } - else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) + else if (code == POINTER_PLUS_EXPR) { tree off = gimple_assign_rhs2 (stmt); if (TREE_CODE (off) == INTEGER_CST @@ -2187,14 +2234,14 @@ tree_ssa_forward_propagate_single_use_va else gsi_next (&gsi); } - else if ((gimple_assign_rhs_code (stmt) == BIT_NOT_EXPR - || gimple_assign_rhs_code (stmt) == NEGATE_EXPR) + else if ((code == BIT_NOT_EXPR + || code == NEGATE_EXPR) && TREE_CODE (rhs) == SSA_NAME) { simplify_not_neg_expr (&gsi); gsi_next (&gsi); } - else if (gimple_assign_rhs_code (stmt) == COND_EXPR) + else if (code == COND_EXPR) { /* In this case the entire COND_EXPR is in rhs1. */ int did_something; @@ -2207,27 +2254,28 @@ tree_ssa_forward_propagate_single_use_va && did_something, stmt, WARN_STRICT_OVERFLOW_CONDITIONAL); gsi_next (&gsi); } - else if (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) - == tcc_comparison) + else if (TREE_CODE_CLASS (code) == tcc_comparison) { if (forward_propagate_comparison (stmt)) cfg_changed = true; gsi_next (&gsi); } - else if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) + else if (code == BIT_AND_EXPR + || code == BIT_IOR_EXPR + || code == BIT_XOR_EXPR) { - simplify_bitwise_and (&gsi, stmt); - gsi_next (&gsi); + if (!simplify_bitwise_binary (&gsi)) + gsi_next (&gsi); } - else if (gimple_assign_rhs_code (stmt) == PLUS_EXPR - || gimple_assign_rhs_code (stmt) == MINUS_EXPR) + else if (code == PLUS_EXPR + || code == MINUS_EXPR) { cfg_changed |= associate_plusminus (stmt); gsi_next (&gsi); } - else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) - || gimple_assign_rhs_code (stmt) == FLOAT_EXPR - || gimple_assign_rhs_code (stmt) == FIX_TRUNC_EXPR) + else if (CONVERT_EXPR_CODE_P (code) + || code == FLOAT_EXPR + || code == FIX_TRUNC_EXPR) { if (!combine_conversions (&gsi)) gsi_next (&gsi);