diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
commit | e252b51ccde010cbd2a146485d8045103cd99533 (patch) | |
tree | e060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/tree-ssa-propagate.c | |
parent | f10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff) | |
parent | 104c05c5284b7822d770ee51a7d91946c7e56d50 (diff) | |
download | gcc-e252b51ccde010cbd2a146485d8045103cd99533.zip gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2 |
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/tree-ssa-propagate.c')
-rw-r--r-- | gcc/tree-ssa-propagate.c | 307 |
1 files changed, 3 insertions, 304 deletions
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index def16c0..6d19410 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -439,302 +439,6 @@ ssa_prop_fini (void) } -/* Return true if EXPR is an acceptable right-hand-side for a - GIMPLE assignment. We validate the entire tree, not just - the root node, thus catching expressions that embed complex - operands that are not permitted in GIMPLE. This function - is needed because the folding routines in fold-const.c - may return such expressions in some cases, e.g., an array - access with an embedded index addition. It may make more - sense to have folding routines that are sensitive to the - constraints on GIMPLE operands, rather than abandoning any - any attempt to fold if the usual folding turns out to be too - aggressive. */ - -bool -valid_gimple_rhs_p (tree expr) -{ - enum tree_code code = TREE_CODE (expr); - - switch (TREE_CODE_CLASS (code)) - { - case tcc_declaration: - if (!is_gimple_variable (expr)) - return false; - break; - - case tcc_constant: - /* All constants are ok. */ - break; - - case tcc_comparison: - /* GENERIC allows comparisons with non-boolean types, reject - those for GIMPLE. Let vector-typed comparisons pass - rules - for GENERIC and GIMPLE are the same here. */ - if (!(INTEGRAL_TYPE_P (TREE_TYPE (expr)) - && (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE - || TYPE_PRECISION (TREE_TYPE (expr)) == 1)) - && ! VECTOR_TYPE_P (TREE_TYPE (expr))) - return false; - - /* Fallthru. */ - case tcc_binary: - if (!is_gimple_val (TREE_OPERAND (expr, 0)) - || !is_gimple_val (TREE_OPERAND (expr, 1))) - return false; - break; - - case tcc_unary: - if (!is_gimple_val (TREE_OPERAND (expr, 0))) - return false; - break; - - case tcc_expression: - switch (code) - { - case ADDR_EXPR: - { - tree t; - if (is_gimple_min_invariant (expr)) - return true; - t = TREE_OPERAND (expr, 0); - while (handled_component_p (t)) - { - /* ??? More checks needed, see the GIMPLE verifier. */ - if ((TREE_CODE (t) == ARRAY_REF - || TREE_CODE (t) == ARRAY_RANGE_REF) - && !is_gimple_val (TREE_OPERAND (t, 1))) - return false; - t = TREE_OPERAND (t, 0); - } - if (!is_gimple_id (t)) - return false; - } - break; - - default: - if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS) - { - if (((code == VEC_COND_EXPR || code == COND_EXPR) - ? !is_gimple_condexpr (TREE_OPERAND (expr, 0)) - : !is_gimple_val (TREE_OPERAND (expr, 0))) - || !is_gimple_val (TREE_OPERAND (expr, 1)) - || !is_gimple_val (TREE_OPERAND (expr, 2))) - return false; - break; - } - return false; - } - break; - - case tcc_vl_exp: - return false; - - case tcc_exceptional: - if (code == CONSTRUCTOR) - { - unsigned i; - tree elt; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, elt) - if (!is_gimple_val (elt)) - return false; - return true; - } - if (code != SSA_NAME) - return false; - break; - - case tcc_reference: - if (code == BIT_FIELD_REF) - return is_gimple_val (TREE_OPERAND (expr, 0)); - return false; - - default: - return false; - } - - return true; -} - - -/* Return true if EXPR is a CALL_EXPR suitable for representation - as a single GIMPLE_CALL statement. If the arguments require - further gimplification, return false. */ - -static bool -valid_gimple_call_p (tree expr) -{ - unsigned i, nargs; - - if (TREE_CODE (expr) != CALL_EXPR) - return false; - - nargs = call_expr_nargs (expr); - for (i = 0; i < nargs; i++) - { - tree arg = CALL_EXPR_ARG (expr, i); - if (is_gimple_reg_type (TREE_TYPE (arg))) - { - if (!is_gimple_val (arg)) - return false; - } - else - if (!is_gimple_lvalue (arg)) - return false; - } - - return true; -} - - -/* Make SSA names defined by OLD_STMT point to NEW_STMT - as their defining statement. */ - -void -move_ssa_defining_stmt_for_defs (gimple *new_stmt, gimple *old_stmt) -{ - tree var; - ssa_op_iter iter; - - if (gimple_in_ssa_p (cfun)) - { - /* Make defined SSA_NAMEs point to the new - statement as their definition. */ - FOR_EACH_SSA_TREE_OPERAND (var, old_stmt, iter, SSA_OP_ALL_DEFS) - { - if (TREE_CODE (var) == SSA_NAME) - SSA_NAME_DEF_STMT (var) = new_stmt; - } - } -} - -/* Helper function for update_gimple_call and update_call_from_tree. - A GIMPLE_CALL STMT is being replaced with GIMPLE_CALL NEW_STMT. */ - -static void -finish_update_gimple_call (gimple_stmt_iterator *si_p, gimple *new_stmt, - gimple *stmt) -{ - gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); - gimple_move_vops (new_stmt, stmt); - gimple_set_location (new_stmt, gimple_location (stmt)); - if (gimple_block (new_stmt) == NULL_TREE) - gimple_set_block (new_stmt, gimple_block (stmt)); - gsi_replace (si_p, new_stmt, false); -} - -/* Update a GIMPLE_CALL statement at iterator *SI_P to call to FN - with number of arguments NARGS, where the arguments in GIMPLE form - follow NARGS argument. */ - -bool -update_gimple_call (gimple_stmt_iterator *si_p, tree fn, int nargs, ...) -{ - va_list ap; - gcall *new_stmt, *stmt = as_a <gcall *> (gsi_stmt (*si_p)); - - gcc_assert (is_gimple_call (stmt)); - va_start (ap, nargs); - new_stmt = gimple_build_call_valist (fn, nargs, ap); - finish_update_gimple_call (si_p, new_stmt, stmt); - va_end (ap); - return true; -} - -/* Update a GIMPLE_CALL statement at iterator *SI_P to reflect the - value of EXPR, which is expected to be the result of folding the - call. This can only be done if EXPR is a CALL_EXPR with valid - GIMPLE operands as arguments, or if it is a suitable RHS expression - for a GIMPLE_ASSIGN. More complex expressions will require - gimplification, which will introduce additional statements. In this - event, no update is performed, and the function returns false. - Note that we cannot mutate a GIMPLE_CALL in-place, so we always - replace the statement at *SI_P with an entirely new statement. - The new statement need not be a call, e.g., if the original call - folded to a constant. */ - -bool -update_call_from_tree (gimple_stmt_iterator *si_p, tree expr) -{ - gimple *stmt = gsi_stmt (*si_p); - - if (valid_gimple_call_p (expr)) - { - /* The call has simplified to another call. */ - tree fn = CALL_EXPR_FN (expr); - unsigned i; - unsigned nargs = call_expr_nargs (expr); - vec<tree> args = vNULL; - gcall *new_stmt; - - if (nargs > 0) - { - args.create (nargs); - args.safe_grow_cleared (nargs, true); - - for (i = 0; i < nargs; i++) - args[i] = CALL_EXPR_ARG (expr, i); - } - - new_stmt = gimple_build_call_vec (fn, args); - finish_update_gimple_call (si_p, new_stmt, stmt); - args.release (); - - return true; - } - else if (valid_gimple_rhs_p (expr)) - { - tree lhs = gimple_call_lhs (stmt); - gimple *new_stmt; - - /* The call has simplified to an expression - that cannot be represented as a GIMPLE_CALL. */ - if (lhs) - { - /* A value is expected. - Introduce a new GIMPLE_ASSIGN statement. */ - STRIP_USELESS_TYPE_CONVERSION (expr); - new_stmt = gimple_build_assign (lhs, expr); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); - gimple_move_vops (new_stmt, stmt); - } - else if (!TREE_SIDE_EFFECTS (expr)) - { - /* No value is expected, and EXPR has no effect. - Replace it with an empty statement. */ - new_stmt = gimple_build_nop (); - if (gimple_in_ssa_p (cfun)) - { - unlink_stmt_vdef (stmt); - release_defs (stmt); - } - } - else - { - /* No value is expected, but EXPR has an effect, - e.g., it could be a reference to a volatile - variable. Create an assignment statement - with a dummy (unused) lhs variable. */ - STRIP_USELESS_TYPE_CONVERSION (expr); - if (gimple_in_ssa_p (cfun)) - lhs = make_ssa_name (TREE_TYPE (expr)); - else - lhs = create_tmp_var (TREE_TYPE (expr)); - new_stmt = gimple_build_assign (lhs, expr); - gimple_move_vops (new_stmt, stmt); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); - } - gimple_set_location (new_stmt, gimple_location (stmt)); - gsi_replace (si_p, new_stmt, false); - return true; - } - else - /* The call simplified to an expression that is - not a valid GIMPLE RHS. */ - return false; -} - /* Entry point to the propagation engine. The VISIT_STMT virtual function is called for every statement @@ -1539,10 +1243,8 @@ propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) && gimple_call_lhs (stmt) != NULL_TREE) { tree expr = NULL_TREE; - bool res; propagate_tree_value (&expr, val); - res = update_call_from_tree (gsi, expr); - gcc_assert (res); + replace_call_with_value (gsi, expr); } else if (gswitch *swtch_stmt = dyn_cast <gswitch *> (stmt)) propagate_tree_value (gimple_switch_index_ptr (swtch_stmt), val); @@ -1556,13 +1258,10 @@ propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) unsigned clean_up_loop_closed_phi (function *fun) { - unsigned i; - edge e; gphi *phi; tree rhs; tree lhs; gphi_iterator gsi; - struct loop *loop; /* Avoid possibly quadratic work when scanning for loop exits across all loops of a nest. */ @@ -1574,11 +1273,11 @@ clean_up_loop_closed_phi (function *fun) calculate_dominance_info (CDI_DOMINATORS); /* Walk over loop in function. */ - FOR_EACH_LOOP_FN (fun, loop, 0) + for (auto loop : loops_list (fun, 0)) { /* Check each exit edege of loop. */ auto_vec<edge> exits = get_loop_exit_edges (loop); - FOR_EACH_VEC_ELT (exits, i, e) + for (edge e : exits) if (single_pred_p (e->dest)) /* Walk over loop-closed PHIs. */ for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi);) |