re PR tree-optimization/91178 (Infinite recursion in split_constant_offset in slp after r260289)
2019-07-17 Richard Biener <rguenther@suse.de> PR tree-optimization/91178 * tree-ssa.c (release_defs_bitset): Iterate from higher to lower SSA names to avoid quadratic behavior in the common case. * tree-data-ref.c (split_constant_offset): Add limit argument and pass it down. Initialize it from PARAM_SSA_NAME_DEF_CHAIN_LIMIT. (split_constant_offset_1): Add limit argument and use it to limit SSA def walking. Optimize the common plus/minus case. From-SVN: r273550
This commit is contained in:
parent
7921a90e33
commit
4efd8968f8
3 changed files with 58 additions and 27 deletions
|
@ -1,3 +1,13 @@
|
|||
2019-07-17 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/91178
|
||||
* tree-ssa.c (release_defs_bitset): Iterate from higher to
|
||||
lower SSA names to avoid quadratic behavior in the common case.
|
||||
* tree-data-ref.c (split_constant_offset): Add limit argument
|
||||
and pass it down. Initialize it from PARAM_SSA_NAME_DEF_CHAIN_LIMIT.
|
||||
(split_constant_offset_1): Add limit argument and use it to
|
||||
limit SSA def walking. Optimize the common plus/minus case.
|
||||
|
||||
2019-07-17 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/91178
|
||||
|
|
|
@ -583,7 +583,8 @@ debug_ddrs (vec<ddr_p> ddrs)
|
|||
|
||||
static void
|
||||
split_constant_offset (tree exp, tree *var, tree *off,
|
||||
hash_map<tree, std::pair<tree, tree> > &cache);
|
||||
hash_map<tree, std::pair<tree, tree> > &cache,
|
||||
unsigned *limit);
|
||||
|
||||
/* Helper function for split_constant_offset. Expresses OP0 CODE OP1
|
||||
(the type of the result is TYPE) as VAR + OFF, where OFF is a nonzero
|
||||
|
@ -594,7 +595,8 @@ split_constant_offset (tree exp, tree *var, tree *off,
|
|||
static bool
|
||||
split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
||||
tree *var, tree *off,
|
||||
hash_map<tree, std::pair<tree, tree> > &cache)
|
||||
hash_map<tree, std::pair<tree, tree> > &cache,
|
||||
unsigned *limit)
|
||||
{
|
||||
tree var0, var1;
|
||||
tree off0, off1;
|
||||
|
@ -615,8 +617,15 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
/* FALLTHROUGH */
|
||||
case PLUS_EXPR:
|
||||
case MINUS_EXPR:
|
||||
split_constant_offset (op0, &var0, &off0, cache);
|
||||
split_constant_offset (op1, &var1, &off1, cache);
|
||||
if (TREE_CODE (op1) == INTEGER_CST)
|
||||
{
|
||||
split_constant_offset (op0, &var0, &off0, cache, limit);
|
||||
*var = var0;
|
||||
*off = size_binop (ocode, off0, fold_convert (ssizetype, op1));
|
||||
return true;
|
||||
}
|
||||
split_constant_offset (op0, &var0, &off0, cache, limit);
|
||||
split_constant_offset (op1, &var1, &off1, cache, limit);
|
||||
*var = fold_build2 (code, type, var0, var1);
|
||||
*off = size_binop (ocode, off0, off1);
|
||||
return true;
|
||||
|
@ -625,7 +634,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
if (TREE_CODE (op1) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
split_constant_offset (op0, &var0, &off0, cache);
|
||||
split_constant_offset (op0, &var0, &off0, cache, limit);
|
||||
*var = fold_build2 (MULT_EXPR, type, var0, op1);
|
||||
*off = size_binop (MULT_EXPR, off0, fold_convert (ssizetype, op1));
|
||||
return true;
|
||||
|
@ -649,7 +658,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
|
||||
if (poffset)
|
||||
{
|
||||
split_constant_offset (poffset, &poffset, &off1, cache);
|
||||
split_constant_offset (poffset, &poffset, &off1, cache, limit);
|
||||
off0 = size_binop (PLUS_EXPR, off0, off1);
|
||||
if (POINTER_TYPE_P (TREE_TYPE (base)))
|
||||
base = fold_build_pointer_plus (base, poffset);
|
||||
|
@ -719,11 +728,15 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
e = std::make_pair (op0, ssize_int (0));
|
||||
}
|
||||
|
||||
if (*limit == 0)
|
||||
return false;
|
||||
--*limit;
|
||||
|
||||
var0 = gimple_assign_rhs1 (def_stmt);
|
||||
var1 = gimple_assign_rhs2 (def_stmt);
|
||||
|
||||
bool res = split_constant_offset_1 (type, var0, subcode, var1,
|
||||
var, off, cache);
|
||||
var, off, cache, limit);
|
||||
if (res && use_cache)
|
||||
*cache.get (op0) = std::make_pair (*var, *off);
|
||||
return res;
|
||||
|
@ -746,7 +759,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
/* Split the unconverted operand and try to prove that
|
||||
wrapping isn't a problem. */
|
||||
tree tmp_var, tmp_off;
|
||||
split_constant_offset (op0, &tmp_var, &tmp_off, cache);
|
||||
split_constant_offset (op0, &tmp_var, &tmp_off, cache, limit);
|
||||
|
||||
/* See whether we have an SSA_NAME whose range is known
|
||||
to be [A, B]. */
|
||||
|
@ -781,7 +794,7 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
*off = wide_int_to_tree (ssizetype, diff);
|
||||
}
|
||||
else
|
||||
split_constant_offset (op0, &var0, off, cache);
|
||||
split_constant_offset (op0, &var0, off, cache, limit);
|
||||
*var = fold_convert (type, var0);
|
||||
return true;
|
||||
}
|
||||
|
@ -798,7 +811,8 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1,
|
|||
|
||||
static void
|
||||
split_constant_offset (tree exp, tree *var, tree *off,
|
||||
hash_map<tree, std::pair<tree, tree> > &cache)
|
||||
hash_map<tree, std::pair<tree, tree> > &cache,
|
||||
unsigned *limit)
|
||||
{
|
||||
tree type = TREE_TYPE (exp), op0, op1, e, o;
|
||||
enum tree_code code;
|
||||
|
@ -812,7 +826,7 @@ split_constant_offset (tree exp, tree *var, tree *off,
|
|||
|
||||
code = TREE_CODE (exp);
|
||||
extract_ops_from_tree (exp, &code, &op0, &op1);
|
||||
if (split_constant_offset_1 (type, op0, code, op1, &e, &o, cache))
|
||||
if (split_constant_offset_1 (type, op0, code, op1, &e, &o, cache, limit))
|
||||
{
|
||||
*var = e;
|
||||
*off = o;
|
||||
|
@ -822,10 +836,11 @@ split_constant_offset (tree exp, tree *var, tree *off,
|
|||
void
|
||||
split_constant_offset (tree exp, tree *var, tree *off)
|
||||
{
|
||||
unsigned limit = PARAM_VALUE (PARAM_SSA_NAME_DEF_CHAIN_LIMIT);
|
||||
static hash_map<tree, std::pair<tree, tree> > *cache;
|
||||
if (!cache)
|
||||
cache = new hash_map<tree, std::pair<tree, tree> > (37);
|
||||
split_constant_offset (exp, var, off, *cache);
|
||||
split_constant_offset (exp, var, off, *cache, &limit);
|
||||
cache->empty ();
|
||||
}
|
||||
|
||||
|
|
|
@ -559,20 +559,25 @@ release_defs_bitset (bitmap toremove)
|
|||
|
||||
/* Performing a topological sort is probably overkill, this will
|
||||
most likely run in slightly superlinear time, rather than the
|
||||
pathological quadratic worst case. */
|
||||
pathological quadratic worst case.
|
||||
But iterate from max SSA name version to min one because
|
||||
that mimics allocation order during code generation behavior best.
|
||||
Use an array for this which we compact on-the-fly with a NULL
|
||||
marker moving towards the end of the vector. */
|
||||
auto_vec<tree, 16> names;
|
||||
names.reserve (bitmap_count_bits (toremove) + 1);
|
||||
names.quick_push (NULL_TREE);
|
||||
EXECUTE_IF_SET_IN_BITMAP (toremove, 0, j, bi)
|
||||
names.quick_push (ssa_name (j));
|
||||
|
||||
bitmap_tree_view (toremove);
|
||||
while (!bitmap_empty_p (toremove))
|
||||
{
|
||||
unsigned to_remove_bit = -1U;
|
||||
EXECUTE_IF_SET_IN_BITMAP (toremove, 0, j, bi)
|
||||
j = names.length () - 1;
|
||||
for (unsigned i = names.length () - 1; names[i];)
|
||||
{
|
||||
if (to_remove_bit != -1U)
|
||||
{
|
||||
bitmap_clear_bit (toremove, to_remove_bit);
|
||||
to_remove_bit = -1U;
|
||||
}
|
||||
|
||||
bool remove_now = true;
|
||||
tree var = ssa_name (j);
|
||||
tree var = names[i];
|
||||
gimple *stmt;
|
||||
imm_use_iterator uit;
|
||||
|
||||
|
@ -617,14 +622,15 @@ release_defs_bitset (bitmap toremove)
|
|||
gsi_remove (&gsi, true);
|
||||
release_defs (def);
|
||||
}
|
||||
|
||||
to_remove_bit = j;
|
||||
bitmap_clear_bit (toremove, SSA_NAME_VERSION (var));
|
||||
}
|
||||
else
|
||||
--i;
|
||||
if (--j != i)
|
||||
names[i] = names[j];
|
||||
}
|
||||
if (to_remove_bit != -1U)
|
||||
bitmap_clear_bit (toremove, to_remove_bit);
|
||||
}
|
||||
|
||||
bitmap_list_view (toremove);
|
||||
}
|
||||
|
||||
/* Disable warnings about missing quoting in GCC diagnostics for
|
||||
|
|
Loading…
Add table
Reference in a new issue