return true;
}
-/* Remove a copy chain ending in NAME along the defs.
+/* Remove a chain of dead statements starting at the definition of
+ NAME. The chain is linked via the first operand of the defining statements.
If NAME was replaced in its only use then this function can be used
- to clean up dead stmts. Returns true if cleanup-cfg has to run. */
+ to clean up dead stmts. The function handles already released SSA
+ names gracefully.
+ Returns true if cleanup-cfg has to run. */
static bool
remove_prop_source_from_use (tree name)
do {
basic_block bb;
- if (!has_zero_uses (name))
+ if (SSA_NAME_IN_FREE_LIST (name)
+ || SSA_NAME_IS_DEFAULT_DEF (name)
+ || !has_zero_uses (name))
return cfg_changed;
stmt = SSA_NAME_DEF_STMT (name);
- bb = gimple_bb (stmt);
- if (!bb)
+ if (gimple_code (stmt) == GIMPLE_PHI
+ || gimple_has_side_effects (stmt))
return cfg_changed;
+
+ bb = gimple_bb (stmt);
gsi = gsi_for_stmt (stmt);
- release_defs (stmt);
+ unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
+ release_defs (stmt);
cfg_changed |= gimple_purge_dead_eh_edges (bb);
- name = (gimple_assign_copy_p (stmt)) ? gimple_assign_rhs1 (stmt) : NULL;
+ name = is_gimple_assign (stmt) ? gimple_assign_rhs1 (stmt) : NULL_TREE;
} while (name && TREE_CODE (name) == SSA_NAME);
return cfg_changed;
considered simplified. */
static tree
-combine_cond_expr_cond (location_t loc, enum tree_code code, tree type,
+combine_cond_expr_cond (gimple stmt, enum tree_code code, tree type,
tree op0, tree op1, bool invariant_only)
{
tree t;
gcc_assert (TREE_CODE_CLASS (code) == tcc_comparison);
- t = fold_binary_loc (loc, code, type, op0, op1);
+ fold_defer_overflow_warnings ();
+ t = fold_binary_loc (gimple_location (stmt), code, type, op0, op1);
if (!t)
- return NULL_TREE;
+ {
+ fold_undefer_overflow_warnings (false, NULL, 0);
+ return NULL_TREE;
+ }
/* Require that we got a boolean type out if we put one in. */
gcc_assert (TREE_CODE (TREE_TYPE (t)) == TREE_CODE (type));
/* Bail out if we required an invariant but didn't get one. */
if (!t || (invariant_only && !is_gimple_min_invariant (t)))
- return NULL_TREE;
+ {
+ fold_undefer_overflow_warnings (false, NULL, 0);
+ return NULL_TREE;
+ }
+
+ fold_undefer_overflow_warnings (!gimple_no_warning_p (stmt), stmt, 0);
return t;
}
were no simplifying combines. */
static tree
-forward_propagate_into_comparison_1 (location_t loc,
+forward_propagate_into_comparison_1 (gimple stmt,
enum tree_code code, tree type,
tree op0, tree op1)
{
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,
+ tmp = combine_cond_expr_cond (stmt, code, type,
rhs0, op1, !single_use0_p);
if (tmp)
return tmp;
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,
+ tmp = combine_cond_expr_cond (stmt, 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,
+ tmp = combine_cond_expr_cond (stmt, code, type,
rhs0, rhs1,
!(single_use0_p && single_use1_p));
tree rhs2 = gimple_assign_rhs2 (stmt);
/* Combine the comparison with defining statements. */
- tmp = forward_propagate_into_comparison_1 (gimple_location (stmt),
+ tmp = forward_propagate_into_comparison_1 (stmt,
gimple_assign_rhs_code (stmt),
TREE_TYPE
(gimple_assign_lhs (stmt)),
if (tmp)
{
gimple_assign_set_rhs_from_tree (gsi, tmp);
- update_stmt (stmt);
+ fold_stmt (gsi);
+ update_stmt (gsi_stmt (*gsi));
+
if (TREE_CODE (rhs1) == SSA_NAME)
cfg_changed |= remove_prop_source_from_use (rhs1);
if (TREE_CODE (rhs2) == SSA_NAME)
static int
forward_propagate_into_gimple_cond (gimple stmt)
{
- location_t loc = gimple_location (stmt);
tree tmp;
enum tree_code code = gimple_cond_code (stmt);
bool cfg_changed = false;
if (TREE_CODE_CLASS (gimple_cond_code (stmt)) != tcc_comparison)
return 0;
- tmp = forward_propagate_into_comparison_1 (loc, code,
+ tmp = forward_propagate_into_comparison_1 (stmt, code,
boolean_type_node,
rhs1, rhs2);
if (tmp)
return (cfg_changed || is_gimple_min_invariant (tmp)) ? 2 : 1;
}
+ /* Canonicalize _Bool == 0 and _Bool != 1 to _Bool != 0 by swapping edges. */
+ if ((TREE_CODE (TREE_TYPE (rhs1)) == BOOLEAN_TYPE
+ || (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+ && TYPE_PRECISION (TREE_TYPE (rhs1)) == 1))
+ && ((code == EQ_EXPR
+ && integer_zerop (rhs2))
+ || (code == NE_EXPR
+ && integer_onep (rhs2))))
+ {
+ basic_block bb = gimple_bb (stmt);
+ gimple_cond_set_code (stmt, NE_EXPR);
+ gimple_cond_set_rhs (stmt, build_zero_cst (TREE_TYPE (rhs1)));
+ EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
+ EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
+ return 1;
+ }
+
return 0;
}
/* Propagate from the ssa name definition statements of COND_EXPR
in the rhs of statement STMT into the conditional if that simplifies it.
- Returns zero if no statement was changed, one if there were
- changes and two if cfg_cleanup needs to run.
-
- This must be kept in sync with forward_propagate_into_gimple_cond. */
+ Returns true zero if the stmt was changed. */
-static int
+static bool
forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
{
gimple stmt = gsi_stmt (*gsi_p);
- location_t loc = gimple_location (stmt);
tree tmp = NULL_TREE;
tree cond = gimple_assign_rhs1 (stmt);
+ bool swap = false;
/* We can do tree combining on SSA_NAME and comparison expressions. */
if (COMPARISON_CLASS_P (cond))
- tmp = forward_propagate_into_comparison_1 (loc, TREE_CODE (cond),
+ tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
boolean_type_node,
TREE_OPERAND (cond, 0),
TREE_OPERAND (cond, 1));
else if (TREE_CODE (cond) == SSA_NAME)
{
- tree name = cond, rhs0;
+ enum tree_code code;
+ tree name = cond;
gimple def_stmt = get_prop_source_stmt (name, true, NULL);
if (!def_stmt || !can_propagate_from (def_stmt))
return 0;
- rhs0 = gimple_assign_rhs1 (def_stmt);
- tmp = combine_cond_expr_cond (loc, NE_EXPR, boolean_type_node, rhs0,
- build_int_cst (TREE_TYPE (rhs0), 0),
- false);
+ code = gimple_assign_rhs_code (def_stmt);
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ tmp = fold_build2_loc (gimple_location (def_stmt),
+ code,
+ boolean_type_node,
+ gimple_assign_rhs1 (def_stmt),
+ gimple_assign_rhs2 (def_stmt));
+ else if ((code == BIT_NOT_EXPR
+ && TYPE_PRECISION (TREE_TYPE (cond)) == 1)
+ || (code == BIT_XOR_EXPR
+ && integer_onep (gimple_assign_rhs2 (def_stmt))))
+ {
+ tmp = gimple_assign_rhs1 (def_stmt);
+ swap = true;
+ }
}
if (tmp)
fprintf (dump_file, "'\n");
}
- gimple_assign_set_rhs_from_tree (gsi_p, unshare_expr (tmp));
+ if (integer_onep (tmp))
+ gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs2 (stmt));
+ else if (integer_zerop (tmp))
+ gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs3 (stmt));
+ else
+ {
+ gimple_assign_set_rhs1 (stmt, unshare_expr (tmp));
+ if (swap)
+ {
+ tree t = gimple_assign_rhs2 (stmt);
+ gimple_assign_set_rhs2 (stmt, gimple_assign_rhs3 (stmt));
+ gimple_assign_set_rhs3 (stmt, t);
+ }
+ }
stmt = gsi_stmt (*gsi_p);
update_stmt (stmt);
- return is_gimple_min_invariant (tmp) ? 2 : 1;
+ return true;
}
return 0;
}
}
gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
- use_stmt = gsi_stmt (*use_stmt_gsi);
-
- /* That should have created gimple, so there is no need to
- record information to undo the propagation. */
- fold_stmt_inplace (use_stmt);
- tidy_after_forward_propagate_addr (use_stmt);
+ fold_stmt (use_stmt_gsi);
+ tidy_after_forward_propagate_addr (gsi_stmt (*use_stmt_gsi));
return true;
}
}
*def_rhs_basep = build2 (MEM_REF, TREE_TYPE (*def_rhs_basep),
new_base, new_offset);
+ TREE_THIS_VOLATILE (*def_rhs_basep) = TREE_THIS_VOLATILE (lhs);
+ TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (lhs);
gimple_assign_set_lhs (use_stmt,
unshare_expr (TREE_OPERAND (def_rhs, 0)));
*def_rhs_basep = saved;
TREE_OPERAND (rhs, 0) = new_ptr;
TREE_OPERAND (rhs, 1)
= double_int_to_tree (TREE_TYPE (TREE_OPERAND (rhs, 1)), off);
- fold_stmt_inplace (use_stmt);
+ fold_stmt_inplace (use_stmt_gsi);
tidy_after_forward_propagate_addr (use_stmt);
return res;
}
- /* If the LHS is a plain dereference and the value type is the same as
+ /* If the RHS is a plain dereference and the value type is the same as
that of the pointed-to type of the address we can put the
- dereferenced address on the LHS preserving the original alias-type. */
+ dereferenced address on the RHS preserving the original alias-type. */
else if (gimple_assign_rhs1 (use_stmt) == rhs
&& useless_type_conversion_p
(TREE_TYPE (gimple_assign_lhs (use_stmt)),
}
*def_rhs_basep = build2 (MEM_REF, TREE_TYPE (*def_rhs_basep),
new_base, new_offset);
+ TREE_THIS_VOLATILE (*def_rhs_basep) = TREE_THIS_VOLATILE (rhs);
+ TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (rhs);
gimple_assign_set_rhs1 (use_stmt,
unshare_expr (TREE_OPERAND (def_rhs, 0)));
*def_rhs_basep = saved;
- fold_stmt_inplace (use_stmt);
+ fold_stmt_inplace (use_stmt_gsi);
tidy_after_forward_propagate_addr (use_stmt);
return res;
}
return false;
rhs2 = gimple_assign_rhs2 (use_stmt);
- /* Try to optimize &x[C1] p+ C2 where C2 is a multiple of the size
- of the elements in X into &x[C1 + C2/element size]. */
+ /* Optimize &x[C1] p+ C2 to &x p+ C3 with C3 = C1 * element_size + C2. */
if (TREE_CODE (rhs2) == INTEGER_CST)
{
- tree new_rhs = maybe_fold_stmt_addition (gimple_location (use_stmt),
- TREE_TYPE (def_rhs),
- def_rhs, rhs2);
- if (new_rhs)
- {
- tree type = TREE_TYPE (gimple_assign_lhs (use_stmt));
- new_rhs = unshare_expr (new_rhs);
- if (!useless_type_conversion_p (type, TREE_TYPE (new_rhs)))
- {
- if (!is_gimple_min_invariant (new_rhs))
- new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs,
- true, NULL_TREE,
- true, GSI_SAME_STMT);
- new_rhs = fold_convert (type, new_rhs);
- }
- gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
- use_stmt = gsi_stmt (*use_stmt_gsi);
- update_stmt (use_stmt);
- tidy_after_forward_propagate_addr (use_stmt);
- return true;
- }
+ tree new_rhs = build1_loc (gimple_location (use_stmt),
+ ADDR_EXPR, TREE_TYPE (def_rhs),
+ fold_build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (def_rhs)),
+ unshare_expr (def_rhs),
+ fold_convert (ptr_type_node,
+ rhs2)));
+ gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
+ use_stmt = gsi_stmt (*use_stmt_gsi);
+ update_stmt (use_stmt);
+ tidy_after_forward_propagate_addr (use_stmt);
+ return true;
}
/* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by
|| use_stmt != stmt2))
break;
- ptr1_align = get_pointer_alignment (ptr1, BIGGEST_ALIGNMENT);
+ ptr1_align = get_pointer_alignment (ptr1);
/* Construct the new source string literal. */
src_buf = XALLOCAVEC (char, src_len + 1);
if (callee1)
always permitted. Returns true if the CFG was changed. */
static bool
-associate_plusminus (gimple stmt)
+associate_plusminus (gimple_stmt_iterator *gsi)
{
+ gimple stmt = gsi_stmt (*gsi);
tree rhs1 = gimple_assign_rhs1 (stmt);
tree rhs2 = gimple_assign_rhs2 (stmt);
enum tree_code code = gimple_assign_rhs_code (stmt);
- gimple_stmt_iterator gsi;
bool changed;
/* We can't reassociate at all for saturating types. */
via commutating the addition and contracting operations to zero
by reassociation. */
- gsi = gsi_for_stmt (stmt);
if (TREE_CODE (rhs1) == SSA_NAME)
{
gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
? TREE_CODE (def_rhs2) : NEGATE_EXPR);
rhs1 = def_rhs2;
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
else if (operand_equal_p (def_rhs2, rhs2, 0)
code = TREE_CODE (def_rhs1);
rhs1 = def_rhs1;
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
else if (TREE_CODE (rhs2) == INTEGER_CST
code = INTEGER_CST;
rhs1 = build_int_cst_type (TREE_TYPE (rhs2), -1);
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
else if (code == PLUS_EXPR
code = NEGATE_EXPR;
rhs1 = def_rhs1;
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
}
? NEGATE_EXPR : TREE_CODE (def_rhs2));
rhs1 = def_rhs2;
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
else if (operand_equal_p (def_rhs2, rhs1, 0)
? TREE_CODE (def_rhs1) : NEGATE_EXPR);
rhs1 = def_rhs1;
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
else if (TREE_CODE (rhs1) == INTEGER_CST
code = INTEGER_CST;
rhs1 = build_int_cst_type (TREE_TYPE (rhs1), -1);
rhs2 = NULL_TREE;
- gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE);
- gcc_assert (gsi_stmt (gsi) == stmt);
+ gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
+ gcc_assert (gsi_stmt (*gsi) == stmt);
gimple_set_modified (stmt, true);
}
}
out:
if (gimple_modified_p (stmt))
{
- fold_stmt_inplace (stmt);
+ fold_stmt_inplace (gsi);
update_stmt (stmt);
if (maybe_clean_or_replace_eh_stmt (stmt, stmt)
&& gimple_purge_dead_eh_edges (gimple_bb (stmt)))
else
gsi_next (&gsi);
}
- else if (code == POINTER_PLUS_EXPR && can_propagate_from (stmt))
+ else if (code == POINTER_PLUS_EXPR)
{
- if (TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST
+ tree off = gimple_assign_rhs2 (stmt);
+ if (TREE_CODE (off) == INTEGER_CST
+ && can_propagate_from (stmt)
+ && !simple_iv_increment_p (stmt)
/* ??? Better adjust the interface to that function
instead of building new trees here. */
&& forward_propagate_addr_expr
- (lhs,
- build1 (ADDR_EXPR,
- TREE_TYPE (rhs),
- fold_build2 (MEM_REF,
- TREE_TYPE (TREE_TYPE (rhs)),
- rhs,
- fold_convert
- (ptr_type_node,
- gimple_assign_rhs2 (stmt))))))
+ (lhs,
+ build1_loc (gimple_location (stmt),
+ ADDR_EXPR, TREE_TYPE (rhs),
+ fold_build2 (MEM_REF,
+ TREE_TYPE (TREE_TYPE (rhs)),
+ rhs,
+ fold_convert (ptr_type_node,
+ off)))))
{
release_defs (stmt);
todoflags |= TODO_remove_unused_locals;
else if (is_gimple_min_invariant (rhs))
{
/* Make sure to fold &a[0] + off_1 here. */
- fold_stmt_inplace (stmt);
+ fold_stmt_inplace (&gsi);
update_stmt (stmt);
if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
gsi_next (&gsi);
}
else if (TREE_CODE_CLASS (code) == tcc_comparison)
{
- forward_propagate_comparison (stmt);
+ if (forward_propagate_comparison (stmt))
+ cfg_changed = true;
gsi_next (&gsi);
}
else
else if (code == COND_EXPR)
{
/* In this case the entire COND_EXPR is in rhs1. */
- int did_something;
- fold_defer_overflow_warnings ();
- did_something = forward_propagate_into_cond (&gsi);
+ changed |= forward_propagate_into_cond (&gsi);
stmt = gsi_stmt (gsi);
- if (did_something == 2)
- cfg_changed = true;
- fold_undefer_overflow_warnings
- (!TREE_NO_WARNING (rhs1) && did_something, stmt,
- WARN_STRICT_OVERFLOW_CONDITIONAL);
- changed = did_something != 0;
}
else if (TREE_CODE_CLASS (code) == tcc_comparison)
{
- bool no_warning = gimple_no_warning_p (stmt);
int did_something;
- fold_defer_overflow_warnings ();
did_something = forward_propagate_into_comparison (&gsi);
if (did_something == 2)
cfg_changed = true;
- fold_undefer_overflow_warnings
- (!no_warning && changed,
- stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
changed = did_something != 0;
}
else if (code == BIT_AND_EXPR
changed = simplify_bitwise_binary (&gsi);
else if (code == PLUS_EXPR
|| code == MINUS_EXPR)
- changed = associate_plusminus (stmt);
+ changed = associate_plusminus (&gsi);
else if (CONVERT_EXPR_CODE_P (code)
|| code == FLOAT_EXPR
|| code == FIX_TRUNC_EXPR)
case GIMPLE_COND:
{
int did_something;
- fold_defer_overflow_warnings ();
did_something = forward_propagate_into_gimple_cond (stmt);
if (did_something == 2)
cfg_changed = true;
- fold_undefer_overflow_warnings
- (did_something, stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
changed = did_something != 0;
break;
}