From d12d8efea8fcb3122b78b3eafb7e35fe7ec2f4bd Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Mon, 30 May 2011 09:19:58 +0000 Subject: [PATCH] tree-ssa-forwprop.c (forward_propagate_into_comparison): New function split out from ... 2011-05-30 Richard Guenther * tree-ssa-forwprop.c (forward_propagate_into_comparison): New function split out from ... (forward_propagate_into_gimple_cond): ... here. Adjust. (forward_propagate_into_cond): Likewise. (forward_propagate_comparison): Also propagate into comparisons on assignment RHS. Change return value to behave similar to forward_propagate_into_cond. (tree_ssa_forward_propagate_single_use_vars): Handle strict-overflow warnings properly for forward_propagate_comparison. From-SVN: r174428 --- gcc/ChangeLog | 12 ++ gcc/tree-ssa-forwprop.c | 412 ++++++++++++++++++++-------------------- 2 files changed, 222 insertions(+), 202 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f4ec0bd327..55522d6d85e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2011-05-30 Richard Guenther + + * tree-ssa-forwprop.c (forward_propagate_into_comparison): + New function split out from ... + (forward_propagate_into_gimple_cond): ... here. Adjust. + (forward_propagate_into_cond): Likewise. + (forward_propagate_comparison): Also propagate into + comparisons on assignment RHS. Change return value to + behave similar to forward_propagate_into_cond. + (tree_ssa_forward_propagate_single_use_vars): Handle + strict-overflow warnings properly for forward_propagate_comparison. + 2011-05-30 Rainer Orth * configure.ac (gcc_cv_lto_plugin): Determine lto plugin support diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 605547081e4..ddc1ac4187d 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -387,6 +387,195 @@ combine_cond_expr_cond (location_t loc, enum tree_code code, tree type, return t; } +/* Combine the comparison OP0 CODE OP1 at LOC with the defining statements + of its operand. Return a new comparison tree or NULL_TREE if there + were no simplifying combines. */ + +static tree +forward_propagate_into_comparison (location_t loc, + enum tree_code code, tree type, + tree op0, tree op1) +{ + tree tmp = NULL_TREE; + tree rhs0 = NULL_TREE, rhs1 = NULL_TREE; + bool single_use0_p = false, single_use1_p = false; + + /* For comparisons use the first operand, that is likely to + simplify comparisons against constants. */ + if (TREE_CODE (op0) == SSA_NAME) + { + gimple def_stmt = get_prop_source_stmt (op0, false, &single_use0_p); + if (def_stmt && can_propagate_from (def_stmt)) + { + rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt); + tmp = combine_cond_expr_cond (loc, code, type, + rhs0, op1, !single_use0_p); + if (tmp) + return tmp; + } + } + + /* If that wasn't successful, try the second operand. */ + if (TREE_CODE (op1) == SSA_NAME) + { + gimple def_stmt = get_prop_source_stmt (op1, false, &single_use1_p); + if (def_stmt && can_propagate_from (def_stmt)) + { + rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt); + tmp = combine_cond_expr_cond (loc, code, type, + op0, rhs1, !single_use1_p); + if (tmp) + return tmp; + } + } + + /* If that wasn't successful either, try both operands. */ + if (rhs0 != NULL_TREE + && rhs1 != NULL_TREE) + tmp = combine_cond_expr_cond (loc, code, type, + rhs0, rhs1, + !(single_use0_p && single_use1_p)); + + return tmp; +} + +/* Forward propagate the comparison defined in STMT like + cond_1 = x CMP y to uses of the form + a_1 = (T')cond_1 + a_1 = !cond_1 + a_1 = cond_1 != 0 + Returns 1 if a transformation was done and 2 if the CFG should + be cleaned up. Else returns 0. */ + +static int +forward_propagate_comparison (gimple stmt) +{ + tree name = gimple_assign_lhs (stmt); + gimple use_stmt; + tree tmp = NULL_TREE; + int did_something = 0; + + /* Combine the comparison with defining statements. */ + do + { + tmp = forward_propagate_into_comparison (gimple_location (stmt), + gimple_assign_rhs_code (stmt), + TREE_TYPE (name), + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt)); + if (tmp) + { + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + bool inv = is_gimple_min_invariant (tmp); + gimple_assign_set_rhs_from_tree (&gsi, tmp); + gcc_assert (gsi_stmt (gsi) == stmt); + update_stmt (stmt); + did_something = MAX (did_something, inv ? 2 : 1); + if (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) != tcc_comparison) + return did_something; + } + } + while (tmp); + + /* Don't propagate ssa names that occur in abnormal phis. */ + if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt))) + || (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt)))) + return did_something; + + /* Do not un-cse comparisons. But propagate through copies. */ + use_stmt = get_prop_dest_stmt (name, &name); + if (!use_stmt) + return did_something; + + /* Conversion of the condition result to another integral type. */ + if (is_gimple_assign (use_stmt) + && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)) + || TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) + == tcc_comparison + || gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) + && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (use_stmt)))) + { + tree lhs = gimple_assign_lhs (use_stmt); + + /* We can propagate the condition into a conversion. */ + if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt))) + { + /* Avoid using fold here as that may create a COND_EXPR with + non-boolean condition as canonical form. */ + tmp = build2 (gimple_assign_rhs_code (stmt), TREE_TYPE (lhs), + gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt)); + } + /* We can propagate the condition into X op CST where op + is EQ_EXPR or NE_EXPR and CST is either one or zero. */ + else if (TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) + == tcc_comparison + && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == SSA_NAME + && TREE_CODE (gimple_assign_rhs2 (use_stmt)) == INTEGER_CST) + { + enum tree_code code = gimple_assign_rhs_code (use_stmt); + tree cst = gimple_assign_rhs2 (use_stmt); + tree cond; + + cond = build2 (gimple_assign_rhs_code (stmt), + TREE_TYPE (cst), + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt)); + + tmp = combine_cond_expr_cond (gimple_location (use_stmt), + code, TREE_TYPE (lhs), + cond, cst, false); + if (tmp == NULL_TREE) + return did_something; + } + /* We can propagate the condition into a statement that + computes the logical negation of the comparison result. */ + else if (gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) + { + tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); + bool nans = HONOR_NANS (TYPE_MODE (type)); + enum tree_code code; + code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans); + if (code == ERROR_MARK) + return did_something; + + tmp = build2 (code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt)); + } + else + return did_something; + + { + gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt); + bool inv = is_gimple_min_invariant (tmp); + gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp)); + did_something = MAX (did_something, inv ? 2 : 1); + use_stmt = gsi_stmt (gsi); + update_stmt (use_stmt); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + tree old_rhs = rhs_to_tree (TREE_TYPE (gimple_assign_lhs (stmt)), + stmt); + fprintf (dump_file, " Replaced '"); + print_generic_expr (dump_file, old_rhs, dump_flags); + fprintf (dump_file, "' with '"); + print_generic_expr (dump_file, tmp, dump_flags); + fprintf (dump_file, "'\n"); + } + + /* Remove defining statements. */ + if (remove_prop_source_from_use (name)) + did_something = 2; + else + did_something = MAX (did_something, 1); + } + + return did_something; +} + /* Propagate from the ssa name definition statements of COND_EXPR in GIMPLE_COND statement STMT into the conditional if that simplifies it. Returns zero if no statement was changed, one if there were @@ -402,52 +591,14 @@ forward_propagate_into_gimple_cond (gimple stmt) do { tree tmp = NULL_TREE; - tree name = NULL_TREE, rhs0 = NULL_TREE, rhs1 = NULL_TREE; - gimple def_stmt; - bool single_use0_p = false, single_use1_p = false; enum tree_code code = gimple_cond_code (stmt); /* We can do tree combining on SSA_NAME and comparison expressions. */ if (TREE_CODE_CLASS (gimple_cond_code (stmt)) == tcc_comparison) - { - /* For comparisons use the first operand, that is likely to - simplify comparisons against constants. */ - if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME) - { - name = gimple_cond_lhs (stmt); - def_stmt = get_prop_source_stmt (name, false, &single_use0_p); - if (def_stmt && can_propagate_from (def_stmt)) - { - tree op1 = gimple_cond_rhs (stmt); - rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt); - tmp = combine_cond_expr_cond (loc, code, boolean_type_node, - rhs0, op1, !single_use0_p); - } - } - /* If that wasn't successful, try the second operand. */ - if (tmp == NULL_TREE - && TREE_CODE (gimple_cond_rhs (stmt)) == SSA_NAME) - { - tree op0 = gimple_cond_lhs (stmt); - name = gimple_cond_rhs (stmt); - def_stmt = get_prop_source_stmt (name, false, &single_use1_p); - if (!def_stmt || !can_propagate_from (def_stmt)) - return did_something; - - rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt); - tmp = combine_cond_expr_cond (loc, code, boolean_type_node, op0, - rhs1, !single_use1_p); - } - /* If that wasn't successful either, try both operands. */ - if (tmp == NULL_TREE - && rhs0 != NULL_TREE - && rhs1 != NULL_TREE) - tmp = combine_cond_expr_cond (loc, code, boolean_type_node, rhs0, - fold_convert_loc (loc, - TREE_TYPE (rhs0), - rhs1), - !(single_use0_p && single_use1_p)); - } + tmp = forward_propagate_into_comparison (loc, code, + boolean_type_node, + gimple_cond_lhs (stmt), + gimple_cond_rhs (stmt)); if (tmp) { @@ -468,8 +619,7 @@ forward_propagate_into_gimple_cond (gimple stmt) update_stmt (stmt); /* Remove defining statements. */ - if (remove_prop_source_from_use (name) - || is_gimple_min_invariant (tmp)) + if (is_gimple_min_invariant (tmp)) did_something = 2; else if (did_something == 0) did_something = 1; @@ -502,57 +652,17 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p) do { tree tmp = NULL_TREE; tree cond = gimple_assign_rhs1 (stmt); - tree name, rhs0 = NULL_TREE, rhs1 = NULL_TREE; - gimple def_stmt; - bool single_use0_p = false, single_use1_p = false; /* We can do tree combining on SSA_NAME and comparison expressions. */ - if (COMPARISON_CLASS_P (cond) - && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME) - { - /* For comparisons use the first operand, that is likely to - simplify comparisons against constants. */ - name = TREE_OPERAND (cond, 0); - def_stmt = get_prop_source_stmt (name, false, &single_use0_p); - if (def_stmt && can_propagate_from (def_stmt)) - { - tree op1 = TREE_OPERAND (cond, 1); - rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt); - tmp = combine_cond_expr_cond (loc, TREE_CODE (cond), - boolean_type_node, - rhs0, op1, !single_use0_p); - } - /* If that wasn't successful, try the second operand. */ - if (tmp == NULL_TREE - && TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME) - { - tree op0 = TREE_OPERAND (cond, 0); - name = TREE_OPERAND (cond, 1); - def_stmt = get_prop_source_stmt (name, false, &single_use1_p); - if (!def_stmt || !can_propagate_from (def_stmt)) - return did_something; - - rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt); - tmp = combine_cond_expr_cond (loc, TREE_CODE (cond), - boolean_type_node, - op0, rhs1, !single_use1_p); - } - /* If that wasn't successful either, try both operands. */ - if (tmp == NULL_TREE - && rhs0 != NULL_TREE - && rhs1 != NULL_TREE) - tmp = combine_cond_expr_cond (loc, TREE_CODE (cond), - boolean_type_node, - rhs0, - fold_convert_loc (loc, - TREE_TYPE (rhs0), - rhs1), - !(single_use0_p && single_use1_p)); - } + if (COMPARISON_CLASS_P (cond)) + tmp = forward_propagate_into_comparison (loc, TREE_CODE (cond), + boolean_type_node, + TREE_OPERAND (cond, 0), + TREE_OPERAND (cond, 1)); else if (TREE_CODE (cond) == SSA_NAME) { - name = cond; - def_stmt = get_prop_source_stmt (name, true, NULL); + tree name = cond, rhs0; + gimple def_stmt = get_prop_source_stmt (name, true, NULL); if (!def_stmt || !can_propagate_from (def_stmt)) return did_something; @@ -578,8 +688,7 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p) update_stmt (stmt); /* Remove defining statements. */ - if (remove_prop_source_from_use (name) - || is_gimple_min_invariant (tmp)) + if (is_gimple_min_invariant (tmp)) did_something = 2; else if (did_something == 0) did_something = 1; @@ -1115,114 +1224,6 @@ forward_propagate_addr_expr (tree name, tree rhs) return all && has_zero_uses (name); } -/* Forward propagate the comparison defined in STMT like - cond_1 = x CMP y to uses of the form - a_1 = (T')cond_1 - a_1 = !cond_1 - a_1 = cond_1 != 0 - Returns true if stmt is now unused. */ - -static bool -forward_propagate_comparison (gimple stmt) -{ - tree name = gimple_assign_lhs (stmt); - gimple use_stmt; - tree tmp = NULL_TREE; - - /* Don't propagate ssa names that occur in abnormal phis. */ - if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt))) - || (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt)))) - return false; - - /* Do not un-cse comparisons. But propagate through copies. */ - use_stmt = get_prop_dest_stmt (name, &name); - if (!use_stmt) - return false; - - /* Conversion of the condition result to another integral type. */ - if (is_gimple_assign (use_stmt) - && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)) - || TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) - == tcc_comparison - || gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) - && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (use_stmt)))) - { - tree lhs = gimple_assign_lhs (use_stmt); - - /* We can propagate the condition into a conversion. */ - if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt))) - { - /* Avoid using fold here as that may create a COND_EXPR with - non-boolean condition as canonical form. */ - tmp = build2 (gimple_assign_rhs_code (stmt), TREE_TYPE (lhs), - gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt)); - } - /* We can propagate the condition into X op CST where op - is EQ_EXPR or NE_EXPR and CST is either one or zero. */ - else if (TREE_CODE_CLASS (gimple_assign_rhs_code (use_stmt)) - == tcc_comparison - && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == SSA_NAME - && TREE_CODE (gimple_assign_rhs2 (use_stmt)) == INTEGER_CST) - { - enum tree_code code = gimple_assign_rhs_code (use_stmt); - tree cst = gimple_assign_rhs2 (use_stmt); - tree cond; - - cond = build2 (gimple_assign_rhs_code (stmt), - TREE_TYPE (cst), - gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - - tmp = combine_cond_expr_cond (gimple_location (use_stmt), - code, TREE_TYPE (lhs), - cond, cst, false); - if (tmp == NULL_TREE) - return false; - } - /* We can propagate the condition into a statement that - computes the logical negation of the comparison result. */ - else if (gimple_assign_rhs_code (use_stmt) == TRUTH_NOT_EXPR) - { - tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); - bool nans = HONOR_NANS (TYPE_MODE (type)); - enum tree_code code; - code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans); - if (code == ERROR_MARK) - return false; - - tmp = build2 (code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - } - else - return false; - - { - gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt); - gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp)); - use_stmt = gsi_stmt (gsi); - update_stmt (use_stmt); - } - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - tree old_rhs = rhs_to_tree (TREE_TYPE (gimple_assign_lhs (stmt)), - stmt); - fprintf (dump_file, " Replaced '"); - print_generic_expr (dump_file, old_rhs, dump_flags); - fprintf (dump_file, "' with '"); - print_generic_expr (dump_file, tmp, dump_flags); - fprintf (dump_file, "'\n"); - } - - /* Remove defining statements. */ - return remove_prop_source_from_use (name); - } - - return false; -} - /* If we have lhs = ~x (STMT), look and see if earlier we had x = ~y. If so, we can change STMT into lhs = y which can later be copy propagated. Similarly for negation. @@ -2314,8 +2315,15 @@ tree_ssa_forward_propagate_single_use_vars (void) } else if (TREE_CODE_CLASS (code) == tcc_comparison) { - if (forward_propagate_comparison (stmt)) + bool no_warning = gimple_no_warning_p (stmt); + int did_something; + fold_defer_overflow_warnings (); + did_something = forward_propagate_comparison (stmt); + if (did_something == 2) cfg_changed = true; + fold_undefer_overflow_warnings + (!no_warning && did_something, + stmt, WARN_STRICT_OVERFLOW_CONDITIONAL); gsi_next (&gsi); } else if (code == BIT_AND_EXPR -- 2.30.2