Second part.

Martin
>From a5226ccfdc46459afc3474472197aabf51331a63 Mon Sep 17 00:00:00 2001
From: Martin Liska <mli...@suse.cz>
Date: Tue, 2 Jul 2019 09:08:27 +0200
Subject: [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR
 c++/23383).

gcc/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* common.opt: Add -fallocation-dce
	* gimple.c (gimple_call_operator_new_p): New.
	(gimple_call_operator_delete_p): Likewise.
	* gimple.h (gimple_call_operator_new_p): Likewise.
	(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.

gcc/c/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* c-decl.c (merge_decls): Merge OPERATOR_DELETE flag.

gcc/cp/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* decl.c (cxx_init_decl_processing): Mark delete operators
	with DECL_SET_IS_OPERATOR_DELETE.

gcc/testsuite/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* g++.dg/cpp1y/new1.C: New test.

libstdc++-v3/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@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.
---
 gcc/c/c-decl.c                                |  2 +
 gcc/common.opt                                |  4 ++
 gcc/cp/decl.c                                 | 24 ++++---
 gcc/gimple.c                                  | 24 +++++++
 gcc/gimple.h                                  |  2 +
 gcc/testsuite/g++.dg/cpp1y/new1.C             | 65 +++++++++++++++++++
 gcc/tree-core.h                               |  1 +
 gcc/tree-ssa-dce.c                            | 34 ++++++++--
 gcc/tree-streamer-in.c                        |  1 +
 gcc/tree-streamer-out.c                       |  1 +
 gcc/tree.h                                    |  8 +++
 .../ext/bitmap_allocator/check_delete.cc      |  2 +
 .../ext/bitmap_allocator/check_new.cc         |  2 +
 .../ext/new_allocator/check_delete.cc         |  2 +
 .../testsuite/ext/new_allocator/check_new.cc  |  2 +
 15 files changed, 160 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/new1.C

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b0a7e34745f..57269751d9c 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2640,6 +2640,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  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);
diff --git a/gcc/common.opt b/gcc/common.opt
index a1544d06824..cc9394e5602 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2207,6 +2207,10 @@ Enum(live_patching_level) String(inline-only-static) Value(LIVE_PATCHING_INLINE_
 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.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0e9b1b55141..1597090b0ec 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4362,8 +4362,10 @@ cxx_init_decl_processing (void)
     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:
@@ -4375,8 +4377,10 @@ cxx_init_decl_processing (void)
 	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)
@@ -4404,8 +4408,10 @@ cxx_init_decl_processing (void)
 					    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)
 	  {
@@ -4415,8 +4421,10 @@ cxx_init_decl_processing (void)
 						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);
 	  }
       }
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 513bde209e2..f0441c12de2 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2695,6 +2695,30 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   return true;
 }
 
+/* Return true when STMT is operator new call.  */
+
+bool
+gimple_call_operator_new_p (const gcall *stmt)
+{
+  tree fndecl;
+
+  if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+    return DECL_IS_OPERATOR_NEW_P (fndecl);
+  return false;
+}
+
+/* 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
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 47070e7f409..27c09940ad8 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1549,6 +1549,8 @@ extern alias_set_type gimple_get_alias_set (tree);
 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_new_p (const gcall *);
+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);
diff --git a/gcc/testsuite/g++.dg/cpp1y/new1.C b/gcc/testsuite/g++.dg/cpp1y/new1.C
new file mode 100644
index 00000000000..a95dd4d1ee3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/new1.C
@@ -0,0 +1,65 @@
+/* { 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"} } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index e0643503e80..cb611956fbd 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1807,6 +1807,7 @@ enum function_decl_type
 {
   NONE,
   OPERATOR_NEW,
+  OPERATOR_DELETE,
   LAMBDA_FUNCTION
 
   /* 0 values left */
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index c73fbabfe29..532e87e17eb 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -237,6 +237,12 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	    default:;
 	    }
+
+	if (callee != NULL_TREE
+	    && flag_allocation_dce
+	    && DECL_IS_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.  */
@@ -588,6 +594,11 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
 	  default:;
 	  }
+
+      if (callee != NULL_TREE
+	  && (DECL_IS_OPERATOR_NEW_P (callee)
+	      || DECL_IS_OPERATOR_DELETE_P (callee)))
+	return false;
     }
 
   if (! gimple_clobber_p (def_stmt))
@@ -774,7 +785,10 @@ propagate_necessity (bool aggressive)
 	  /* 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;
@@ -784,10 +798,11 @@ propagate_necessity (bool aggressive)
 	      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_OPERATOR_NEW_P (def_callee)))
 		continue;
 	    }
 
@@ -842,6 +857,11 @@ propagate_necessity (bool aggressive)
 		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
 		continue;
 
+	      if (callee != NULL_TREE
+		  && (DECL_IS_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);
@@ -1262,7 +1282,9 @@ eliminate_unnecessary_stmts (void)
 	     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)
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 7bd21ae7bc5..8b6d4025ddb 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -334,6 +334,7 @@ unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   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);
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index 7e93e6c23bb..dbdc5d5e736 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -296,6 +296,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   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);
diff --git a/gcc/tree.h b/gcc/tree.h
index 117c2e13335..caa54c2a43d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3009,6 +3009,14 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
 #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) \
diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
index 1b445643599..1ad1f3c242c 100644
--- a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
+++ b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
@@ -15,6 +15,8 @@
 // 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>
diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
index 0c5f9b6da7c..be16952c10d 100644
--- a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
+++ b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
@@ -15,6 +15,8 @@
 // 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>
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc b/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
index 8778bc9ccaa..dccee1d5293 100644
--- a/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
+++ b/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
@@ -17,6 +17,8 @@
 // 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>
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc b/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
index fd90d284224..a1d164a6d49 100644
--- a/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
+++ b/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
@@ -17,6 +17,8 @@
 // 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>
-- 
2.22.0

Reply via email to