mirror of git://gcc.gnu.org/git/gcc.git
tree-ssa-reassoc.c (bip_map): Remove decl.
2012-05-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com> * tree-ssa-reassoc.c (bip_map): Remove decl. (completely_remove_stmt): Remove function. (remove_def_if_absorbed_call): Remove function. (remove_visited_stmt_chain): Remove __builtin_powi handling. (possibly_move_powi): Remove function. (rewrite_expr_tree): Remove calls to possibly_move_powi. (rewrite_expr_tree_parallel): Likewise. (attempt_builtin_powi): Build multiplies explicitly rather than relying on the ops vector and rank system. (transform_stmt_to_copy): New function. (transform_stmt_to_multiply): Likewise. (reassociate_bb): Handle leftover operations after __builtin_powi optimization; build a final multiply if necessary. From-SVN: r187652
This commit is contained in:
parent
387df87160
commit
917a52020a
|
@ -1,3 +1,19 @@
|
|||
2012-05-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
|
||||
|
||||
* tree-ssa-reassoc.c (bip_map): Remove decl.
|
||||
(completely_remove_stmt): Remove function.
|
||||
(remove_def_if_absorbed_call): Remove function.
|
||||
(remove_visited_stmt_chain): Remove __builtin_powi handling.
|
||||
(possibly_move_powi): Remove function.
|
||||
(rewrite_expr_tree): Remove calls to possibly_move_powi.
|
||||
(rewrite_expr_tree_parallel): Likewise.
|
||||
(attempt_builtin_powi): Build multiplies explicitly rather than
|
||||
relying on the ops vector and rank system.
|
||||
(transform_stmt_to_copy): New function.
|
||||
(transform_stmt_to_multiply): Likewise.
|
||||
(reassociate_bb): Handle leftover operations after __builtin_powi
|
||||
optimization; build a final multiply if necessary.
|
||||
|
||||
2012-05-18 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cgraphunit.c (varpool_finalize_decl): Allow external decls.
|
||||
|
|
|
@ -200,10 +200,6 @@ static long *bb_rank;
|
|||
/* Operand->rank hashtable. */
|
||||
static struct pointer_map_t *operand_rank;
|
||||
|
||||
/* Map from inserted __builtin_powi calls to multiply chains that
|
||||
feed them. */
|
||||
static struct pointer_map_t *bip_map;
|
||||
|
||||
/* Forward decls. */
|
||||
static long get_rank (tree);
|
||||
|
||||
|
@ -2184,32 +2180,6 @@ is_phi_for_stmt (gimple stmt, tree operand)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Remove STMT, unlink its virtual defs, and release its SSA defs. */
|
||||
|
||||
static inline void
|
||||
completely_remove_stmt (gimple stmt)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
|
||||
gsi_remove (&gsi, true);
|
||||
unlink_stmt_vdef (stmt);
|
||||
release_defs (stmt);
|
||||
}
|
||||
|
||||
/* If OP is defined by a builtin call that has been absorbed by
|
||||
reassociation, remove its defining statement completely. */
|
||||
|
||||
static inline void
|
||||
remove_def_if_absorbed_call (tree op)
|
||||
{
|
||||
gimple stmt;
|
||||
|
||||
if (TREE_CODE (op) == SSA_NAME
|
||||
&& has_zero_uses (op)
|
||||
&& is_gimple_call ((stmt = SSA_NAME_DEF_STMT (op)))
|
||||
&& gimple_visited_p (stmt))
|
||||
completely_remove_stmt (stmt);
|
||||
}
|
||||
|
||||
/* Remove def stmt of VAR if VAR has zero uses and recurse
|
||||
on rhs1 operand if so. */
|
||||
|
||||
|
@ -2218,7 +2188,6 @@ remove_visited_stmt_chain (tree var)
|
|||
{
|
||||
gimple stmt;
|
||||
gimple_stmt_iterator gsi;
|
||||
tree var2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
@ -2228,95 +2197,15 @@ remove_visited_stmt_chain (tree var)
|
|||
if (is_gimple_assign (stmt) && gimple_visited_p (stmt))
|
||||
{
|
||||
var = gimple_assign_rhs1 (stmt);
|
||||
var2 = gimple_assign_rhs2 (stmt);
|
||||
gsi = gsi_for_stmt (stmt);
|
||||
gsi_remove (&gsi, true);
|
||||
release_defs (stmt);
|
||||
/* A multiply whose operands are both fed by builtin pow/powi
|
||||
calls must check whether to remove rhs2 as well. */
|
||||
remove_def_if_absorbed_call (var2);
|
||||
}
|
||||
else if (is_gimple_call (stmt) && gimple_visited_p (stmt))
|
||||
{
|
||||
completely_remove_stmt (stmt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If OP is an SSA name, find its definition and determine whether it
|
||||
is a call to __builtin_powi. If so, move the definition prior to
|
||||
STMT. Only do this during early reassociation. */
|
||||
|
||||
static void
|
||||
possibly_move_powi (gimple stmt, tree op)
|
||||
{
|
||||
gimple stmt2, *mpy;
|
||||
tree fndecl;
|
||||
gimple_stmt_iterator gsi1, gsi2;
|
||||
|
||||
if (!first_pass_instance
|
||||
|| !flag_unsafe_math_optimizations
|
||||
|| TREE_CODE (op) != SSA_NAME)
|
||||
return;
|
||||
|
||||
stmt2 = SSA_NAME_DEF_STMT (op);
|
||||
|
||||
if (!is_gimple_call (stmt2)
|
||||
|| !has_single_use (gimple_call_lhs (stmt2)))
|
||||
return;
|
||||
|
||||
fndecl = gimple_call_fndecl (stmt2);
|
||||
|
||||
if (!fndecl
|
||||
|| DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
|
||||
return;
|
||||
|
||||
switch (DECL_FUNCTION_CODE (fndecl))
|
||||
{
|
||||
CASE_FLT_FN (BUILT_IN_POWI):
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move the __builtin_powi. */
|
||||
gsi1 = gsi_for_stmt (stmt);
|
||||
gsi2 = gsi_for_stmt (stmt2);
|
||||
gsi_move_before (&gsi2, &gsi1);
|
||||
|
||||
/* See if there are multiplies feeding the __builtin_powi base
|
||||
argument that must also be moved. */
|
||||
while ((mpy = (gimple *) pointer_map_contains (bip_map, stmt2)) != NULL)
|
||||
{
|
||||
/* If we've already moved this statement, we're done. This is
|
||||
identified by a NULL entry for the statement in bip_map. */
|
||||
gimple *next = (gimple *) pointer_map_contains (bip_map, *mpy);
|
||||
if (next && !*next)
|
||||
return;
|
||||
|
||||
stmt = stmt2;
|
||||
stmt2 = *mpy;
|
||||
gsi1 = gsi_for_stmt (stmt);
|
||||
gsi2 = gsi_for_stmt (stmt2);
|
||||
gsi_move_before (&gsi2, &gsi1);
|
||||
|
||||
/* The moved multiply may be DAG'd from multiple calls if it
|
||||
was the result of a cached multiply. Only move it once.
|
||||
Rank order ensures we move it to the right place the first
|
||||
time. */
|
||||
if (next)
|
||||
*next = NULL;
|
||||
else
|
||||
{
|
||||
next = (gimple *) pointer_map_insert (bip_map, *mpy);
|
||||
*next = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function checks three consequtive operands in
|
||||
passed operands vector OPS starting from OPINDEX and
|
||||
swaps two operands if it is profitable for binary operation
|
||||
|
@ -2421,9 +2310,6 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex,
|
|||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
|
||||
possibly_move_powi (stmt, oe1->op);
|
||||
possibly_move_powi (stmt, oe2->op);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2469,8 +2355,6 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex,
|
|||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
|
||||
possibly_move_powi (stmt, oe->op);
|
||||
}
|
||||
/* Recurse on the LHS of the binary operator, which is guaranteed to
|
||||
be the non-leaf side. */
|
||||
|
@ -2644,9 +2528,6 @@ rewrite_expr_tree_parallel (gimple stmt, int width,
|
|||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmts[i], 0, 0);
|
||||
}
|
||||
|
||||
possibly_move_powi (stmts[i], op1);
|
||||
possibly_move_powi (stmts[i], op2);
|
||||
}
|
||||
|
||||
remove_visited_stmt_chain (last_rhs1);
|
||||
|
@ -3222,11 +3103,10 @@ get_reassoc_pow_ssa_name (tree *target, tree type)
|
|||
|
||||
/* Look for repeated operands in OPS in the multiply tree rooted at
|
||||
STMT. Replace them with an optimal sequence of multiplies and powi
|
||||
builtin calls, and remove the used operands from OPS. Push new
|
||||
SSA names onto OPS that represent the introduced multiplies and
|
||||
builtin calls. */
|
||||
builtin calls, and remove the used operands from OPS. Return an
|
||||
SSA name representing the value of the replacement sequence. */
|
||||
|
||||
static void
|
||||
static tree
|
||||
attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
||||
tree *target)
|
||||
{
|
||||
|
@ -3235,6 +3115,7 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
operand_entry_t oe;
|
||||
repeat_factor_t rf1, rf2;
|
||||
repeat_factor rfnew;
|
||||
tree result = NULL_TREE;
|
||||
tree target_ssa, iter_result;
|
||||
tree type = TREE_TYPE (gimple_get_lhs (stmt));
|
||||
tree powi_fndecl = mathfn_built_in (type, BUILT_IN_POWI);
|
||||
|
@ -3244,7 +3125,7 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
/* Nothing to do if BUILT_IN_POWI doesn't exist for this type and
|
||||
target. */
|
||||
if (!powi_fndecl)
|
||||
return;
|
||||
return NULL_TREE;
|
||||
|
||||
/* Allocate the repeated factor vector. */
|
||||
repeat_factor_vec = VEC_alloc (repeat_factor, heap, 10);
|
||||
|
@ -3315,7 +3196,6 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
while (true)
|
||||
{
|
||||
HOST_WIDE_INT power;
|
||||
gimple last_mul = NULL;
|
||||
|
||||
/* First look for the largest cached product of factors from
|
||||
preceding iterations. If found, create a builtin_powi for
|
||||
|
@ -3353,25 +3233,14 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
}
|
||||
else
|
||||
{
|
||||
gimple *value;
|
||||
|
||||
iter_result = get_reassoc_pow_ssa_name (target, type);
|
||||
pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
|
||||
build_int_cst (integer_type_node,
|
||||
power));
|
||||
gimple_call_set_lhs (pow_stmt, iter_result);
|
||||
gimple_set_location (pow_stmt, gimple_location (stmt));
|
||||
/* Temporarily place the call; we will move it and its
|
||||
feeding multiplies to the correct place during
|
||||
rewrite_expr. */
|
||||
gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
|
||||
|
||||
if (!operand_equal_p (rf1->repr, rf1->factor, 0))
|
||||
{
|
||||
value = (gimple *) pointer_map_insert (bip_map, pow_stmt);
|
||||
*value = SSA_NAME_DEF_STMT (rf1->repr);
|
||||
}
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
unsigned elt;
|
||||
|
@ -3457,15 +3326,6 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
gsi_insert_before (&gsi, mul_stmt, GSI_SAME_STMT);
|
||||
rf1->repr = target_ssa;
|
||||
|
||||
/* Chain multiplies together for later movement. */
|
||||
if (last_mul)
|
||||
{
|
||||
gimple *value
|
||||
= (gimple *) pointer_map_insert (bip_map, mul_stmt);
|
||||
*value = last_mul;
|
||||
}
|
||||
last_mul = mul_stmt;
|
||||
|
||||
/* Don't reprocess the multiply we just introduced. */
|
||||
gimple_set_visited (mul_stmt, true);
|
||||
}
|
||||
|
@ -3481,19 +3341,22 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
gimple_call_set_lhs (pow_stmt, iter_result);
|
||||
gimple_set_location (pow_stmt, gimple_location (stmt));
|
||||
gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
|
||||
|
||||
/* If we inserted a chain of multiplies before the pow_stmt,
|
||||
record that fact so we can move it later when we move the
|
||||
pow_stmt. */
|
||||
if (last_mul)
|
||||
{
|
||||
gimple *value = (gimple *) pointer_map_insert (bip_map, pow_stmt);
|
||||
*value = last_mul;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append the result of this iteration to the ops vector. */
|
||||
add_to_ops_vec (ops, iter_result);
|
||||
/* If we previously formed at least one other builtin_powi call,
|
||||
form the product of this one and those others. */
|
||||
if (result)
|
||||
{
|
||||
tree new_result = get_reassoc_pow_ssa_name (target, type);
|
||||
mul_stmt = gimple_build_assign_with_ops (MULT_EXPR, new_result,
|
||||
result, iter_result);
|
||||
gimple_set_location (mul_stmt, gimple_location (stmt));
|
||||
gsi_insert_before (&gsi, mul_stmt, GSI_SAME_STMT);
|
||||
gimple_set_visited (mul_stmt, true);
|
||||
result = new_result;
|
||||
}
|
||||
else
|
||||
result = iter_result;
|
||||
|
||||
/* Decrement the occurrence count of each element in the product
|
||||
by the count found above, and remove this many copies of each
|
||||
|
@ -3534,6 +3397,59 @@ attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops,
|
|||
clean up. */
|
||||
VEC_qsort (operand_entry_t, *ops, sort_by_operand_rank);
|
||||
VEC_free (repeat_factor, heap, repeat_factor_vec);
|
||||
|
||||
/* Return the final product computed herein. Note that there may
|
||||
still be some elements with single occurrence count left in OPS;
|
||||
those will be handled by the normal reassociation logic. */
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Transform STMT at *GSI into a copy by replacing its rhs with NEW_RHS. */
|
||||
|
||||
static void
|
||||
transform_stmt_to_copy (gimple_stmt_iterator *gsi, gimple stmt, tree new_rhs)
|
||||
{
|
||||
tree rhs1;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Transforming ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
|
||||
rhs1 = gimple_assign_rhs1 (stmt);
|
||||
gimple_assign_set_rhs_from_tree (gsi, new_rhs);
|
||||
update_stmt (stmt);
|
||||
remove_visited_stmt_chain (rhs1);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transform STMT at *GSI into a multiply of RHS1 and RHS2. */
|
||||
|
||||
static void
|
||||
transform_stmt_to_multiply (gimple_stmt_iterator *gsi, gimple stmt,
|
||||
tree rhs1, tree rhs2)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Transforming ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
|
||||
gimple_assign_set_rhs_with_ops_1 (gsi, MULT_EXPR, rhs1, rhs2, NULL_TREE);
|
||||
update_stmt (gsi_stmt (*gsi));
|
||||
remove_visited_stmt_chain (rhs1);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reassociate expressions in basic block BB and its post-dominator as
|
||||
|
@ -3606,7 +3522,7 @@ reassociate_bb (basic_block bb)
|
|||
if (associative_tree_code (rhs_code))
|
||||
{
|
||||
VEC(operand_entry_t, heap) *ops = NULL;
|
||||
bip_map = pointer_map_create ();
|
||||
tree powi_result = NULL_TREE;
|
||||
|
||||
/* There may be no immediate uses left by the time we
|
||||
get here because we may have eliminated them all. */
|
||||
|
@ -3630,28 +3546,21 @@ reassociate_bb (basic_block bb)
|
|||
if (first_pass_instance
|
||||
&& rhs_code == MULT_EXPR
|
||||
&& flag_unsafe_math_optimizations)
|
||||
attempt_builtin_powi (stmt, &ops, &target);
|
||||
powi_result = attempt_builtin_powi (stmt, &ops, &target);
|
||||
|
||||
if (VEC_length (operand_entry_t, ops) == 1)
|
||||
/* If the operand vector is now empty, all operands were
|
||||
consumed by the __builtin_powi optimization. */
|
||||
if (VEC_length (operand_entry_t, ops) == 0)
|
||||
transform_stmt_to_copy (&gsi, stmt, powi_result);
|
||||
else if (VEC_length (operand_entry_t, ops) == 1)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Transforming ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
|
||||
rhs1 = gimple_assign_rhs1 (stmt);
|
||||
gimple_assign_set_rhs_from_tree (&gsi,
|
||||
VEC_last (operand_entry_t,
|
||||
ops)->op);
|
||||
update_stmt (stmt);
|
||||
remove_visited_stmt_chain (rhs1);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, " into ");
|
||||
print_gimple_stmt (dump_file, stmt, 0, 0);
|
||||
}
|
||||
tree last_op = VEC_last (operand_entry_t, ops)->op;
|
||||
|
||||
if (powi_result)
|
||||
transform_stmt_to_multiply (&gsi, stmt, last_op,
|
||||
powi_result);
|
||||
else
|
||||
transform_stmt_to_copy (&gsi, stmt, last_op);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3668,10 +3577,27 @@ reassociate_bb (basic_block bb)
|
|||
rewrite_expr_tree_parallel (stmt, width, ops);
|
||||
else
|
||||
rewrite_expr_tree (stmt, 0, ops, false);
|
||||
|
||||
/* If we combined some repeated factors into a
|
||||
__builtin_powi call, multiply that result by the
|
||||
reassociated operands. */
|
||||
if (powi_result)
|
||||
{
|
||||
gimple mul_stmt;
|
||||
tree type = TREE_TYPE (gimple_get_lhs (stmt));
|
||||
tree target_ssa = get_reassoc_pow_ssa_name (&target,
|
||||
type);
|
||||
gimple_set_lhs (stmt, target_ssa);
|
||||
update_stmt (stmt);
|
||||
mul_stmt = gimple_build_assign_with_ops (MULT_EXPR, lhs,
|
||||
powi_result,
|
||||
target_ssa);
|
||||
gimple_set_location (mul_stmt, gimple_location (stmt));
|
||||
gsi_insert_after (&gsi, mul_stmt, GSI_NEW_STMT);
|
||||
}
|
||||
}
|
||||
|
||||
VEC_free (operand_entry_t, heap, ops);
|
||||
pointer_map_destroy (bip_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue