re PR middle-end/90726 (exponential behavior on SCEV results everywhere)

2019-06-04  Richard Biener  <rguenther@suse.de>

	PR middle-end/90726
	* tree-chrec.c (chrec_contains_symbols): Add to visited.
	(tree_contains_chrecs): Likewise.
	(chrec_contains_symbols_defined_in_loop): Move here and avoid
	exponential behaivor from ...
	* tree-scalar-evolution.c (chrec_contains_symbols_defined_in_loop):
	... here.
	(expression_expensive_p): Avoid exponential behavior and compute
	expanded size, rejecting any expansion.
	* tree-ssa-loop-ivopts.c (abnormal_ssa_name_p): Remove.
	(idx_contains_abnormal_ssa_name_p): Likewise.
	(contains_abnormal_ssa_name_p_1): New helper for walk_tree.
	(contains_abnormal_ssa_name_p): Simplify and use
	walk_tree_without_duplicates.

	* gcc.dg/pr90726.c: New testcase.

From-SVN: r271903
This commit is contained in:
Richard Biener 2019-06-04 09:05:10 +00:00 committed by Richard Biener
parent d62887a42b
commit 5fd8a9cb5b
6 changed files with 206 additions and 139 deletions

View File

@ -1,3 +1,20 @@
2019-06-04 Richard Biener <rguenther@suse.de>
PR middle-end/90726
* tree-chrec.c (chrec_contains_symbols): Add to visited.
(tree_contains_chrecs): Likewise.
(chrec_contains_symbols_defined_in_loop): Move here and avoid
exponential behaivor from ...
* tree-scalar-evolution.c (chrec_contains_symbols_defined_in_loop):
... here.
(expression_expensive_p): Avoid exponential behavior and compute
expanded size, rejecting any expansion.
* tree-ssa-loop-ivopts.c (abnormal_ssa_name_p): Remove.
(idx_contains_abnormal_ssa_name_p): Likewise.
(contains_abnormal_ssa_name_p_1): New helper for walk_tree.
(contains_abnormal_ssa_name_p): Simplify and use
walk_tree_without_duplicates.
2019-06-04 Richard Biener <rguenther@suse.de>
PR tree-optimization/90738

View File

@ -1,3 +1,8 @@
2019-06-04 Richard Biener <rguenther@suse.de>
PR middle-end/90726
* gcc.dg/pr90726.c: New testcase.
2019-06-04 Richard Biener <rguenther@suse.de>
PR tree-optimization/90738

View File

@ -0,0 +1,56 @@
/* { dg-do compile } */
/* { dg-options "-fgimple -O2 -fno-ivopts" } */
int __GIMPLE (ssa,guessed_local(12348030),startwith("fix_loops"))
un (int dd)
{
int s2;
int q8;
int nz;
__BB(2,guessed_local(12348030)):
goto __BB3(guessed(134217728));
__BB(3,loop_header(1),guessed_local(37044096)):
nz_7 = __PHI (__BB2: 0, __BB5: nz_10);
q8_13 = dd_9(D) * dd_9(D);
q8_17 = q8_13 * q8_13;
q8_21 = q8_17 * q8_17;
q8_25 = q8_21 * q8_21;
q8_29 = q8_25 * q8_25;
q8_33 = q8_29 * q8_29;
q8_37 = q8_33 * q8_33;
q8_41 = q8_37 * q8_37;
q8_45 = q8_41 * q8_41;
q8_49 = q8_45 * q8_45;
q8_53 = q8_49 * q8_49;
q8_57 = q8_53 * q8_53;
q8_61 = q8_57 * q8_57;
q8_65 = q8_61 * q8_61;
q8_69 = q8_65 * q8_65;
q8_73 = q8_69 * q8_69;
q8_77 = q8_73 * q8_73;
q8_81 = q8_77 * q8_77;
q8_85 = q8_81 * q8_81;
q8_89 = q8_85 * q8_85;
q8_93 = q8_89 * q8_89;
q8_97 = q8_93 * q8_93;
q8_101 = q8_97 * q8_97;
q8_105 = q8_101 * q8_101;
q8_109 = q8_105 * q8_105;
q8_113 = q8_109 * q8_109;
q8_117 = q8_113 * q8_113;
q8_121 = q8_117 * q8_117;
nz_10 = nz_7 + 1;
if (nz_10 != 3)
goto __BB5(guessed(89478485));
else
goto __BB4(guessed(44739243));
__BB(5,guessed_local(24696064)):
goto __BB3(precise(134217728));
__BB(4,guessed_local(12348031)):
return q8_121;
}

View File

