diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc index c1973aa36c4..12ac0e7865a 100644 --- a/gcc/ipa-modref.cc +++ b/gcc/ipa-modref.cc @@ -5600,4 +5600,36 @@ ipa_modref_cc_finalize () 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" diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index 1bbe9bffee0..a0eb63a0afa 100644 --- a/gcc/ipa-modref.h +++ b/gcc/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); void ipa_modref_cc_finalize (); 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. */ static const int implicit_const_eaf_flags diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr109442.C b/gcc/testsuite/g++.dg/tree-ssa/pr109442.C new file mode 100644 index 00000000000..ec40c470c8d --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr109442.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-O1 -fdump-tree-optimized" } +#include +#define T int +T vat1(std::vector 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" } } diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc index 643a1efd870..70e3843cabf 100644 --- a/gcc/tree-ssa-dce.cc +++ b/gcc/tree-ssa-dce.cc @@ -69,6 +69,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-propagate.h" #include "gimple-fold.h" #include "tree-ssa.h" +#include "ipa-modref-tree.h" +#include "ipa-modref.h" static struct stmt_stats { @@ -998,24 +1000,6 @@ propagate_necessity (bool aggressive) tree callee = gimple_call_fndecl (call); 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 && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee) || DECL_IS_OPERATOR_DELETE_P (callee)) @@ -1025,9 +1009,9 @@ propagate_necessity (bool aggressive) if (is_removable_cxa_atexit_call (call)) continue; + bool all_refs = false; /* Calls implicitly load from memory, their arguments in addition may explicitly perform memory loads. */ - mark_all_reaching_defs_necessary (call); for (i = 0; i < gimple_call_num_args (call); ++i) { tree arg = gimple_call_arg (call, i); @@ -1038,7 +1022,13 @@ propagate_necessity (bool aggressive) arg = TREE_OPERAND (arg, 0); if (!ref_may_be_aliased (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)) {