mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
Avoid expicit builtion list in tree-ssa-dce
while working on -fmalloc-dce I noticed that tree-ssa-dce.cc still has an outdated list of builtions that are known to not read memory that can be replaced by query to fnspec and modref. If I get things right, dce does some dead store removal, but only on those memory object that are non-aliased (automatic variabels with no address taken) and for all other memory addresses it resorts to mark_all_reaching_defs_necessary expecting DSE to do the rest. So we really want to only check if there are no memory reads at all rather then trying to understand them by parsing fnspec or modref summary. I did run testsuite ensuring that all builtins matched previously are still matched. There are few testcases where this check fails, due to type incompatibility. New code uses gimple_call_builtin while other just checked callee_decl. We test things like calling free() without parmeter which I don't think we want to care about, but there is also testase declaring void * calloc (long, long) where builtin declaration expects unsigned long. I am not sure if this case should not be allowed by gimple_call_builtin? Bootstrappe/regtested x86_64-linux. OK? gcc/ChangeLog: * ipa-modref.cc (ipa_modref_callee_reads_no_memory_p): New function. * ipa-modref.h (ipa_modref_callee_reads_no_memory_p): Declare * tree-ssa-dce.cc (propagate_necessity): Use it.
This commit is contained in:
parent
101f8c73d5
commit
cc33f880e5
@ -5600,4 +5600,36 @@ ipa_modref_cc_finalize ()
|
|||||||
escape_summaries = NULL;
|
escape_summaries = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if call is known to perform no memory reads. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
ipa_modref_callee_reads_no_memory_p (gcall *call)
|
||||||
|
{
|
||||||
|
if (gimple_call_flags (call) & ECF_CONST)
|
||||||
|
return true;
|
||||||
|
attr_fnspec fnspec = gimple_call_fnspec (call);
|
||||||
|
if (fnspec.known_p ()
|
||||||
|
&& !fnspec.global_memory_read_p ())
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (unsigned int i = 0; i < gimple_call_num_args (call) && !found; i++)
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
|
||||||
|
;
|
||||||
|
else if (!fnspec.arg_specified_p (i)
|
||||||
|
|| fnspec.arg_maybe_read_p (i))
|
||||||
|
found = true;
|
||||||
|
if (!found)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For interposed calls we can not be sure that the other, semantically
|
||||||
|
equivalent body, will not perform some redundant load from memory
|
||||||
|
that may become undefined if we optimize out some stores. */
|
||||||
|
bool interposed;
|
||||||
|
modref_summary *sum = get_modref_function_summary (call, &interposed);
|
||||||
|
if (sum && !interposed && !sum->global_memory_read && !sum->loads)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#include "gt-ipa-modref.h"
|
#include "gt-ipa-modref.h"
|
||||||
|
@ -75,6 +75,7 @@ modref_summary *get_modref_function_summary (cgraph_node *func);
|
|||||||
modref_summary *get_modref_function_summary (gcall *call, bool *interposed);
|
modref_summary *get_modref_function_summary (gcall *call, bool *interposed);
|
||||||
void ipa_modref_cc_finalize ();
|
void ipa_modref_cc_finalize ();
|
||||||
void ipa_merge_modref_summary_after_inlining (cgraph_edge *e);
|
void ipa_merge_modref_summary_after_inlining (cgraph_edge *e);
|
||||||
|
bool ipa_modref_callee_reads_no_memory_p (gcall *call);
|
||||||
|
|
||||||
/* All flags that are implied by the ECF_CONST functions. */
|
/* All flags that are implied by the ECF_CONST functions. */
|
||||||
static const int implicit_const_eaf_flags
|
static const int implicit_const_eaf_flags
|
||||||
|
12
gcc/testsuite/g++.dg/tree-ssa/pr109442.C
Normal file
12
gcc/testsuite/g++.dg/tree-ssa/pr109442.C
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// { dg-do compile { target c++11 } }
|
||||||
|
// { dg-options "-O1 -fdump-tree-optimized" }
|
||||||
|
#include <vector>
|
||||||
|
#define T int
|
||||||
|
T vat1(std::vector<T> v1) {
|
||||||
|
auto v = v1;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
// This should compile to empty function; check that no size of
|
||||||
|
// vector is determined and there is no allocation
|
||||||
|
// { dg-final { scan-tree-dump-not "_M_start" "optimized" } }
|
||||||
|
// { dg-final { scan-tree-dump-not "delete" "optimized" } }
|
@ -69,6 +69,8 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "tree-ssa-propagate.h"
|
#include "tree-ssa-propagate.h"
|
||||||
#include "gimple-fold.h"
|
#include "gimple-fold.h"
|
||||||
#include "tree-ssa.h"
|
#include "tree-ssa.h"
|
||||||
|
#include "ipa-modref-tree.h"
|
||||||
|
#include "ipa-modref.h"
|
||||||
|
|
||||||
static struct stmt_stats
|
static struct stmt_stats
|
||||||
{
|
{
|
||||||
@ -998,24 +1000,6 @@ propagate_necessity (bool aggressive)
|
|||||||
tree callee = gimple_call_fndecl (call);
|
tree callee = gimple_call_fndecl (call);
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
/* Calls to functions that are merely acting as barriers
|
|
||||||
or that only store to memory do not make any previous
|
|
||||||
stores necessary. */
|
|
||||||
if (callee != NULL_TREE
|
|
||||||
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
|
|
||||||
&& (DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET_CHK
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_MALLOC
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_ALIGNED_ALLOC
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_CALLOC
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END
|
|
||||||
|| ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE
|
|
||||||
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (callee != NULL_TREE
|
if (callee != NULL_TREE
|
||||||
&& (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
|
&& (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
|
||||||
|| DECL_IS_OPERATOR_DELETE_P (callee))
|
|| DECL_IS_OPERATOR_DELETE_P (callee))
|
||||||
@ -1025,9 +1009,9 @@ propagate_necessity (bool aggressive)
|
|||||||
if (is_removable_cxa_atexit_call (call))
|
if (is_removable_cxa_atexit_call (call))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
bool all_refs = false;
|
||||||
/* Calls implicitly load from memory, their arguments
|
/* Calls implicitly load from memory, their arguments
|
||||||
in addition may explicitly perform memory loads. */
|
in addition may explicitly perform memory loads. */
|
||||||
mark_all_reaching_defs_necessary (call);
|
|
||||||
for (i = 0; i < gimple_call_num_args (call); ++i)
|
for (i = 0; i < gimple_call_num_args (call); ++i)
|
||||||
{
|
{
|
||||||
tree arg = gimple_call_arg (call, i);
|
tree arg = gimple_call_arg (call, i);
|
||||||
@ -1038,7 +1022,13 @@ propagate_necessity (bool aggressive)
|
|||||||
arg = TREE_OPERAND (arg, 0);
|
arg = TREE_OPERAND (arg, 0);
|
||||||
if (!ref_may_be_aliased (arg))
|
if (!ref_may_be_aliased (arg))
|
||||||
mark_aliased_reaching_defs_necessary (call, arg);
|
mark_aliased_reaching_defs_necessary (call, arg);
|
||||||
|
else
|
||||||
|
all_refs = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!all_refs && ipa_modref_callee_reads_no_memory_p (call))
|
||||||
|
continue;
|
||||||
|
mark_all_reaching_defs_necessary (call);
|
||||||
}
|
}
|
||||||
else if (gimple_assign_single_p (stmt))
|
else if (gimple_assign_single_p (stmt))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user