@ -35,6 +35,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-loop-ivopts.h"
#include "tree-ssa-loop-niter.h"
#include "tree-chrec.h"
#include "gimple.h"
#include "tree-ssa-loop.h"
#include "dumpfile.h"
#include "params.h"
#include "tree-scalar-evolution.h"
@ -959,6 +961,9 @@ chrec_contains_symbols (const_tree chrec, hash_set<const_tree> &visited,
&& flow_loop_nested_p (get_chrec_loop (chrec), loop))
return true;
if (visited.add (chrec))
return false;
n = TREE_OPERAND_LENGTH (chrec);
for (i = 0; i < n; i++)
if (chrec_contains_symbols (TREE_OPERAND (chrec, i), visited, loop))
@ -978,6 +983,63 @@ chrec_contains_symbols (const_tree chrec, struct loop* loop)
return chrec_contains_symbols (chrec, visited, loop);
}
/* Return true when CHREC contains symbolic names defined in
LOOP_NB. */
static bool
chrec_contains_symbols_defined_in_loop (const_tree chrec, unsigned loop_nb,
hash_set<const_tree> &visited)
{
int i, n;
if (chrec == NULL_TREE)
return false;
if (is_gimple_min_invariant (chrec))
return false;
if (TREE_CODE (chrec) == SSA_NAME)
{
gimple *def;
loop_p def_loop, loop;
if (SSA_NAME_IS_DEFAULT_DEF (chrec))
return false;
def = SSA_NAME_DEF_STMT (chrec);
def_loop = loop_containing_stmt (def);
loop = get_loop (cfun, loop_nb);
if (def_loop == NULL)
return false;
if (loop == def_loop || flow_loop_nested_p (loop, def_loop))
return true;
return false;
}
if (visited.add (chrec))
return false;
n = TREE_OPERAND_LENGTH (chrec);
for (i = 0; i < n; i++)
if (chrec_contains_symbols_defined_in_loop (TREE_OPERAND (chrec, i),
loop_nb, visited))
return true;
return false;
}
/* Return true when CHREC contains symbolic names defined in
LOOP_NB. */
bool
chrec_contains_symbols_defined_in_loop (const_tree chrec, unsigned loop_nb)
{
hash_set<const_tree> visited;
return chrec_contains_symbols_defined_in_loop (chrec, loop_nb, visited);
}
/* Determines whether the chrec contains undetermined coefficients. */
static bool
@ -1026,6 +1088,9 @@ tree_contains_chrecs (const_tree expr, int *size, hash_set<const_tree> &visited)
if (tree_is_chrec (expr))
return true;
if (visited.add (expr))
return false;
n = TREE_OPERAND_LENGTH (expr);
for (i = 0; i < n; i++)
if (tree_contains_chrecs (TREE_OPERAND (expr, i), size, visited))

View File

@ -411,49 +411,6 @@ instantiate_cache_type::~instantiate_cache_type ()
static instantiate_cache_type *global_cache;
/* Return true when CHREC contains symbolic names defined in
LOOP_NB. */
bool
chrec_contains_symbols_defined_in_loop (const_tree chrec, unsigned loop_nb)
{
int i, n;
if (chrec == NULL_TREE)
return false;
if (is_gimple_min_invariant (chrec))
return false;
if (TREE_CODE (chrec) == SSA_NAME)
{
gimple *def;
loop_p def_loop, loop;
if (SSA_NAME_IS_DEFAULT_DEF (chrec))
return false;
def = SSA_NAME_DEF_STMT (chrec);
def_loop = loop_containing_stmt (def);
loop = get_loop (cfun, loop_nb);
if (def_loop == NULL)
return false;
if (loop == def_loop || flow_loop_nested_p (loop, def_loop))
return true;
return false;
}
n = TREE_OPERAND_LENGTH (chrec);
for (i = 0; i < n; i++)
if (chrec_contains_symbols_defined_in_loop (TREE_OPERAND (chrec, i),
loop_nb))
return true;
return false;
}
/* Return true when PHI is a loop-phi-node. */
static bool
@ -3505,8 +3462,9 @@ scev_finalize (void)
/* Returns true if the expression EXPR is considered to be too expensive
for scev_const_prop. */
bool
expression_expensive_p (tree expr)
static bool
expression_expensive_p (tree expr, hash_map<tree, uint64_t> &cache,
uint64_t &cost)
{
enum tree_code code;
@ -3530,6 +3488,19 @@ expression_expensive_p (tree expr)
return true;
}
bool visited_p;
uint64_t &local_cost = cache.get_or_insert (expr, &visited_p);
if (visited_p)
{
uint64_t tem = cost + local_cost;
if (tem < cost)
return true;
cost = tem;
return false;
}
local_cost = 1;
uint64_t op_cost = 0;
if (code == CALL_EXPR)
{
tree arg;
@ -3568,39 +3539,62 @@ expression_expensive_p (tree expr)
if (!is_inexpensive_builtin (get_callee_fndecl (expr)))
return true;
FOR_EACH_CALL_EXPR_ARG (arg, iter, expr)
if (expression_expensive_p (arg))
if (expression_expensive_p (arg, cache, op_cost))
return true;
*cache.get (expr) += op_cost;
cost += op_cost + 1;
return false;
}
if (code == COND_EXPR)
return (expression_expensive_p (TREE_OPERAND (expr, 0))
|| (EXPR_P (TREE_OPERAND (expr, 1))
&& EXPR_P (TREE_OPERAND (expr, 2)))
/* If either branch has side effects or could trap. */
|| TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
|| generic_expr_could_trap_p (TREE_OPERAND (expr, 1))
|| TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))
|| generic_expr_could_trap_p (TREE_OPERAND (expr, 0))
|| expression_expensive_p (TREE_OPERAND (expr, 1))
|| expression_expensive_p (TREE_OPERAND (expr, 2)));
{
if (expression_expensive_p (TREE_OPERAND (expr, 0), cache, op_cost)
|| (EXPR_P (TREE_OPERAND (expr, 1))
&& EXPR_P (TREE_OPERAND (expr, 2)))
/* If either branch has side effects or could trap. */
|| TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
|| generic_expr_could_trap_p (TREE_OPERAND (expr, 1))
|| TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))
|| generic_expr_could_trap_p (TREE_OPERAND (expr, 0))
|| expression_expensive_p (TREE_OPERAND (expr, 1),
cache, op_cost)
|| expression_expensive_p (TREE_OPERAND (expr, 2),
cache, op_cost))
return true;
*cache.get (expr) += op_cost;
cost += op_cost + 1;
return false;
}
switch (TREE_CODE_CLASS (code))
{
case tcc_binary:
case tcc_comparison:
if (expression_expensive_p (TREE_OPERAND (expr, 1)))
if (expression_expensive_p (TREE_OPERAND (expr, 1), cache, op_cost))
return true;
/* Fallthru. */
case tcc_unary:
return expression_expensive_p (TREE_OPERAND (expr, 0));
if (expression_expensive_p (TREE_OPERAND (expr, 0), cache, op_cost))
return true;
*cache.get (expr) += op_cost;
cost += op_cost + 1;
return false;
default:
return true;
}
}
bool
expression_expensive_p (tree expr)
{
hash_map<tree, uint64_t> cache;
uint64_t expanded_size = 0;
return (expression_expensive_p (expr, cache, expanded_size)
|| expanded_size > cache.elements ());
}
/* Do final value replacement for LOOP, return true if we did anything. */
bool

