tree-ssa-dse.c (dse_classify_store): Remove use_stmt parameter, add by_clobber_p one.

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

	* tree-ssa-dse.c (dse_classify_store): Remove use_stmt parameter,
	add by_clobber_p one.  Change algorithm to collect all defs
	representing uses we need to walk and try reducing them to
	a single one before failing.
	(dse_dom_walker::dse_optimize_stmt): Adjust.

	* gcc.dg/tree-ssa/ssa-dse-31.c: New testcase.

From-SVN: r260253
This commit is contained in:
Richard Biener 2018-05-15 11:30:29 +00:00 committed by Richard Biener
parent 35b361b116
commit afe3cc7388
4 changed files with 94 additions and 42 deletions

View File

@ -1,3 +1,11 @@
2018-05-15 Richard Biener <rguenther@suse.de>
* tree-ssa-dse.c (dse_classify_store): Remove use_stmt parameter,
add by_clobber_p one. Change algorithm to collect all defs
representing uses we need to walk and try reducing them to
a single one before failing.
(dse_dom_walker::dse_optimize_stmt): Adjust.
2018-05-13 Mark Wielaard <mark@klomp.org> 2018-05-13 Mark Wielaard <mark@klomp.org>
* dwarf2out.c (dwarf_OP): Handle DW_OP_addrx and DW_OP_constx. * dwarf2out.c (dwarf_OP): Handle DW_OP_addrx and DW_OP_constx.

View File

@ -1,3 +1,7 @@
2018-05-15 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-dse-31.c: New testcase.
2018-05-15 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> 2018-05-15 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
PR tree-optimization/83648 PR tree-optimization/83648

View File

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

View File

