| Index: gcc/gcc/tree-ssa-loop-im.c
|
| diff --git a/gcc/gcc/tree-ssa-loop-im.c b/gcc/gcc/tree-ssa-loop-im.c
|
| index 65c0b0d0b6fef08e15bed2f818dd4f61875fd274..90b3a38b448b38e2351aff67982b8e404c5fd039 100644
|
| --- a/gcc/gcc/tree-ssa-loop-im.c
|
| +++ b/gcc/gcc/tree-ssa-loop-im.c
|
| @@ -1,19 +1,19 @@
|
| /* Loop invariant motion.
|
| - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software
|
| - Foundation, Inc.
|
| -
|
| + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010
|
| + Free Software Foundation, Inc.
|
| +
|
| This file is part of GCC.
|
| -
|
| +
|
| GCC is free software; you can redistribute it and/or modify it
|
| under the terms of the GNU General Public License as published by the
|
| Free Software Foundation; either version 3, or (at your option) any
|
| later version.
|
| -
|
| +
|
| GCC is distributed in the hope that it will be useful, but WITHOUT
|
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| for more details.
|
| -
|
| +
|
| You should have received a copy of the GNU General Public License
|
| along with GCC; see the file COPYING3. If not see
|
| <http://www.gnu.org/licenses/>. */
|
| @@ -251,13 +251,13 @@ clear_lim_data (gimple stmt)
|
| /* Calls CBCK for each index in memory reference ADDR_P. There are two
|
| kinds situations handled; in each of these cases, the memory reference
|
| and DATA are passed to the callback:
|
| -
|
| +
|
| Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
|
| pass the pointer to the index to the callback.
|
|
|
| Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
|
| pointer to addr to the callback.
|
| -
|
| +
|
| If the callback returns false, the whole search stops and false is returned.
|
| Otherwise the function returns true after traversing through the whole
|
| reference *ADDR_P. */
|
| @@ -362,7 +362,7 @@ movement_possibility (gimple stmt)
|
| if (gimple_get_lhs (stmt) == NULL_TREE)
|
| return MOVE_IMPOSSIBLE;
|
|
|
| - if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS))
|
| + if (gimple_vdef (stmt))
|
| return MOVE_IMPOSSIBLE;
|
|
|
| if (stmt_ends_bb_p (stmt)
|
| @@ -452,14 +452,14 @@ outermost_invariant_loop (tree def, struct loop *loop)
|
|
|
| /* DATA is a structure containing information associated with a statement
|
| inside LOOP. DEF is one of the operands of this statement.
|
| -
|
| +
|
| Find the outermost loop enclosing LOOP in that value of DEF is invariant
|
| and record this in DATA->max_loop field. If DEF itself is defined inside
|
| this loop as well (i.e. we need to hoist it out of the loop if we want
|
| to hoist the statement represented by DATA), record the statement in that
|
| DEF is defined to the DATA->depends list. Additionally if ADD_COST is true,
|
| add the cost of the computation of DEF to the DATA->cost.
|
| -
|
| +
|
| If DEF is not invariant in LOOP, return false. Otherwise return TRUE. */
|
|
|
| static bool
|
| @@ -657,7 +657,7 @@ mem_ref_in_stmt (gimple stmt)
|
| If MUST_PRESERVE_EXEC is true, additionally choose such a loop that
|
| we preserve the fact whether STMT is executed. It also fills other related
|
| information to LIM_DATA (STMT).
|
| -
|
| +
|
| The function returns false if STMT cannot be hoisted outside of the loop it
|
| is defined in, and true otherwise. */
|
|
|
| @@ -670,7 +670,7 @@ determine_max_movement (gimple stmt, bool must_preserve_exec)
|
| struct lim_aux_data *lim_data = get_lim_data (stmt);
|
| tree val;
|
| ssa_op_iter iter;
|
| -
|
| +
|
| if (must_preserve_exec)
|
| level = ALWAYS_EXECUTED_IN (bb);
|
| else
|
| @@ -681,7 +681,7 @@ determine_max_movement (gimple stmt, bool must_preserve_exec)
|
| if (!add_dependency (val, lim_data, loop, true))
|
| return false;
|
|
|
| - if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_USES))
|
| + if (gimple_vuse (stmt))
|
| {
|
| mem_ref_p ref = mem_ref_in_stmt (stmt);
|
|
|
| @@ -694,7 +694,7 @@ determine_max_movement (gimple stmt, bool must_preserve_exec)
|
| }
|
| else
|
| {
|
| - FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_VIRTUAL_USES)
|
| + if ((val = gimple_vuse (stmt)) != NULL_TREE)
|
| {
|
| if (!add_dependency (val, lim_data, loop, false))
|
| return false;
|
| @@ -764,6 +764,7 @@ rewrite_reciprocal (gimple_stmt_iterator *bsi)
|
| gimple stmt, stmt1, stmt2;
|
| tree var, name, lhs, type;
|
| tree real_one;
|
| + gimple_stmt_iterator gsi;
|
|
|
| stmt = gsi_stmt (*bsi);
|
| lhs = gimple_assign_lhs (stmt);
|
| @@ -798,8 +799,9 @@ rewrite_reciprocal (gimple_stmt_iterator *bsi)
|
| /* Replace division stmt with reciprocal and multiply stmts.
|
| The multiply stmt is not invariant, so update iterator
|
| and avoid rescanning. */
|
| - gsi_replace (bsi, stmt1, true);
|
| - gsi_insert_after (bsi, stmt2, GSI_NEW_STMT);
|
| + gsi = *bsi;
|
| + gsi_insert_before (bsi, stmt1, GSI_NEW_STMT);
|
| + gsi_replace (&gsi, stmt2, true);
|
|
|
| /* Continue processing with invariant reciprocal statement. */
|
| return stmt1;
|
| @@ -858,6 +860,8 @@ rewrite_bittest (gimple_stmt_iterator *bsi)
|
| if (outermost_invariant_loop (b, loop_containing_stmt (stmt1)) != NULL
|
| && outermost_invariant_loop (a, loop_containing_stmt (stmt1)) == NULL)
|
| {
|
| + gimple_stmt_iterator rsi;
|
| +
|
| /* 1 << B */
|
| var = create_tmp_var (TREE_TYPE (a), "shifttmp");
|
| add_referenced_var (var);
|
| @@ -878,8 +882,14 @@ rewrite_bittest (gimple_stmt_iterator *bsi)
|
| SET_USE (use, name);
|
| gimple_cond_set_rhs (use_stmt, build_int_cst_type (TREE_TYPE (name), 0));
|
|
|
| - gsi_insert_before (bsi, stmt1, GSI_SAME_STMT);
|
| - gsi_replace (bsi, stmt2, true);
|
| + /* Don't use gsi_replace here, none of the new assignments sets
|
| + the variable originally set in stmt. Move bsi to stmt1, and
|
| + then remove the original stmt, so that we get a chance to
|
| + retain debug info for it. */
|
| + rsi = *bsi;
|
| + gsi_insert_before (bsi, stmt1, GSI_NEW_STMT);
|
| + gsi_insert_before (&rsi, stmt2, GSI_SAME_STMT);
|
| + gsi_remove (&rsi, true);
|
|
|
| return stmt1;
|
| }
|
| @@ -999,7 +1009,7 @@ determine_invariantness (void)
|
|
|
| memset (&walk_data, 0, sizeof (struct dom_walk_data));
|
| walk_data.dom_direction = CDI_DOMINATORS;
|
| - walk_data.before_dom_children_before_stmts = determine_invariantness_stmt;
|
| + walk_data.before_dom_children = determine_invariantness_stmt;
|
|
|
| init_walk_dominator_tree (&walk_data);
|
| walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
|
| @@ -1073,14 +1083,14 @@ move_computations (void)
|
|
|
| memset (&walk_data, 0, sizeof (struct dom_walk_data));
|
| walk_data.dom_direction = CDI_DOMINATORS;
|
| - walk_data.before_dom_children_before_stmts = move_computations_stmt;
|
| + walk_data.before_dom_children = move_computations_stmt;
|
|
|
| init_walk_dominator_tree (&walk_data);
|
| walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
|
| fini_walk_dominator_tree (&walk_data);
|
|
|
| gsi_commit_edge_inserts ();
|
| - if (need_ssa_update_p ())
|
| + if (need_ssa_update_p (cfun))
|
| rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
|
| }
|
|
|
| @@ -1128,7 +1138,7 @@ force_move_till_op (tree op, struct loop *orig_loop, struct loop *loop)
|
| return;
|
|
|
| gcc_assert (TREE_CODE (op) == SSA_NAME);
|
| -
|
| +
|
| stmt = SSA_NAME_DEF_STMT (op);
|
| if (gimple_nop_p (stmt))
|
| return;
|
| @@ -1309,13 +1319,12 @@ gather_mem_refs_stmt (struct loop *loop, gimple stmt)
|
| hashval_t hash;
|
| PTR *slot;
|
| mem_ref_p ref;
|
| - ssa_op_iter oi;
|
| tree vname;
|
| bool is_stored;
|
| bitmap clvops;
|
| unsigned id;
|
|
|
| - if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
|
| + if (!gimple_vuse (stmt))
|
| return;
|
|
|
| mem = simple_mem_ref_in_stmt (stmt, &is_stored);
|
| @@ -1347,14 +1356,14 @@ gather_mem_refs_stmt (struct loop *loop, gimple stmt)
|
| if (is_stored)
|
| mark_ref_stored (ref, loop);
|
|
|
| - FOR_EACH_SSA_TREE_OPERAND (vname, stmt, oi, SSA_OP_VIRTUAL_USES)
|
| + if ((vname = gimple_vuse (stmt)) != NULL_TREE)
|
| bitmap_set_bit (ref->vops, DECL_UID (SSA_NAME_VAR (vname)));
|
| record_mem_ref_loc (ref, loop, stmt, mem);
|
| return;
|
|
|
| fail:
|
| clvops = VEC_index (bitmap, memory_accesses.clobbered_vops, loop->num);
|
| - FOR_EACH_SSA_TREE_OPERAND (vname, stmt, oi, SSA_OP_VIRTUAL_USES)
|
| + if ((vname = gimple_vuse (stmt)) != NULL_TREE)
|
| bitmap_set_bit (clvops, DECL_UID (SSA_NAME_VAR (vname)));
|
| }
|
|
|
| @@ -1755,7 +1764,7 @@ gen_lsm_tmp_name (tree ref)
|
| gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
|
| lsm_tmp_name_add ("_RE");
|
| break;
|
| -
|
| +
|
| case IMAGPART_EXPR:
|
| gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
|
| lsm_tmp_name_add ("_IM");
|
| @@ -1795,6 +1804,10 @@ gen_lsm_tmp_name (tree ref)
|
| lsm_tmp_name_add ("R");
|
| break;
|
|
|
| + case INTEGER_CST:
|
| + /* Nothing. */
|
| + break;
|
| +
|
| default:
|
| gcc_unreachable ();
|
| }
|
| @@ -1887,16 +1900,22 @@ hoist_memory_references (struct loop *loop, bitmap mem_refs,
|
| }
|
| }
|
|
|
| -/* Returns true if REF is always accessed in LOOP. */
|
| +/* Returns true if REF is always accessed in LOOP. If STORED_P is true
|
| + make sure REF is always stored to in LOOP. */
|
|
|
| static bool
|
| -ref_always_accessed_p (struct loop *loop, mem_ref_p ref)
|
| +ref_always_accessed_p (struct loop *loop, mem_ref_p ref, bool stored_p)
|
| {
|
| VEC (mem_ref_loc_p, heap) *locs = NULL;
|
| unsigned i;
|
| mem_ref_loc_p loc;
|
| bool ret = false;
|
| struct loop *must_exec;
|
| + tree base;
|
| +
|
| + base = get_base_address (ref->mem);
|
| + if (INDIRECT_REF_P (base))
|
| + base = TREE_OPERAND (base, 0);
|
|
|
| get_all_locs_in_loop (loop, ref, &locs);
|
| for (i = 0; VEC_iterate (mem_ref_loc_p, locs, i, loc); i++)
|
| @@ -1904,6 +1923,22 @@ ref_always_accessed_p (struct loop *loop, mem_ref_p ref)
|
| if (!get_lim_data (loc->stmt))
|
| continue;
|
|
|
| + /* If we require an always executed store make sure the statement
|
| + stores to the reference. */
|
| + if (stored_p)
|
| + {
|
| + tree lhs;
|
| + if (!gimple_get_lhs (loc->stmt))
|
| + continue;
|
| + lhs = get_base_address (gimple_get_lhs (loc->stmt));
|
| + if (!lhs)
|
| + continue;
|
| + if (INDIRECT_REF_P (lhs))
|
| + lhs = TREE_OPERAND (lhs, 0);
|
| + if (lhs != base)
|
| + continue;
|
| + }
|
| +
|
| must_exec = get_lim_data (loc->stmt)->always_executed_in;
|
| if (!must_exec)
|
| continue;
|
| @@ -2041,6 +2076,8 @@ ref_indep_loop_p (struct loop *loop, mem_ref_p ref)
|
| static bool
|
| can_sm_ref_p (struct loop *loop, mem_ref_p ref)
|
| {
|
| + tree base;
|
| +
|
| /* Unless the reference is stored in the loop, there is nothing to do. */
|
| if (!bitmap_bit_p (ref->stored, loop->num))
|
| return false;
|
| @@ -2051,9 +2088,14 @@ can_sm_ref_p (struct loop *loop, mem_ref_p ref)
|
| || !for_each_index (&ref->mem, may_move_till, loop))
|
| return false;
|
|
|
| - /* If it can trap, it must be always executed in LOOP. */
|
| - if (tree_could_trap_p (ref->mem)
|
| - && !ref_always_accessed_p (loop, ref))
|
| + /* If it can trap, it must be always executed in LOOP.
|
| + Readonly memory locations may trap when storing to them, but
|
| + tree_could_trap_p is a predicate for rvalues, so check that
|
| + explicitly. */
|
| + base = get_base_address (ref->mem);
|
| + if ((tree_could_trap_p (ref->mem)
|
| + || (DECL_P (base) && TREE_READONLY (base)))
|
| + && !ref_always_accessed_p (loop, ref, true))
|
| return false;
|
|
|
| /* And it must be independent on all other memory references
|
|
|