+2019-07-25 Martin Liska <mliska@suse.cz>
+ Dominik Infuhr <dominik.infuehr@theobroma-systems.com>
+
+ PR c++/23383
+ * common.opt: Add -fallocation-dce
+ * gimple.c (gimple_call_operator_delete_p): New.
+ * gimple.h (gimple_call_operator_delete_p): Likewise.
+ * tree-core.h (enum function_decl_type): Add OPERATOR_DELETE.
+ * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Handle
+ DECL_IS_OPERATOR_DELETE_P.
+ (mark_all_reaching_defs_necessary_1): Likewise.
+ (propagate_necessity): Likewise.
+ (eliminate_unnecessary_stmts): Handle
+ gimple_call_operator_delete_p.
+ * tree-streamer-in.c (unpack_ts_function_decl_value_fields):
+ Add packing of OPERATOR_DELETE.
+ * tree-streamer-out.c (pack_ts_function_decl_value_fields):
+ Similarly here.
+ * tree.h (DECL_IS_OPERATOR_DELETE_P): New.
+ (DECL_SET_IS_OPERATOR_DELETE): New.
+ (DECL_IS_REPLACEABLE_OPERATOR_NEW_P): Likewise.
+
2019-07-25 Martin Liska <mliska@suse.cz>
* calls.c (maybe_warn_alloc_args_overflow): Use new macros
+2019-07-25 Martin Liska <mliska@suse.cz>
+ Dominik Infuhr <dominik.infuehr@theobroma-systems.com>
+
+ PR c++/23383
+ * c-decl.c (merge_decls): Merge OPERATOR_DELETE flag.
+
2019-07-25 Martin Liska <mliska@suse.cz>
* c-decl.c (merge_decls): Use new macros
DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
if (DECL_IS_OPERATOR_NEW_P (olddecl))
DECL_SET_IS_OPERATOR_NEW (newdecl, true);
+ if (DECL_IS_OPERATOR_DELETE_P (olddecl))
+ DECL_SET_IS_OPERATOR_DELETE (newdecl, true);
TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
EnumValue
Enum(live_patching_level) String(inline-clone) Value(LIVE_PATCHING_INLINE_CLONE)
+fallocation-dce
+Common Report Var(flag_allocation_dce) Init(1) Optimization
+Tell DCE to remove unused C++ allocations.
+
flive-range-shrinkage
Common Report Var(flag_live_range_shrinkage) Init(0) Optimization
Relief of register pressure through live range shrinkage.
+2019-07-25 Martin Liska <mliska@suse.cz>
+ Dominik Infuhr <dominik.infuehr@theobroma-systems.com>
+
+ PR c++/23383
+ * decl.c (cxx_init_decl_processing): Mark delete operators
+ with DECL_SET_IS_OPERATOR_DELETE.
+
2019-07-25 Martin Liska <mliska@suse.cz>
* decl.c (duplicate_decls): Use new macros
opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_SET_IS_OPERATOR_NEW (opnew, true);
- push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
- push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ tree opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
if (flag_sized_deallocation)
{
/* Also push the sized deallocation variants:
deltype = cp_build_type_attribute_variant (void_ftype_ptr_size,
extvisattr);
deltype = build_exception_variant (deltype, empty_except_spec);
- push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
- push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
}
if (aligned_new_threshold)
align_type_node, NULL_TREE);
deltype = cp_build_type_attribute_variant (deltype, extvisattr);
deltype = build_exception_variant (deltype, empty_except_spec);
- push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
- push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
if (flag_sized_deallocation)
{
NULL_TREE);
deltype = cp_build_type_attribute_variant (deltype, extvisattr);
deltype = build_exception_variant (deltype, empty_except_spec);
- push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
- push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ DECL_SET_IS_OPERATOR_DELETE (opdel, true);
}
}
return true;
}
+/* Return true when STMT is operator delete call. */
+
+bool
+gimple_call_operator_delete_p (const gcall *stmt)
+{
+ tree fndecl;
+
+ if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+ return DECL_IS_OPERATOR_DELETE_P (fndecl);
+ return false;
+}
+
/* Return true when STMT is builtins call. */
bool
extern bool gimple_ior_addresses_taken (bitmap, gimple *);
extern bool gimple_builtin_call_types_compatible_p (const gimple *, tree);
extern combined_fn gimple_call_combined_fn (const gimple *);
+extern bool gimple_call_operator_delete_p (const gcall *);
extern bool gimple_call_builtin_p (const gimple *);
extern bool gimple_call_builtin_p (const gimple *, enum built_in_class);
extern bool gimple_call_builtin_p (const gimple *, enum built_in_function);
+2019-07-25 Martin Liska <mliska@suse.cz
+ Dominik Infuhr <dominik.infuehr@theobroma-systems.com>
+
+ PR c++/23383
+ * g++.dg/cpp1y/new1.C: New test.
+
2019-07-25 Eric Botcazou <ebotcazou@adacore.com>
PR testsuite/91245
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce-details" } */
+
+#include <stdlib.h>
+
+void
+new_without_use() {
+ int *x = new int;
+}
+
+void
+new_array_without_use() {
+ int *x = new int[5];
+}
+
+void
+new_primitive() {
+ int *x = new int;
+ delete x;
+}
+
+void
+new_array() {
+ int *x = new int[10];
+ delete [] x;
+}
+
+void
+new_primitive_store() {
+ int *x = new int;
+ *x = 10;
+ delete x;
+}
+
+void
+new_primitive_load() {
+ int *x = new int;
+ int tmp = *x;
+ delete x;
+}
+
+int
+new_primitive_load_with_use() {
+ int *x = new int;
+ int tmp = *x;
+ delete x;
+ return tmp;
+}
+
+void
+new_array_store() {
+ int *x = new int[10];
+ x[4] = 10;
+ delete [] x;
+}
+
+void
+new_array_load() {
+ int *x = new int[10];
+ int tmp = x[4];
+ delete [] x;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 5 "cddce1"} } */
+/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator new" 7 "cddce1"} } */
{
NONE,
OPERATOR_NEW,
+ OPERATOR_DELETE,
LAMBDA_FUNCTION
/* 0 values left */
default:;
}
+
+ if (callee != NULL_TREE
+ && flag_allocation_dce
+ && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+ return;
+
/* Most, but not all function calls are required. Function calls that
produce no result and have no side effects (i.e. const pure
functions) are unnecessary. */
default:;
}
+
+ if (callee != NULL_TREE
+ && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+ || DECL_IS_OPERATOR_DELETE_P (callee)))
+ return false;
}
if (! gimple_clobber_p (def_stmt))
/* If this is a call to free which is directly fed by an
allocation function do not mark that necessary through
processing the argument. */
- if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+ || (is_gimple_call (stmt)
+ && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))
+
{
tree ptr = gimple_call_arg (stmt, 0);
gimple *def_stmt;
if (TREE_CODE (ptr) == SSA_NAME
&& is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
&& (def_callee = gimple_call_fndecl (def_stmt))
- && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
- || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
- || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+ && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+ && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
+ || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+ || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+ || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
continue;
}
|| 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)))
+ continue;
+
/* Calls implicitly load from memory, their arguments
in addition may explicitly perform memory loads. */
mark_all_reaching_defs_necessary (stmt);
defining statement of its argument is not necessary
(and thus is getting removed). */
if (gimple_plf (stmt, STMT_NECESSARY)
- && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+ || (is_gimple_call (stmt)
+ && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
{
tree ptr = gimple_call_arg (stmt, 0);
if (TREE_CODE (ptr) == SSA_NAME)
DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_SET_IS_OPERATOR_NEW (expr, (unsigned) bp_unpack_value (bp, 1));
+ DECL_SET_IS_OPERATOR_DELETE (expr, (unsigned) bp_unpack_value (bp, 1));
DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
bp_pack_value (bp, DECL_IS_OPERATOR_NEW_P (expr), 1);
+ bp_pack_value (bp, DECL_IS_OPERATOR_DELETE_P (expr), 1);
bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
#define DECL_IS_OPERATOR_NEW_P(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_NEW)
+#define DECL_IS_REPLACEABLE_OPERATOR_NEW_P(NODE) \
+ (DECL_IS_OPERATOR_NEW_P (NODE) && DECL_IS_MALLOC (NODE))
+
#define DECL_SET_IS_OPERATOR_NEW(NODE, VAL) \
set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_NEW, VAL)
+/* Nonzero in a FUNCTION_DECL means this function should be treated as
+ C++ operator delete. */
+#define DECL_IS_OPERATOR_DELETE_P(NODE) \
+ (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_DELETE)
+
+#define DECL_SET_IS_OPERATOR_DELETE(NODE, VAL) \
+ set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_DELETE, VAL)
+
/* Nonzero in a FUNCTION_DECL means this function may return more
than once. */
#define DECL_IS_RETURNS_TWICE(NODE) \
+2019-07-25 Martin Liska <mliska@suse.cz>
+ Dominik Infuhr <dominik.infuehr@theobroma-systems.com>
+
+ PR c++/23383
+ * testsuite/ext/bitmap_allocator/check_delete.cc: Add
+ -fno-allocation-dce.
+ * testsuite/ext/bitmap_allocator/check_new.cc: Likewise.
+ * testsuite/ext/new_allocator/check_delete.cc: Likewise.
+ * testsuite/ext/new_allocator/check_new.cc: Likewise.
+
2019-07-22 Jonathan Wakely <jwakely@redhat.com>
* testsuite/26_numerics/bit/bitops.count/*: Rename to ...
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// { dg-options "-fno-allocation-dce" }
+
// 20.4.1.1 allocator members
#include <cstdlib>
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// { dg-options "-fno-allocation-dce" }
+
// 20.4.1.1 allocator members
#include <cstdlib>
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// { dg-options "-fno-allocation-dce" }
+
// 20.4.1.1 allocator members
#include <cstdlib>
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// { dg-options "-fno-allocation-dce" }
+
// 20.4.1.1 allocator members
#include <cstdlib>