@ -516,18 +516,21 @@ live_bytes_read (ao_ref use_ref, ao_ref *ref, sbitmap live)
} }
/* A helper of dse_optimize_stmt. /* A helper of dse_optimize_stmt.
Given a GIMPLE_ASSIGN in STMT that writes to REF, find a candidate Given a GIMPLE_ASSIGN in STMT that writes to REF, classify it
statement *USE_STMT that may prove STMT to be dead. according to downstream uses and defs. Sets *BY_CLOBBER_P to true
Return TRUE if the above conditions are met, otherwise FALSE. */ if only clobber statements influenced the classification result.
Returns the classification. */
static dse_store_status static dse_store_status
dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt, dse_classify_store (ao_ref *ref, gimple *stmt,
bool byte_tracking_enabled, sbitmap live_bytes) bool byte_tracking_enabled, sbitmap live_bytes,
bool *by_clobber_p = NULL)
{ {
gimple *temp; gimple *temp;
unsigned cnt = 0; unsigned cnt = 0;
*use_stmt = NULL; if (by_clobber_p)
*by_clobber_p = true;
/* Find the first dominated statement that clobbers (part of) the /* Find the first dominated statement that clobbers (part of) the
memory stmt stores to with no intermediate statement that may use memory stmt stores to with no intermediate statement that may use
@ -551,7 +554,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
else else
defvar = gimple_vdef (temp); defvar = gimple_vdef (temp);
defvar_def = temp; defvar_def = temp;
temp = NULL; auto_vec<gimple *, 10> defs;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar) FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar)
{ {
cnt++; cnt++;
@ -569,9 +572,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
See gcc.c-torture/execute/20051110-*.c. */ See gcc.c-torture/execute/20051110-*.c. */
else if (gimple_code (use_stmt) == GIMPLE_PHI) else if (gimple_code (use_stmt) == GIMPLE_PHI)
{ {
if (temp /* Make sure we are not in a loop latch block. */
/* Make sure we are not in a loop latch block. */ if (gimple_bb (stmt) == gimple_bb (use_stmt)
|| gimple_bb (stmt) == gimple_bb (use_stmt)
|| dominated_by_p (CDI_DOMINATORS, || dominated_by_p (CDI_DOMINATORS,
gimple_bb (stmt), gimple_bb (use_stmt)) gimple_bb (stmt), gimple_bb (use_stmt))
/* We can look through PHIs to regions post-dominating /* We can look through PHIs to regions post-dominating
@ -589,7 +591,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
&& !dominated_by_p (CDI_DOMINATORS, && !dominated_by_p (CDI_DOMINATORS,
gimple_bb (defvar_def), gimple_bb (defvar_def),
gimple_bb (use_stmt))) gimple_bb (use_stmt)))
temp = use_stmt; defs.safe_push (use_stmt);
} }
/* If the statement is a use the store is not dead. */ /* If the statement is a use the store is not dead. */
else if (ref_maybe_used_by_stmt_p (use_stmt, ref)) else if (ref_maybe_used_by_stmt_p (use_stmt, ref))
@ -597,7 +599,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
/* Handle common cases where we can easily build an ao_ref /* Handle common cases where we can easily build an ao_ref
structure for USE_STMT and in doing so we find that the structure for USE_STMT and in doing so we find that the
references hit non-live bytes and thus can be ignored. */ references hit non-live bytes and thus can be ignored. */
if (byte_tracking_enabled && (!gimple_vdef (use_stmt) || !temp)) if (byte_tracking_enabled
&& (!gimple_vdef (use_stmt) || defs.is_empty ()))
{ {
if (is_gimple_assign (use_stmt)) if (is_gimple_assign (use_stmt))
{ {
@ -613,7 +616,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
/* If this statement has a VDEF, then it is the /* If this statement has a VDEF, then it is the
first store we have seen, so walk through it. */ first store we have seen, so walk through it. */
if (gimple_vdef (use_stmt)) if (gimple_vdef (use_stmt))
temp = use_stmt; defs.safe_push (use_stmt);
continue; continue;
} }
} }
@ -622,17 +625,10 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
fail = true; fail = true;
BREAK_FROM_IMM_USE_STMT (ui); BREAK_FROM_IMM_USE_STMT (ui);
} }
/* If this is a store, remember it or bail out if we have /* If this is a store, remember it as we possibly need to walk the
multiple ones (the will be in different CFG parts then). */ defs uses. */
else if (gimple_vdef (use_stmt)) else if (gimple_vdef (use_stmt))
{ defs.safe_push (use_stmt);
if (temp)
{
fail = true;
BREAK_FROM_IMM_USE_STMT (ui);
}
temp = use_stmt;
}
} }
if (fail) if (fail)
@ -647,25 +643,54 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
/* If we didn't find any definition this means the store is dead /* If we didn't find any definition this means the store is dead
if it isn't a store to global reachable memory. In this case if it isn't a store to global reachable memory. In this case
just pretend the stmt makes itself dead. Otherwise fail. */ just pretend the stmt makes itself dead. Otherwise fail. */
if (!temp) if (defs.is_empty ())
{ {
if (ref_may_alias_global_p (ref)) if (ref_may_alias_global_p (ref))
return DSE_STORE_LIVE; return DSE_STORE_LIVE;
temp = stmt; if (by_clobber_p)
break; *by_clobber_p = false;
return DSE_STORE_DEAD;
} }
if (byte_tracking_enabled && temp) /* Process defs and remove paths starting with a kill from further
clear_bytes_written_by (live_bytes, temp, ref); processing. */
} for (unsigned i = 0; i < defs.length (); ++i)
/* Continue walking until we reach a full kill as a single statement if (stmt_kills_ref_p (defs[i], ref))
or there are no more live bytes. */ {
while (!stmt_kills_ref_p (temp, ref) if (by_clobber_p && !gimple_clobber_p (defs[i]))
&& !(byte_tracking_enabled && bitmap_empty_p (live_bytes))); *by_clobber_p = false;
defs.unordered_remove (i);
}
*use_stmt = temp; /* If all defs kill the ref we are done. */
return DSE_STORE_DEAD; if (defs.is_empty ())
return DSE_STORE_DEAD;
/* If more than one def survives fail. */
if (defs.length () > 1)
{
/* STMT might be partially dead and we may be able to reduce
how many memory locations it stores into. */
if (byte_tracking_enabled && !gimple_clobber_p (stmt))
return DSE_STORE_MAYBE_PARTIAL_DEAD;
return DSE_STORE_LIVE;
}
temp = defs[0];
/* Track partial kills. */
if (byte_tracking_enabled)
{
clear_bytes_written_by (live_bytes, temp, ref);
if (bitmap_empty_p (live_bytes))
{
if (by_clobber_p && !gimple_clobber_p (temp))
*by_clobber_p = false;
return DSE_STORE_DEAD;
}
}
}
/* Continue walking until there are no more live bytes. */
while (1);
} }
@ -795,11 +820,10 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi)
return; return;
} }
gimple *use_stmt;
enum dse_store_status store_status; enum dse_store_status store_status;
m_byte_tracking_enabled m_byte_tracking_enabled
= setup_live_bytes_from_ref (&ref, m_live_bytes); = setup_live_bytes_from_ref (&ref, m_live_bytes);
store_status = dse_classify_store (&ref, stmt, &use_stmt, store_status = dse_classify_store (&ref, stmt,
m_byte_tracking_enabled, m_byte_tracking_enabled,
m_live_bytes); m_live_bytes);
if (store_status == DSE_STORE_LIVE) if (store_status == DSE_STORE_LIVE)
@ -823,20 +847,20 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi)
if (is_gimple_assign (stmt)) if (is_gimple_assign (stmt))
{ {
gimple *use_stmt; bool by_clobber_p = false;
/* Self-assignments are zombies. */ /* Self-assignments are zombies. */
if (operand_equal_p (gimple_assign_rhs1 (stmt), if (operand_equal_p (gimple_assign_rhs1 (stmt),
gimple_assign_lhs (stmt), 0)) gimple_assign_lhs (stmt), 0))
use_stmt = stmt; ;
else else
{ {
m_byte_tracking_enabled m_byte_tracking_enabled
= setup_live_bytes_from_ref (&ref, m_live_bytes); = setup_live_bytes_from_ref (&ref, m_live_bytes);
enum dse_store_status store_status; enum dse_store_status store_status;
store_status = dse_classify_store (&ref, stmt, &use_stmt, store_status = dse_classify_store (&ref, stmt,
m_byte_tracking_enabled, m_byte_tracking_enabled,
m_live_bytes); m_live_bytes, &by_clobber_p);
if (store_status == DSE_STORE_LIVE) if (store_status == DSE_STORE_LIVE)
return; return;
@ -852,7 +876,7 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi)
/* But only remove *this_2(D) ={v} {CLOBBER} if killed by /* But only remove *this_2(D) ={v} {CLOBBER} if killed by
another clobber stmt. */ another clobber stmt. */
if (gimple_clobber_p (stmt) if (gimple_clobber_p (stmt)
&& !gimple_clobber_p (use_stmt)) && !by_clobber_p)
return; return;
delete_dead_assignment (gsi); delete_dead_assignment (gsi);