re PR tree-optimization/81488 (gcc goes off the limits allocating memory in gimple-ssa-strength-reduction.c)
2017-08-22 Bill Schmidt <wschmidt@linux.vnet.ibm.com> PR tree-optimization/81488 * gimple-ssa-strength-reduction (struct slsr_cand_d): Add visited and cached_basis fields. (MAX_SPREAD): New constant. (alloc_cand_and_find_basis): Initialize new fields. (clear_visited): New function. (create_phi_basis_1): Rename from create_phi_basis, set visited and cached_basis fields. (create_phi_basis): New wrapper function. (phi_add_costs_1): Rename from phi_add_costs, add spread parameter, set visited field, short-circuit when limits reached. (phi_add_costs): New wrapper function. (record_phi_increments_1): Rename from record_phi_increments, set visited field. (record_phi_increments): New wrapper function. (phi_incr_cost_1): Rename from phi_incr_cost, set visited field. (phi_incr_cost): New wrapper function. (all_phi_incrs_profitable_1): Rename from all_phi_incrs_profitable, set visited field. (all_phi_incrs_profitable): New wrapper function. From-SVN: r251286
This commit is contained in:
parent
03a9562184
commit
65d3dce8e8
@ -1,3 +1,26 @@
|
||||
2017-08-22 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
|
||||
|
||||
PR tree-optimization/81488
|
||||
* gimple-ssa-strength-reduction (struct slsr_cand_d): Add visited
|
||||
and cached_basis fields.
|
||||
(MAX_SPREAD): New constant.
|
||||
(alloc_cand_and_find_basis): Initialize new fields.
|
||||
(clear_visited): New function.
|
||||
(create_phi_basis_1): Rename from create_phi_basis, set visited
|
||||
and cached_basis fields.
|
||||
(create_phi_basis): New wrapper function.
|
||||
(phi_add_costs_1): Rename from phi_add_costs, add spread
|
||||
parameter, set visited field, short-circuit when limits reached.
|
||||
(phi_add_costs): New wrapper function.
|
||||
(record_phi_increments_1): Rename from record_phi_increments, set
|
||||
visited field.
|
||||
(record_phi_increments): New wrapper function.
|
||||
(phi_incr_cost_1): Rename from phi_incr_cost, set visited field.
|
||||
(phi_incr_cost): New wrapper function.
|
||||
(all_phi_incrs_profitable_1): Rename from
|
||||
all_phi_incrs_profitable, set visited field.
|
||||
(all_phi_incrs_profitable): New wrapper function.
|
||||
|
||||
2017-08-22 Richard Sandiford <richard.sandiford@linaro.org>
|
||||
Alan Hayward <alan.hayward@arm.com>
|
||||
David Sherwood <david.sherwood@arm.com>
|
||||
|
@ -281,6 +281,14 @@ struct slsr_cand_d
|
||||
/* Savings that can be expected from eliminating dead code if this
|
||||
candidate is replaced. */
|
||||
int dead_savings;
|
||||
|
||||
/* For PHI candidates, use a visited flag to keep from processing the
|
||||
same PHI twice from multiple paths. */
|
||||
int visited;
|
||||
|
||||
/* We sometimes have to cache a phi basis with a phi candidate to
|
||||
avoid processing it twice. Valid only if visited==1. */
|
||||
tree cached_basis;
|
||||
};
|
||||
|
||||
typedef struct slsr_cand_d slsr_cand, *slsr_cand_t;
|
||||
@ -369,7 +377,11 @@ enum count_phis_status
|
||||
DONT_COUNT_PHIS = 0,
|
||||
COUNT_PHIS = 1
|
||||
};
|
||||
|
||||
|
||||
/* Constrain how many PHI nodes we will visit for a conditional
|
||||
candidate (depth and breadth). */
|
||||
const int MAX_SPREAD = 16;
|
||||
|
||||
/* Pointer map embodying a mapping from statements to candidates. */
|
||||
static hash_map<gimple *, slsr_cand_t> *stmt_cand_map;
|
||||
|
||||
@ -671,6 +683,8 @@ alloc_cand_and_find_basis (enum cand_kind kind, gimple *gs, tree base,
|
||||
c->sibling = 0;
|
||||
c->def_phi = kind == CAND_MULT ? find_phi_def (base) : 0;
|
||||
c->dead_savings = savings;
|
||||
c->visited = 0;
|
||||
c->cached_basis = NULL_TREE;
|
||||
|
||||
cand_vec.safe_push (c);
|
||||
|
||||
@ -2317,19 +2331,33 @@ create_add_on_incoming_edge (slsr_cand_t c, tree basis_name,
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/* Given a candidate C with BASIS_NAME being the LHS of C's basis which
|
||||
is hidden by the phi node FROM_PHI, create a new phi node in the same
|
||||
block as FROM_PHI. The new phi is suitable for use as a basis by C,
|
||||
with its phi arguments representing conditional adjustments to the
|
||||
hidden basis along conditional incoming paths. Those adjustments are
|
||||
made by creating add statements (and sometimes recursively creating
|
||||
phis) along those incoming paths. LOC is the location to attach to
|
||||
the introduced statements. KNOWN_STRIDE is true iff C's stride is a
|
||||
constant. */
|
||||
/* Clear the visited field for a tree of PHI candidates. */
|
||||
|
||||
static void
|
||||
clear_visited (gphi *phi)
|
||||
{
|
||||
unsigned i;
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (phi);
|
||||
|
||||
if (phi_cand->visited)
|
||||
{
|
||||
phi_cand->visited = 0;
|
||||
|
||||
for (i = 0; i < gimple_phi_num_args (phi); i++)
|
||||
{
|
||||
tree arg = gimple_phi_arg_def (phi, i);
|
||||
gimple *arg_def = SSA_NAME_DEF_STMT (arg);
|
||||
if (gimple_code (arg_def) == GIMPLE_PHI)
|
||||
clear_visited (as_a <gphi *> (arg_def));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursive helper function for create_phi_basis. */
|
||||
|
||||
static tree
|
||||
create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
location_t loc, bool known_stride)
|
||||
create_phi_basis_1 (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
location_t loc, bool known_stride)
|
||||
{
|
||||
int i;
|
||||
tree name, phi_arg;
|
||||
@ -2340,6 +2368,10 @@ create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (from_phi);
|
||||
auto_vec<tree> phi_args (nargs);
|
||||
|
||||
if (phi_cand->visited)
|
||||
return phi_cand->cached_basis;
|
||||
phi_cand->visited = 1;
|
||||
|
||||
/* Process each argument of the existing phi that represents
|
||||
conditionally-executed add candidates. */
|
||||
for (i = 0; i < nargs; i++)
|
||||
@ -2367,8 +2399,8 @@ create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
process it in the same fashion to ensure that all basis
|
||||
adjustments are made along its incoming edges. */
|
||||
if (gimple_code (arg_def) == GIMPLE_PHI)
|
||||
feeding_def = create_phi_basis (c, arg_def, basis_name,
|
||||
loc, known_stride);
|
||||
feeding_def = create_phi_basis_1 (c, arg_def, basis_name,
|
||||
loc, known_stride);
|
||||
else
|
||||
{
|
||||
slsr_cand_t arg_cand = base_cand_from_table (arg);
|
||||
@ -2403,9 +2435,31 @@ create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
print_gimple_stmt (dump_file, phi, 0);
|
||||
}
|
||||
|
||||
phi_cand->cached_basis = name;
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Given a candidate C with BASIS_NAME being the LHS of C's basis which
|
||||
is hidden by the phi node FROM_PHI, create a new phi node in the same
|
||||
block as FROM_PHI. The new phi is suitable for use as a basis by C,
|
||||
with its phi arguments representing conditional adjustments to the
|
||||
hidden basis along conditional incoming paths. Those adjustments are
|
||||
made by creating add statements (and sometimes recursively creating
|
||||
phis) along those incoming paths. LOC is the location to attach to
|
||||
the introduced statements. KNOWN_STRIDE is true iff C's stride is a
|
||||
constant. */
|
||||
|
||||
static tree
|
||||
create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name,
|
||||
location_t loc, bool known_stride)
|
||||
{
|
||||
tree retval = create_phi_basis_1 (c, from_phi, basis_name, loc,
|
||||
known_stride);
|
||||
gcc_assert (retval);
|
||||
clear_visited (as_a <gphi *> (from_phi));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Given a candidate C whose basis is hidden by at least one intervening
|
||||
phi, introduce a matching number of new phis to represent its basis
|
||||
adjusted by conditional increments along possible incoming paths. Then
|
||||
@ -2429,25 +2483,29 @@ replace_conditional_candidate (slsr_cand_t c)
|
||||
loc = gimple_location (c->cand_stmt);
|
||||
name = create_phi_basis (c, lookup_cand (c->def_phi)->cand_stmt,
|
||||
basis_name, loc, KNOWN_STRIDE);
|
||||
|
||||
/* Replace C with an add of the new basis phi and a constant. */
|
||||
widest_int bump = c->index * wi::to_widest (c->stride);
|
||||
|
||||
replace_mult_candidate (c, name, bump);
|
||||
}
|
||||
|
||||
/* Compute the expected costs of inserting basis adjustments for
|
||||
candidate C with phi-definition PHI. The cost of inserting
|
||||
one adjustment is given by ONE_ADD_COST. If PHI has arguments
|
||||
which are themselves phi results, recursively calculate costs
|
||||
for those phis as well. */
|
||||
/* Recursive helper function for phi_add_costs. SPREAD is a measure of
|
||||
how many PHI nodes we have visited at this point in the tree walk. */
|
||||
|
||||
static int
|
||||
phi_add_costs (gimple *phi, slsr_cand_t c, int one_add_cost)
|
||||
phi_add_costs_1 (gimple *phi, slsr_cand_t c, int one_add_cost, int *spread)
|
||||
{
|
||||
unsigned i;
|
||||
int cost = 0;
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (phi);
|
||||
|
||||
if (phi_cand->visited)
|
||||
return 0;
|
||||
|
||||
phi_cand->visited = 1;
|
||||
(*spread)++;
|
||||
|
||||
/* If we work our way back to a phi that isn't dominated by the hidden
|
||||
basis, this isn't a candidate for replacement. Indicate this by
|
||||
returning an unreasonably high cost. It's not easy to detect
|
||||
@ -2469,7 +2527,12 @@ phi_add_costs (gimple *phi, slsr_cand_t c, int one_add_cost)
|
||||
gimple *arg_def = SSA_NAME_DEF_STMT (arg);
|
||||
|
||||
if (gimple_code (arg_def) == GIMPLE_PHI)
|
||||
cost += phi_add_costs (arg_def, c, one_add_cost);
|
||||
{
|
||||
cost += phi_add_costs_1 (arg_def, c, one_add_cost, spread);
|
||||
|
||||
if (cost >= COST_INFINITE || *spread > MAX_SPREAD)
|
||||
return COST_INFINITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
slsr_cand_t arg_cand = base_cand_from_table (arg);
|
||||
@ -2483,6 +2546,20 @@ phi_add_costs (gimple *phi, slsr_cand_t c, int one_add_cost)
|
||||
return cost;
|
||||
}
|
||||
|
||||
/* Compute the expected costs of inserting basis adjustments for
|
||||
candidate C with phi-definition PHI. The cost of inserting
|
||||
one adjustment is given by ONE_ADD_COST. If PHI has arguments
|
||||
which are themselves phi results, recursively calculate costs
|
||||
for those phis as well. */
|
||||
|
||||
static int
|
||||
phi_add_costs (gimple *phi, slsr_cand_t c, int one_add_cost)
|
||||
{
|
||||
int spread = 0;
|
||||
int retval = phi_add_costs_1 (phi, c, one_add_cost, &spread);
|
||||
clear_visited (as_a <gphi *> (phi));
|
||||
return retval;
|
||||
}
|
||||
/* For candidate C, each sibling of candidate C, and each dependent of
|
||||
candidate C, determine whether the candidate is dependent upon a
|
||||
phi that hides its basis. If not, replace the candidate unconditionally.
|
||||
@ -2648,18 +2725,18 @@ record_increment (slsr_cand_t c, widest_int increment, bool is_phi_adjust)
|
||||
}
|
||||
}
|
||||
|
||||
/* Given phi statement PHI that hides a candidate from its BASIS, find
|
||||
the increments along each incoming arc (recursively handling additional
|
||||
phis that may be present) and record them. These increments are the
|
||||
difference in index between the index-adjusting statements and the
|
||||
index of the basis. */
|
||||
/* Recursive helper function for record_phi_increments. */
|
||||
|
||||
static void
|
||||
record_phi_increments (slsr_cand_t basis, gimple *phi)
|
||||
record_phi_increments_1 (slsr_cand_t basis, gimple *phi)
|
||||
{
|
||||
unsigned i;
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (phi);
|
||||
|
||||
if (phi_cand->visited)
|
||||
return;
|
||||
phi_cand->visited = 1;
|
||||
|
||||
for (i = 0; i < gimple_phi_num_args (phi); i++)
|
||||
{
|
||||
tree arg = gimple_phi_arg_def (phi, i);
|
||||
@ -2669,7 +2746,7 @@ record_phi_increments (slsr_cand_t basis, gimple *phi)
|
||||
gimple *arg_def = SSA_NAME_DEF_STMT (arg);
|
||||
|
||||
if (gimple_code (arg_def) == GIMPLE_PHI)
|
||||
record_phi_increments (basis, arg_def);
|
||||
record_phi_increments_1 (basis, arg_def);
|
||||
else
|
||||
{
|
||||
slsr_cand_t arg_cand = base_cand_from_table (arg);
|
||||
@ -2680,6 +2757,19 @@ record_phi_increments (slsr_cand_t basis, gimple *phi)
|
||||
}
|
||||
}
|
||||
|
||||
/* Given phi statement PHI that hides a candidate from its BASIS, find
|
||||
the increments along each incoming arc (recursively handling additional
|
||||
phis that may be present) and record them. These increments are the
|
||||
difference in index between the index-adjusting statements and the
|
||||
index of the basis. */
|
||||
|
||||
static void
|
||||
record_phi_increments (slsr_cand_t basis, gimple *phi)
|
||||
{
|
||||
record_phi_increments_1 (basis, phi);
|
||||
clear_visited (as_a <gphi *> (phi));
|
||||
}
|
||||
|
||||
/* Determine how many times each unique increment occurs in the set
|
||||
of candidates rooted at C's parent, recording the data in the
|
||||
increment vector. For each unique increment I, if an initializer
|
||||
@ -2717,21 +2807,21 @@ record_increments (slsr_cand_t c)
|
||||
record_increments (lookup_cand (c->dependent));
|
||||
}
|
||||
|
||||
/* Add up and return the costs of introducing add statements that
|
||||
require the increment INCR on behalf of candidate C and phi
|
||||
statement PHI. Accumulate into *SAVINGS the potential savings
|
||||
from removing existing statements that feed PHI and have no other
|
||||
uses. */
|
||||
/* Recursive helper function for phi_incr_cost. */
|
||||
|
||||
static int
|
||||
phi_incr_cost (slsr_cand_t c, const widest_int &incr, gimple *phi,
|
||||
int *savings)
|
||||
phi_incr_cost_1 (slsr_cand_t c, const widest_int &incr, gimple *phi,
|
||||
int *savings)
|
||||
{
|
||||
unsigned i;
|
||||
int cost = 0;
|
||||
slsr_cand_t basis = lookup_cand (c->basis);
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (phi);
|
||||
|
||||
if (phi_cand->visited)
|
||||
return 0;
|
||||
phi_cand->visited = 1;
|
||||
|
||||
for (i = 0; i < gimple_phi_num_args (phi); i++)
|
||||
{
|
||||
tree arg = gimple_phi_arg_def (phi, i);
|
||||
@ -2744,7 +2834,7 @@ phi_incr_cost (slsr_cand_t c, const widest_int &incr, gimple *phi,
|
||||
{
|
||||
int feeding_savings = 0;
|
||||
tree feeding_var = gimple_phi_result (arg_def);
|
||||
cost += phi_incr_cost (c, incr, arg_def, &feeding_savings);
|
||||
cost += phi_incr_cost_1 (c, incr, arg_def, &feeding_savings);
|
||||
if (uses_consumed_by_stmt (feeding_var, phi))
|
||||
*savings += feeding_savings;
|
||||
}
|
||||
@ -2768,6 +2858,21 @@ phi_incr_cost (slsr_cand_t c, const widest_int &incr, gimple *phi,
|
||||
return cost;
|
||||
}
|
||||
|
||||
/* Add up and return the costs of introducing add statements that
|
||||
require the increment INCR on behalf of candidate C and phi
|
||||
statement PHI. Accumulate into *SAVINGS the potential savings
|
||||
from removing existing statements that feed PHI and have no other
|
||||
uses. */
|
||||
|
||||
static int
|
||||
phi_incr_cost (slsr_cand_t c, const widest_int &incr, gimple *phi,
|
||||
int *savings)
|
||||
{
|
||||
int retval = phi_incr_cost_1 (c, incr, phi, savings);
|
||||
clear_visited (as_a <gphi *> (phi));
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Return the first candidate in the tree rooted at C that has not
|
||||
already been replaced, favoring siblings over dependents. */
|
||||
|
||||
@ -3309,16 +3414,21 @@ insert_initializers (slsr_cand_t c)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return TRUE iff all required increments for candidates feeding PHI
|
||||
are profitable (and legal!) to replace on behalf of candidate C. */
|
||||
/* Recursive helper function for all_phi_incrs_profitable. */
|
||||
|
||||
static bool
|
||||
all_phi_incrs_profitable (slsr_cand_t c, gphi *phi)
|
||||
all_phi_incrs_profitable_1 (slsr_cand_t c, gphi *phi, int *spread)
|
||||
{
|
||||
unsigned i;
|
||||
slsr_cand_t basis = lookup_cand (c->basis);
|
||||
slsr_cand_t phi_cand = *stmt_cand_map->get (phi);
|
||||
|
||||
if (phi_cand->visited)
|
||||
return true;
|
||||
|
||||
phi_cand->visited = 1;
|
||||
(*spread)++;
|
||||
|
||||
/* If the basis doesn't dominate the PHI (including when the PHI is
|
||||
in the same block as the basis), we won't be able to create a PHI
|
||||
using the basis here. */
|
||||
@ -3346,7 +3456,9 @@ all_phi_incrs_profitable (slsr_cand_t c, gphi *phi)
|
||||
|
||||
if (gimple_code (arg_def) == GIMPLE_PHI)
|
||||
{
|
||||
if (!all_phi_incrs_profitable (c, as_a <gphi *> (arg_def)))
|
||||
if (!all_phi_incrs_profitable_1 (c, as_a <gphi *> (arg_def),
|
||||
spread)
|
||||
|| *spread > MAX_SPREAD)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -3388,6 +3500,18 @@ all_phi_incrs_profitable (slsr_cand_t c, gphi *phi)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return TRUE iff all required increments for candidates feeding PHI
|
||||
are profitable (and legal!) to replace on behalf of candidate C. */
|
||||
|
||||
static bool
|
||||
all_phi_incrs_profitable (slsr_cand_t c, gphi *phi)
|
||||
{
|
||||
int spread = 0;
|
||||
bool retval = all_phi_incrs_profitable_1 (c, phi, &spread);
|
||||
clear_visited (phi);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Create a NOP_EXPR that copies FROM_EXPR into a new SSA name of
|
||||
type TO_TYPE, and insert it in front of the statement represented
|
||||
by candidate C. Use *NEW_VAR to create the new SSA name. Return
|
||||
|
Loading…
Reference in New Issue
Block a user