View File

@ -944,36 +944,19 @@ stmt_after_increment (struct loop *loop, struct iv_cand *cand, gimple *stmt)
}
}
/* Returns true if EXP is a ssa name that occurs in an abnormal phi node. */
/* walk_tree callback for contains_abnormal_ssa_name_p. */
static bool
abnormal_ssa_name_p (tree exp)
static tree
contains_abnormal_ssa_name_p_1 (tree *tp, int *walk_subtrees, void *)
{
if (!exp)
return false;
if (TREE_CODE (*tp) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (*tp))
return *tp;
if (TREE_CODE (exp) != SSA_NAME)
return false;
if (!EXPR_P (*tp))
*walk_subtrees = 0;
return SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) != 0;
}
/* Returns false if BASE or INDEX contains a ssa name that occurs in an
abnormal phi node. Callback for for_each_index. */
static bool
idx_contains_abnormal_ssa_name_p (tree base, tree *index,
void *data ATTRIBUTE_UNUSED)
{
if (TREE_CODE (base) == ARRAY_REF || TREE_CODE (base) == ARRAY_RANGE_REF)
{
if (abnormal_ssa_name_p (TREE_OPERAND (base, 2)))
return false;
if (abnormal_ssa_name_p (TREE_OPERAND (base, 3)))
return false;
}
return !abnormal_ssa_name_p (*index);
return NULL_TREE;
}
/* Returns true if EXPR contains a ssa name that occurs in an
@ -982,61 +965,8 @@ idx_contains_abnormal_ssa_name_p (tree base, tree *index,
bool
contains_abnormal_ssa_name_p (tree expr)
{
enum tree_code code;
enum tree_code_class codeclass;
if (!expr)
return false;
code = TREE_CODE (expr);
codeclass = TREE_CODE_CLASS (code);
if (code == CALL_EXPR)
{
tree arg;
call_expr_arg_iterator iter;
FOR_EACH_CALL_EXPR_ARG (arg, iter, expr)
if (contains_abnormal_ssa_name_p (arg))
return true;
return false;
}
if (code == SSA_NAME)
return SSA_NAME_OCCURS_IN_ABNORMAL_PHI (expr) != 0;
if (code == INTEGER_CST
|| is_gimple_min_invariant (expr))
return false;
if (code == ADDR_EXPR)
return !for_each_index (&TREE_OPERAND (expr, 0),
idx_contains_abnormal_ssa_name_p,
NULL);
if (code == COND_EXPR)
return contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 0))
|| contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 1))
|| contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 2));
switch (codeclass)
{
case tcc_binary:
case tcc_comparison:
if (contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 1)))
return true;
/* Fallthru. */
case tcc_unary:
if (contains_abnormal_ssa_name_p (TREE_OPERAND (expr, 0)))
return true;
break;
default:
gcc_unreachable ();
}
return false;
return walk_tree_without_duplicates
(&expr, contains_abnormal_ssa_name_p_1, NULL) != NULL_TREE;
}
/* Returns the structure describing number of iterations determined from