params.def (PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE): New param.

2018-05-16  Richard Biener  <rguenther@suse.de>

	* params.def (PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE): New param.
	* doc/invoke.texi (dse-max-alias-queries-per-store): Document.
	* tree-ssa-dse.c: Include tree-ssa-loop.h.
	(check_name): New callback.
	(dse_classify_store): Track cycles via a visited bitmap of PHI
	defs and simplify handling of in-loop and across loop dead stores
	and properly fail for loop-variant refs.  Handle byte-tracking with
	multiple defs.  Use PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE for
	limiting the walk.

	* gcc.dg/tree-ssa/ssa-dse-32.c: New testcase.
	* gcc.dg/tree-ssa/ssa-dse-33.c: Likewise.
	* gcc.dg/uninit-pr81897-2.c: Use -fno-tree-dse.

From-SVN: r260288
This commit is contained in:
Richard Biener 2018-05-16 13:02:27 +00:00 committed by Richard Biener
parent 1f3cb66326
commit 311eb8168e
8 changed files with 118 additions and 51 deletions

View File

@ -1,3 +1,15 @@
2018-05-16 Richard Biener <rguenther@suse.de>
* params.def (PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE): New param.
* doc/invoke.texi (dse-max-alias-queries-per-store): Document.
* tree-ssa-dse.c: Include tree-ssa-loop.h.
(check_name): New callback.
(dse_classify_store): Track cycles via a visited bitmap of PHI
defs and simplify handling of in-loop and across loop dead stores
and properly fail for loop-variant refs. Handle byte-tracking with
multiple defs. Use PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE for
limiting the walk.
2018-05-16 Richard Sandiford <richard.sandiford@linaro.org>
* tree-vectorizer.h (vect_get_vector_types_for_stmt): Declare.

View File

@ -10439,6 +10439,11 @@ Average number of iterations of a loop.
Maximum size (in bytes) of objects tracked bytewise by dead store elimination.
Larger values may result in larger compilation times.
@item dse-max-alias-queries-per-store
Maximum number of queries into the alias oracle per store.
Larger values result in larger compilation times and may result in more
removed dead stores.
@item scev-max-expr-size
Bound on size of expressions used in the scalar evolutions analyzer.
Large expressions slow the analyzer.

View File

