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"
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
--- /dev/null
+// { 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" } }
#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
{
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))
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);
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))
{