/* Loop invariant motion.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
if (LIM_DATA (def_stmt) && LIM_DATA (def_stmt)->max_loop)
max_loop = find_common_loop (max_loop,
- LIM_DATA (def_stmt)->max_loop->outer);
+ loop_outer (LIM_DATA (def_stmt)->max_loop));
if (max_loop == loop)
return NULL;
- max_loop = superloop_at_depth (loop, max_loop->depth + 1);
+ max_loop = superloop_at_depth (loop, loop_depth (max_loop) + 1);
return max_loop;
}
cost += 20;
break;
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ cost += 20;
+ break;
+
default:
break;
}
stmt_loop = find_common_loop (orig_loop, stmt_loop);
if (LIM_DATA (stmt) && LIM_DATA (stmt)->tgt_loop)
stmt_loop = find_common_loop (stmt_loop,
- LIM_DATA (stmt)->tgt_loop->outer);
+ loop_outer (LIM_DATA (stmt)->tgt_loop));
if (flow_loop_nested_p (stmt_loop, level))
return;
free (data);
}
+/* Rewrite a/b to a*(1/b). Return the invariant stmt to process. */
+
+static tree
+rewrite_reciprocal (block_stmt_iterator *bsi)
+{
+ tree stmt, lhs, rhs, stmt1, stmt2, var, name, tmp;
+
+ stmt = bsi_stmt (*bsi);
+ lhs = GENERIC_TREE_OPERAND (stmt, 0);
+ rhs = GENERIC_TREE_OPERAND (stmt, 1);
+
+ /* stmt must be GIMPLE_MODIFY_STMT. */
+ var = create_tmp_var (TREE_TYPE (rhs), "reciptmp");
+ add_referenced_var (var);
+
+ tmp = build2 (RDIV_EXPR, TREE_TYPE (rhs),
+ build_real (TREE_TYPE (rhs), dconst1),
+ TREE_OPERAND (rhs, 1));
+ stmt1 = build_gimple_modify_stmt (var, tmp);
+ name = make_ssa_name (var, stmt1);
+ GIMPLE_STMT_OPERAND (stmt1, 0) = name;
+ tmp = build2 (MULT_EXPR, TREE_TYPE (rhs),
+ name, TREE_OPERAND (rhs, 0));
+ stmt2 = build_gimple_modify_stmt (lhs, tmp);
+
+ /* Replace division stmt with reciprocal and multiply stmts.
+ The multiply stmt is not invariant, so update iterator
+ and avoid rescanning. */
+ bsi_replace (bsi, stmt1, true);
+ bsi_insert_after (bsi, stmt2, BSI_NEW_STMT);
+ SSA_NAME_DEF_STMT (lhs) = stmt2;
+
+ /* Continue processing with invariant reciprocal statement. */
+ return stmt1;
+}
+
+/* Check if the pattern at *BSI is a bittest of the form
+ (A >> B) & 1 != 0 and in this case rewrite it to A & (1 << B) != 0. */
+
+static tree
+rewrite_bittest (block_stmt_iterator *bsi)
+{
+ tree stmt, lhs, rhs, var, name, use_stmt, stmt1, stmt2, t;
+ use_operand_p use;
+
+ stmt = bsi_stmt (*bsi);
+ lhs = GENERIC_TREE_OPERAND (stmt, 0);
+ rhs = GENERIC_TREE_OPERAND (stmt, 1);
+
+ /* Verify that the single use of lhs is a comparison against zero. */
+ if (TREE_CODE (lhs) != SSA_NAME
+ || !single_imm_use (lhs, &use, &use_stmt)
+ || TREE_CODE (use_stmt) != COND_EXPR)
+ return stmt;
+ t = COND_EXPR_COND (use_stmt);
+ if (TREE_OPERAND (t, 0) != lhs
+ || (TREE_CODE (t) != NE_EXPR
+ && TREE_CODE (t) != EQ_EXPR)
+ || !integer_zerop (TREE_OPERAND (t, 1)))
+ return stmt;
+
+ /* Get at the operands of the shift. The rhs is TMP1 & 1. */
+ stmt1 = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+ if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
+ return stmt;
+
+ /* There is a conversion inbetween possibly inserted by fold. */
+ t = GIMPLE_STMT_OPERAND (stmt1, 1);
+ if (TREE_CODE (t) == NOP_EXPR
+ || TREE_CODE (t) == CONVERT_EXPR)
+ {
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != SSA_NAME
+ || !has_single_use (t))
+ return stmt;
+ stmt1 = SSA_NAME_DEF_STMT (t);
+ if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
+ return stmt;
+ t = GIMPLE_STMT_OPERAND (stmt1, 1);
+ }
+
+ /* Verify that B is loop invariant but A is not. Verify that with
+ all the stmt walking we are still in the same loop. */
+ if (TREE_CODE (t) == RSHIFT_EXPR
+ && loop_containing_stmt (stmt1) == loop_containing_stmt (stmt)
+ && outermost_invariant_loop_expr (TREE_OPERAND (t, 1),
+ loop_containing_stmt (stmt1)) != NULL
+ && outermost_invariant_loop_expr (TREE_OPERAND (t, 0),
+ loop_containing_stmt (stmt1)) == NULL)
+ {
+ tree a = TREE_OPERAND (t, 0);
+ tree b = TREE_OPERAND (t, 1);
+
+ /* 1 << B */
+ var = create_tmp_var (TREE_TYPE (a), "shifttmp");
+ add_referenced_var (var);
+ t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a),
+ build_int_cst (TREE_TYPE (a), 1), b);
+ stmt1 = build_gimple_modify_stmt (var, t);
+ name = make_ssa_name (var, stmt1);
+ GIMPLE_STMT_OPERAND (stmt1, 0) = name;
+
+ /* A & (1 << B) */
+ t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name);
+ stmt2 = build_gimple_modify_stmt (var, t);
+ name = make_ssa_name (var, stmt2);
+ GIMPLE_STMT_OPERAND (stmt2, 0) = name;
+ SET_USE (use, name);
+
+ bsi_insert_before (bsi, stmt1, BSI_SAME_STMT);
+ bsi_replace (bsi, stmt2, true);
+
+ return stmt1;
+ }
+
+ return stmt;
+}
+
+
/* Determine the outermost loops in that statements in basic block BB are
invariant, and record them to the LIM_DATA associated with the statements.
Callback for walk_dominator_tree. */
bool maybe_never = ALWAYS_EXECUTED_IN (bb) == NULL;
struct loop *outermost = ALWAYS_EXECUTED_IN (bb);
- if (!bb->loop_father->outer)
+ if (!loop_outer (bb->loop_father))
return;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Basic block %d (loop %d -- depth %d):\n\n",
- bb->index, bb->loop_father->num, bb->loop_father->depth);
+ bb->index, bb->loop_father->num, loop_depth (bb->loop_father));
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
continue;
}
- /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal
- to be hoisted out of loop, saving expensive divide. */
- if (pos == MOVE_POSSIBLE
- && (rhs = GENERIC_TREE_OPERAND (stmt, 1)) != NULL
- && TREE_CODE (rhs) == RDIV_EXPR
- && flag_unsafe_math_optimizations
- && !flag_trapping_math
- && outermost_invariant_loop_expr (TREE_OPERAND (rhs, 1),
- loop_containing_stmt (stmt)) != NULL
- && outermost_invariant_loop_expr (rhs,
- loop_containing_stmt (stmt)) == NULL)
+ if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
{
- tree lhs, stmt1, stmt2, var, name;
-
- lhs = GENERIC_TREE_OPERAND (stmt, 0);
-
- /* stmt must be GIMPLE_MODIFY_STMT. */
- var = create_tmp_var (TREE_TYPE (rhs), "reciptmp");
- add_referenced_var (var);
-
- stmt1 = build2 (GIMPLE_MODIFY_STMT, void_type_node, var,
- build2 (RDIV_EXPR, TREE_TYPE (rhs),
- build_real (TREE_TYPE (rhs), dconst1),
- TREE_OPERAND (rhs, 1)));
- name = make_ssa_name (var, stmt1);
- GIMPLE_STMT_OPERAND (stmt1, 0) = name;
- stmt2 = build2 (GIMPLE_MODIFY_STMT, void_type_node, lhs,
- build2 (MULT_EXPR, TREE_TYPE (rhs),
- name, TREE_OPERAND (rhs, 0)));
-
- /* Replace division stmt with reciprocal and multiply stmts.
- The multiply stmt is not invariant, so update iterator
- and avoid rescanning. */
- bsi_replace (&bsi, stmt1, true);
- bsi_insert_after (&bsi, stmt2, BSI_NEW_STMT);
- SSA_NAME_DEF_STMT (lhs) = stmt2;
-
- /* Continue processing with invariant reciprocal statement. */
- stmt = stmt1;
+ rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+
+ /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal
+ to be hoisted out of loop, saving expensive divide. */
+ if (pos == MOVE_POSSIBLE
+ && TREE_CODE (rhs) == RDIV_EXPR
+ && flag_unsafe_math_optimizations
+ && !flag_trapping_math
+ && outermost_invariant_loop_expr (TREE_OPERAND (rhs, 1),
+ loop_containing_stmt (stmt)) != NULL
+ && outermost_invariant_loop_expr (rhs,
+ loop_containing_stmt (stmt)) == NULL)
+ stmt = rewrite_reciprocal (&bsi);
+
+ /* If the shift count is invariant, convert (A >> B) & 1 to
+ A & (1 << B) allowing the bit mask to be hoisted out of the loop
+ saving an expensive shift. */
+ if (pos == MOVE_POSSIBLE
+ && TREE_CODE (rhs) == BIT_AND_EXPR
+ && integer_onep (TREE_OPERAND (rhs, 1))
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
+ && has_single_use (TREE_OPERAND (rhs, 0)))
+ stmt = rewrite_bittest (&bsi);
}
stmt_ann (stmt)->common.aux = xcalloc (1, sizeof (struct lim_aux_data));
{
print_generic_stmt_indented (dump_file, stmt, 0, 2);
fprintf (dump_file, " invariant up to level %d, cost %d.\n\n",
- LIM_DATA (stmt)->max_loop->depth,
+ loop_depth (LIM_DATA (stmt)->max_loop),
LIM_DATA (stmt)->cost);
}
struct dom_walk_data walk_data;
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;
init_walk_dominator_tree (&walk_data);
tree stmt;
unsigned cost = 0;
- if (!bb->loop_father->outer)
+ if (!loop_outer (bb->loop_father))
return;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
struct dom_walk_data walk_data;
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;
init_walk_dominator_tree (&walk_data);
}
/* Determines name for temporary variable that replaces REF.
- The name is accumulated into the lsm_tmp_name variable. */
+ The name is accumulated into the lsm_tmp_name variable.
+ N is added to the name of the temporary. */
-static char *
-get_lsm_tmp_name (tree ref)
+char *
+get_lsm_tmp_name (tree ref, unsigned n)
{
+ char ns[2];
+
lsm_tmp_name_length = 0;
gen_lsm_tmp_name (ref);
lsm_tmp_name_add ("_lsm");
+ if (n < 10)
+ {
+ ns[0] = '0' + n;
+ ns[1] = 0;
+ lsm_tmp_name_add (ns);
+ }
return lsm_tmp_name;
}
}
tmp_var = make_rename_temp (TREE_TYPE (ref),
- get_lsm_tmp_name (ref));
+ get_lsm_tmp_name (ref, ~0));
fmt_data.loop = loop;
fmt_data.orig_loop = loop;
LIM_DATA (aref->stmt)->sm_done = true;
/* Emit the load & stores. */
- load = build2_gimple (GIMPLE_MODIFY_STMT, tmp_var, ref);
+ load = build_gimple_modify_stmt (tmp_var, ref);
get_stmt_ann (load)->common.aux = xcalloc (1, sizeof (struct lim_aux_data));
LIM_DATA (load)->max_loop = loop;
LIM_DATA (load)->tgt_loop = loop;
for (i = 0; VEC_iterate (edge, exits, i, ex); i++)
{
- store = build2_gimple (GIMPLE_MODIFY_STMT, unshare_expr (ref), tmp_var);
+ store = build_gimple_modify_stmt (unshare_expr (ref), tmp_var);
bsi_insert_on_edge (ex, store);
}
}