@ -547,6 +547,11 @@ DEFPARAM(PARAM_DSE_MAX_OBJECT_SIZE,
"Maximum size (in bytes) of objects tracked bytewise by dead store elimination.",
256, 0, 0)
DEFPARAM(PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE,
"dse-max-alias-queries-per-store",
"Maximum number of queries into the alias oracle per store.",
256, 0, 0)
DEFPARAM(PARAM_SCEV_MAX_EXPR_SIZE,
"scev-max-expr-size",
"Bound on size of expressions used in the scalar evolutions analyzer.",

View File

@ -1,3 +1,9 @@
2018-05-16 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-dse-32.c: New testcase.
* gcc.dg/tree-ssa/ssa-dse-33.c: Likewise.
* gcc.dg/uninit-pr81897-2.c: Use -fno-tree-dse.
2018-05-16 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.target/aarch64/sve/vcond_10.c: New test.

View File

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-dse1-details" } */
void f(int n)
{
char *p = __builtin_malloc (1);
int i;
do
*p = 0;
while (++i < n);
}
/* { dg-final { scan-tree-dump-times "Deleted dead store" 1 "dse1" } } */

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-dse1-details" } */
void f(char *p, int n)
{
for (int i = 0; i < n; ++i)
*p = 0; /* Removed by DSE. */
*p = 1;
}
void g(char *p, int n)
{
int i = 0;
do
*p = 0; /* Not yet removed by DSE. */
while (++i < n);
*p = 1;
}
/* { dg-final { scan-tree-dump-times "Deleted dead store" 2 "dse1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "Deleted dead store" 1 "dse1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fno-tree-ccp -Wmaybe-uninitialized" } */
/* { dg-options "-O1 -fno-tree-ccp -fno-tree-dse -Wmaybe-uninitialized" } */
int oo;

View File

@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-cfgcleanup.h"
#include "params.h"
#include "alias.h"
#include "tree-ssa-loop.h"
/* This file implements dead store elimination.
@ -515,6 +516,21 @@ live_bytes_read (ao_ref use_ref, ao_ref *ref, sbitmap live)
return true;
}
/* Callback for dse_classify_store calling for_each_index. Verify that
indices are invariant in the loop with backedge PHI in basic-block DATA. */
static bool
check_name (tree, tree *idx, void *data)
{
basic_block phi_bb = (basic_block) data;
if (TREE_CODE (*idx) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (*idx)
&& dominated_by_p (CDI_DOMINATORS, gimple_bb (SSA_NAME_DEF_STMT (*idx)),
phi_bb))
return false;
return true;
}
/* A helper of dse_optimize_stmt.
Given a GIMPLE_ASSIGN in STMT that writes to REF, classify it
according to downstream uses and defs. Sets *BY_CLOBBER_P to true
@ -527,7 +543,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt,
bool *by_clobber_p = NULL)
{
gimple *temp;
unsigned cnt = 0;
int cnt = 0;
auto_bitmap visited;
if (by_clobber_p)
*by_clobber_p = true;
@ -539,58 +556,50 @@ dse_classify_store (ao_ref *ref, gimple *stmt,
temp = stmt;
do
{
gimple *use_stmt, *defvar_def;
gimple *use_stmt;
imm_use_iterator ui;
bool fail = false;
tree defvar;
/* Limit stmt walking to be linear in the number of possibly
dead stores. */
if (++cnt > 256)
return DSE_STORE_LIVE;
if (gimple_code (temp) == GIMPLE_PHI)
defvar = PHI_RESULT (temp);
{
/* If we visit this PHI by following a backedge then we have to
make sure ref->ref only refers to SSA names that are invariant
with respect to the loop represented by this PHI node. */
if (dominated_by_p (CDI_DOMINATORS, gimple_bb (stmt),
gimple_bb (temp))
&& !for_each_index (ref->ref ? &ref->ref : &ref->base,
check_name, gimple_bb (temp)))
return DSE_STORE_LIVE;
defvar = PHI_RESULT (temp);
bitmap_set_bit (visited, SSA_NAME_VERSION (defvar));
}
else
defvar = gimple_vdef (temp);
defvar_def = temp;
auto_vec<gimple *, 10> defs;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar)
{
cnt++;
/* If we ever reach our DSE candidate stmt again fail. We
cannot handle dead stores in loops. */
if (use_stmt == stmt)
/* Limit stmt walking. */
if (++cnt > PARAM_VALUE (PARAM_DSE_MAX_ALIAS_QUERIES_PER_STORE))
{
fail = true;
BREAK_FROM_IMM_USE_STMT (ui);
}
/* We have visited ourselves already so ignore STMT for the
purpose of chaining. */
if (use_stmt == stmt)
;
/* In simple cases we can look through PHI nodes, but we
have to be careful with loops and with memory references
containing operands that are also operands of PHI nodes.
See gcc.c-torture/execute/20051110-*.c. */
else if (gimple_code (use_stmt) == GIMPLE_PHI)
{
/* Make sure we are not in a loop latch block. */
if (gimple_bb (stmt) == gimple_bb (use_stmt)
|| dominated_by_p (CDI_DOMINATORS,
gimple_bb (stmt), gimple_bb (use_stmt))
/* We can look through PHIs to regions post-dominating
the DSE candidate stmt. */
|| !dominated_by_p (CDI_POST_DOMINATORS,
gimple_bb (stmt), gimple_bb (use_stmt)))
{
fail = true;
BREAK_FROM_IMM_USE_STMT (ui);
}
/* Do not consider the PHI as use if it dominates the
stmt defining the virtual operand we are processing,
we have processed it already in this case. */
if (gimple_bb (defvar_def) != gimple_bb (use_stmt)
&& !dominated_by_p (CDI_DOMINATORS,
gimple_bb (defvar_def),
gimple_bb (use_stmt)))
/* If we already visited this PHI ignore it for further
processing. */
if (!bitmap_bit_p (visited,
SSA_NAME_VERSION (PHI_RESULT (use_stmt))))
defs.safe_push (use_stmt);
}
/* If the statement is a use the store is not dead. */
@ -600,25 +609,20 @@ dse_classify_store (ao_ref *ref, gimple *stmt,
structure for USE_STMT and in doing so we find that the
references hit non-live bytes and thus can be ignored. */
if (byte_tracking_enabled
&& (!gimple_vdef (use_stmt) || defs.is_empty ()))
&& is_gimple_assign (use_stmt))
{
if (is_gimple_assign (use_stmt))
ao_ref use_ref;
ao_ref_init (&use_ref, gimple_assign_rhs1 (use_stmt));
if (valid_ao_ref_for_dse (&use_ref)
&& use_ref.base == ref->base
&& known_eq (use_ref.size, use_ref.max_size)
&& !live_bytes_read (use_ref, ref, live_bytes))
{
/* Other cases were noted as non-aliasing by
the call to ref_maybe_used_by_stmt_p. */
ao_ref use_ref;
ao_ref_init (&use_ref, gimple_assign_rhs1 (use_stmt));
if (valid_ao_ref_for_dse (&use_ref)
&& use_ref.base == ref->base
&& known_eq (use_ref.size, use_ref.max_size)
&& !live_bytes_read (use_ref, ref, live_bytes))
{
/* If this statement has a VDEF, then it is the
first store we have seen, so walk through it. */
if (gimple_vdef (use_stmt))
defs.safe_push (use_stmt);
continue;
}
/* If this is a store, remember it as we possibly
need to walk the defs uses. */
if (gimple_vdef (use_stmt))
defs.safe_push (use_stmt);
continue;
}
}