public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
@ 2017-11-21 11:35 Dominik Inführ
  2017-11-21 17:13 ` Jeff Law
                   ` (3 more replies)
  0 siblings, 4 replies; 91+ messages in thread
From: Dominik Inführ @ 2017-11-21 11:35 UTC (permalink / raw)
  To: GCC Patches


[-- Attachment #1.1: Type: text/plain, Size: 330 bytes --]

Hi,

this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.

Best,
Dominik


[-- Attachment #1.2: dce-new-delete.diff --]
[-- Type: application/octet-stream, Size: 14200 bytes --]

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d95a2b6ea4f..4ed8c2d191a 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2454,6 +2454,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
+	  DECL_IS_OPERATOR_DELETE (newdecl) |= DECL_IS_OPERATOR_DELETE (olddecl);
 	  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/cp/decl.c b/gcc/cp/decl.c
index 54e06568e46..d1c77b1d670 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4182,8 +4182,11 @@ cxx_init_decl_processing (void)
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_IS_OPERATOR_NEW (opnew) = 1;
-    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_IS_OPERATOR_DELETE (opdel) = 1;
+    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+    DECL_IS_OPERATOR_DELETE (opdel) = 1;
+
     if (flag_sized_deallocation)
       {
 	/* Also push the sized deallocation variants:
@@ -4195,8 +4198,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);
+	opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
 	push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
       }
 
     if (aligned_new_threshold)
@@ -4224,8 +4229,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_IS_OPERATOR_DELETE (opdel) = 1;
+	opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
 
 	if (flag_sized_deallocation)
 	  {
@@ -4235,8 +4242,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_IS_OPERATOR_DELETE (opdel) = 1;
+	    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	    DECL_IS_OPERATOR_DELETE (opdel) = 1;
 	  }
       }
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c986a732004..27aab5aa3b5 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2543,6 +2543,32 @@ 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 gimple *stmt)
+{
+  tree fndecl;
+
+  if (is_gimple_call (stmt)
+      && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+    return DECL_IS_OPERATOR_NEW (fndecl);
+  return false;
+}
+
+/* Return true when STMT is operator delete call.  */
+
+bool
+gimple_call_operator_delete_p (const gimple *stmt)
+{
+  tree fndecl;
+
+  if (is_gimple_call (stmt)
+      && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+    return DECL_IS_OPERATOR_DELETE (fndecl);
+  return false;
+}
+
 /* Return true when STMT is builtins call.  */
 
 bool
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 334def89398..c9c25c2a228 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1514,6 +1514,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 gimple *);
+extern bool gimple_call_operator_delete_p (const gimple *);
 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..b966cf5d7b7
--- /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" 4 "cddce1"} } */
+/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator new" 6 "cddce1"} } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index aa54221253c..9a406c5d86c 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
   unsigned has_debug_args_flag : 1;
   unsigned tm_clone_flag : 1;
   unsigned versioned_function : 1;
-  /* No bits left.  */
+
+  unsigned operator_delete_flag : 1;
+  /* 31 bits left.  */
 };
 
 struct GTY(()) tree_translation_unit_decl {
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index a5f0edf7893..571a0b7bb5a 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -238,6 +238,11 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	    default:;
 	    }
+
+	if (callee != NULL_TREE
+	    && DECL_IS_OPERATOR_NEW (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.  */
@@ -581,6 +586,11 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
 	  default:;
 	  }
+
+      if (callee != NULL_TREE
+	  && (DECL_IS_OPERATOR_NEW (callee)
+	      || DECL_IS_OPERATOR_DELETE (callee)))
+	return false;
     }
 
   if (! gimple_clobber_p (def_stmt))
@@ -767,20 +777,23 @@ 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)
+	      || gimple_call_operator_delete_p (stmt))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
 	      tree def_callee;
+
 	      /* If the pointer we free is defined by an allocation
 		 function do not add the call to the worklist.  */
 	      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 (def_callee)))
 		{
 		  gimple *bounds_def_stmt;
 		  tree bounds;
@@ -794,7 +807,24 @@ propagate_necessity (bool aggressive)
 			  && chkp_gimple_call_builtin_p (bounds_def_stmt,
 							 BUILT_IN_CHKP_BNDRET)
 			  && gimple_call_arg (bounds_def_stmt, 0) == ptr))
-		    continue;
+		    {
+		      /* For operator delete [] we need to keep size operand
+			 alive. Otherwise this operand isn't available anymore
+			 when we finally decide that this stmt is necessary in
+			eliminate_unnecessary_stmts. If it should really be
+			unnecessary, a later pass can clean this up.  */
+		      if (gimple_call_operator_delete_p (stmt))
+			{
+			  for (unsigned i=1; i < gimple_call_num_args (stmt); ++i)
+			    {
+			      tree arg = gimple_call_arg (stmt, i);
+			      if (TREE_CODE (arg) == SSA_NAME)
+				mark_operand_necessary (arg);
+			    }
+			}
+
+		      continue;
+		    }
 		}
 	    }
 
@@ -849,6 +879,11 @@ propagate_necessity (bool aggressive)
 		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
 		continue;
 
+	      if (callee != NULL_TREE
+		  && (DECL_IS_OPERATOR_NEW (callee)
+		      || DECL_IS_OPERATOR_DELETE (callee)))
+		continue;
+
 	      /* Calls implicitly load from memory, their arguments
 	         in addition may explicitly perform memory loads.  */
 	      mark_all_reaching_defs_necessary (stmt);
@@ -1269,7 +1304,8 @@ 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)
+		  || gimple_call_operator_delete_p (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 baf0c5bf837..eb8a2aa1a93 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -326,6 +326,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_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_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 7f52d455f5e..a63d16deb23 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -287,6 +287,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 (expr), 1);
+  bp_pack_value (bp, DECL_IS_OPERATOR_DELETE (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 0ec092aa812..88d7e73fd09 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2866,6 +2866,11 @@ extern void decl_fini_priority_insert (tree, priority_type);
 #define DECL_IS_OPERATOR_NEW(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.operator_new_flag)
 
+/* Nonzero in a FUNCTION_DECL means this function should be treated as
+   C++ operator delete.  */
+#define DECL_IS_OPERATOR_DELETE(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.operator_delete_flag)
+
 /* 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 bc36ed595e0..10e26615fb7 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-tree-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 073d588f3b9..7efd325bec2 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-tree-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 ce6c1da3e27..30390c266d0 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-tree-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 d410f5f7feb..18396482d9a 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-tree-dce" }
+
 // 20.4.1.1 allocator members
 
 #include <cstdlib>

[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 842 bytes --]

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 11:35 [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Dominik Inführ
@ 2017-11-21 17:13 ` Jeff Law
  2017-11-21 17:36   ` Dominik Inführ
  2017-11-22 10:40   ` Martin Jambor
  2017-11-22  9:33 ` Richard Biener
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 91+ messages in thread
From: Jeff Law @ 2017-11-21 17:13 UTC (permalink / raw)
  To: Dominik Inführ, GCC Patches

On 11/21/2017 04:14 AM, Dominik Inführ wrote:
> Hi,
> 
> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.
Just a note, we've transitioned into stage3 in preparation for the
upcoming gcc-8 release in the spring.  During stage3 we're addressing
bugfixes, not further enhancements (with the exception of enhancements
that were posted prior to stage1 close).

So it's unlikely anyone will dig into this right now, unless there's an
existing bugzilla around this missed optimization.

Just wanted to let you know where things stood so you don't interpret
silence as "we don't care".

jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 17:13 ` Jeff Law
@ 2017-11-21 17:36   ` Dominik Inführ
  2017-11-21 17:45     ` Jeff Law
  2017-11-22 10:40   ` Martin Jambor
  1 sibling, 1 reply; 91+ messages in thread
From: Dominik Inführ @ 2017-11-21 17:36 UTC (permalink / raw)
  To: Jeff Law; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1189 bytes --]

Thanks for the reply, I know that it’s too late for GCC 8. I wanted to get some feedback on this patch, so I could address all issues until GCC 9 development starts. But I suppose it is better to just post it again later.

Dominik

> On 21 Nov 2017, at 18:09, Jeff Law <law@redhat.com> wrote:
> 
> On 11/21/2017 04:14 AM, Dominik Inführ wrote:
>> Hi,
>> 
>> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.
> Just a note, we've transitioned into stage3 in preparation for the
> upcoming gcc-8 release in the spring.  During stage3 we're addressing
> bugfixes, not further enhancements (with the exception of enhancements
> that were posted prior to stage1 close).
> 
> So it's unlikely anyone will dig into this right now, unless there's an
> existing bugzilla around this missed optimization.
> 
> Just wanted to let you know where things stood so you don't interpret
> silence as "we don't care".
> 
> jeff


[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 842 bytes --]

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 17:36   ` Dominik Inführ
@ 2017-11-21 17:45     ` Jeff Law
  0 siblings, 0 replies; 91+ messages in thread
From: Jeff Law @ 2017-11-21 17:45 UTC (permalink / raw)
  To: Dominik Inführ; +Cc: GCC Patches

On 11/21/2017 10:30 AM, Dominik Inführ wrote:
> Thanks for the reply, I know that it’s too late for GCC 8. I wanted to get some feedback on this patch, so I could address all issues until GCC 9 development starts. But I suppose it is better to just post it again later.
The problem is most folks' attention will be on bugfixing for the next
few months.

I did quickly scan the patch and didn't see anything terribly concerning
other than extending the one structure which folks will want to look at
more closely.  We always look closely at extending any core data
structures as that impacts memory usage.

I'll probably have to refer to the C++ experts on any specific language
issues that come into play when we open the trunk up again for new
development and come back to the patch.

Jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 11:35 [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Dominik Inführ
  2017-11-21 17:13 ` Jeff Law
@ 2017-11-22  9:33 ` Richard Biener
  2017-11-22 10:41   ` Jakub Jelinek
  2017-11-22 13:03 ` Nathan Sidwell
  2017-11-22 21:45 ` Marc Glisse
  3 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2017-11-22  9:33 UTC (permalink / raw)
  To: Dominik Inführ; +Cc: GCC Patches

On Tue, Nov 21, 2017 at 12:14 PM, Dominik Inführ
<dominik.infuehr@theobroma-systems.com> wrote:
> Hi,
>
> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.

Few comments.

+/* Return true when STMT is operator new call.  */
+
+bool
+gimple_call_operator_new_p (const gimple *stmt)
+{
+  tree fndecl;
+
+  if (is_gimple_call (stmt)
+      && (fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+    return DECL_IS_OPERATOR_NEW (fndecl);
+  return false;

make these take a gcall * please and drop the is_gimple_call check.

diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index aa54221253c..9a406c5d86c 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
   unsigned has_debug_args_flag : 1;
   unsigned tm_clone_flag : 1;
   unsigned versioned_function : 1;
-  /* No bits left.  */
+
+  unsigned operator_delete_flag : 1;
+  /* 31 bits left.  */

while it looks bad reality is that on 64bit pointer hosts we had 32 bits left.

Note that we could really pack things better and even make function_decl
smaller by using the tail-padding (for 64bit pointer hosts...) in
tree_decl_with_vis
which also has 32 + 14 bits left.

+                     /* For operator delete [] we need to keep size operand
+                        alive. Otherwise this operand isn't available anymore
+                        when we finally decide that this stmt is necessary in
+                       eliminate_unnecessary_stmts. If it should really be
+                       unnecessary, a later pass can clean this up.  */
+                     if (gimple_call_operator_delete_p (stmt))
+                       {
+                         for (unsigned i=1; i < gimple_call_num_args
(stmt); ++i)
+                           {
+                             tree arg = gimple_call_arg (stmt, i);
+                             if (TREE_CODE (arg) == SSA_NAME)
+                               mark_operand_necessary (arg);
+                           }
+                       }

bah ... so the "hack" for malloc/free pair removal doesn't really work very well
for new/delete.  What you do looks reasonable but in the end we might support
sth like "tentatively not necessary" and a late marking things necessary that
have been proven to be necessary anyway.

diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
index bc36ed595e0..10e26615fb7 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-tree-dce" }
+
 // 20.4.1.1 allocator members

hmm.  I think it would be better to add a new C++ FE option
-fno-allocation-dce that
simply doesn't set DECL_IS_OPERATOR_{NEW,DELETE} similar to how we have
-fno-lifetime-dse?  There might be projects that are not happy with this DCE and
disabling _all_ DCE just to keep existing behavior looks bad.

Otherwise the patch looks straight-forward in case C++ folks are happy with it.

Thanks for working on this!  I think that if you manage to convince C++ folks
and fix the -fno-allocation-dce missing then I'd like to have this in
early stage3.
We've been requesting this for a long time.

Richard.


> Best,
> Dominik
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 17:13 ` Jeff Law
  2017-11-21 17:36   ` Dominik Inführ
@ 2017-11-22 10:40   ` Martin Jambor
  2017-11-22 18:03     ` Jeff Law
  1 sibling, 1 reply; 91+ messages in thread
From: Martin Jambor @ 2017-11-22 10:40 UTC (permalink / raw)
  To: Jeff Law, Dominik Inführ, GCC Patches

On Tue, Nov 21 2017, Jeff Law wrote:
> On 11/21/2017 04:14 AM, Dominik Inführ wrote:
>> Hi,
>> 
>> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.
> Just a note, we've transitioned into stage3 in preparation for the
> upcoming gcc-8 release in the spring.  During stage3 we're addressing
> bugfixes, not further enhancements (with the exception of enhancements
> that were posted prior to stage1 close).
>
> So it's unlikely anyone will dig into this right now, unless there's an
> existing bugzilla around this missed optimization.

Unless I am mistaken, I think it is PR 23383

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-22  9:33 ` Richard Biener
@ 2017-11-22 10:41   ` Jakub Jelinek
  2017-11-27  9:57     ` Dominik Inführ
  0 siblings, 1 reply; 91+ messages in thread
From: Jakub Jelinek @ 2017-11-22 10:41 UTC (permalink / raw)
  To: Richard Biener; +Cc: Dominik Inführ, GCC Patches

On Wed, Nov 22, 2017 at 10:30:29AM +0100, Richard Biener wrote:
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
>    unsigned has_debug_args_flag : 1;
>    unsigned tm_clone_flag : 1;
>    unsigned versioned_function : 1;
> -  /* No bits left.  */
> +
> +  unsigned operator_delete_flag : 1;
> +  /* 31 bits left.  */
> 
> while it looks bad reality is that on 64bit pointer hosts we had 32 bits left.

But we can just add it to say tree_decl_common which has 14 spare bits or
tree_decl_with_vis which has another 14 spare bits.  By just noting the flag
applies only to FUNCTION_DECLs and enforcing it in the tree.h macros,
it will be easy to reuse that bit for something different for trees other
than FUNCTION_DECL.

	Jakub

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 11:35 [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Dominik Inführ
  2017-11-21 17:13 ` Jeff Law
  2017-11-22  9:33 ` Richard Biener
@ 2017-11-22 13:03 ` Nathan Sidwell
  2017-11-22 14:18   ` Richard Biener
  2017-11-22 21:45 ` Marc Glisse
  3 siblings, 1 reply; 91+ messages in thread
From: Nathan Sidwell @ 2017-11-22 13:03 UTC (permalink / raw)
  To: Dominik Inführ, GCC Patches

On 11/21/2017 06:14 AM, Dominik Inführ wrote:
> Hi,
> 
> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.

nice.

> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
>    unsigned has_debug_args_flag : 1;
>    unsigned tm_clone_flag : 1;
>    unsigned versioned_function : 1;
> -  /* No bits left.  */
> +
> +  unsigned operator_delete_flag : 1;
> +  /* 31 bits left.  */
>  };

that's unpleasant.  We have DECL_IS_{MALLOC,OPERATOR_{NEW,DELETE}} 
flags, which are all mutually exclusive.  If only there was a way to 
encode a 4-valued enumeration in fewer than 3 bits ... :)  (not sure why 
we don't have DECL_IS_FREE, and as we don't, why is 
DECL_IS_OPERATOR_DELETE needed?

(we also have DECL_IS_{CON,DE}STRUCTOR flags, which I think are also 
mutually exclusive with the above.  So that's 5 or (6 if we add 
DECL_IS_FREE), that could be encoded in 3 bits.

There may be even more mutually exclusive flags, 
DECL_STATIC_{CON,DE}STRUCTOR may be candiates?


nathan

-- 
Nathan Sidwell

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-22 13:03 ` Nathan Sidwell
@ 2017-11-22 14:18   ` Richard Biener
  2017-11-22 14:45     ` Nathan Sidwell
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2017-11-22 14:18 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: Dominik Inführ, GCC Patches

On Wed, Nov 22, 2017 at 1:47 PM, Nathan Sidwell <nathan@acm.org> wrote:
> On 11/21/2017 06:14 AM, Dominik Inführ wrote:
>>
>> Hi,
>>
>> this patch tries to extend tree-ssa-dce.c to remove unnecessary
>> new/delete-pairs (it already does that for malloc/free). Clang does it too
>> and it seems to be allowed by
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve
>> bootstrapped/regtested on aarch64-linux and x86_64-linux.
>
>
> nice.
>
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
>>    unsigned has_debug_args_flag : 1;
>>    unsigned tm_clone_flag : 1;
>>    unsigned versioned_function : 1;
>> -  /* No bits left.  */
>> +
>> +  unsigned operator_delete_flag : 1;
>> +  /* 31 bits left.  */
>>  };
>
>
> that's unpleasant.  We have DECL_IS_{MALLOC,OPERATOR_{NEW,DELETE}} flags,
> which are all mutually exclusive.  If only there was a way to encode a
> 4-valued enumeration in fewer than 3 bits ... :)  (not sure why we don't
> have DECL_IS_FREE, and as we don't, why is DECL_IS_OPERATOR_DELETE needed?
>
> (we also have DECL_IS_{CON,DE}STRUCTOR flags, which I think are also
> mutually exclusive with the above.  So that's 5 or (6 if we add
> DECL_IS_FREE), that could be encoded in 3 bits.
>
> There may be even more mutually exclusive flags,
> DECL_STATIC_{CON,DE}STRUCTOR may be candiates?

Yes, there's room for cleanup (as I noted).  And ok, if we don't want
to regress 32bit hosts we can put
a new flag in decl_common indeed.

So please do that.

Anything else can be done as followup and need not be done as part of
this patch.  An enum for
this would work I guess.

Richard.

>
> nathan
>
> --
> Nathan Sidwell

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-22 14:18   ` Richard Biener
@ 2017-11-22 14:45     ` Nathan Sidwell
  0 siblings, 0 replies; 91+ messages in thread
From: Nathan Sidwell @ 2017-11-22 14:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Dominik Inführ, GCC Patches

On 11/22/2017 08:59 AM, Richard Biener wrote:

> Anything else can be done as followup and need not be done as part of
> this patch.  An enum for
> this would work I guess.

I've added this to https://gcc.gnu.org/wiki/ImprovementProjects:

Compress DECL flags

     tree-core defines a number of bit flags (DECL_IS_MALLOC, 
DECL_IS_OPERATOR_NEW, DECL_CONSTRUCTOR, DECL_STATIC_CONSTRUCTOR, etc) 
that are mutually exclusive. It would be better to use some kind of 
enumeration, rather than individual flags. (We've run out of bits). 
(Suggested by Richard Biener & Nathan Sidwell)

[The reason I put names on these things, is so there's someone to 
contact if the intent isn't clear]

nathan

-- 
Nathan Sidwell

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-22 10:40   ` Martin Jambor
@ 2017-11-22 18:03     ` Jeff Law
  0 siblings, 0 replies; 91+ messages in thread
From: Jeff Law @ 2017-11-22 18:03 UTC (permalink / raw)
  To: Martin Jambor, Dominik Inführ, GCC Patches

On 11/22/2017 03:31 AM, Martin Jambor wrote:
> On Tue, Nov 21 2017, Jeff Law wrote:
>> On 11/21/2017 04:14 AM, Dominik Inführ wrote:
>>> Hi,
>>>
>>> this patch tries to extend tree-ssa-dce.c to remove unnecessary new/delete-pairs (it already does that for malloc/free). Clang does it too and it seems to be allowed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve bootstrapped/regtested on aarch64-linux and x86_64-linux.
>> Just a note, we've transitioned into stage3 in preparation for the
>> upcoming gcc-8 release in the spring.  During stage3 we're addressing
>> bugfixes, not further enhancements (with the exception of enhancements
>> that were posted prior to stage1 close).
>>
>> So it's unlikely anyone will dig into this right now, unless there's an
>> existing bugzilla around this missed optimization.
> 
> Unless I am mistaken, I think it is PR 23383
I think 23383 touches on some of these issues, but I'm not sure it's the
same thing.  Marking new with the malloc attribute should in theory be
all that's necessary to address the original issue in 23383.

Marking *should* allow the alias analysis code to disambiguate "a" and
"b" and in turn allow us to determine that the return value is always
"1".  That's the crux of 23383.

The final comment notes we can omit the calls which is good as it gives
us freedom in c++14 mode.   I'm going to assume that the requirement is
that we have to provide suitable space either on the stack, in a
register or within another object and that removal of that additional
space is valid if we determine it's actually not needed.

Anyway, 23383 is likely a piece what's done with this patch.  Namely
that with this patch we'd likely wipe out the new/delete pair for "b" as
the value is never used and never escapes.  Then we'd probably do the
same for "a".  But ISTM this is beyond what the BZ was complaining about.


You could make the argument that the marking done by the patch should go
in under 23383, that seems pretty easy.  You might then argue that the
DCE extension is a trivial extension of that work, trivial enough that
it could be considered under the umbrella of 23383.

Jeff



> 
> Martin
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-21 11:35 [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Dominik Inführ
                   ` (2 preceding siblings ...)
  2017-11-22 13:03 ` Nathan Sidwell
@ 2017-11-22 21:45 ` Marc Glisse
  3 siblings, 0 replies; 91+ messages in thread
From: Marc Glisse @ 2017-11-22 21:45 UTC (permalink / raw)
  To: Dominik Inführ; +Cc: GCC Patches

(please try to convince your mailer to use something other than 
Content-Type: application/octet-stream for a patch)

On Tue, 21 Nov 2017, Dominik Inführ wrote:

> this patch tries to extend tree-ssa-dce.c to remove unnecessary 
> new/delete-pairs (it already does that for malloc/free). Clang does it 
> too and it seems to be allowed by 
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html. I’ve 
> bootstrapped/regtested on aarch64-linux and x86_64-linux.

In clang, they (i.e. more or less the authors of the paper you mention) 
went through the trouble of introducing __builtin_operator_new 
specifically so not all calls to operator new were affected, but 
essentially only the calls to the global operator new that come from new 
expressions or from std::allocator. This appears to be a deliberate change 
between N3537 and N3664, although I did not find the rationale.

So you might want to check with the committee if optimizing more calls is 
ok.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-22 10:41   ` Jakub Jelinek
@ 2017-11-27  9:57     ` Dominik Inführ
  2017-11-27 10:48       ` Jakub Jelinek
                         ` (2 more replies)
  0 siblings, 3 replies; 91+ messages in thread
From: Dominik Inführ @ 2017-11-27  9:57 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, GCC Patches


[-- Attachment #1.1: Type: text/plain, Size: 900 bytes --]

Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.

The problem with this patch is what Marc noticed: it omits too many allocations. The C++ standard seems to only allow to omit "replaceable global allocation functions (18.6.1.1, 18.6.1.2)”. So e.g. no class-specific or user-defined allocations. I am not sure what’s the best way to implement this. Just checking the function declarations might not be enough and seems more like a hack. The better way seems to introduce a __builtin_operator_new like Marc mentioned. In which way would you implement this? Could you please give me some pointers here to look at?

Thanks,
Dominik


[-- Attachment #1.2: dce-new-delete2.diff.txt --]
[-- Type: text/plain, Size: 15318 bytes --]

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d95a2b6ea4f..4ed8c2d191a 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2454,6 +2454,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
+	  DECL_IS_OPERATOR_DELETE (newdecl) |= DECL_IS_OPERATOR_DELETE (olddecl);
 	  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 f8f2ed3db8a..526c7df63d7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2119,6 +2119,10 @@ starts and when the destructor finishes.
 flifetime-dse=
 Common Joined RejectNegative UInteger Var(flag_lifetime_dse) Optimization IntegerRange(0, 2)
 
+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 54e06568e46..d1c77b1d670 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4182,8 +4182,11 @@ cxx_init_decl_processing (void)
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_IS_OPERATOR_NEW (opnew) = 1;
-    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_IS_OPERATOR_DELETE (opdel) = 1;
+    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+    DECL_IS_OPERATOR_DELETE (opdel) = 1;
+
     if (flag_sized_deallocation)
       {
 	/* Also push the sized deallocation variants:
@@ -4195,8 +4198,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);
+	opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
 	push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
       }
 
     if (aligned_new_threshold)
@@ -4224,8 +4229,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_IS_OPERATOR_DELETE (opdel) = 1;
+	opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_IS_OPERATOR_DELETE (opdel) = 1;
 
 	if (flag_sized_deallocation)
 	  {
@@ -4235,8 +4242,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_IS_OPERATOR_DELETE (opdel) = 1;
+	    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	    DECL_IS_OPERATOR_DELETE (opdel) = 1;
 	  }
       }
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c986a732004..b4cce195e57 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2543,6 +2543,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 (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 (fndecl);
+  return false;
+}
+
 /* Return true when STMT is builtins call.  */
 
 bool
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 334def89398..01d37227f09 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1514,6 +1514,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..b966cf5d7b7
--- /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" 4 "cddce1"} } */
+/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator new" 6 "cddce1"} } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index aa54221253c..f3ee0dea98b 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1723,7 +1723,9 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* Belong to FUNCTION_DECL exclusively.  */
+ unsigned operator_delete_flag : 1;
+ /* 13 unused bits. */
 };
 
 struct GTY(()) tree_var_decl {
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index a5f0edf7893..e9086911d12 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -238,6 +238,12 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	    default:;
 	    }
+
+	if (callee != NULL_TREE
+	    && flag_allocation_dce
+	    && DECL_IS_OPERATOR_NEW (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.  */
@@ -581,6 +587,11 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
 	  default:;
 	  }
+
+      if (callee != NULL_TREE
+	  && (DECL_IS_OPERATOR_NEW (callee)
+	      || DECL_IS_OPERATOR_DELETE (callee)))
+	return false;
     }
 
   if (! gimple_clobber_p (def_stmt))
@@ -767,20 +778,24 @@ 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;
 	      tree def_callee;
+
 	      /* If the pointer we free is defined by an allocation
 		 function do not add the call to the worklist.  */
 	      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 (def_callee)))
 		{
 		  gimple *bounds_def_stmt;
 		  tree bounds;
@@ -794,7 +809,24 @@ propagate_necessity (bool aggressive)
 			  && chkp_gimple_call_builtin_p (bounds_def_stmt,
 							 BUILT_IN_CHKP_BNDRET)
 			  && gimple_call_arg (bounds_def_stmt, 0) == ptr))
-		    continue;
+		    {
+		      /* For operator delete [] we need to keep size operand
+			 alive. Otherwise this operand isn't available anymore
+			 when we finally decide that this stmt is necessary in
+			eliminate_unnecessary_stmts. If it should really be
+			unnecessary, a later pass can clean this up.  */
+		      if (gimple_call_operator_delete_p (as_a <gcall *> (stmt)))
+			{
+			  for (unsigned i=1; i < gimple_call_num_args (stmt); ++i)
+			    {
+			      tree arg = gimple_call_arg (stmt, i);
+			      if (TREE_CODE (arg) == SSA_NAME)
+				mark_operand_necessary (arg);
+			    }
+			}
+
+		      continue;
+		    }
 		}
 	    }
 
@@ -849,6 +881,11 @@ propagate_necessity (bool aggressive)
 		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
 		continue;
 
+	      if (callee != NULL_TREE
+		  && (DECL_IS_OPERATOR_NEW (callee)
+		      || DECL_IS_OPERATOR_DELETE (callee)))
+		continue;
+
 	      /* Calls implicitly load from memory, their arguments
 	         in addition may explicitly perform memory loads.  */
 	      mark_all_reaching_defs_necessary (stmt);
@@ -1269,7 +1306,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 baf0c5bf837..eb8a2aa1a93 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -326,6 +326,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_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_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 7f52d455f5e..a63d16deb23 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -287,6 +287,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 (expr), 1);
+  bp_pack_value (bp, DECL_IS_OPERATOR_DELETE (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 0ec092aa812..98f6ea0f6d4 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2866,6 +2866,11 @@ extern void decl_fini_priority_insert (tree, priority_type);
 #define DECL_IS_OPERATOR_NEW(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.operator_new_flag)
 
+/* Nonzero in a FUNCTION_DECL means this function should be treated as
+   C++ operator delete.  */
+#define DECL_IS_OPERATOR_DELETE(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->decl_with_vis.operator_delete_flag)
+
 /* 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 bc36ed595e0..1df4b71b598 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 073d588f3b9..c7d745249f5 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 ce6c1da3e27..aa098ad2c65 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 d410f5f7feb..21ad642a3fe 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>

[-- Attachment #1.3: Type: text/plain, Size: 911 bytes --]


> On 22 Nov 2017, at 11:37, Jakub Jelinek <jakub@redhat.com> wrote:
> 
> On Wed, Nov 22, 2017 at 10:30:29AM +0100, Richard Biener wrote:
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
>>   unsigned has_debug_args_flag : 1;
>>   unsigned tm_clone_flag : 1;
>>   unsigned versioned_function : 1;
>> -  /* No bits left.  */
>> +
>> +  unsigned operator_delete_flag : 1;
>> +  /* 31 bits left.  */
>> 
>> while it looks bad reality is that on 64bit pointer hosts we had 32 bits left.
> 
> But we can just add it to say tree_decl_common which has 14 spare bits or
> tree_decl_with_vis which has another 14 spare bits.  By just noting the flag
> applies only to FUNCTION_DECLs and enforcing it in the tree.h macros,
> it will be easy to reuse that bit for something different for trees other
> than FUNCTION_DECL.
> 
> 	Jakub


[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 842 bytes --]

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-27  9:57     ` Dominik Inführ
@ 2017-11-27 10:48       ` Jakub Jelinek
  2017-11-27 17:04       ` Jeff Law
  2017-11-29  8:13       ` Martin Sebor
  2 siblings, 0 replies; 91+ messages in thread
From: Jakub Jelinek @ 2017-11-27 10:48 UTC (permalink / raw)
  To: Dominik Inführ; +Cc: Richard Biener, GCC Patches

On Mon, Nov 27, 2017 at 10:22:52AM +0100, Dominik Inführ wrote:
> @@ -4195,8 +4198,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);
> +	opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
> +	DECL_IS_OPERATOR_DELETE (opdel) = 1;
>  	push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);

Missing "opdel = " above.

> +	DECL_IS_OPERATOR_DELETE (opdel) = 1;
>        }
>  
>      if (aligned_new_threshold)


	Jakub

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-27  9:57     ` Dominik Inführ
  2017-11-27 10:48       ` Jakub Jelinek
@ 2017-11-27 17:04       ` Jeff Law
  2017-11-28 11:55         ` Richard Biener
  2017-11-29  8:13       ` Martin Sebor
  2 siblings, 1 reply; 91+ messages in thread
From: Jeff Law @ 2017-11-27 17:04 UTC (permalink / raw)
  To: Dominik Inführ, Jakub Jelinek; +Cc: Richard Biener, GCC Patches

On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
> 
> The problem with this patch is what Marc noticed: it omits too many allocations. The C++ standard seems to only allow to omit "replaceable global allocation functions (18.6.1.1, 18.6.1.2)”. So e.g. no class-specific or user-defined allocations. I am not sure what’s the best way to implement this. Just checking the function declarations might not be enough and seems more like a hack. The better way seems to introduce a __builtin_operator_new like Marc mentioned. In which way would you implement this? Could you please give me some pointers here to look at?
Just a nit.  Make sure to mention BZ 23383 in your ChangeLog entry.
Like this:

	c++/23383
	* tree-core.h (blah blah): What changed.


Jakub and Richi probably have a better understanding of the builtin
mechanisms than I do.  I'll leave it for them to comment on how best to
proceed there.

jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-27 17:04       ` Jeff Law
@ 2017-11-28 11:55         ` Richard Biener
  2017-11-28 14:48           ` Jakub Jelinek
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2017-11-28 11:55 UTC (permalink / raw)
  To: Jeff Law; +Cc: Dominik Inführ, Jakub Jelinek, GCC Patches

On Mon, Nov 27, 2017 at 5:58 PM, Jeff Law <law@redhat.com> wrote:
> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>> Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
>>
>> The problem with this patch is what Marc noticed: it omits too many allocations. The C++ standard seems to only allow to omit "replaceable global allocation functions (18.6.1.1, 18.6.1.2)”. So e.g. no class-specific or user-defined allocations. I am not sure what’s the best way to implement this. Just checking the function declarations might not be enough and seems more like a hack. The better way seems to introduce a __builtin_operator_new like Marc mentioned. In which way would you implement this? Could you please give me some pointers here to look at?
> Just a nit.  Make sure to mention BZ 23383 in your ChangeLog entry.
> Like this:
>
>         c++/23383
>         * tree-core.h (blah blah): What changed.
>
>
> Jakub and Richi probably have a better understanding of the builtin
> mechanisms than I do.  I'll leave it for them to comment on how best to
> proceed there.

I don't see why a builtin is necessary, can the FE not see which one
is the global allocation function?
Anyways, there are no FE specific builtins, traditionally FEs have
used special keywords - you might
want to search for RID_BUILTIN_LAUNDER for example.

Richard.

> jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-28 11:55         ` Richard Biener
@ 2017-11-28 14:48           ` Jakub Jelinek
  0 siblings, 0 replies; 91+ messages in thread
From: Jakub Jelinek @ 2017-11-28 14:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, Dominik Inführ, GCC Patches

On Tue, Nov 28, 2017 at 12:52:12PM +0100, Richard Biener wrote:
> On Mon, Nov 27, 2017 at 5:58 PM, Jeff Law <law@redhat.com> wrote:
> > On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> >> Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
> >>
> >> The problem with this patch is what Marc noticed: it omits too many allocations. The C++ standard seems to only allow to omit "replaceable global allocation functions (18.6.1.1, 18.6.1.2)”. So e.g. no class-specific or user-defined allocations. I am not sure what’s the best way to implement this. Just checking the function declarations might not be enough and seems more like a hack. The better way seems to introduce a __builtin_operator_new like Marc mentioned. In which way would you implement this? Could you please give me some pointers here to look at?
> > Just a nit.  Make sure to mention BZ 23383 in your ChangeLog entry.
> > Like this:
> >
> >         c++/23383
> >         * tree-core.h (blah blah): What changed.
> >
> >
> > Jakub and Richi probably have a better understanding of the builtin
> > mechanisms than I do.  I'll leave it for them to comment on how best to
> > proceed there.
> 
> I don't see why a builtin is necessary, can the FE not see which one
> is the global allocation function?

It should, and finding it by namespace and name is IMHO not a hack,
that is how the C++ standard specifies those.

> Anyways, there are no FE specific builtins, traditionally FEs have
> used special keywords - you might
> want to search for RID_BUILTIN_LAUNDER for example.

Those are there just for parsing them, there is nothing special needed
to parse the standard new/delete operators.

	Jakub

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-27  9:57     ` Dominik Inführ
  2017-11-27 10:48       ` Jakub Jelinek
  2017-11-27 17:04       ` Jeff Law
@ 2017-11-29  8:13       ` Martin Sebor
  2017-11-29  9:33         ` Jakub Jelinek
  2017-12-01  1:23         ` Jeff Law
  2 siblings, 2 replies; 91+ messages in thread
From: Martin Sebor @ 2017-11-29  8:13 UTC (permalink / raw)
  To: Dominik Inführ, Jakub Jelinek; +Cc: Richard Biener, GCC Patches

On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> Thanks for all the reviews! IÂ’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). IÂ’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
>
It's great to be able to eliminate pairs of these calls.  For
unpaired calls, though, I think it would be even more useful to
also issue a warning.  Otherwise the elimination will mask bugs
that might only show up without optimization, or with other
compilers (such as older versions of GCC).  I realize GCC doesn't
warn for these bugs involving malloc, but I think it should for
the same reason.

> The problem with this patch is what Marc noticed: it omits too many allocations. The C++ standard seems to only allow to omit "replaceable global allocation functions (18.6.1.1, 18.6.1.2)”. So e.g. no class-specific or user-defined allocations. I am not sure what’s the best way to implement this. Just checking the function declarations might not be enough and seems more like a hack. The better way seems to introduce a __builtin_operator_new like Marc mentioned. In which way would you implement this? Could you please give me some pointers here to look at?

I'm not sure there is a way to do it other than by comparing
the name.  To see where to insert the built-in and when, you
might want to look at cp/init.c.

Martin

>
> Thanks,
> Dominik
>
>
>
>
>> On 22 Nov 2017, at 11:37, Jakub Jelinek <jakub@redhat.com> wrote:
>>
>> On Wed, Nov 22, 2017 at 10:30:29AM +0100, Richard Biener wrote:
>>> --- a/gcc/tree-core.h
>>> +++ b/gcc/tree-core.h
>>> @@ -1787,7 +1787,9 @@ struct GTY(()) tree_function_decl {
>>>   unsigned has_debug_args_flag : 1;
>>>   unsigned tm_clone_flag : 1;
>>>   unsigned versioned_function : 1;
>>> -  /* No bits left.  */
>>> +
>>> +  unsigned operator_delete_flag : 1;
>>> +  /* 31 bits left.  */
>>>
>>> while it looks bad reality is that on 64bit pointer hosts we had 32 bits left.
>>
>> But we can just add it to say tree_decl_common which has 14 spare bits or
>> tree_decl_with_vis which has another 14 spare bits.  By just noting the flag
>> applies only to FUNCTION_DECLs and enforcing it in the tree.h macros,
>> it will be easy to reuse that bit for something different for trees other
>> than FUNCTION_DECL.
>>
>> 	Jakub
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29  8:13       ` Martin Sebor
@ 2017-11-29  9:33         ` Jakub Jelinek
  2017-11-29 16:29           ` Martin Sebor
  2017-12-01  1:24           ` Jeff Law
  2017-12-01  1:23         ` Jeff Law
  1 sibling, 2 replies; 91+ messages in thread
From: Jakub Jelinek @ 2017-11-29  9:33 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Dominik Inführ, Richard Biener, GCC Patches

On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> > Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
> > 
> It's great to be able to eliminate pairs of these calls.  For
> unpaired calls, though, I think it would be even more useful to
> also issue a warning.  Otherwise the elimination will mask bugs

??  I hope you're only talking about allocation where the returned
pointer can't leak elsewhere, doing allocation in one function
(e.g. constructor, or whatever other function) and deallocation in some
other one is so common such a warning would be not just useless, but
harmful with almost all occurrences being false positives.

Warning on malloc/standard operator new or malloc/realloc-like function
when the return pointer can't escape the current function is reasonable.

	Jakub

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29  9:33         ` Jakub Jelinek
@ 2017-11-29 16:29           ` Martin Sebor
  2017-11-29 16:53             ` David Malcolm
                               ` (2 more replies)
  2017-12-01  1:24           ` Jeff Law
  1 sibling, 3 replies; 91+ messages in thread
From: Martin Sebor @ 2017-11-29 16:29 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Dominik Inführ, Richard Biener, GCC Patches

On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
> On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
>> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>>> Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
>>>
>> It's great to be able to eliminate pairs of these calls.  For
>> unpaired calls, though, I think it would be even more useful to
>> also issue a warning.  Otherwise the elimination will mask bugs
>
> ??  I hope you're only talking about allocation where the returned
> pointer can't leak elsewhere, doing allocation in one function
> (e.g. constructor, or whatever other function) and deallocation in some
> other one is so common such a warning would be not just useless, but
> harmful with almost all occurrences being false positives.
>
> Warning on malloc/standard operator new or malloc/realloc-like function
> when the return pointer can't escape the current function is reasonable.

Yes, warn for leaks, or for calls to delete/free with no matching
new/malloc (when they can be detected).

 From the test case included in the patch, warn on the first two
of the following three functions:

+++ 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;
+}

An obvious extension to such a checker would then be to also detect
possible invalid deallocations, as in:

   void f (unsigned n)
   {
     void *p = n < 256 ? alloca (n) : malloc (n);
     // ...
     free (p);
   }

David Malcolm was working on something like that earlier this year
so he might have some thoughts on this as well.

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29 16:29           ` Martin Sebor
@ 2017-11-29 16:53             ` David Malcolm
  2017-11-29 17:01               ` Andrew Pinski
  2018-05-13 17:19               ` Marc Glisse
  2017-11-29 18:05             ` [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Richard Biener
  2017-12-04 12:20             ` Trevor Saunders
  2 siblings, 2 replies; 91+ messages in thread
From: David Malcolm @ 2017-11-29 16:53 UTC (permalink / raw)
  To: Martin Sebor, Jakub Jelinek
  Cc: Dominik Inführ, Richard Biener, GCC Patches

On Wed, 2017-11-29 at 08:56 -0700, Martin Sebor wrote:
> On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
> > On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
> > > On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> > > > Thanks for all the reviews! I’ve revised the patch, the
> > > > operator_delete_flag is now stored in tree_decl_with_vis (there
> > > > already seem to be some FUNCTION_DECL-flags in there). I’ve
> > > > also added the option -fallocation-dce to disable this
> > > > optimization. It bootstraps and no regressions on aarch64 and
> > > > x86_64.
> > > > 
> > > 
> > > It's great to be able to eliminate pairs of these calls.  For
> > > unpaired calls, though, I think it would be even more useful to
> > > also issue a warning.  Otherwise the elimination will mask bugs
> > 
> > ??  I hope you're only talking about allocation where the returned
> > pointer can't leak elsewhere, doing allocation in one function
> > (e.g. constructor, or whatever other function) and deallocation in
> > some
> > other one is so common such a warning would be not just useless,
> > but
> > harmful with almost all occurrences being false positives.
> > 
> > Warning on malloc/standard operator new or malloc/realloc-like
> > function
> > when the return pointer can't escape the current function is
> > reasonable.
> 
> Yes, warn for leaks, or for calls to delete/free with no matching
> new/malloc (when they can be detected).
> 
>  From the test case included in the patch, warn on the first two
> of the following three functions:
> 
> +++ 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;
> +}
> 
> An obvious extension to such a checker would then be to also detect
> possible invalid deallocations, as in:
> 
>    void f (unsigned n)
>    {
>      void *p = n < 256 ? alloca (n) : malloc (n);
>      // ...
>      free (p);
>    }
> 
> David Malcolm was working on something like that earlier this year
> so he might have some thoughts on this as well.

I was experimenting with optimizing away matching malloc/free pairs,
moving the allocation to either the stack, or to a thread-local
obstack, under certain conditions, or to hoist allocations out of
loops.  

I didn't get any significant wins, but much of this was due to my lack
of experience with the middle-end, and being drawn back to front-
end/diagnostic improvements.

Issues I ran into included:

* wrapper functions like "Perl_malloc" which require LTO for the
optimization to be able to see the allocations

* 435.gromacs has this "interesting" function:

  unsigned maxavail(void)
  {
    char *ptr;
    unsigned low,high,size;
  
    low=0;
    high=256e6;
    while ((high-low) > 4) {
      size=(high+low)/2;
      if ((ptr=malloc((size_t)size))==NULL)
        high=size;
      else {
        free(ptr);
        low=size;
      }
    }
    return low;
  }

  i.e. a loop which attempts a binary search of malloc calls to try to
find a threshold at which they fail.


Dave

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29 16:53             ` David Malcolm
@ 2017-11-29 17:01               ` Andrew Pinski
  2018-05-13 17:19               ` Marc Glisse
  1 sibling, 0 replies; 91+ messages in thread
From: Andrew Pinski @ 2017-11-29 17:01 UTC (permalink / raw)
  To: David Malcolm
  Cc: Martin Sebor, Jakub Jelinek, Dominik Inführ, Richard Biener,
	GCC Patches

On Wed, Nov 29, 2017 at 8:15 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Wed, 2017-11-29 at 08:56 -0700, Martin Sebor wrote:
>> On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
>> > On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
>> > > On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>> > > > Thanks for all the reviews! I’ve revised the patch, the
>> > > > operator_delete_flag is now stored in tree_decl_with_vis (there
>> > > > already seem to be some FUNCTION_DECL-flags in there). I’ve
>> > > > also added the option -fallocation-dce to disable this
>> > > > optimization. It bootstraps and no regressions on aarch64 and
>> > > > x86_64.
>> > > >
>> > >
>> > > It's great to be able to eliminate pairs of these calls.  For
>> > > unpaired calls, though, I think it would be even more useful to
>> > > also issue a warning.  Otherwise the elimination will mask bugs
>> >
>> > ??  I hope you're only talking about allocation where the returned
>> > pointer can't leak elsewhere, doing allocation in one function
>> > (e.g. constructor, or whatever other function) and deallocation in
>> > some
>> > other one is so common such a warning would be not just useless,
>> > but
>> > harmful with almost all occurrences being false positives.
>> >
>> > Warning on malloc/standard operator new or malloc/realloc-like
>> > function
>> > when the return pointer can't escape the current function is
>> > reasonable.
>>
>> Yes, warn for leaks, or for calls to delete/free with no matching
>> new/malloc (when they can be detected).
>>
>>  From the test case included in the patch, warn on the first two
>> of the following three functions:
>>
>> +++ 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;
>> +}
>>
>> An obvious extension to such a checker would then be to also detect
>> possible invalid deallocations, as in:
>>
>>    void f (unsigned n)
>>    {
>>      void *p = n < 256 ? alloca (n) : malloc (n);
>>      // ...
>>      free (p);
>>    }
>>
>> David Malcolm was working on something like that earlier this year
>> so he might have some thoughts on this as well.
>
> I was experimenting with optimizing away matching malloc/free pairs,
> moving the allocation to either the stack, or to a thread-local
> obstack, under certain conditions, or to hoist allocations out of
> loops.
>
> I didn't get any significant wins, but much of this was due to my lack
> of experience with the middle-end, and being drawn back to front-
> end/diagnostic improvements.
>
> Issues I ran into included:
>
> * wrapper functions like "Perl_malloc" which require LTO for the
> optimization to be able to see the allocations
>
> * 435.gromacs has this "interesting" function:

It is still in the upstream sources too:
https://sourcecodebrowser.com/gromacs/3.3.1/smalloc_8h.html#a776f070172af6850dda887c7358fa630

Thanks,
Andrew Pinski

>
>   unsigned maxavail(void)
>   {
>     char *ptr;
>     unsigned low,high,size;
>
>     low=0;
>     high=256e6;
>     while ((high-low) > 4) {
>       size=(high+low)/2;
>       if ((ptr=malloc((size_t)size))==NULL)
>         high=size;
>       else {
>         free(ptr);
>         low=size;
>       }
>     }
>     return low;
>   }
>
>   i.e. a loop which attempts a binary search of malloc calls to try to
> find a threshold at which they fail.
>
>
> Dave

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29 16:29           ` Martin Sebor
  2017-11-29 16:53             ` David Malcolm
@ 2017-11-29 18:05             ` Richard Biener
  2017-12-04 12:20             ` Trevor Saunders
  2 siblings, 0 replies; 91+ messages in thread
From: Richard Biener @ 2017-11-29 18:05 UTC (permalink / raw)
  To: Martin Sebor, Jakub Jelinek; +Cc: Dominik Inführ, GCC Patches

On November 29, 2017 4:56:44 PM GMT+01:00, Martin Sebor <msebor@gmail.com> wrote:
>On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
>> On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
>>> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>>>> Thanks for all the reviews! I’ve revised the patch, the
>operator_delete_flag is now stored in tree_decl_with_vis (there already
>seem to be some FUNCTION_DECL-flags in there). I’ve also added the
>option -fallocation-dce to disable this optimization. It bootstraps and
>no regressions on aarch64 and x86_64.
>>>>
>>> It's great to be able to eliminate pairs of these calls.  For
>>> unpaired calls, though, I think it would be even more useful to
>>> also issue a warning.  Otherwise the elimination will mask bugs
>>
>> ??  I hope you're only talking about allocation where the returned
>> pointer can't leak elsewhere, doing allocation in one function
>> (e.g. constructor, or whatever other function) and deallocation in
>some
>> other one is so common such a warning would be not just useless, but
>> harmful with almost all occurrences being false positives.
>>
>> Warning on malloc/standard operator new or malloc/realloc-like
>function
>> when the return pointer can't escape the current function is
>reasonable.
>
>Yes, warn for leaks, or for calls to delete/free with no matching
>new/malloc (when they can be detected).
>
> From the test case included in the patch, warn on the first two
>of the following three functions:
>
>+++ 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;
>+}
>
>An obvious extension to such a checker would then be to also detect
>possible invalid deallocations, as in:
>
>   void f (unsigned n)
>   {
>     void *p = n < 256 ? alloca (n) : malloc (n);
>     // ...
>     free (p);
>   }
>
>David Malcolm was working on something like that earlier this year
>so he might have some thoughts on this as well.

Or

P = new x;
Free (P) ;

Richard. 

>Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29  8:13       ` Martin Sebor
  2017-11-29  9:33         ` Jakub Jelinek
@ 2017-12-01  1:23         ` Jeff Law
  1 sibling, 0 replies; 91+ messages in thread
From: Jeff Law @ 2017-12-01  1:23 UTC (permalink / raw)
  To: Martin Sebor, Dominik Inführ, Jakub Jelinek
  Cc: Richard Biener, GCC Patches

On 11/28/2017 09:11 PM, Martin Sebor wrote:
> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>> Thanks for all the reviews! IÂ’ve revised the patch, the
>> operator_delete_flag is now stored in tree_decl_with_vis (there
>> already seem to be some FUNCTION_DECL-flags in there). IÂ’ve also added
>> the option -fallocation-dce to disable this optimization. It
>> bootstraps and no regressions on aarch64 and x86_64.
>>
> It's great to be able to eliminate pairs of these calls.  For
> unpaired calls, though, I think it would be even more useful to
> also issue a warning.  Otherwise the elimination will mask bugs
> that might only show up without optimization, or with other
> compilers (such as older versions of GCC).  I realize GCC doesn't
> warn for these bugs involving malloc, but I think it should for
> the same reason.
Aldy and I looked at this stuff a while ago -- to do anything reasonable
you have to build a much stronger static analysis engine than we've got
in GCC right now.  THe false positive rate will be way too high to be
useful on real world code.

I don't see how the optimizatino changes anything WRT warnings though.
If you don't have a clear pair where all the proper preconditions are
met, then you don't do anything.  Those preconditions would include that
you actually have a pair as opposed to just the allocation point.


Jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29  9:33         ` Jakub Jelinek
  2017-11-29 16:29           ` Martin Sebor
@ 2017-12-01  1:24           ` Jeff Law
  1 sibling, 0 replies; 91+ messages in thread
From: Jeff Law @ 2017-12-01  1:24 UTC (permalink / raw)
  To: Jakub Jelinek, Martin Sebor
  Cc: Dominik Inführ, Richard Biener, GCC Patches

On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
> On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
>> On 11/27/2017 02:22 AM, Dominik Inführ wrote:
>>> Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
>>>
>> It's great to be able to eliminate pairs of these calls.  For
>> unpaired calls, though, I think it would be even more useful to
>> also issue a warning.  Otherwise the elimination will mask bugs
> 
> ??  I hope you're only talking about allocation where the returned
> pointer can't leak elsewhere, doing allocation in one function
> (e.g. constructor, or whatever other function) and deallocation in some
> other one is so common such a warning would be not just useless, but
> harmful with almost all occurrences being false positives.
> 
> Warning on malloc/standard operator new or malloc/realloc-like function
> when the return pointer can't escape the current function is reasonable.
That's probably a special enough case to be worth a warning
(non-escaping without deallocation).

My comments about needing a stronger analysis engine were for the more
general problem of resource leak detection.

jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29 16:29           ` Martin Sebor
  2017-11-29 16:53             ` David Malcolm
  2017-11-29 18:05             ` [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Richard Biener
@ 2017-12-04 12:20             ` Trevor Saunders
  2 siblings, 0 replies; 91+ messages in thread
From: Trevor Saunders @ 2017-12-04 12:20 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Jakub Jelinek, Dominik Inführ, Richard Biener, GCC Patches

On Wed, Nov 29, 2017 at 08:56:44AM -0700, Martin Sebor wrote:
> On 11/29/2017 01:30 AM, Jakub Jelinek wrote:
> > On Tue, Nov 28, 2017 at 09:11:00PM -0700, Martin Sebor wrote:
> > > On 11/27/2017 02:22 AM, Dominik Inführ wrote:
> > > > Thanks for all the reviews! I’ve revised the patch, the operator_delete_flag is now stored in tree_decl_with_vis (there already seem to be some FUNCTION_DECL-flags in there). I’ve also added the option -fallocation-dce to disable this optimization. It bootstraps and no regressions on aarch64 and x86_64.
> > > > 
> > > It's great to be able to eliminate pairs of these calls.  For
> > > unpaired calls, though, I think it would be even more useful to
> > > also issue a warning.  Otherwise the elimination will mask bugs
> > 
> > ??  I hope you're only talking about allocation where the returned
> > pointer can't leak elsewhere, doing allocation in one function
> > (e.g. constructor, or whatever other function) and deallocation in some
> > other one is so common such a warning would be not just useless, but
> > harmful with almost all occurrences being false positives.
> > 
> > Warning on malloc/standard operator new or malloc/realloc-like function
> > when the return pointer can't escape the current function is reasonable.
> 
> Yes, warn for leaks, or for calls to delete/free with no matching
> new/malloc (when they can be detected).
> 
> From the test case included in the patch, warn on the first two
> of the following three functions:
> 
> +++ 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;
> +}
> 
> An obvious extension to such a checker would then be to also detect
> possible invalid deallocations, as in:
> 
>   void f (unsigned n)
>   {
>     void *p = n < 256 ? alloca (n) : malloc (n);
>     // ...
>     free (p);
>   }
> 
> David Malcolm was working on something like that earlier this year
> so he might have some thoughts on this as well.

I also sent https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00491.html a
while back, sorry I haven't gotten to  improving it yet though its gcc 9
stuff at this point I guess.

thanks

Trev

> 
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs
  2017-11-29 16:53             ` David Malcolm
  2017-11-29 17:01               ` Andrew Pinski
@ 2018-05-13 17:19               ` Marc Glisse
  2019-07-02 11:49                 ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Liška
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2018-05-13 17:19 UTC (permalink / raw)
  To: David Malcolm; +Cc: GCC Patches

On Wed, 29 Nov 2017, David Malcolm wrote:

> I was experimenting with optimizing away matching malloc/free pairs,
> moving the allocation to either the stack, or to a thread-local
> obstack, under certain conditions, or to hoist allocations out of
> loops.
>
> I didn't get any significant wins, but much of this was due to my lack
> of experience with the middle-end, and being drawn back to front-
> end/diagnostic improvements.

Hello,

could you share what you have? Is this something you might work on again 
at some point?

I had a go (very limited) at this problem some years ago, and would be 
interested in looking at your approach.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2018-05-13 17:19               ` Marc Glisse
@ 2019-07-02 11:49                 ` Martin Liška
  2019-07-02 11:50                   ` [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383) Martin Liška
                                     ` (2 more replies)
  0 siblings, 3 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-02 11:49 UTC (permalink / raw)
  To: Marc Glisse, David Malcolm; +Cc: GCC Patches, Richard Biener, dominik.infuehr

[-- Attachment #1: Type: text/plain, Size: 256 bytes --]

Hi.

After the discussion with Richi and Nathan, I made a place in tree_function_decl
and I rebased the original Dominik's patch on top of that.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Come-up-with-function_decl_type-and-use-it-in-tree_f.patch --]
[-- Type: text/x-patch, Size: 16370 bytes --]

From cdf41c7e6d00680b6c7fc31234025aef0091bd9c Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 2 Jul 2019 08:30:09 +0200
Subject: [PATCH 1/2] Come up with function_decl_type and use it in
 tree_function_decl.

gcc/ChangeLog:

2019-07-02  Martin Liska  <mliska@suse.cz>

	* calls.c (maybe_warn_alloc_args_overflow): Use new macros
	(e.g. DECL_SET_LAMBDA_FUNCTION and DECL_LAMBDA_FUNCTION_P).
	* coverage.c (coverage_begin_function): Likewise.
	* fold-const.c (tree_expr_nonzero_warnv_p): Likewise.
	* gimple.c (gimple_call_nonnull_result_p): Likewise.
	* ipa-icf.c (sem_item::compare_referenced_symbol_properties): Likewise.
	(sem_item::hash_referenced_symbol_properties): Likewise.
	* lto-streamer-out.c (hash_tree): Likewise.
	* predict.c (expr_expected_value_1): Likewise.
	* tree-inline.c (expand_call_inline): Likewise.
	* tree-streamer-in.c (unpack_ts_function_decl_value_fields): Likewise.
	* tree-streamer-out.c (pack_ts_function_decl_value_fields): Likewise.
	* tree-core.h (enum function_decl_type): New enum.
	(struct tree_function_decl): Remove operator_new_flag and lambda_function.
	* tree.h (FUNCTION_DECL_DECL_TYPE): New.
	(set_function_decl_type): Likewise.
	(DECL_IS_OPERATOR_NEW_P): New.
	(DECL_SET_IS_OPERATOR_NEW): Likewise.
	(DECL_LAMBDA_FUNCTION): Likewise.
	(DECL_LAMBDA_FUNCTION_P): Likewise.
	(DECL_IS_OPERATOR_NEW): Remove.
	(DECL_SET_LAMBDA_FUNCTION): Likewise.

gcc/c/ChangeLog:

2019-07-02  Martin Liska  <mliska@suse.cz>

	* c-decl.c (merge_decls): Use new macros
	(e.g. DECL_SET_LAMBDA_FUNCTION and DECL_LAMBDA_FUNCTION_P).

gcc/cp/ChangeLog:

2019-07-02  Martin Liska  <mliska@suse.cz>

	* decl.c (duplicate_decls): Use new macros
	(e.g. DECL_SET_LAMBDA_FUNCTION and DECL_LAMBDA_FUNCTION_P).
	(cxx_init_decl_processing): Likewise.
	(grok_op_properties): Likewise.
	* parser.c (cp_parser_lambda_declarator_opt): Likewise.

gcc/lto/ChangeLog:

2019-07-02  Martin Liska  <mliska@suse.cz>

	* lto-common.c (compare_tree_sccs_1): Use new macros
	(e.g. DECL_SET_LAMBDA_FUNCTION and DECL_LAMBDA_FUNCTION_P).
---
 gcc/c/c-decl.c          |  3 ++-
 gcc/calls.c             |  2 +-
 gcc/coverage.c          |  2 +-
 gcc/cp/decl.c           | 13 +++++++------
 gcc/cp/parser.c         |  2 +-
 gcc/fold-const.c        |  2 +-
 gcc/gimple.c            |  2 +-
 gcc/ipa-icf.c           |  6 +++---
 gcc/lto-streamer-out.c  |  2 +-
 gcc/lto/lto-common.c    |  2 +-
 gcc/predict.c           |  2 +-
 gcc/tree-core.h         | 20 +++++++++++++++++---
 gcc/tree-inline.c       |  2 +-
 gcc/tree-streamer-in.c  |  2 +-
 gcc/tree-streamer-out.c |  2 +-
 gcc/tree.h              | 34 ++++++++++++++++++++++++++++++----
 16 files changed, 70 insertions(+), 28 deletions(-)

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index cb2f49fa5a2..b0a7e34745f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2638,7 +2638,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
-	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
+	  if (DECL_IS_OPERATOR_NEW_P (olddecl))
+	    DECL_SET_IS_OPERATOR_NEW (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/calls.c b/gcc/calls.c
index 6ab138e7bb0..7507b698e27 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1395,7 +1395,7 @@ maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2])
 		  && fn
 		  && !args[1]
 		  && lang_GNU_CXX ()
-		  && DECL_IS_OPERATOR_NEW (fn)
+		  && DECL_IS_OPERATOR_NEW_P (fn)
 		  && integer_all_onesp (args[i]))
 		continue;
 
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 1ffefd5f482..a63cb94e9f3 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -643,7 +643,7 @@ coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum)
 		     (DECL_ASSEMBLER_NAME (current_function_decl)));
   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
 		       && !DECL_FUNCTION_VERSIONED (current_function_decl)
-		       && !DECL_LAMBDA_FUNCTION (current_function_decl));
+		       && !DECL_LAMBDA_FUNCTION_P (current_function_decl));
   gcov_write_filename (xloc.file);
   gcov_write_unsigned (xloc.line);
   gcov_write_unsigned (xloc.column);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bb9d19a8172..0e9b1b55141 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2292,7 +2292,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
-	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
+	  if (DECL_IS_OPERATOR_NEW_P (olddecl))
+	    DECL_SET_IS_OPERATOR_NEW (newdecl, true);
 	  DECL_LOOPING_CONST_OR_PURE_P (newdecl)
 	    |= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
 
@@ -4357,10 +4358,10 @@ cxx_init_decl_processing (void)
     deltype = build_exception_variant (deltype, empty_except_spec);
     tree opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
-    DECL_IS_OPERATOR_NEW (opnew) = 1;
+    DECL_SET_IS_OPERATOR_NEW (opnew, true);
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
-    DECL_IS_OPERATOR_NEW (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);
     if (flag_sized_deallocation)
@@ -4393,10 +4394,10 @@ cxx_init_decl_processing (void)
 	newtype = build_exception_variant (newtype, new_eh_spec);
 	opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
 	DECL_IS_MALLOC (opnew) = 1;
-	DECL_IS_OPERATOR_NEW (opnew) = 1;
+	DECL_SET_IS_OPERATOR_NEW (opnew, true);
 	opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
 	DECL_IS_MALLOC (opnew) = 1;
-	DECL_IS_OPERATOR_NEW (opnew) = 1;
+	DECL_SET_IS_OPERATOR_NEW (opnew, true);
 
 	/* operator delete (void *, align_val_t); */
 	deltype = build_function_type_list (void_type_node, ptr_type_node,
@@ -13637,7 +13638,7 @@ grok_op_properties (tree decl, bool complain)
 	coerce_delete_type (decl, loc);
       else
 	{
-	  DECL_IS_OPERATOR_NEW (decl) = 1;
+	  DECL_SET_IS_OPERATOR_NEW (decl, true);
 	  TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl), loc);
 	}
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 12814102465..7cded50dcfc 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10977,7 +10977,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	DECL_ARTIFICIAL (fco) = 1;
 	/* Give the object parameter a different name.  */
 	DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier;
-	DECL_LAMBDA_FUNCTION (fco) = 1;
+	DECL_SET_LAMBDA_FUNCTION (fco, true);
       }
     if (template_param_list)
       {
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 0ca472d422f..a8ae5652682 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -9250,7 +9250,7 @@ tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
 	tree fndecl = get_callee_fndecl (t);
 	if (!fndecl) return false;
 	if (flag_delete_null_pointer_checks && !flag_check_new
-	    && DECL_IS_OPERATOR_NEW (fndecl)
+	    && DECL_IS_OPERATOR_NEW_P (fndecl)
 	    && !TREE_NOTHROW (fndecl))
 	  return true;
 	if (flag_delete_null_pointer_checks
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 63c8d5e85ae..513bde209e2 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1583,7 +1583,7 @@ gimple_call_nonnull_result_p (gcall *call)
   if (!fndecl)
     return false;
   if (flag_delete_null_pointer_checks && !flag_check_new
-      && DECL_IS_OPERATOR_NEW (fndecl)
+      && DECL_IS_OPERATOR_NEW_P (fndecl)
       && !TREE_NOTHROW (fndecl))
     return true;
 
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 7c486eda758..ce544d45e88 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -344,8 +344,8 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
 	    return return_false_with_msg ("inline attributes are different");
 	}
 
-      if (DECL_IS_OPERATOR_NEW (n1->decl)
-	  != DECL_IS_OPERATOR_NEW (n2->decl))
+      if (DECL_IS_OPERATOR_NEW_P (n1->decl)
+	  != DECL_IS_OPERATOR_NEW_P (n2->decl))
 	return return_false_with_msg ("operator new flags are different");
     }
 
@@ -409,7 +409,7 @@ sem_item::hash_referenced_symbol_properties (symtab_node *ref,
 	  hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (ref->decl));
 	  hstate.add_flag (DECL_DECLARED_INLINE_P (ref->decl));
 	}
-      hstate.add_flag (DECL_IS_OPERATOR_NEW (ref->decl));
+      hstate.add_flag (DECL_IS_OPERATOR_NEW_P (ref->decl));
     }
   else if (is_a <varpool_node *> (ref))
     {
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index dc68429303c..574f51dbb66 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1121,12 +1121,12 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
       hstate.add_int (DECL_BUILT_IN_CLASS (t));
       hstate.add_flag (DECL_STATIC_CONSTRUCTOR (t));
       hstate.add_flag (DECL_STATIC_DESTRUCTOR (t));
+      hstate.add_flag (FUNCTION_DECL_DECL_TYPE (t));
       hstate.add_flag (DECL_UNINLINABLE (t));
       hstate.add_flag (DECL_POSSIBLY_INLINED (t));
       hstate.add_flag (DECL_IS_NOVOPS (t));
       hstate.add_flag (DECL_IS_RETURNS_TWICE (t));
       hstate.add_flag (DECL_IS_MALLOC (t));
-      hstate.add_flag (DECL_IS_OPERATOR_NEW (t));
       hstate.add_flag (DECL_DECLARED_INLINE_P (t));
       hstate.add_flag (DECL_STATIC_CHAIN (t));
       hstate.add_flag (DECL_NO_INLINE_WARNING_P (t));
diff --git a/gcc/lto/lto-common.c b/gcc/lto/lto-common.c
index 1275b673506..acb7d5d8bec 100644
--- a/gcc/lto/lto-common.c
+++ b/gcc/lto/lto-common.c
@@ -1213,7 +1213,7 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
       compare_values (DECL_IS_NOVOPS);
       compare_values (DECL_IS_RETURNS_TWICE);
       compare_values (DECL_IS_MALLOC);
-      compare_values (DECL_IS_OPERATOR_NEW);
+      compare_values (DECL_IS_OPERATOR_NEW_P);
       compare_values (DECL_DECLARED_INLINE_P);
       compare_values (DECL_STATIC_CHAIN);
       compare_values (DECL_NO_INLINE_WARNING_P);
diff --git a/gcc/predict.c b/gcc/predict.c
index ad19d1295e0..debf27bf5f8 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -2450,7 +2450,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
 	      return NULL;
 	    }
 
-	  if (DECL_IS_MALLOC (decl) || DECL_IS_OPERATOR_NEW (decl))
+	  if (DECL_IS_MALLOC (decl) || DECL_IS_OPERATOR_NEW_P (decl))
 	    {
 	      if (predictor)
 		*predictor = PRED_MALLOC_NONNULL;
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 23f8f01317e..e0643503e80 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1801,6 +1801,17 @@ struct GTY(()) tree_decl_non_common {
   tree result;
 };
 
+/* Classify a special function declaration type.  */
+
+enum function_decl_type
+{
+  NONE,
+  OPERATOR_NEW,
+  LAMBDA_FUNCTION
+
+  /* 0 values left */
+};
+
 /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
    arguments/result/saved_tree fields by front ends.   It was either inherit
    FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
@@ -1840,19 +1851,22 @@ struct GTY(()) tree_function_decl {
   unsigned novops_flag : 1;
   unsigned returns_twice_flag : 1;
   unsigned malloc_flag : 1;
-  unsigned operator_new_flag : 1;
   unsigned declared_inline_flag : 1;
   unsigned no_inline_warning_flag : 1;
 
   unsigned no_instrument_function_entry_exit : 1;
+
+  /* Align the bitfield to boundary of a byte.  */
+  ENUM_BITFIELD(function_decl_type) decl_type: 2;
+
   unsigned no_limit_stack : 1;
   unsigned disregard_inline_limits : 1;
   unsigned pure_flag : 1;
   unsigned looping_const_or_pure_flag : 1;
   unsigned has_debug_args_flag : 1;
   unsigned versioned_function : 1;
-  unsigned lambda_function: 1;
-  /* No bits left.  */
+
+  /* 0 bits left.  */
 };
 
 struct GTY(()) tree_translation_unit_decl {
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 450af460dd0..22ac06255a5 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -4883,7 +4883,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
      we may get confused if the compiler sees that the inlined new
      function returns a pointer which was just deleted.  See bug
      33407.  */
-  if (DECL_IS_OPERATOR_NEW (fn))
+  if (DECL_IS_OPERATOR_NEW_P (fn))
     {
       return_slot = NULL;
       modify_dest = NULL;
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 35b3e9874d5..7bd21ae7bc5 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -333,7 +333,7 @@ unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
-  DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_SET_IS_OPERATOR_NEW (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 a83057ec277..7e93e6c23bb 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -295,7 +295,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   bp_pack_value (bp, DECL_IS_NOVOPS (expr), 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 (expr), 1);
+  bp_pack_value (bp, DECL_IS_OPERATOR_NEW_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 1a43e6b7ff8..117c2e13335 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2980,11 +2980,34 @@ extern void decl_fini_priority_insert (tree, priority_type);
 #define DECL_IS_MALLOC(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.malloc_flag)
 
+/* Macro for direct set and get of function_decl.decl_type.  */
+#define FUNCTION_DECL_DECL_TYPE(NODE) \
+  (NODE->function_decl.decl_type)
+
+/* Set decl_type of a DECL.  Set it to T when SET is true, or reset
+   it to NONE.  */
+
+static inline void
+set_function_decl_type (tree decl, function_decl_type t, bool set)
+{
+  if (set)
+    {
+      gcc_assert (FUNCTION_DECL_DECL_TYPE (decl) == NONE
+		  || FUNCTION_DECL_DECL_TYPE (decl) == t);
+      decl->function_decl.decl_type = t;
+    }
+  else if (FUNCTION_DECL_DECL_TYPE (decl) == t)
+    FUNCTION_DECL_DECL_TYPE (decl) = NONE;
+}
+
 /* Nonzero in a FUNCTION_DECL means this function should be treated as
    C++ operator new, meaning that it returns a pointer for which we
    should not use type based aliasing.  */
-#define DECL_IS_OPERATOR_NEW(NODE) \
-  (FUNCTION_DECL_CHECK (NODE)->function_decl.operator_new_flag)
+#define DECL_IS_OPERATOR_NEW_P(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_NEW)
+
+#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 may return more
    than once.  */
@@ -3129,8 +3152,11 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
    (FUNCTION_DECL_CHECK (NODE)->decl_with_vis.cxx_destructor)
 
 /* In FUNCTION_DECL, this is set if this function is a lambda function.  */
-#define DECL_LAMBDA_FUNCTION(NODE) \
-  (FUNCTION_DECL_CHECK (NODE)->function_decl.lambda_function)
+#define DECL_LAMBDA_FUNCTION_P(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == LAMBDA_FUNCTION)
+
+#define DECL_SET_LAMBDA_FUNCTION(NODE, VAL) \
+  set_function_decl_type (FUNCTION_DECL_CHECK (NODE), LAMBDA_FUNCTION, VAL)
 
 /* In FUNCTION_DECL that represent an virtual method this is set when
    the method is final.  */
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383).
  2019-07-02 11:49                 ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Liška
@ 2019-07-02 11:50                   ` Martin Liška
  2019-08-02 21:34                     ` H.J. Lu
  2019-07-02 16:02                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Sebor
  2019-07-02 17:15                   ` Marc Glisse
  2 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-02 11:50 UTC (permalink / raw)
  To: Marc Glisse, David Malcolm; +Cc: GCC Patches, Richard Biener, dominik.infuehr

[-- Attachment #1: Type: text/plain, Size: 21 bytes --]

Second part.

Martin

[-- Attachment #2: 0002-Extend-DCE-to-remove-unnecessary-new-delete-pairs-PR.patch --]
[-- Type: text/x-patch, Size: 17191 bytes --]

From a5226ccfdc46459afc3474472197aabf51331a63 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@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  <mliska@suse.cz>
	    Dominik Infuhr  <dominik.infuehr@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  <mliska@suse.cz>
	    Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>

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

gcc/cp/ChangeLog:

2019-07-02  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.

gcc/testsuite/ChangeLog:

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

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

libstdc++-v3/ChangeLog:

2019-07-02  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.
---
 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


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-02 11:49                 ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Liška
  2019-07-02 11:50                   ` [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383) Martin Liška
@ 2019-07-02 16:02                   ` Martin Sebor
  2019-07-02 17:15                   ` Marc Glisse
  2 siblings, 0 replies; 91+ messages in thread
From: Martin Sebor @ 2019-07-02 16:02 UTC (permalink / raw)
  To: Martin Liška, Marc Glisse, David Malcolm
  Cc: GCC Patches, Richard Biener, dominik.infuehr

On 7/2/19 5:49 AM, Martin Liška wrote:
> Hi.
> 
> After the discussion with Richi and Nathan, I made a place in tree_function_decl
> and I rebased the original Dominik's patch on top of that.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

FWIW, I think there is a choice between using the convention to end
names of a predicate in _P and between using _IS_ in the predicate
name.  E.g., DECL_P or CALL_P, vs DECL_IS_BUILTIN, or
CLASSTYPE_IS_TEMPLATE.  There are a handful of examples that use
both _IS_ and _P but those are in minority, so I would suggest to
choose one or the other (but not both) for new names.

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-02 11:49                 ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Liška
  2019-07-02 11:50                   ` [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383) Martin Liška
  2019-07-02 16:02                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Sebor
@ 2019-07-02 17:15                   ` Marc Glisse
  2019-07-03 15:03                     ` Martin Liška
  2 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-02 17:15 UTC (permalink / raw)
  To: Martin Liška
  Cc: David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On Tue, 2 Jul 2019, Martin Liška wrote:

> After the discussion with Richi and Nathan, I made a place in tree_function_decl
> and I rebased the original Dominik's patch on top of that.

So, last time there were some questions about the legality of this 
transformation. Did you change the exact set of functions on which this is 
applied? Or has there been a clarification in the standard saying that 
this is ok? (or were we mistaken the first time to believe that there 
might be an issue?)

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-02 17:15                   ` Marc Glisse
@ 2019-07-03 15:03                     ` Martin Liška
  2019-07-03 16:44                       ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-03 15:03 UTC (permalink / raw)
  To: gcc-patches, Marc Glisse; +Cc: David Malcolm, Richard Biener, dominik.infuehr

On 7/2/19 7:15 PM, Marc Glisse wrote:
> On Tue, 2 Jul 2019, Martin Liška wrote:
> 
>> After the discussion with Richi and Nathan, I made a place in tree_function_decl
>> and I rebased the original Dominik's patch on top of that.
> 
> So, last time there were some questions about the legality of this transformation. Did you change the exact set of functions on which this is applied?

Yes. I was not included in the original discussion, but I hope the transformation is valid.
Btw. clang also removes the new/delete pairs and I guess it was the original motivation of the patch.

Martin

Or has there been a clarification in the standard saying that this is ok? (or were we mistaken the first time to believe that there might be an issue?)
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-03 15:03                     ` Martin Liška
@ 2019-07-03 16:44                       ` Richard Biener
  2019-07-04 22:21                         ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-07-03 16:44 UTC (permalink / raw)
  To: Martin Liška, gcc-patches, Marc Glisse
  Cc: David Malcolm, dominik.infuehr

On July 3, 2019 4:53:30 PM GMT+02:00, "Martin Liška" <mliska@suse.cz> wrote:
>On 7/2/19 7:15 PM, Marc Glisse wrote:
>> On Tue, 2 Jul 2019, Martin Liška wrote:
>> 
>>> After the discussion with Richi and Nathan, I made a place in
>tree_function_decl
>>> and I rebased the original Dominik's patch on top of that.
>> 
>> So, last time there were some questions about the legality of this
>transformation. Did you change the exact set of functions on which this
>is applied?
>
>Yes. I was not included in the original discussion, but I hope the
>transformation is valid.
>Btw. clang also removes the new/delete pairs and I guess it was the
>original motivation of the patch.

We also remove malloc/free pairs which the C standard does not explicitly allow (but also doesn't explicitly forbid). I don't think standards need to enumerate everything allowed and I don't know any explicit wording in the C++ standard that forbids this. It's only that users can override the allocation functions (but so can they in C) and it was suggested we need to preserve side effects unknown to the compiler. 

Richard. 

>Martin
>
>Or has there been a clarification in the standard saying that this is
>ok? (or were we mistaken the first time to believe that there might be
>an issue?)
>> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-03 16:44                       ` Richard Biener
@ 2019-07-04 22:21                         ` Marc Glisse
  2019-07-08 13:02                           ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-04 22:21 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Liška, gcc-patches, David Malcolm, dominik.infuehr

On Wed, 3 Jul 2019, Richard Biener wrote:

> On July 3, 2019 4:53:30 PM GMT+02:00, "Martin Liška" <mliska@suse.cz> wrote:
>> On 7/2/19 7:15 PM, Marc Glisse wrote:
>>> On Tue, 2 Jul 2019, Martin Liška wrote:
>>>
>>>> After the discussion with Richi and Nathan, I made a place in
>> tree_function_decl
>>>> and I rebased the original Dominik's patch on top of that.
>>>
>>> So, last time there were some questions about the legality of this
>> transformation. Did you change the exact set of functions on which this
>> is applied?
>>
>> Yes. I was not included in the original discussion, but I hope the
>> transformation is valid.
>> Btw. clang also removes the new/delete pairs and I guess it was the
>> original motivation of the patch.
>
> We also remove malloc/free pairs which the C standard does not explicitly allow (but also doesn't explicitly forbid). I don't think standards need to enumerate everything allowed and I don't know any explicit wording in the C++ standard that forbids this.

The C++ standard has explicit wording allowing to remove new-delete pairs 
in some circumstances (expr.new, allocator.members), so I would assume 
that other circumstances are forbidden (not that I care much, I am just 
afraid someone might).

The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable 
global deallocation functions, not all delete operators, contrary to 
DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those 
seem to be the ones for which the optimization is legal (well, not quite, 
the rules are in terms of operator new, and I am not sure how well 
operator delete has to match, but close enough).

> It's only that users can override the allocation functions (but so can 
> they in C) and it was suggested we need to preserve side effects unknown 
> to the compiler.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-04 22:21                         ` Marc Glisse
@ 2019-07-08 13:02                           ` Martin Liška
  2019-07-08 22:00                             ` Jason Merrill
  2019-07-09  2:28                             ` Marc Glisse
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-08 13:02 UTC (permalink / raw)
  To: Marc Glisse, Richard Biener
  Cc: gcc-patches, David Malcolm, dominik.infuehr, Jason Merrill,
	Nathan Sidwell

On 7/5/19 12:09 AM, Marc Glisse wrote:
> On Wed, 3 Jul 2019, Richard Biener wrote:
> 
>> On July 3, 2019 4:53:30 PM GMT+02:00, "Martin Liška" <mliska@suse.cz> wrote:
>>> On 7/2/19 7:15 PM, Marc Glisse wrote:
>>>> On Tue, 2 Jul 2019, Martin Liška wrote:
>>>>
>>>>> After the discussion with Richi and Nathan, I made a place in
>>> tree_function_decl
>>>>> and I rebased the original Dominik's patch on top of that.
>>>>
>>>> So, last time there were some questions about the legality of this
>>> transformation. Did you change the exact set of functions on which this
>>> is applied?
>>>
>>> Yes. I was not included in the original discussion, but I hope the
>>> transformation is valid.
>>> Btw. clang also removes the new/delete pairs and I guess it was the
>>> original motivation of the patch.
>>
>> We also remove malloc/free pairs which the C standard does not explicitly allow (but also doesn't explicitly forbid). I don't think standards need to enumerate everything allowed and I don't know any explicit wording in the C++ standard that forbids this.
> 
> The C++ standard has explicit wording allowing to remove new-delete pairs in some circumstances (expr.new, allocator.members), so I would assume that other circumstances are forbidden (not that I care much, I am just afraid someone might).

I hope some C++ FE maintainers can help us here?

> 
> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global deallocation functions, not all delete operators, contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem to be the ones for which the optimization is legal (well, not quite, the rules are in terms of operator new, and I am not sure how well operator delete has to match, but close enough).

Are you talking about this location where we set OPERATOR_NEW:
https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
?

That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.

Thanks,
Martin

> 
>> It's only that users can override the allocation functions (but so can they in C) and it was suggested we need to preserve side effects unknown to the compiler.
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-08 13:02                           ` Martin Liška
@ 2019-07-08 22:00                             ` Jason Merrill
  2019-07-09  2:28                             ` Marc Glisse
  1 sibling, 0 replies; 91+ messages in thread
From: Jason Merrill @ 2019-07-08 22:00 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Richard Biener, gcc-patches List, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Mon, Jul 8, 2019 at 8:51 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/5/19 12:09 AM, Marc Glisse wrote:
> > On Wed, 3 Jul 2019, Richard Biener wrote:
> >
> >> On July 3, 2019 4:53:30 PM GMT+02:00, "Martin Liška" <mliska@suse.cz> wrote:
> >>> On 7/2/19 7:15 PM, Marc Glisse wrote:
> >>>> On Tue, 2 Jul 2019, Martin Liška wrote:
> >>>>
> >>>>> After the discussion with Richi and Nathan, I made a place in
> >>> tree_function_decl
> >>>>> and I rebased the original Dominik's patch on top of that.
> >>>>
> >>>> So, last time there were some questions about the legality of this
> >>> transformation. Did you change the exact set of functions on which this
> >>> is applied?
> >>>
> >>> Yes. I was not included in the original discussion, but I hope the
> >>> transformation is valid.
> >>> Btw. clang also removes the new/delete pairs and I guess it was the
> >>> original motivation of the patch.
> >>
> >> We also remove malloc/free pairs which the C standard does not explicitly allow (but also doesn't explicitly forbid). I don't think standards need to enumerate everything allowed and I don't know any explicit wording in the C++ standard that forbids this.
> >
> > The C++ standard has explicit wording allowing to remove new-delete pairs in some circumstances (expr.new, allocator.members), so I would assume that other circumstances are forbidden (not that I care much, I am just afraid someone might).
>
> I hope some C++ FE maintainers can help us here?

Seems fine to me.

[expr.new] says "An implementation is allowed to omit a call to a
replaceable global allocation function (17.6.2.1, 17.6.2.2).
When it does so, the storage is instead provided by the implementation
or provided by extending the allocation
of another new-expression."

In the case of this optimization, the implementation is providing no
storage, but that is fine because it is not observable.

The circumstances described after the above quote have to do with when
two allocations can be combined, which doesn't apply to this
optimization.

std::allocate says "it is unspecified when or how often [::operator
new] is called."

Jason

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-08 13:02                           ` Martin Liška
  2019-07-08 22:00                             ` Jason Merrill
@ 2019-07-09  2:28                             ` Marc Glisse
  2019-07-09  7:52                               ` Marc Glisse
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-09  2:28 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Jason Merrill, Nathan Sidwell

On Mon, 8 Jul 2019, Martin Liška wrote:

>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the 
>> replaceable global deallocation functions, not all delete operators, 
>> contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the 
>> other hand, those seem to be the ones for which the optimization is 
>> legal (well, not quite, the rules are in terms of operator new, and I 
>> am not sure how well operator delete has to match, but close enough).
>
> Are you talking about this location where we set OPERATOR_NEW:
> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
> ?
>
> That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.

Yes, I think that's the place.

Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
seems misleading, but setting it would let us optimize in cases where we
are not really allowed to. Maybe just rename your macro to
DECL_IS_GLOBAL_OPERATOR_DELETE?

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-09  2:28                             ` Marc Glisse
@ 2019-07-09  7:52                               ` Marc Glisse
  2019-07-09  8:49                                 ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-09  7:52 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Jason Merrill, Nathan Sidwell

On Tue, 9 Jul 2019, Marc Glisse wrote:

> On Mon, 8 Jul 2019, Martin Liška wrote:
>
>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable 
>>> global deallocation functions, not all delete operators, contrary to 
>>> DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those 
>>> seem to be the ones for which the optimization is legal (well, not quite, 
>>> the rules are in terms of operator new, and I am not sure how well 
>>> operator delete has to match, but close enough).
>> 
>> Are you talking about this location where we set OPERATOR_NEW:
>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>> ?
>> 
>> That's the only place where we set OPERATOR_NEW flag and not 
>> OPERATOR_DELETE.
>
> Yes, I think that's the place.
>
> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
> seems misleading, but setting it would let us optimize in cases where we
> are not really allowed to. Maybe just rename your macro to
> DECL_IS_GLOBAL_OPERATOR_DELETE?

Hmm, I replied too fast.

Global operator delete does not seem like a good terminology, the ones 
marked in the patch would be the usual (=non-placement) replaceable 
deallocation functions.

I cannot find a requirement that operator new and operator delete should 
match. The rules to omit allocation are stated in terms of which operator 
new is called, but do not seem to care which operator delete is used. So 
allocating with the global operator new and deallocating with a class 
overload of operator delete can be removed, but not the reverse (not sure 
how they came up with such a rule...). Which means we would need:

keep DECL_IS_OPERATOR_NEW for the current uses

DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && 
DECL_IS_MALLOC? not exactly but close I think) for DCE

DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE

Maybe we can ignore the class-specific operator delete if it simplifies 
things.

Sorry for the messy comments, the messy rules don't help...

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-09  7:52                               ` Marc Glisse
@ 2019-07-09  8:49                                 ` Martin Liška
  2019-07-09 10:22                                   ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-09  8:49 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Jason Merrill, Nathan Sidwell

On 7/9/19 9:49 AM, Marc Glisse wrote:
> On Tue, 9 Jul 2019, Marc Glisse wrote:
> 
>> On Mon, 8 Jul 2019, Martin Liška wrote:
>>
>>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global deallocation functions, not all delete operators, contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem to be the ones for which the optimization is legal (well, not quite, the rules are in terms of operator new, and I am not sure how well operator delete has to match, but close enough).
>>>
>>> Are you talking about this location where we set OPERATOR_NEW:
>>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>>> ?
>>>
>>> That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.
>>
>> Yes, I think that's the place.
>>
>> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
>> seems misleading, but setting it would let us optimize in cases where we
>> are not really allowed to. Maybe just rename your macro to
>> DECL_IS_GLOBAL_OPERATOR_DELETE?
> 
> Hmm, I replied too fast.
> 
> Global operator delete does not seem like a good terminology, the ones marked in the patch would be the usual (=non-placement) replaceable deallocation functions.
> 
> I cannot find a requirement that operator new and operator delete should match. The rules to omit allocation are stated in terms of which operator new is called, but do not seem to care which operator delete is used. So allocating with the global operator new and deallocating with a class overload of operator delete can be removed, but not the reverse (not sure how they came up with such a rule...). Which means we would need:

Thank you Mark for digging deep in that.

> 
> keep DECL_IS_OPERATOR_NEW for the current uses
> 
> DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC? not exactly but close I think) for DCE
> 
> DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE

Note that with the current version of the patch we are out of free bits in struct GTY(()) tree_function_decl.
Would it be possible to tweak the current patch to cover what you described?

> 
> Maybe we can ignore the class-specific operator delete if it simplifies things.

I would like to make it as simple as possible, yes :P

Martin

> 
> Sorry for the messy comments, the messy rules don't help...
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-09  8:49                                 ` Martin Liška
@ 2019-07-09 10:22                                   ` Marc Glisse
  2019-07-09 21:02                                     ` Jason Merrill
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-09 10:22 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Jason Merrill, Nathan Sidwell

On Tue, 9 Jul 2019, Martin Liška wrote:

> On 7/9/19 9:49 AM, Marc Glisse wrote:
>> On Tue, 9 Jul 2019, Marc Glisse wrote:
>>
>>> On Mon, 8 Jul 2019, Martin Liška wrote:
>>>
>>>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global deallocation functions, not all delete operators, contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem to be the ones for which the optimization is legal (well, not quite, the rules are in terms of operator new, and I am not sure how well operator delete has to match, but close enough).
>>>>
>>>> Are you talking about this location where we set OPERATOR_NEW:
>>>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>>>> ?
>>>>
>>>> That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.
>>>
>>> Yes, I think that's the place.
>>>
>>> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
>>> seems misleading, but setting it would let us optimize in cases where we
>>> are not really allowed to. Maybe just rename your macro to
>>> DECL_IS_GLOBAL_OPERATOR_DELETE?
>>
>> Hmm, I replied too fast.
>>
>> Global operator delete does not seem like a good terminology, the ones marked in the patch would be the usual (=non-placement) replaceable deallocation functions.
>>
>> I cannot find a requirement that operator new and operator delete should match. The rules to omit allocation are stated in terms of which operator new is called, but do not seem to care which operator delete is used. So allocating with the global operator new and deallocating with a class overload of operator delete can be removed, but not the reverse (not sure how they came up with such a rule...). Which means we would need:
>
> Thank you Mark for digging deep in that.
>
>>
>> keep DECL_IS_OPERATOR_NEW for the current uses
>>
>> DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC? not exactly but close I think) for DCE
>>
>> DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE
>
> Note that with the current version of the patch we are out of free bits in struct GTY(()) tree_function_decl.
> Would it be possible to tweak the current patch to cover what you described?

If you approximate DECL_IS_REPLACEABLE_OPERATOR_NEW with 
DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC, it shouldn't need more bits than 
the current patch. I think the main difference is if a user adds attribute 
malloc to his class-specific operator new, where it will enable DCE, but 
since the attribute is non-standard, we can just document that behavior, 
it might even be desirable.

I am not very confident about anything I said in this thread, for all I 
know I may be misguiding you, please make sure someone else who 
understands the C++ standard approves your final patch.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-09 10:22                                   ` Marc Glisse
@ 2019-07-09 21:02                                     ` Jason Merrill
  2019-07-11  6:48                                       ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Jason Merrill @ 2019-07-09 21:02 UTC (permalink / raw)
  To: Marc Glisse, Martin Liška
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Nathan Sidwell

On 7/9/19 6:17 AM, Marc Glisse wrote:
> On Tue, 9 Jul 2019, Martin Liška wrote:
> 
>> On 7/9/19 9:49 AM, Marc Glisse wrote:
>>> On Tue, 9 Jul 2019, Marc Glisse wrote:
>>>
>>>> On Mon, 8 Jul 2019, Martin Liška wrote:
>>>>
>>>>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the 
>>>>>> replaceable global deallocation functions, not all delete 
>>>>>> operators, contrary to DECL_IS_OPERATOR_NEW, so the name is 
>>>>>> misleading. On the other hand, those seem to be the ones for which 
>>>>>> the optimization is legal (well, not quite, the rules are in terms 
>>>>>> of operator new, and I am not sure how well operator delete has to 
>>>>>> match, but close enough).
>>>>>
>>>>> Are you talking about this location where we set OPERATOR_NEW:
>>>>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>>>>> ?
>>>>>
>>>>> That's the only place where we set OPERATOR_NEW flag and not 
>>>>> OPERATOR_DELETE.
>>>>
>>>> Yes, I think that's the place.
>>>>
>>>> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
>>>> seems misleading, but setting it would let us optimize in cases 
>>>> where we
>>>> are not really allowed to. Maybe just rename your macro to
>>>> DECL_IS_GLOBAL_OPERATOR_DELETE?
>>>
>>> Hmm, I replied too fast.
>>>
>>> Global operator delete does not seem like a good terminology, the 
>>> ones marked in the patch would be the usual (=non-placement) 
>>> replaceable deallocation functions.
>>>
>>> I cannot find a requirement that operator new and operator delete 
>>> should match. The rules to omit allocation are stated in terms of 
>>> which operator new is called, but do not seem to care which operator 
>>> delete is used. So allocating with the global operator new and 
>>> deallocating with a class overload of operator delete can be removed, 
>>> but not the reverse (not sure how they came up with such a rule...). 

Correct.  The standard just says that an implementation is allowed to 
omit a call to the replaceable ::operator new; it does not place any 
constraints on that, the conditions for such omission are left up to the 
implementation.

If the user's code uses global new and class delete for the same 
pointer, that would suggest that they're doing something odd, and we 
might as well leave it alone.  I would expect this to be very rare.

>>> Which means we would need:
>>
>> Thank you Mark for digging deep in that.
>>
>>>
>>> keep DECL_IS_OPERATOR_NEW for the current uses
>>>
>>> DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW 
>>> && DECL_IS_MALLOC? not exactly but close I think) for DCE
>>>
>>> DECL_IS_OPERATOR_DELETE (which also includes some class overloads) 
>>> for DCE
>>
>> Note that with the current version of the patch we are out of free 
>> bits in struct GTY(()) tree_function_decl.
>> Would it be possible to tweak the current patch to cover what you 
>> described?
> 
> If you approximate DECL_IS_REPLACEABLE_OPERATOR_NEW with 
> DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC, it shouldn't need more bits than 
> the current patch. I think the main difference is if a user adds 
> attribute malloc to his class-specific operator new, where it will 
> enable DCE, but since the attribute is non-standard, we can just 
> document that behavior, it might even be desirable.

Sure, it seems desirable to me.

Jason

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-09 21:02                                     ` Jason Merrill
@ 2019-07-11  6:48                                       ` Martin Liška
  2019-07-22 14:00                                         ` Martin Liška
                                                           ` (2 more replies)
  0 siblings, 3 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-11  6:48 UTC (permalink / raw)
  To: Jason Merrill, Marc Glisse
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 3485 bytes --]

On 7/9/19 11:00 PM, Jason Merrill wrote:
> On 7/9/19 6:17 AM, Marc Glisse wrote:
>> On Tue, 9 Jul 2019, Martin Liška wrote:
>>
>>> On 7/9/19 9:49 AM, Marc Glisse wrote:
>>>> On Tue, 9 Jul 2019, Marc Glisse wrote:
>>>>
>>>>> On Mon, 8 Jul 2019, Martin Liška wrote:
>>>>>
>>>>>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global deallocation functions, not all delete operators, contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem to be the ones for which the optimization is legal (well, not quite, the rules are in terms of operator new, and I am not sure how well operator delete has to match, but close enough).
>>>>>>
>>>>>> Are you talking about this location where we set OPERATOR_NEW:
>>>>>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>>>>>> ?
>>>>>>
>>>>>> That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.
>>>>>
>>>>> Yes, I think that's the place.
>>>>>
>>>>> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
>>>>> seems misleading, but setting it would let us optimize in cases where we
>>>>> are not really allowed to. Maybe just rename your macro to
>>>>> DECL_IS_GLOBAL_OPERATOR_DELETE?
>>>>
>>>> Hmm, I replied too fast.
>>>>
>>>> Global operator delete does not seem like a good terminology, the ones marked in the patch would be the usual (=non-placement) replaceable deallocation functions.
>>>>
>>>> I cannot find a requirement that operator new and operator delete should match. The rules to omit allocation are stated in terms of which operator new is called, but do not seem to care which operator delete is used. So allocating with the global operator new and deallocating with a class overload of operator delete can be removed, but not the reverse (not sure how they came up with such a rule...). 
> 
> Correct.  The standard just says that an implementation is allowed to omit a call to the replaceable ::operator new; it does not place any constraints on that, the conditions for such omission are left up to the implementation.
> 
> If the user's code uses global new and class delete for the same pointer, that would suggest that they're doing something odd, and we might as well leave it alone.  I would expect this to be very rare.
> 
>>>> Which means we would need:
>>>
>>> Thank you Mark for digging deep in that.
>>>
>>>>
>>>> keep DECL_IS_OPERATOR_NEW for the current uses
>>>>
>>>> DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC? not exactly but close I think) for DCE
>>>>
>>>> DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE
>>>
>>> Note that with the current version of the patch we are out of free bits in struct GTY(()) tree_function_decl.
>>> Would it be possible to tweak the current patch to cover what you described?
>>
>> If you approximate DECL_IS_REPLACEABLE_OPERATOR_NEW with DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC, it shouldn't need more bits than the current patch. I think the main difference is if a user adds attribute malloc to his class-specific operator new, where it will enable DCE, but since the attribute is non-standard, we can just document that behavior, it might even be desirable.
> 
> Sure, it seems desirable to me.
> 
> Jason

Ok, I hopefully addressed the suggested improvements to the patch.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Extend-DCE-to-remove-unnecessary-new-delete-pairs-PR.patch --]
[-- Type: text/x-patch, Size: 17118 bytes --]

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

gcc/ChangeLog:

2019-07-02  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.

gcc/c/ChangeLog:

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

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

gcc/cp/ChangeLog:

2019-07-02  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.

gcc/testsuite/ChangeLog:

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

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

libstdc++-v3/ChangeLog:

2019-07-02  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.
---
 gcc/c/c-decl.c                                |  2 +
 gcc/common.opt                                |  4 ++
 gcc/cp/decl.c                                 | 24 ++++---
 gcc/gimple.c                                  | 12 ++++
 gcc/gimple.h                                  |  1 +
 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                                    | 11 ++++
 .../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, 150 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 b1392213fe3..42f7baf06e2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2641,6 +2641,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 b998b25522b..11637c8cab0 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2211,6 +2211,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 28adb205078..9cafec84c6e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4363,8 +4363,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:
@@ -4376,8 +4378,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)
@@ -4405,8 +4409,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)
 	  {
@@ -4416,8 +4422,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..a0eac8703bd 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2695,6 +2695,18 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   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
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 47070e7f409..f5872178109 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1549,6 +1549,7 @@ 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_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 1b1a50df52a..e22e1c67699 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,6 +1813,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 6398c1e4457..90b3f4d7c45 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_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.  */
@@ -588,6 +594,11 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
 	  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))
@@ -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_REPLACEABLE_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_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);
@@ -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 f2880f1021f..7ab72a7e0d7 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 308836fba73..95cd583f4ae 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3017,9 +3017,20 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
 #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) \
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


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-11  6:48                                       ` Martin Liška
@ 2019-07-22 14:00                                         ` Martin Liška
  2019-07-24 19:05                                         ` Jeff Law
  2019-07-25  2:17                                         ` Marc Glisse
  2 siblings, 0 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-22 14:00 UTC (permalink / raw)
  To: Jason Merrill, Marc Glisse
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Nathan Sidwell

PING^1

On 7/11/19 8:45 AM, Martin Liška wrote:
> On 7/9/19 11:00 PM, Jason Merrill wrote:
>> On 7/9/19 6:17 AM, Marc Glisse wrote:
>>> On Tue, 9 Jul 2019, Martin Liška wrote:
>>>
>>>> On 7/9/19 9:49 AM, Marc Glisse wrote:
>>>>> On Tue, 9 Jul 2019, Marc Glisse wrote:
>>>>>
>>>>>> On Mon, 8 Jul 2019, Martin Liška wrote:
>>>>>>
>>>>>>>> The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global deallocation functions, not all delete operators, contrary to DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem to be the ones for which the optimization is legal (well, not quite, the rules are in terms of operator new, and I am not sure how well operator delete has to match, but close enough).
>>>>>>>
>>>>>>> Are you talking about this location where we set OPERATOR_NEW:
>>>>>>> https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
>>>>>>> ?
>>>>>>>
>>>>>>> That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.
>>>>>>
>>>>>> Yes, I think that's the place.
>>>>>>
>>>>>> Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
>>>>>> seems misleading, but setting it would let us optimize in cases where we
>>>>>> are not really allowed to. Maybe just rename your macro to
>>>>>> DECL_IS_GLOBAL_OPERATOR_DELETE?
>>>>>
>>>>> Hmm, I replied too fast.
>>>>>
>>>>> Global operator delete does not seem like a good terminology, the ones marked in the patch would be the usual (=non-placement) replaceable deallocation functions.
>>>>>
>>>>> I cannot find a requirement that operator new and operator delete should match. The rules to omit allocation are stated in terms of which operator new is called, but do not seem to care which operator delete is used. So allocating with the global operator new and deallocating with a class overload of operator delete can be removed, but not the reverse (not sure how they came up with such a rule...). 
>>
>> Correct.  The standard just says that an implementation is allowed to omit a call to the replaceable ::operator new; it does not place any constraints on that, the conditions for such omission are left up to the implementation.
>>
>> If the user's code uses global new and class delete for the same pointer, that would suggest that they're doing something odd, and we might as well leave it alone.  I would expect this to be very rare.
>>
>>>>> Which means we would need:
>>>>
>>>> Thank you Mark for digging deep in that.
>>>>
>>>>>
>>>>> keep DECL_IS_OPERATOR_NEW for the current uses
>>>>>
>>>>> DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC? not exactly but close I think) for DCE
>>>>>
>>>>> DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE
>>>>
>>>> Note that with the current version of the patch we are out of free bits in struct GTY(()) tree_function_decl.
>>>> Would it be possible to tweak the current patch to cover what you described?
>>>
>>> If you approximate DECL_IS_REPLACEABLE_OPERATOR_NEW with DECL_IS_OPERATOR_NEW && DECL_IS_MALLOC, it shouldn't need more bits than the current patch. I think the main difference is if a user adds attribute malloc to his class-specific operator new, where it will enable DCE, but since the attribute is non-standard, we can just document that behavior, it might even be desirable.
>>
>> Sure, it seems desirable to me.
>>
>> Jason
> 
> Ok, I hopefully addressed the suggested improvements to the patch.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-11  6:48                                       ` Martin Liška
  2019-07-22 14:00                                         ` Martin Liška
@ 2019-07-24 19:05                                         ` Jeff Law
  2019-07-25 10:24                                           ` Richard Biener
  2019-07-25  2:17                                         ` Marc Glisse
  2 siblings, 1 reply; 91+ messages in thread
From: Jeff Law @ 2019-07-24 19:05 UTC (permalink / raw)
  To: Martin Liška, Jason Merrill, Marc Glisse
  Cc: Richard Biener, gcc-patches, David Malcolm, dominik.infuehr,
	Nathan Sidwell

On 7/11/19 12:45 AM, Martin Liška wrote:
> On 7/9/19 11:00 PM, Jason Merrill wrote:

> Ok, I hopefully addressed the suggested improvements to the patch.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Thanks,
> Martin
> 
> 0001-Extend-DCE-to-remove-unnecessary-new-delete-pairs-PR.patch
> 
> From 771d9128144745fe530577912521fc8228ca7424 Mon Sep 17 00:00:00 2001
> From: Martin Liska <mliska@suse.cz>
> Date: Tue, 2 Jul 2019 09:08:27 +0200
> Subject: [PATCH] Extend DCE to remove unnecessary new/delete-pairs (PR
>  c++/23383).
> 
> gcc/ChangeLog:
> 
> 2019-07-02  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.
> 
> gcc/c/ChangeLog:
> 
> 2019-07-02  Martin Liska  <mliska@suse.cz>
> 	    Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>
> 
> 	PR c++/23383
> 	* c-decl.c (merge_decls): Merge OPERATOR_DELETE flag.
> 
> gcc/cp/ChangeLog:
> 
> 2019-07-02  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.
> 
> gcc/testsuite/ChangeLog:
> 
> 2019-07-02  Martin Liska  <mliska@suse.cz
> 	    Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>
> 
> 	PR c++/23383
> 	* g++.dg/cpp1y/new1.C: New test.
> 
> libstdc++-v3/ChangeLog:
> 
> 2019-07-02  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.
OK.

I don't see the 2/2 from this series in my queue.  Has it already been
dealt with?

jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-11  6:48                                       ` Martin Liška
  2019-07-22 14:00                                         ` Martin Liška
  2019-07-24 19:05                                         ` Jeff Law
@ 2019-07-25  2:17                                         ` Marc Glisse
  2019-07-25  8:34                                           ` Martin Liška
  2 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-25  2:17 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

I would also mark DECL_IS_OPERATOR_DELETE_P the other operators delete, 
because of the name of the macro, but it is not important for this patch.

DCE has special code to avoid removing the LHS of malloc when it is 
unused. Is there something different about operator new that makes it not 
need the same handling?

The patch is happy to simplify malloc+delete or new+free. That makes sense 
to me, if someone wants to diagnose weird mixes, that's a separate work 
they can do later.

(Not this patch: I wonder how much speed we would lose by making 
gimple_call_operator_delete_p take a gimple* and check if the thing is a 
call, so we don't have to repeat is_gimple_call and as_a<gcall*> in half 
of the callers. An overload (overkill) would of course lose nothing. But, 
with just the gimple* version, especially if it was in a .h, I wonder if 
we would manage to eliminate the overhead of checking is_gimple_call when 
we already know it is a call)

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-25  2:17                                         ` Marc Glisse
@ 2019-07-25  8:34                                           ` Martin Liška
  2019-07-25 12:21                                             ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-25  8:34 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/25/19 2:53 AM, Marc Glisse wrote:
> I would also mark DECL_IS_OPERATOR_DELETE_P the other operators delete, because of the name of the macro, but it is not important for this patch.

I'm planning to install the patch as is right after I'll get an approval of the 1/2 part.

Feel free to prepare a patch that will put the DECL_IS_OPERATOR_DELETE_P to other delete operators.

Thanks,
Martin

> 
> DCE has special code to avoid removing the LHS of malloc when it is unused. Is there something different about operator new that makes it not need the same handling?
> 
> The patch is happy to simplify malloc+delete or new+free. That makes sense to me, if someone wants to diagnose weird mixes, that's a separate work they can do later.
> 
> (Not this patch: I wonder how much speed we would lose by making gimple_call_operator_delete_p take a gimple* and check if the thing is a call, so we don't have to repeat is_gimple_call and as_a<gcall*> in half of the callers. An overload (overkill) would of course lose nothing. But, with just the gimple* version, especially if it was in a .h, I wonder if we would manage to eliminate the overhead of checking is_gimple_call when we already know it is a call)
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-24 19:05                                         ` Jeff Law
@ 2019-07-25 10:24                                           ` Richard Biener
  0 siblings, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-07-25 10:24 UTC (permalink / raw)
  To: Jeff Law
  Cc: Martin Liška, Jason Merrill, Marc Glisse, GCC Patches,
	David Malcolm, dominik.infuehr, Nathan Sidwell

On Wed, Jul 24, 2019 at 9:02 PM Jeff Law <law@redhat.com> wrote:
>
> On 7/11/19 12:45 AM, Martin Liška wrote:
> > On 7/9/19 11:00 PM, Jason Merrill wrote:
>
> > Ok, I hopefully addressed the suggested improvements to the patch.
> >
> > Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >
> > Ready to be installed?
> > Thanks,
> > Martin
> >
> > 0001-Extend-DCE-to-remove-unnecessary-new-delete-pairs-PR.patch
> >
> > From 771d9128144745fe530577912521fc8228ca7424 Mon Sep 17 00:00:00 2001
> > From: Martin Liska <mliska@suse.cz>
> > Date: Tue, 2 Jul 2019 09:08:27 +0200
> > Subject: [PATCH] Extend DCE to remove unnecessary new/delete-pairs (PR
> >  c++/23383).
> >
> > gcc/ChangeLog:
> >
> > 2019-07-02  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.
> >
> > gcc/c/ChangeLog:
> >
> > 2019-07-02  Martin Liska  <mliska@suse.cz>
> >           Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>
> >
> >       PR c++/23383
> >       * c-decl.c (merge_decls): Merge OPERATOR_DELETE flag.
> >
> > gcc/cp/ChangeLog:
> >
> > 2019-07-02  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.
> >
> > gcc/testsuite/ChangeLog:
> >
> > 2019-07-02  Martin Liska  <mliska@suse.cz
> >           Dominik Infuhr  <dominik.infuehr@theobroma-systems.com>
> >
> >       PR c++/23383
> >       * g++.dg/cpp1y/new1.C: New test.
> >
> > libstdc++-v3/ChangeLog:
> >
> > 2019-07-02  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.
> OK.
>
> I don't see the 2/2 from this series in my queue.  Has it already been
> dealt with?

You approved 2/2.

1/2 is OK as well.

Thanks,
Richard.

>
> jeff

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-25  8:34                                           ` Martin Liška
@ 2019-07-25 12:21                                             ` Marc Glisse
  2019-07-25 13:50                                               ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-25 12:21 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Thu, 25 Jul 2019, Martin Liška wrote:

>> DCE has special code to avoid removing the LHS of malloc when it is unused. Is there something different about operator new that makes it not need the same handling?

If you take gcc.dg/torture/pr51692.c and replace __builtin_calloc (1, 
sizeof (double)) with new double(), we get an ICE with -O or higher...

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-25 12:21                                             ` Marc Glisse
@ 2019-07-25 13:50                                               ` Martin Liška
  2019-07-25 15:41                                                 ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-25 13:50 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/25/19 2:18 PM, Marc Glisse wrote:
> On Thu, 25 Jul 2019, Martin Liška wrote:
> 
>>> DCE has special code to avoid removing the LHS of malloc when it is unused. Is there something different about operator new that makes it not need the same handling?
> 
> If you take gcc.dg/torture/pr51692.c and replace __builtin_calloc (1, sizeof (double)) with new double(), we get an ICE with -O or higher...
> 

I can see, I'm working on that.

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-25 13:50                                               ` Martin Liška
@ 2019-07-25 15:41                                                 ` Martin Liška
  2019-07-28 21:50                                                   ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Martin Liška
  2019-07-29  9:59                                                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Richard Biener
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-25 15:41 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 614 bytes --]

On 7/25/19 3:30 PM, Martin Liška wrote:
> On 7/25/19 2:18 PM, Marc Glisse wrote:
>> On Thu, 25 Jul 2019, Martin Liška wrote:
>>
>>>> DCE has special code to avoid removing the LHS of malloc when it is unused. Is there something different about operator new that makes it not need the same handling?
>>
>> If you take gcc.dg/torture/pr51692.c and replace __builtin_calloc (1, sizeof (double)) with new double(), we get an ICE with -O or higher...
>>
> 
> I can see, I'm working on that.
> 
> Martin
> 

There's a patch candidate I've been testing right now.

Ready to be installed after tests?
Thanks,
Martin

[-- Attachment #2: 0001-Fix-ICE-seen-in-tree-ssa-dce.c-for-new-delete-pair.patch --]
[-- Type: text/x-patch, Size: 2373 bytes --]

From 4a7d515eda8591277dad01e1cd43a33883f2dcef Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 25 Jul 2019 17:24:51 +0200
Subject: [PATCH] Fix ICE seen in tree-ssa-dce.c for new/delete pair.

gcc/ChangeLog:

2019-07-25  Martin Liska  <mliska@suse.cz>

	* tree-ssa-dce.c (eliminate_unnecessary_stmts): Do not
	remove LHS of operator new call.  It's handled latter.

gcc/testsuite/ChangeLog:

2019-07-25  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp1y/new1.C (test_unused): Add new case that causes
	ICE.
---
 gcc/testsuite/g++.dg/cpp1y/new1.C |  8 ++++++++
 gcc/tree-ssa-dce.c                | 13 +++++++------
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/gcc/testsuite/g++.dg/cpp1y/new1.C b/gcc/testsuite/g++.dg/cpp1y/new1.C
index a95dd4d1ee3..5e4f1bf6b0b 100644
--- a/gcc/testsuite/g++.dg/cpp1y/new1.C
+++ b/gcc/testsuite/g++.dg/cpp1y/new1.C
@@ -61,5 +61,13 @@ new_array_load() {
   delete [] x;
 }
 
+void
+test_unused() {
+  volatile double d = 0.0;
+  double *p = new double ();
+  d += 1.0;
+  delete p;
+}
+
 /* { 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-ssa-dce.c b/gcc/tree-ssa-dce.c
index 90b3f4d7c45..cf507fa0453 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1341,12 +1341,13 @@ eliminate_unnecessary_stmts (void)
 		     did not mark as necessary, it will confuse the
 		     special logic we apply to malloc/free pair removal.  */
 		  && (!(call = gimple_call_fndecl (stmt))
-		      || DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
-		      || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
-			  && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
-			  && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
-			  && !ALLOCA_FUNCTION_CODE_P
-			      (DECL_FUNCTION_CODE (call)))))
+		      || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
+			   || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
+			       && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+			       && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
+			       && !ALLOCA_FUNCTION_CODE_P
+			       (DECL_FUNCTION_CODE (call))))
+			  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
 		{
 		  something_changed = true;
 		  if (dump_file && (dump_flags & TDF_DETAILS))
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-25 15:41                                                 ` Martin Liška
@ 2019-07-28 21:50                                                   ` Martin Liška
  2019-07-29 10:03                                                     ` Richard Biener
  2019-07-29  9:59                                                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Richard Biener
  1 sibling, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-28 21:50 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Jason Merrill, Richard Biener, gcc-patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 286 bytes --]

Hi.

And there's one more patch that deals with delete operator
which has a second argument (size). That definition GIMPLE
statement of the size must be also properly marked.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Remove-also-2nd-argument-for-unused-delete-operator-.patch --]
[-- Type: text/x-patch, Size: 1972 bytes --]

From 3d69c779ad5de447cd5ddba2595d2b1586dc5d3c Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Sun, 28 Jul 2019 13:04:28 +0200
Subject: [PATCH] Remove also 2nd argument for unused delete operator (PR
 tree-optimization/91270).

gcc/ChangeLog:

2019-07-28  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* tree-ssa-dce.c (eliminate_unnecessary_stmts): Delete also 2nd
	argument of a delete operator.

gcc/testsuite/ChangeLog:

2019-07-28  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* g++.dg/torture/pr91270.C: New test.
---
 gcc/testsuite/g++.dg/torture/pr91270.C | 10 ++++++++++
 gcc/tree-ssa-dce.c                     | 14 ++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr91270.C

diff --git a/gcc/testsuite/g++.dg/torture/pr91270.C b/gcc/testsuite/g++.dg/torture/pr91270.C
new file mode 100644
index 00000000000..60d766e9e9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr91270.C
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+struct S {
+  ~S();
+};
+int a = 123;
+void fn1() {
+  S *s = new S[a];
+  delete[] s;
+}
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index cf507fa0453..e5a1a9b7aa3 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -1294,6 +1294,20 @@ eliminate_unnecessary_stmts (void)
 		      && !gimple_plf (def_stmt, STMT_NECESSARY))
 		    gimple_set_plf (stmt, STMT_NECESSARY, false);
 		}
+
+	      /* Some delete operators have 2 arguments, where
+		 the second argument is size of the deallocated memory.  */
+	      if (gimple_call_num_args (stmt) == 2)
+		{
+		  tree ptr = gimple_call_arg (stmt, 1);
+		  if (TREE_CODE (ptr) == SSA_NAME)
+		    {
+		      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+		      if (!gimple_nop_p (def_stmt)
+			  && !gimple_plf (def_stmt, STMT_NECESSARY))
+			gimple_set_plf (stmt, STMT_NECESSARY, false);
+		    }
+		}
 	    }
 
 	  /* If GSI is not necessary then remove it.  */
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl.
  2019-07-25 15:41                                                 ` Martin Liška
  2019-07-28 21:50                                                   ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Martin Liška
@ 2019-07-29  9:59                                                   ` Richard Biener
  1 sibling, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-07-29  9:59 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Thu, Jul 25, 2019 at 5:27 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/25/19 3:30 PM, Martin Liška wrote:
> > On 7/25/19 2:18 PM, Marc Glisse wrote:
> >> On Thu, 25 Jul 2019, Martin Liška wrote:
> >>
> >>>> DCE has special code to avoid removing the LHS of malloc when it is unused. Is there something different about operator new that makes it not need the same handling?
> >>
> >> If you take gcc.dg/torture/pr51692.c and replace __builtin_calloc (1, sizeof (double)) with new double(), we get an ICE with -O or higher...
> >>
> >
> > I can see, I'm working on that.
> >
> > Martin
> >
>
> There's a patch candidate I've been testing right now.
>
> Ready to be installed after tests?

OK.

Richard.

> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-28 21:50                                                   ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Martin Liška
@ 2019-07-29 10:03                                                     ` Richard Biener
  2019-07-29 10:54                                                       ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-07-29 10:03 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Sun, Jul 28, 2019 at 4:57 PM Martin Liška <mliska@suse.cz> wrote:
>
> Hi.
>
> And there's one more patch that deals with delete operator
> which has a second argument (size). That definition GIMPLE
> statement of the size must be also properly marked.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> Ready to be installed?

This isn't a proper fix.  You can't mark a random operand as necessary
during elimination - this only works in very constraint cases.  Here
it will break down if the stmt you just marked depends on another stmt
only used by the stmt you just marked (and thus also not necessary).

The fix is to propagate_necessity where you either have to excempt
the two-operator delete from handling or to mark its second operand
as necessary despite eventually deleting the call.  You can avoid
this in case the allocation function used the exact same size argument.

Richard.

> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-29 10:03                                                     ` Richard Biener
@ 2019-07-29 10:54                                                       ` Martin Liška
  2019-07-29 14:40                                                         ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-29 10:54 UTC (permalink / raw)
  To: Richard Biener
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/29/19 11:59 AM, Richard Biener wrote:
> On Sun, Jul 28, 2019 at 4:57 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> Hi.
>>
>> And there's one more patch that deals with delete operator
>> which has a second argument (size). That definition GIMPLE
>> statement of the size must be also properly marked.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
> 
> This isn't a proper fix.  You can't mark a random operand as necessary
> during elimination - this only works in very constraint cases.  Here
> it will break down if the stmt you just marked depends on another stmt
> only used by the stmt you just marked (and thus also not necessary).

Ah, I see.

> 
> The fix is to propagate_necessity where you either have to excempt
> the two-operator delete from handling

We want to process also these delete operators.

> or to mark its second operand
> as necessary despite eventually deleting the call.

Really marking that as necessary? Why?

> You can avoid
> this in case the allocation function used the exact same size argument.

That's not the case as the operator new happens in a loop:

  <bb 5> :
  # iftmp.0_15 = PHI <iftmp.0_21(3), iftmp.0_20(4)>
  _23 = operator new [] (iftmp.0_15);
  _24 = _23;
  MEM[(sizetype *)_24] = _19;
  _26 = _24 + 8;
  _27 = _26;
  _2 = _19 + 18446744073709551615;
  _28 = (long int) _2;

  <bb 6> :
  # _12 = PHI <_27(5), _29(7)>
  # _13 = PHI <_28(5), _30(7)>
  if (_13 < 0)
    goto <bb 8>; [INV]
  else
    goto <bb 7>; [INV]

Btw. is the hunk moved to propagate_necessity still wrong:

diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index cf507fa0453..1c890889932 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -803,7 +803,23 @@ propagate_necessity (bool aggressive)
 			   || 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;
+		{
+		  /* Some delete operators have 2 arguments, where
+		     the second argument is size of the deallocated memory.  */
+		  if (gimple_call_num_args (stmt) == 2)
+		    {
+		      tree ptr = gimple_call_arg (stmt, 1);
+		      if (TREE_CODE (ptr) == SSA_NAME)
+			{
+			  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+			  if (!gimple_nop_p (def_stmt)
+			      && !gimple_plf (def_stmt, STMT_NECESSARY))
+			    gimple_set_plf (stmt, STMT_NECESSARY, false);
+			}
+		    }
+
+		  continue;
+		}
 	    }
 
 	  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)

Thanks,
Martin

> 
> Richard.
> 
>> Thanks,
>> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-29 10:54                                                       ` Martin Liška
@ 2019-07-29 14:40                                                         ` Richard Biener
  2019-07-30  7:48                                                           ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-07-29 14:40 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Mon, Jul 29, 2019 at 12:37 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/29/19 11:59 AM, Richard Biener wrote:
> > On Sun, Jul 28, 2019 at 4:57 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> Hi.
> >>
> >> And there's one more patch that deals with delete operator
> >> which has a second argument (size). That definition GIMPLE
> >> statement of the size must be also properly marked.
> >>
> >> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >>
> >> Ready to be installed?
> >
> > This isn't a proper fix.  You can't mark a random operand as necessary
> > during elimination - this only works in very constraint cases.  Here
> > it will break down if the stmt you just marked depends on another stmt
> > only used by the stmt you just marked (and thus also not necessary).
>
> Ah, I see.
>
> >
> > The fix is to propagate_necessity where you either have to excempt
> > the two-operator delete from handling
>
> We want to process also these delete operators.
>
> > or to mark its second operand
> > as necessary despite eventually deleting the call.
>
> Really marking that as necessary? Why?
>
> > You can avoid
> > this in case the allocation function used the exact same size argument.
>
> That's not the case as the operator new happens in a loop:
>
>   <bb 5> :
>   # iftmp.0_15 = PHI <iftmp.0_21(3), iftmp.0_20(4)>
>   _23 = operator new [] (iftmp.0_15);
>   _24 = _23;
>   MEM[(sizetype *)_24] = _19;
>   _26 = _24 + 8;
>   _27 = _26;
>   _2 = _19 + 18446744073709551615;
>   _28 = (long int) _2;
>
>   <bb 6> :
>   # _12 = PHI <_27(5), _29(7)>
>   # _13 = PHI <_28(5), _30(7)>
>   if (_13 < 0)
>     goto <bb 8>; [INV]
>   else
>     goto <bb 7>; [INV]
>
> Btw. is the hunk moved to propagate_necessity still wrong:
>
> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> index cf507fa0453..1c890889932 100644
> --- a/gcc/tree-ssa-dce.c
> +++ b/gcc/tree-ssa-dce.c
> @@ -803,7 +803,23 @@ propagate_necessity (bool aggressive)
>                            || 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;
> +               {
> +                 /* Some delete operators have 2 arguments, where
> +                    the second argument is size of the deallocated memory.  */
> +                 if (gimple_call_num_args (stmt) == 2)

Please make sure this only matches operator delete (just make the check
we already do above also set a bool flag).

> +                   {
> +                     tree ptr = gimple_call_arg (stmt, 1);
> +                     if (TREE_CODE (ptr) == SSA_NAME)

you can use mark_operand_necessary (ptr) here (but please name 'ptr'
differently ;))

And note you can elide this in case the size arguments to new and delete
match.  I notice the above also matches

   ptr = malloc (4);
   delete ptr;

not sure if intended (or harmful).

Richard.

> +                       {
> +                         gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
> +                         if (!gimple_nop_p (def_stmt)
> +                             && !gimple_plf (def_stmt, STMT_NECESSARY))
> +                           gimple_set_plf (stmt, STMT_NECESSARY, false);
> +                       }
> +                   }
> +
> +                 continue;
> +               }
>             }
>
>           FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
>
> Thanks,
> Martin
>
> >
> > Richard.
> >
> >> Thanks,
> >> Martin
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-29 14:40                                                         ` Richard Biener
@ 2019-07-30  7:48                                                           ` Martin Liška
  2019-07-30  8:09                                                             ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-30  7:48 UTC (permalink / raw)
  To: Richard Biener
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 3034 bytes --]

Hi.

After playing with the test-case, I noticed that we don't want
to handle new/delete operators with a varying (SSA_NAME) as a second argument.

Considering following test-case:

$ cat /tmp/new.C
struct S {
  S ();
  ~S();
};
int a = 123;
void fn1() {
  S *s = new S[a];
  delete[] s;
}

$ ./xg++ -B. /tmp/new.C -O2 -fdump-tree-gimple=/dev/stdout:


  a.1_1 = a;
  D.2341 = (sizetype) a.1_1;
  if (D.2341 <= 9223372036854775800) goto <D.2342>; else goto <D.2343>;
  <D.2342>:
  iftmp.0 = D.2341 + 8;
  goto <D.2344>;
  <D.2343>:
  iftmp.0 = 18446744073709551615;
  <D.2344>:
  D.2323 = operator new [] (iftmp.0);
  MEM[(sizetype *)D.2323] = D.2341;
  try
    {
      D.2324 = D.2323 + 8;
      D.2325 = D.2324;
      _2 = D.2341 + 18446744073709551615;
      D.2326 = (long int) _2;
      try
        {
          <D.2346>:
          if (D.2326 < 0) goto <D.2338>; else goto <D.2347>;
          <D.2347>:
          S::S (D.2325);
          D.2325 = D.2325 + 1;
          D.2326 = D.2326 + -1;
          goto <D.2346>;
          <D.2338>:
        }
      catch
        {
          {
            struct S * D.2336;

            if (D.2324 != 0B) goto <D.2348>; else goto <D.2349>;
            <D.2348>:
            _3 = (sizetype) D.2326;
            _4 = D.2341 - _3;
            _5 = _4 + 18446744073709551615;
            D.2336 = D.2324 + _5;
            <D.2350>:
            if (D.2336 == D.2324) goto <D.2351>; else goto <D.2352>;
            <D.2352>:
            D.2336 = D.2336 + 18446744073709551615;
            S::~S (D.2336);
            goto <D.2350>;
            <D.2351>:
            goto <D.2353>;
            <D.2349>:
            <D.2353>:
          }
        }
      retval.2 = D.2324;
    }
  catch
    {
      if (D.2341 <= 9223372036854775800) goto <D.2355>; else goto <D.2356>;
      <D.2355>:
      iftmp.3 = D.2341 + 8;
      goto <D.2357>;
      <D.2356>:
      iftmp.3 = 18446744073709551615;
      <D.2357>:
      operator delete [] (D.2323, iftmp.3);
    }
  s = D.2323 + 8;
  {
    struct S * D.2337;

    if (s != 0B) goto <D.2358>; else goto <D.2359>;
    <D.2358>:
    try
      {
        _6 = s + 18446744073709551608;
        _7 = *_6;
        D.2337 = s + _7;
        <D.2360>:
        if (D.2337 == s) goto <D.2361>; else goto <D.2362>;
        <D.2362>:
        D.2337 = D.2337 + 18446744073709551615;
        S::~S (D.2337);
        goto <D.2360>;
        <D.2361>:
      }
    finally
      {
        _8 = s + 18446744073709551608;
        _9 = *_8;
        _10 = _9 + 8;
        _11 = s + 18446744073709551608;
        operator delete [] (_11, _10);
      }
    goto <D.2363>;
    <D.2359>:
    <D.2363>:
  }
}


as seen from the dump, we first make a operator new[] for a capped value
based on variable 'a'. Latter we have a loop that calls S:S and catch block contains another
loop calling S::~S. Similarly last part contains delete[] which is based on number of really
allocated memory (that lives in *D.2323).

Anyway that's not a candidate for DCE. I'm testing following patch.

Martin

[-- Attachment #2: 0001-DCE-do-not-handle-delete-operators-with-a-SSA_NAME-a.patch --]
[-- Type: text/x-patch, Size: 2947 bytes --]

From 312626229bfd4162550891bd8947b0fe310da6f5 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 30 Jul 2019 09:24:56 +0200
Subject: [PATCH] DCE: do not handle delete operators with a SSA_NAME as a size
 argument (PR tree-optimization/91270).

gcc/ChangeLog:

2019-07-30  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* tree-ssa-dce.c (simple_delete_operator_p): New.
	(propagate_necessity): Use it to filter delete operators
	that we want to delete.
	(eliminate_unnecessary_stmts): Likewise.

gcc/testsuite/ChangeLog:

2019-07-30  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* g++.dg/torture/pr91270.C: New test.
---
 gcc/testsuite/g++.dg/torture/pr91270.C | 10 ++++++++++
 gcc/tree-ssa-dce.c                     | 19 ++++++++++++++-----
 2 files changed, 24 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr91270.C

diff --git a/gcc/testsuite/g++.dg/torture/pr91270.C b/gcc/testsuite/g++.dg/torture/pr91270.C
new file mode 100644
index 00000000000..60d766e9e9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr91270.C
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+struct S {
+  ~S();
+};
+int a = 123;
+void fn1() {
+  S *s = new S[a];
+  delete[] s;
+}
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 763b76f0e53..e844824dc12 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -646,6 +646,18 @@ degenerate_phi_p (gimple *phi)
   return true;
 }
 
+/* Return true when a GIMPLE STMT is a delete call operator that
+   has either one argument or second argument is an integer constant.  */
+
+static bool
+simple_delete_operator_p (gimple *stmt)
+{
+  return (is_gimple_call (stmt)
+	  && (gimple_call_operator_delete_p (as_a <gcall *> (stmt))
+	      && (gimple_call_num_args (stmt) == 1
+		  || TREE_CODE (gimple_call_arg (stmt, 1)) == INTEGER_CST)));
+}
+
 /* Propagate necessity using the operands of necessary statements.
    Process the uses on each statement in the worklist, and add all
    feeding statements which contribute to the calculation of this
@@ -805,9 +817,7 @@ propagate_necessity (bool aggressive)
 	     allocation function do not mark that necessary through
 	     processing the argument.  */
 	  if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
-	      || (is_gimple_call (stmt)
-		  && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))
-
+	      || simple_delete_operator_p (stmt))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
@@ -1306,8 +1316,7 @@ eliminate_unnecessary_stmts (void)
 	     (and thus is getting removed).  */
 	  if (gimple_plf (stmt, STMT_NECESSARY)
 	      && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
-		  || (is_gimple_call (stmt)
-		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
+		  || simple_delete_operator_p (stmt)))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      if (TREE_CODE (ptr) == SSA_NAME)
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30  7:48                                                           ` Martin Liška
@ 2019-07-30  8:09                                                             ` Martin Liška
  2019-07-30  8:42                                                               ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-30  8:09 UTC (permalink / raw)
  To: Richard Biener
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/30/19 9:46 AM, Martin Liška wrote:
> Anyway that's not a candidate for DCE. I'm testing following patch.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

One alternative approach can be to drop DECL_SET_IS_OPERATOR_DELETE in:
cat -n gcc/cp/decl.c | less
...
  4410          deltype = cp_build_type_attribute_variant (deltype, extvisattr);
  4411          deltype = build_exception_variant (deltype, empty_except_spec);
  4412          opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
  4413          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
  4414          opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
  4415          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
  4416  
  4417          if (flag_sized_deallocation)
  4418            {
  4419              /* operator delete (void *, size_t, align_val_t); */
  4420              deltype = build_function_type_list (void_type_node, ptr_type_node,
  4421                                                  size_type_node, align_type_node,
  4422                                                  NULL_TREE);
  4423              deltype = cp_build_type_attribute_variant (deltype, extvisattr);
  4424              deltype = build_exception_variant (deltype, empty_except_spec);
  4425              opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
  4426              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
  4427              opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
  4428              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
  4429            }
  4430        }

at lines 4426 and 4428.

Richi what do you prefer?
Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30  8:09                                                             ` Martin Liška
@ 2019-07-30  8:42                                                               ` Richard Biener
  2019-07-30 10:20                                                                 ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-07-30  8:42 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Tue, Jul 30, 2019 at 10:07 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/30/19 9:46 AM, Martin Liška wrote:
> > Anyway that's not a candidate for DCE. I'm testing following patch.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> One alternative approach can be to drop DECL_SET_IS_OPERATOR_DELETE in:
> cat -n gcc/cp/decl.c | less
> ...
>   4410          deltype = cp_build_type_attribute_variant (deltype, extvisattr);
>   4411          deltype = build_exception_variant (deltype, empty_except_spec);
>   4412          opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
>   4413          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>   4414          opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
>   4415          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>   4416
>   4417          if (flag_sized_deallocation)
>   4418            {
>   4419              /* operator delete (void *, size_t, align_val_t); */
>   4420              deltype = build_function_type_list (void_type_node, ptr_type_node,
>   4421                                                  size_type_node, align_type_node,
>   4422                                                  NULL_TREE);
>   4423              deltype = cp_build_type_attribute_variant (deltype, extvisattr);
>   4424              deltype = build_exception_variant (deltype, empty_except_spec);
>   4425              opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
>   4426              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>   4427              opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
>   4428              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>   4429            }
>   4430        }
>
> at lines 4426 and 4428.
>
> Richi what do you prefer?

I don't understand why a "not simple" delete operator isn't fine to be
DCEd?  Does C++
somehow allow mismatching size specifications here?  And what's the semantics
then?

Thus I'd rather go with your earlier patch to mark the op necessary.

Richard.

> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30  8:42                                                               ` Richard Biener
@ 2019-07-30 10:20                                                                 ` Martin Liška
  2019-07-30 10:28                                                                   ` Richard Biener
  2019-07-30 12:08                                                                   ` Marc Glisse
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-30 10:20 UTC (permalink / raw)
  To: Richard Biener
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 2268 bytes --]

On 7/30/19 10:40 AM, Richard Biener wrote:
> On Tue, Jul 30, 2019 at 10:07 AM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 7/30/19 9:46 AM, Martin Liška wrote:
>>> Anyway that's not a candidate for DCE. I'm testing following patch.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> One alternative approach can be to drop DECL_SET_IS_OPERATOR_DELETE in:
>> cat -n gcc/cp/decl.c | less
>> ...
>>   4410          deltype = cp_build_type_attribute_variant (deltype, extvisattr);
>>   4411          deltype = build_exception_variant (deltype, empty_except_spec);
>>   4412          opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
>>   4413          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>>   4414          opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
>>   4415          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>>   4416
>>   4417          if (flag_sized_deallocation)
>>   4418            {
>>   4419              /* operator delete (void *, size_t, align_val_t); */
>>   4420              deltype = build_function_type_list (void_type_node, ptr_type_node,
>>   4421                                                  size_type_node, align_type_node,
>>   4422                                                  NULL_TREE);
>>   4423              deltype = cp_build_type_attribute_variant (deltype, extvisattr);
>>   4424              deltype = build_exception_variant (deltype, empty_except_spec);
>>   4425              opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
>>   4426              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>>   4427              opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
>>   4428              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
>>   4429            }
>>   4430        }
>>
>> at lines 4426 and 4428.
>>
>> Richi what do you prefer?
> 
> I don't understand why a "not simple" delete operator isn't fine to be
> DCEd?  Does C++
> somehow allow mismatching size specifications here?

No, they are the same.

>  And what's the semantics
> then?
> 
> Thus I'd rather go with your earlier patch to mark the op necessary.

Ok, I'm sending tested patch.

Ready for trunk?
Thanks,
Martin

> 
> Richard.
> 
>> Martin


[-- Attachment #2: 0001-Mark-2nd-argument-of-delete-operator-as-needed-PR-tr.patch --]
[-- Type: text/x-patch, Size: 2549 bytes --]

From b4645189743b2670f77028933086fff56c46eb75 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Sun, 28 Jul 2019 13:04:28 +0200
Subject: [PATCH] Mark 2nd argument of delete operator as needed (PR
 tree-optimization/91270).

gcc/cp/ChangeLog:

2019-07-30  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* tree-ssa-dce.c (propagate_necessity): Mark 2nd argument
	of delete operator as needed.

gcc/testsuite/ChangeLog:

2019-07-30  Martin Liska  <mliska@suse.cz>

	PR tree-optimization/91270
	* g++.dg/torture/pr91270.C: New test.
---
 gcc/testsuite/g++.dg/torture/pr91270.C | 10 ++++++++++
 gcc/tree-ssa-dce.c                     | 19 +++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr91270.C

diff --git a/gcc/testsuite/g++.dg/torture/pr91270.C b/gcc/testsuite/g++.dg/torture/pr91270.C
new file mode 100644
index 00000000000..60d766e9e9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr91270.C
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+struct S {
+  ~S();
+};
+int a = 123;
+void fn1() {
+  S *s = new S[a];
+  delete[] s;
+}
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 763b76f0e53..c816fccceb4 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -804,10 +804,11 @@ 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.  */
+	  bool is_delete_operator
+	    = (is_gimple_call (stmt)
+	       && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
 	  if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
-	      || (is_gimple_call (stmt)
-		  && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))
-
+	      || is_delete_operator)
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
@@ -822,7 +823,17 @@ propagate_necessity (bool aggressive)
 			   || 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;
+		{
+		  /* Some delete operators have size as 2nd argument.  */
+		  if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
+		    {
+		      tree size_argument = gimple_call_arg (stmt, 1);
+		      if (TREE_CODE (size_argument) == SSA_NAME)
+			mark_operand_necessary (size_argument);
+		    }
+
+		  continue;
+		}
 	    }
 
 	  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 10:20                                                                 ` Martin Liška
@ 2019-07-30 10:28                                                                   ` Richard Biener
  2019-07-30 12:08                                                                   ` Marc Glisse
  1 sibling, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-07-30 10:28 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Tue, Jul 30, 2019 at 12:11 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/30/19 10:40 AM, Richard Biener wrote:
> > On Tue, Jul 30, 2019 at 10:07 AM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> On 7/30/19 9:46 AM, Martin Liška wrote:
> >>> Anyway that's not a candidate for DCE. I'm testing following patch.
> >>
> >> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >>
> >> One alternative approach can be to drop DECL_SET_IS_OPERATOR_DELETE in:
> >> cat -n gcc/cp/decl.c | less
> >> ...
> >>   4410          deltype = cp_build_type_attribute_variant (deltype, extvisattr);
> >>   4411          deltype = build_exception_variant (deltype, empty_except_spec);
> >>   4412          opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
> >>   4413          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
> >>   4414          opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
> >>   4415          DECL_SET_IS_OPERATOR_DELETE (opdel, true);
> >>   4416
> >>   4417          if (flag_sized_deallocation)
> >>   4418            {
> >>   4419              /* operator delete (void *, size_t, align_val_t); */
> >>   4420              deltype = build_function_type_list (void_type_node, ptr_type_node,
> >>   4421                                                  size_type_node, align_type_node,
> >>   4422                                                  NULL_TREE);
> >>   4423              deltype = cp_build_type_attribute_variant (deltype, extvisattr);
> >>   4424              deltype = build_exception_variant (deltype, empty_except_spec);
> >>   4425              opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
> >>   4426              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
> >>   4427              opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
> >>   4428              DECL_SET_IS_OPERATOR_DELETE (opdel, true);
> >>   4429            }
> >>   4430        }
> >>
> >> at lines 4426 and 4428.
> >>
> >> Richi what do you prefer?
> >
> > I don't understand why a "not simple" delete operator isn't fine to be
> > DCEd?  Does C++
> > somehow allow mismatching size specifications here?
>
> No, they are the same.
>
> >  And what's the semantics
> > then?
> >
> > Thus I'd rather go with your earlier patch to mark the op necessary.
>
> Ok, I'm sending tested patch.
>
> Ready for trunk?

OK with the tests in

          if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
-             || (is_gimple_call (stmt)
-                 && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))
-
+             || is_delete_operator)

exchanged (you already compuited is_delete_operator, no need to check for
BUILT_IN_FREE if it is true).

Richard.

> Thanks,
> Martin
>
> >
> > Richard.
> >
> >> Martin
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 10:20                                                                 ` Martin Liška
  2019-07-30 10:28                                                                   ` Richard Biener
@ 2019-07-30 12:08                                                                   ` Marc Glisse
  2019-07-30 12:12                                                                     ` Martin Liška
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-30 12:08 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

+		  /* Some delete operators have size as 2nd argument.  */

Some delete operators have 3 arguments. From cp/decl.c:

             /* operator delete (void *, size_t, align_val_t); */

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 12:08                                                                   ` Marc Glisse
@ 2019-07-30 12:12                                                                     ` Martin Liška
  2019-07-30 13:14                                                                       ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-30 12:12 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/30/19 1:35 PM, Marc Glisse wrote:
> +          /* Some delete operators have size as 2nd argument.  */
> 
> Some delete operators have 3 arguments. From cp/decl.c:
> 
>             /* operator delete (void *, size_t, align_val_t); */
> 

Yep, I know. The patch I installed expects at least 2 arguments:

+                 /* Some delete operators have size as 2nd argument.  */
+                 if (is_delete_operator && gimple_call_num_args (stmt) >= 2)

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 12:12                                                                     ` Martin Liška
@ 2019-07-30 13:14                                                                       ` Marc Glisse
  2019-07-30 13:41                                                                         ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-30 13:14 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Tue, 30 Jul 2019, Martin Liška wrote:

> On 7/30/19 1:35 PM, Marc Glisse wrote:
>> +          /* Some delete operators have size as 2nd argument.  */
>>
>> Some delete operators have 3 arguments. From cp/decl.c:
>>
>>             /* operator delete (void *, size_t, align_val_t); */
>>
>
> Yep, I know. The patch I installed expects at least 2 arguments:
>
> +                 /* Some delete operators have size as 2nd argument.  */
> +                 if (is_delete_operator && gimple_call_num_args (stmt) >= 2)

True, I guess I am a bit confused why the second argument (which could be 
either size or alignment) needs special handling (mark_operand_necessary) 
while the third one does not (it is usually a constant).

I tried to experiment to understand, but it is complicated because 
including <new> disables the optimization:

#include <new>
void fn1() {
     char*p=new char;
     delete p;
}

This ICEs with -O -std=c++17:

int a = 64;
std::align_val_t b{64};
void fn1() {
   void *s = operator new(a,b);
   operator delete(s,8+*(unsigned long*)s,b);
}


-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 13:14                                                                       ` Marc Glisse
@ 2019-07-30 13:41                                                                         ` Martin Liška
  2019-07-30 14:37                                                                           ` Marc Glisse
  2019-07-31 10:00                                                                           ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Richard Biener
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-07-30 13:41 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On 7/30/19 3:09 PM, Marc Glisse wrote:
> On Tue, 30 Jul 2019, Martin Liška wrote:
> 
>> On 7/30/19 1:35 PM, Marc Glisse wrote:
>>> +          /* Some delete operators have size as 2nd argument.  */
>>>
>>> Some delete operators have 3 arguments. From cp/decl.c:
>>>
>>>             /* operator delete (void *, size_t, align_val_t); */
>>>
>>
>> Yep, I know. The patch I installed expects at least 2 arguments:
>>
>> +                 /* Some delete operators have size as 2nd argument.  */
>> +                 if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
> 
> True, I guess I am a bit confused why the second argument (which could be either size or alignment) needs special handling (mark_operand_necessary) while the third one does not (it is usually a constant).

Ah, that's bad, both of them need a care:

diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index bec13cd5930..80d5f5c30f7 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -824,13 +824,16 @@ propagate_necessity (bool aggressive)
 			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
 		      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
 		{
-		  /* Some delete operators have size as 2nd argument.  */
+		  /* Delete operators can have alignment and (or) size as next
+		     arguments.  When being a SSA_NAME, they must be marked
+		     as necessary.  */
 		  if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
-		    {
-		      tree size_argument = gimple_call_arg (stmt, 1);
-		      if (TREE_CODE (size_argument) == SSA_NAME)
-			mark_operand_necessary (size_argument);
-		    }
+		    for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
+		      {
+			tree arg = gimple_call_arg (stmt, i);
+			if (TREE_CODE (arg) == SSA_NAME)
+			  mark_operand_necessary (arg);
+		      }
 
 		  continue;
 		}

> 
> I tried to experiment to understand, but it is complicated because including <new> disables the optimization:
> 
> #include <new>
> void fn1() {
>     char*p=new char;
>     delete p;
> }
> 
> This ICEs with -O -std=c++17:
> 
> int a = 64;
> std::align_val_t b{64};
> void fn1() {
>   void *s = operator new(a,b);
>   operator delete(s,8+*(unsigned long*)s,b);
> }
> 
> 

I can't see it on current master. Can you?

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 13:41                                                                         ` Martin Liška
@ 2019-07-30 14:37                                                                           ` Marc Glisse
  2019-07-31  8:42                                                                             ` [PATCH] Mark necessary 2nd and later args for delete op Martin Liška
  2019-07-31 10:00                                                                           ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Richard Biener
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-07-30 14:37 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Tue, 30 Jul 2019, Martin Liška wrote:

> Ah, that's bad, both of them need a care:

Yes, that makes more sense to me, thanks.

>> I tried to experiment to understand, but it is complicated because including <new> disables the optimization:
>>
>> #include <new>
>> void fn1() {
>>     char*p=new char;
>>     delete p;
>> }
>>
>> This ICEs with -O -std=c++17:
>>
>> int a = 64;
>> std::align_val_t b{64};
>> void fn1() {
>>   void *s = operator new(a,b);
>>   operator delete(s,8+*(unsigned long*)s,b);
>> }
>>
>>
>
> I can't see it on current master. Can you?

Yes. I just did a clean build to make sure.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH] Mark necessary 2nd and later args for delete op.
  2019-07-30 14:37                                                                           ` Marc Glisse
@ 2019-07-31  8:42                                                                             ` Martin Liška
  2019-07-31 10:24                                                                               ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-07-31  8:42 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Richard Biener, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 867 bytes --]

On 7/30/19 4:00 PM, Marc Glisse wrote:
> On Tue, 30 Jul 2019, Martin Liška wrote:
> 
>> Ah, that's bad, both of them need a care:
> 
> Yes, that makes more sense to me, thanks.
> 
>>> I tried to experiment to understand, but it is complicated because including <new> disables the optimization:
>>>
>>> #include <new>
>>> void fn1() {
>>>     char*p=new char;
>>>     delete p;
>>> }
>>>
>>> This ICEs with -O -std=c++17:
>>>
>>> int a = 64;
>>> std::align_val_t b{64};
>>> void fn1() {
>>>   void *s = operator new(a,b);
>>>   operator delete(s,8+*(unsigned long*)s,b);
>>> }
>>>
>>>
>>
>> I can't see it on current master. Can you?
> 
> Yes. I just did a clean build to make sure.
> 

That's addressed in a patch I'm attaching.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Mark-necessary-2nd-and-later-args-for-delete-op.patch --]
[-- Type: text/x-patch, Size: 1538 bytes --]

From cd975aaccbbed3c03bbd246e0802c94693a0962d Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 30 Jul 2019 15:40:24 +0200
Subject: [PATCH] Mark necessary 2nd and later args for delete op.

gcc/ChangeLog:

2019-07-30  Martin Liska  <mliska@suse.cz>

	* tree-ssa-dce.c (propagate_necessity): Delete operator can
	have size and (or) alignment as 2nd and later arguments.
	Mark all of them as necessary.
---
 gcc/tree-ssa-dce.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index bec13cd5930..80d5f5c30f7 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -824,13 +824,16 @@ propagate_necessity (bool aggressive)
 			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
 		      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
 		{
-		  /* Some delete operators have size as 2nd argument.  */
+		  /* Delete operators can have alignment and (or) size as next
+		     arguments.  When being a SSA_NAME, they must be marked
+		     as necessary.  */
 		  if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
-		    {
-		      tree size_argument = gimple_call_arg (stmt, 1);
-		      if (TREE_CODE (size_argument) == SSA_NAME)
-			mark_operand_necessary (size_argument);
-		    }
+		    for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
+		      {
+			tree arg = gimple_call_arg (stmt, i);
+			if (TREE_CODE (arg) == SSA_NAME)
+			  mark_operand_necessary (arg);
+		      }
 
 		  continue;
 		}
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270).
  2019-07-30 13:41                                                                         ` Martin Liška
  2019-07-30 14:37                                                                           ` Marc Glisse
@ 2019-07-31 10:00                                                                           ` Richard Biener
  1 sibling, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-07-31 10:00 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Tue, Jul 30, 2019 at 3:39 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/30/19 3:09 PM, Marc Glisse wrote:
> > On Tue, 30 Jul 2019, Martin Liška wrote:
> >
> >> On 7/30/19 1:35 PM, Marc Glisse wrote:
> >>> +          /* Some delete operators have size as 2nd argument.  */
> >>>
> >>> Some delete operators have 3 arguments. From cp/decl.c:
> >>>
> >>>             /* operator delete (void *, size_t, align_val_t); */
> >>>
> >>
> >> Yep, I know. The patch I installed expects at least 2 arguments:
> >>
> >> +                 /* Some delete operators have size as 2nd argument.  */
> >> +                 if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
> >
> > True, I guess I am a bit confused why the second argument (which could be either size or alignment) needs special handling (mark_operand_necessary) while the third one does not (it is usually a constant).
>
> Ah, that's bad, both of them need a care:
>
> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> index bec13cd5930..80d5f5c30f7 100644
> --- a/gcc/tree-ssa-dce.c
> +++ b/gcc/tree-ssa-dce.c
> @@ -824,13 +824,16 @@ propagate_necessity (bool aggressive)
>                            || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
>                       || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
>                 {
> -                 /* Some delete operators have size as 2nd argument.  */
> +                 /* Delete operators can have alignment and (or) size as next
> +                    arguments.  When being a SSA_NAME, they must be marked
> +                    as necessary.  */
>                   if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
> -                   {
> -                     tree size_argument = gimple_call_arg (stmt, 1);
> -                     if (TREE_CODE (size_argument) == SSA_NAME)
> -                       mark_operand_necessary (size_argument);
> -                   }
> +                   for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
> +                     {
> +                       tree arg = gimple_call_arg (stmt, i);
> +                       if (TREE_CODE (arg) == SSA_NAME)
> +                         mark_operand_necessary (arg);
> +                     }
>
>                   continue;
>                 }

Pre-approved.

> >
> > I tried to experiment to understand, but it is complicated because including <new> disables the optimization:
> >
> > #include <new>
> > void fn1() {
> >     char*p=new char;
> >     delete p;
> > }
> >
> > This ICEs with -O -std=c++17:
> >
> > int a = 64;
> > std::align_val_t b{64};
> > void fn1() {
> >   void *s = operator new(a,b);
> >   operator delete(s,8+*(unsigned long*)s,b);
> > }
> >
> >
>
> I can't see it on current master. Can you?
>
> Martin
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Mark necessary 2nd and later args for delete op.
  2019-07-31  8:42                                                                             ` [PATCH] Mark necessary 2nd and later args for delete op Martin Liška
@ 2019-07-31 10:24                                                                               ` Richard Biener
  0 siblings, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-07-31 10:24 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, Jason Merrill, GCC Patches, David Malcolm,
	dominik.infuehr, Nathan Sidwell

On Wed, Jul 31, 2019 at 10:37 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 7/30/19 4:00 PM, Marc Glisse wrote:
> > On Tue, 30 Jul 2019, Martin Liška wrote:
> >
> >> Ah, that's bad, both of them need a care:
> >
> > Yes, that makes more sense to me, thanks.
> >
> >>> I tried to experiment to understand, but it is complicated because including <new> disables the optimization:
> >>>
> >>> #include <new>
> >>> void fn1() {
> >>>     char*p=new char;
> >>>     delete p;
> >>> }
> >>>
> >>> This ICEs with -O -std=c++17:
> >>>
> >>> int a = 64;
> >>> std::align_val_t b{64};
> >>> void fn1() {
> >>>   void *s = operator new(a,b);
> >>>   operator delete(s,8+*(unsigned long*)s,b);
> >>> }
> >>>
> >>>
> >>
> >> I can't see it on current master. Can you?
> >
> > Yes. I just did a clean build to make sure.
> >
>
> That's addressed in a patch I'm attaching.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> Ready to be installed?

OK.

> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383).
  2019-07-02 11:50                   ` [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383) Martin Liška
@ 2019-08-02 21:34                     ` H.J. Lu
  2019-08-05  6:44                       ` [PATCH] Handle new operators with no arguments in DCE Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: H.J. Lu @ 2019-08-02 21:34 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On Tue, Jul 2, 2019 at 4:50 AM Martin Liška <mliska@suse.cz> wrote:
>
> Second part.
>
> Martin

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91334

-- 
H.J.

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH] Handle new operators with no arguments in DCE.
  2019-08-02 21:34                     ` H.J. Lu
@ 2019-08-05  6:44                       ` Martin Liška
  2019-08-05  7:08                         ` Marc Glisse
  2019-08-05 12:13                         ` Richard Biener
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-08-05  6:44 UTC (permalink / raw)
  To: H.J. Lu
  Cc: Marc Glisse, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

[-- Attachment #1: Type: text/plain, Size: 450 bytes --]

On 8/2/19 11:34 PM, H.J. Lu wrote:
> On Tue, Jul 2, 2019 at 4:50 AM Martin Liška <mliska@suse.cz> wrote:
>>
>> Second part.
>>
>> Martin
> 
> This caused:
> 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91334
> 

Hi.

I'm sending fix for the ICE. The issue is that we can end up
with a ctor without an argument (when not being used).

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Handle-new-operators-with-no-arguments-in-DCE.patch --]
[-- Type: text/x-patch, Size: 2823 bytes --]

From 76d215d59f32c5f6cbcb0a0ad4ecbfff8f181770 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Mon, 5 Aug 2019 06:55:45 +0200
Subject: [PATCH] Handle new operators with no arguments in DCE.

gcc/ChangeLog:

2019-08-05  Martin Liska  <mliska@suse.cz>

	PR c++/91334
	* tree-ssa-dce.c (propagate_necessity): Handle new operators
	with not arguments.
	(eliminate_unnecessary_stmts): Likewise.

gcc/testsuite/ChangeLog:

2019-08-05  Martin Liska  <mliska@suse.cz>

	PR c++/91334
	* g++.dg/torture/pr91334.C: New test.
---
 gcc/testsuite/g++.dg/torture/pr91334.C | 14 ++++++++++++++
 gcc/tree-ssa-dce.c                     | 22 ++++++++++++++++------
 2 files changed, 30 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr91334.C

diff --git a/gcc/testsuite/g++.dg/torture/pr91334.C b/gcc/testsuite/g++.dg/torture/pr91334.C
new file mode 100644
index 00000000000..ba79d712b07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr91334.C
@@ -0,0 +1,14 @@
+/* PR c++/91334.  */
+/* { dg-do compile } */
+
+#include <new>
+#include <stdlib.h>
+
+struct A {
+  A() { throw 0; }
+  void* operator new(size_t size, double = 0.0) { return ::operator new(size);}
+  void operator delete(void* p, double) { exit(0); }
+  void operator delete(void* p) { abort(); }
+};
+
+int main() { try { new A; } catch(...) {} }
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 80d5f5c30f7..afb7bd9dedc 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -810,6 +810,11 @@ propagate_necessity (bool aggressive)
 	  if (is_delete_operator
 	      || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
 	    {
+	      /* It can happen that a user delete operator has the pointer
+		 argument optimized out already.  */
+	      if (gimple_call_num_args (stmt) == 0)
+		continue;
+
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
 	      tree def_callee;
@@ -1323,13 +1328,18 @@ eliminate_unnecessary_stmts (void)
 		  || (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)
+	      /* It can happen that a user delete operator has the pointer
+		 argument optimized out already.  */
+	      if (gimple_call_num_args (stmt) > 0)
 		{
-		  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
-		  if (!gimple_nop_p (def_stmt)
-		      && !gimple_plf (def_stmt, STMT_NECESSARY))
-		    gimple_set_plf (stmt, STMT_NECESSARY, false);
+		  tree ptr = gimple_call_arg (stmt, 0);
+		  if (TREE_CODE (ptr) == SSA_NAME)
+		    {
+		      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+		      if (!gimple_nop_p (def_stmt)
+			  && !gimple_plf (def_stmt, STMT_NECESSARY))
+			gimple_set_plf (stmt, STMT_NECESSARY, false);
+		    }
 		}
 	    }
 
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05  6:44                       ` [PATCH] Handle new operators with no arguments in DCE Martin Liška
@ 2019-08-05  7:08                         ` Marc Glisse
  2019-08-05  9:53                           ` Martin Liška
  2019-08-05 12:13                         ` Richard Biener
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-08-05  7:08 UTC (permalink / raw)
  To: Martin Liška
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On Mon, 5 Aug 2019, Martin Liška wrote:

> I'm sending fix for the ICE. The issue is that we can end up
> with a ctor without an argument (when not being used).

Ah, I didn't realize that after cloning and drastically changing the 
signature it would still count as operator new/delete. Is getting down to 
0 arguments the only bad thing that can happen? Can't we have an operator 
delete (void*, void*) where the first argument gets optimized out and we 
end up optimizing as if the second argument was actually the memory being 
released? Should we do some sanity-checking when propagating the 
new/delete flags to clones?

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05  7:08                         ` Marc Glisse
@ 2019-08-05  9:53                           ` Martin Liška
  2019-08-05 11:57                             ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-05  9:53 UTC (permalink / raw)
  To: Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On 8/5/19 9:07 AM, Marc Glisse wrote:
> On Mon, 5 Aug 2019, Martin Liška wrote:
> 
>> I'm sending fix for the ICE. The issue is that we can end up
>> with a ctor without an argument (when not being used).
> 
> Ah, I didn't realize that after cloning and drastically changing the signature it would still count as operator new/delete. Is getting down to 0 arguments the only bad thing that can happen? Can't we have an operator delete (void*, void*) where the first argument gets optimized out and we end up optimizing as if the second argument was actually the memory being released? Should we do some sanity-checking when propagating the new/delete flags to clones?
> 

It can theoretically happen, but it should be properly handled in the following
code:

   810            if (is_delete_operator
   811                || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
   812              {
   813                /* It can happen that a user delete operator has the pointer
   814                   argument optimized out already.  */
   815                if (gimple_call_num_args (stmt) == 0)
   816                  continue;
   817  
   818                tree ptr = gimple_call_arg (stmt, 0);
   819                gimple *def_stmt;
   820                tree def_callee;
   821                /* If the pointer we free is defined by an allocation
   822                   function do not add the call to the worklist.  */
   823                if (TREE_CODE (ptr) == SSA_NAME
   824                    && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
   825                    && (def_callee = gimple_call_fndecl (def_stmt))
   826                    && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
   827                         && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
   828                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
   829                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
   830                        || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
   831                  {
   832                    /* Delete operators can have alignment and (or) size as next
   833                       arguments.  When being a SSA_NAME, they must be marked
   834                       as necessary.  */
   835                    if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
   836                      for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
   837                        {
   838                          tree arg = gimple_call_arg (stmt, i);
   839                          if (TREE_CODE (arg) == SSA_NAME)
   840                            mark_operand_necessary (arg);
   841                        }

Where we verify that first argument of delete call is defined as a LHS of a new operator.

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05  9:53                           ` Martin Liška
@ 2019-08-05 11:57                             ` Marc Glisse
  2019-08-05 12:52                               ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-08-05 11:57 UTC (permalink / raw)
  To: Martin Liška
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On Mon, 5 Aug 2019, Martin Liška wrote:

> On 8/5/19 9:07 AM, Marc Glisse wrote:
>> On Mon, 5 Aug 2019, Martin Liška wrote:
>>
>>> I'm sending fix for the ICE. The issue is that we can end up
>>> with a ctor without an argument (when not being used).
>>
>> Ah, I didn't realize that after cloning and drastically changing the signature it would still count as operator new/delete. Is getting down to 0 arguments the only bad thing that can happen? Can't we have an operator delete (void*, void*) where the first argument gets optimized out and we end up optimizing as if the second argument was actually the memory being released? Should we do some sanity-checking when propagating the new/delete flags to clones?
>>
>
> It can theoretically happen, but it should be properly handled in the following
> code:
>
>   810            if (is_delete_operator
>   811                || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
>   812              {
>   813                /* It can happen that a user delete operator has the pointer
>   814                   argument optimized out already.  */
>   815                if (gimple_call_num_args (stmt) == 0)
>   816                  continue;
>   817
>   818                tree ptr = gimple_call_arg (stmt, 0);
>   819                gimple *def_stmt;
>   820                tree def_callee;
>   821                /* If the pointer we free is defined by an allocation
>   822                   function do not add the call to the worklist.  */
>   823                if (TREE_CODE (ptr) == SSA_NAME
>   824                    && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
>   825                    && (def_callee = gimple_call_fndecl (def_stmt))
>   826                    && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
>   827                         && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
>   828                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
>   829                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
>   830                        || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
>   831                  {
>   832                    /* Delete operators can have alignment and (or) size as next
>   833                       arguments.  When being a SSA_NAME, they must be marked
>   834                       as necessary.  */
>   835                    if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
>   836                      for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
>   837                        {
>   838                          tree arg = gimple_call_arg (stmt, i);
>   839                          if (TREE_CODE (arg) == SSA_NAME)
>   840                            mark_operand_necessary (arg);
>   841                        }
>
> Where we verify that first argument of delete call is defined as a LHS of a new operator.

What I am saying is that it may be the wrong operator new.

Imagine something like:

struct A {
   A();
   __attribute__((malloc)) static void* operator new(unsigned long sz, void*,bool);
   static void operator delete(void* ptr, void*,bool);
};
int main(){
   int*p=new int;
   new(p,true) A;
}

At the beginning, it has

     D.2321 = A::operator new (1, p, 1);

and

     A::operator delete (D.2321, p, 1);

Now imagine we have access to the body of the functions, and the last one 
is transformed into

     operator delete.clone (p)

(the first argument was removed)
p does come from an operator new, so we do see a matched pair new+delete, 
but it is the wrong pair.

I admit that's rather unlikely, but with clones that have a different 
signature, many assumptions we could make on the functions become unsafe, 
and I am not clear on the scale of this issue.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05  6:44                       ` [PATCH] Handle new operators with no arguments in DCE Martin Liška
  2019-08-05  7:08                         ` Marc Glisse
@ 2019-08-05 12:13                         ` Richard Biener
  1 sibling, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-08-05 12:13 UTC (permalink / raw)
  To: Martin Liška
  Cc: H.J. Lu, Marc Glisse, David Malcolm, GCC Patches, dominik.infuehr

On Mon, Aug 5, 2019 at 8:44 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/2/19 11:34 PM, H.J. Lu wrote:
> > On Tue, Jul 2, 2019 at 4:50 AM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> Second part.
> >>
> >> Martin
> >
> > This caused:
> >
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91334
> >
>
> Hi.
>
> I'm sending fix for the ICE. The issue is that we can end up
> with a ctor without an argument (when not being used).
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> Ready to be installed?

OK as a stop-gap for now, please discuss stuff further with Marc, I think
he's right that this isn't a good solution.  Can we check cgraph_node->clone_of
or so and simply disregard all clones?  We do not record the "original"
parameter position...

Richard.

> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05 11:57                             ` Marc Glisse
@ 2019-08-05 12:52                               ` Martin Liška
  2019-08-05 13:46                                 ` Marc Glisse
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-05 12:52 UTC (permalink / raw)
  To: Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On 8/5/19 1:57 PM, Marc Glisse wrote:
> On Mon, 5 Aug 2019, Martin Liška wrote:
> 
>> On 8/5/19 9:07 AM, Marc Glisse wrote:
>>> On Mon, 5 Aug 2019, Martin Liška wrote:
>>>
>>>> I'm sending fix for the ICE. The issue is that we can end up
>>>> with a ctor without an argument (when not being used).
>>>
>>> Ah, I didn't realize that after cloning and drastically changing the signature it would still count as operator new/delete. Is getting down to 0 arguments the only bad thing that can happen? Can't we have an operator delete (void*, void*) where the first argument gets optimized out and we end up optimizing as if the second argument was actually the memory being released? Should we do some sanity-checking when propagating the new/delete flags to clones?
>>>
>>
>> It can theoretically happen, but it should be properly handled in the following
>> code:
>>
>>   810            if (is_delete_operator
>>   811                || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
>>   812              {
>>   813                /* It can happen that a user delete operator has the pointer
>>   814                   argument optimized out already.  */
>>   815                if (gimple_call_num_args (stmt) == 0)
>>   816                  continue;
>>   817
>>   818                tree ptr = gimple_call_arg (stmt, 0);
>>   819                gimple *def_stmt;
>>   820                tree def_callee;
>>   821                /* If the pointer we free is defined by an allocation
>>   822                   function do not add the call to the worklist.  */
>>   823                if (TREE_CODE (ptr) == SSA_NAME
>>   824                    && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
>>   825                    && (def_callee = gimple_call_fndecl (def_stmt))
>>   826                    && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
>>   827                         && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
>>   828                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
>>   829                             || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
>>   830                        || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
>>   831                  {
>>   832                    /* Delete operators can have alignment and (or) size as next
>>   833                       arguments.  When being a SSA_NAME, they must be marked
>>   834                       as necessary.  */
>>   835                    if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
>>   836                      for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
>>   837                        {
>>   838                          tree arg = gimple_call_arg (stmt, i);
>>   839                          if (TREE_CODE (arg) == SSA_NAME)
>>   840                            mark_operand_necessary (arg);
>>   841                        }
>>
>> Where we verify that first argument of delete call is defined as a LHS of a new operator.
> 
> What I am saying is that it may be the wrong operator new.
> 
> Imagine something like:
> 
> struct A {
>   A();
>   __attribute__((malloc)) static void* operator new(unsigned long sz, void*,bool);
>   static void operator delete(void* ptr, void*,bool);
> };
> int main(){
>   int*p=new int;
>   new(p,true) A;
> }
> 
> At the beginning, it has
> 
>     D.2321 = A::operator new (1, p, 1);
> 
> and
> 
>     A::operator delete (D.2321, p, 1);
> 
> Now imagine we have access to the body of the functions, and the last one is transformed into
> 
>     operator delete.clone (p)

You are right. It can really lead to confusion of the DCE.

What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate operators
that were somehow modified by an IPA optimization. Do you believe it will be sufficient?

Thanks,
Martin

> 
> (the first argument was removed)
> p does come from an operator new, so we do see a matched pair new+delete, but it is the wrong pair.
> 
> I admit that's rather unlikely, but with clones that have a different signature, many assumptions we could make on the functions become unsafe, and I am not clear on the scale of this issue.
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05 12:52                               ` Martin Liška
@ 2019-08-05 13:46                                 ` Marc Glisse
  2019-08-06 14:07                                   ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-08-05 13:46 UTC (permalink / raw)
  To: Martin Liška
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener, dominik.infuehr

On Mon, 5 Aug 2019, Martin Liška wrote:

> You are right. It can really lead to confusion of the DCE.
>
> What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate operators
> that were somehow modified by an IPA optimization.

Looks similar to the cgraph_node->clone_of that Richard was talking about. 
I have no idea which one would be best.

> Do you believe it will be sufficient?

In DCE only consider the operator delete that are not clones? (possibly 
the same for operator new? I don't know how much we can change the return 
value of a function in a clone) I guess that should work, and it wouldn't 
impact the common case with default, global operator new/delete.

An alternative would be to clear the DECL_IS_OPERATOR_DELETE flag when 
creating a clone (possibly only if it modified the first parameter?). 
There is probably not much information in the fact that a function that 
doesn't even take a pointer used to be an operator delete.


By the way, I just thought of something, now that we handle class-specific 
operator new/delete (but you could do the same with the global replacable 
ones as well):

#include <stdio.h>
int count = 0;
struct A {
   __attribute__((malloc,noinline))
   static void* operator new(unsigned long sz){++count;return ::operator new(sz);}
   static void operator delete(void* ptr){--count;::operator delete(ptr);}
};
int main(){
   delete new A;
   printf("%d\n",count);
}

If we do not inline anything, we can remove the pair and nothing touches 
count. If we inline both new and delete, we can then remove the inner pair 
instead, count increases and decreases, fine. If we inline only one of 
them, and DCE the mismatched pair new/delete, we get something 
inconsistent (count is -1).

This seems to indicate we should check that the new and delete match 
somehow...

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-05 13:46                                 ` Marc Glisse
@ 2019-08-06 14:07                                   ` Martin Liška
  2019-08-06 15:35                                     ` [PATCH] Detect not-cloned new/delete operators " Martin Liška
  2019-08-07  9:54                                     ` [PATCH] Handle new operators with no arguments " Richard Biener
  0 siblings, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-08-06 14:07 UTC (permalink / raw)
  To: Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On 8/5/19 3:46 PM, Marc Glisse wrote:
> On Mon, 5 Aug 2019, Martin Liška wrote:
> 
>> You are right. It can really lead to confusion of the DCE.
>>
>> What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate operators
>> that were somehow modified by an IPA optimization.
> 
> Looks similar to the cgraph_node->clone_of that Richard was talking about. I have no idea which one would be best.


Hm, strange that the ISRA clones don't have n->clone_of set. It's created here:

#0  cgraph_node::create (decl=<function_decl 0x7ffff721c300 _ZN1AdlEPvd.isra.0>) at /home/marxin/Programming/gcc/gcc/profile-count.h:751
#1  0x0000000000bc8342 in cgraph_node::create_version_clone (this=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, new_decl=<optimized out>, redirect_callers=..., bbs_to_copy=0x0, suffix=0x1b74427 "isra") at /home/marxin/Programming/gcc/gcc/cgraphclones.c:960
#2  0x0000000000bc9b9a in cgraph_node::create_version_clone_with_body (this=this@entry=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, redirect_callers=redirect_callers@entry=..., tree_map=tree_map@entry=0x0, args_to_skip=args_to_skip@entry=0x0, 
    skip_return=skip_return@entry=false, bbs_to_copy=bbs_to_copy@entry=0x0, new_entry_block=<optimized out>, suffix=<optimized out>, target_attributes=<optimized out>) at /home/marxin/Programming/gcc/gcc/cgraphclones.c:1071
#3  0x00000000010e4611 in modify_function (adjustments=..., node=<cgraph_node * 0x7ffff7208000 "operator delete"/64>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5493
#4  ipa_early_sra () at /home/marxin/Programming/gcc/gcc/tree-sra.c:5731
#5  (anonymous namespace)::pass_early_ipa_sra::execute (this=<optimized out>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5778

@Martin, @Honza: Why do we not set clone_of in this transformation?

> 
>> Do you believe it will be sufficient?
> 
> In DCE only consider the operator delete that are not clones? (possibly the same for operator new? I don't know how much we can change the return value of a function in a clone) I guess that should work, and it wouldn't impact the common case with default, global operator new/delete.

I tent to limit that the only cgraph nodes that are not clones. I'm going to prepare a patch for it.

> 
> An alternative would be to clear the DECL_IS_OPERATOR_DELETE flag when creating a clone (possibly only if it modified the first parameter?). There is probably not much information in the fact that a function that doesn't even take a pointer used to be an operator delete.
> 
> 
> By the way, I just thought of something, now that we handle class-specific operator new/delete (but you could do the same with the global replacable ones as well):
> 
> #include <stdio.h>
> int count = 0;
> struct A {
>   __attribute__((malloc,noinline))
>   static void* operator new(unsigned long sz){++count;return ::operator new(sz);}
>   static void operator delete(void* ptr){--count;::operator delete(ptr);}
> };
> int main(){
>   delete new A;
>   printf("%d\n",count);
> }
> 
> If we do not inline anything, we can remove the pair and nothing touches count. If we inline both new and delete, we can then remove the inner pair instead, count increases and decreases, fine. If we inline only one of them, and DCE the mismatched pair new/delete, we get something inconsistent (count is -1).
> 
> This seems to indicate we should check that the new and delete match somehow...
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-06 14:07                                   ` Martin Liška
@ 2019-08-06 15:35                                     ` Martin Liška
  2019-08-06 15:59                                       ` Marc Glisse
  2019-08-06 17:30                                       ` Martin Jambor
  2019-08-07  9:54                                     ` [PATCH] Handle new operators with no arguments " Richard Biener
  1 sibling, 2 replies; 91+ messages in thread
From: Martin Liška @ 2019-08-06 15:35 UTC (permalink / raw)
  To: Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 3896 bytes --]

On 8/6/19 2:42 PM, Martin Liška wrote:
> On 8/5/19 3:46 PM, Marc Glisse wrote:
>> On Mon, 5 Aug 2019, Martin Liška wrote:
>>
>>> You are right. It can really lead to confusion of the DCE.
>>>
>>> What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate operators
>>> that were somehow modified by an IPA optimization.
>>
>> Looks similar to the cgraph_node->clone_of that Richard was talking about. I have no idea which one would be best.
> 
> 
> Hm, strange that the ISRA clones don't have n->clone_of set. It's created here:
> 
> #0  cgraph_node::create (decl=<function_decl 0x7ffff721c300 _ZN1AdlEPvd.isra.0>) at /home/marxin/Programming/gcc/gcc/profile-count.h:751
> #1  0x0000000000bc8342 in cgraph_node::create_version_clone (this=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, new_decl=<optimized out>, redirect_callers=..., bbs_to_copy=0x0, suffix=0x1b74427 "isra") at /home/marxin/Programming/gcc/gcc/cgraphclones.c:960
> #2  0x0000000000bc9b9a in cgraph_node::create_version_clone_with_body (this=this@entry=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, redirect_callers=redirect_callers@entry=..., tree_map=tree_map@entry=0x0, args_to_skip=args_to_skip@entry=0x0, 
>     skip_return=skip_return@entry=false, bbs_to_copy=bbs_to_copy@entry=0x0, new_entry_block=<optimized out>, suffix=<optimized out>, target_attributes=<optimized out>) at /home/marxin/Programming/gcc/gcc/cgraphclones.c:1071
> #3  0x00000000010e4611 in modify_function (adjustments=..., node=<cgraph_node * 0x7ffff7208000 "operator delete"/64>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5493
> #4  ipa_early_sra () at /home/marxin/Programming/gcc/gcc/tree-sra.c:5731
> #5  (anonymous namespace)::pass_early_ipa_sra::execute (this=<optimized out>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5778
> 
> @Martin, @Honza: Why do we not set clone_of in this transformation?

If I'm correct cgraph_node::clone is used for inline clones only?

Anyway, I'm sending patch that considers only such new/delete operators
that are not a clone of an original type. That should make the current
DCE code more solid.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

> 
>>
>>> Do you believe it will be sufficient?
>>
>> In DCE only consider the operator delete that are not clones? (possibly the same for operator new? I don't know how much we can change the return value of a function in a clone) I guess that should work, and it wouldn't impact the common case with default, global operator new/delete.
> 
> I tent to limit that the only cgraph nodes that are not clones. I'm going to prepare a patch for it.
> 
>>
>> An alternative would be to clear the DECL_IS_OPERATOR_DELETE flag when creating a clone (possibly only if it modified the first parameter?). There is probably not much information in the fact that a function that doesn't even take a pointer used to be an operator delete.
>>
>>
>> By the way, I just thought of something, now that we handle class-specific operator new/delete (but you could do the same with the global replacable ones as well):
>>
>> #include <stdio.h>
>> int count = 0;
>> struct A {
>>   __attribute__((malloc,noinline))
>>   static void* operator new(unsigned long sz){++count;return ::operator new(sz);}
>>   static void operator delete(void* ptr){--count;::operator delete(ptr);}
>> };
>> int main(){
>>   delete new A;
>>   printf("%d\n",count);
>> }
>>
>> If we do not inline anything, we can remove the pair and nothing touches count. If we inline both new and delete, we can then remove the inner pair instead, count increases and decreases, fine. If we inline only one of them, and DCE the mismatched pair new/delete, we get something inconsistent (count is -1).
>>
>> This seems to indicate we should check that the new and delete match somehow...
>>
> 


[-- Attachment #2: 0001-Detect-not-cloned-new-delete-operators-in-DCE.patch --]
[-- Type: text/x-patch, Size: 6720 bytes --]

From 94110a47f0c13424d2e39d8f14bcc896a6097bd3 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 6 Aug 2019 16:14:48 +0200
Subject: [PATCH] Detect not-cloned new/delete operators in DCE.

gcc/ChangeLog:

2019-08-06  Martin Liska  <mliska@suse.cz>

	* gimple.c (gimple_call_operator_delete_p): Remove.
	* gimple.h (gimple_call_operator_delete_p): Likewise.
	* tree-ssa-dce.c (operator_new_candidate_p): New.
	(operator_delete_candidate_p): Likewise.
	(mark_stmt_if_obviously_necessary): Use operator_new_candidate_p
	and operator_delete_candidate_p in order to detect operators
	that are not not clones.
	(mark_all_reaching_defs_necessary_1): Likewise.
	(propagate_necessity): Likewise.
	(eliminate_unnecessary_stmts): Likewise.
---
 gcc/gimple.c       | 12 ----------
 gcc/gimple.h       |  1 -
 gcc/tree-ssa-dce.c | 59 ++++++++++++++++++++++++++--------------------
 3 files changed, 34 insertions(+), 38 deletions(-)

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..684b8831b4d 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2707,18 +2707,6 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   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
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..7a1e1f49099 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1548,7 +1548,6 @@ 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_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/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index afb7bd9dedc..05d30e6c839 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -114,6 +114,25 @@ static bool cfg_altered;
 /* When non-NULL holds map from basic block index into the postorder.  */
 static int *bb_postorder;
 
+/* Return true when FNDECL is a new operator and not a clone.  */
+
+static bool
+operator_new_candidate_p (tree fndecl)
+{
+  return (fndecl != NULL_TREE
+	  && DECL_IS_OPERATOR_NEW_P (fndecl)
+	  && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE);
+}
+
+/* Return true when FNDECL is a delete operator and not a clone.  */
+
+static bool
+operator_delete_candidate_p (tree fndecl)
+{
+  return (fndecl != NULL_TREE
+	  && DECL_IS_OPERATOR_DELETE_P (fndecl)
+	  && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE);
+}
 
 /* True if we should treat any stmt with a vdef as necessary.  */
 
@@ -248,7 +267,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	if (callee != NULL_TREE
 	    && flag_allocation_dce
-	    && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+	    && operator_new_candidate_p (callee))
 	  return;
 
 	/* Most, but not all function calls are required.  Function calls that
@@ -613,8 +632,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 	  }
 
       if (callee != NULL_TREE
-	  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-	      || DECL_IS_OPERATOR_DELETE_P (callee)))
+	  && (operator_new_candidate_p (callee)
+	      || operator_delete_candidate_p (callee)))
 	return false;
     }
 
@@ -806,15 +825,10 @@ propagate_necessity (bool aggressive)
 	     processing the argument.  */
 	  bool is_delete_operator
 	    = (is_gimple_call (stmt)
-	       && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+	       && operator_delete_candidate_p (gimple_call_fndecl (as_a <gcall *> (stmt))));
 	  if (is_delete_operator
 	      || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) == 0)
-		continue;
-
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
 	      tree def_callee;
@@ -827,7 +841,7 @@ propagate_necessity (bool aggressive)
 		       && (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)))
+		      || operator_new_candidate_p (def_callee)))
 		{
 		  /* Delete operators can have alignment and (or) size as next
 		     arguments.  When being a SSA_NAME, they must be marked
@@ -900,8 +914,8 @@ propagate_necessity (bool aggressive)
 		continue;
 
 	      if (callee != NULL_TREE
-		  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-		      || DECL_IS_OPERATOR_DELETE_P (callee)))
+		  && (operator_new_candidate_p (callee)
+		      || operator_delete_candidate_p (callee)))
 		continue;
 
 	      /* Calls implicitly load from memory, their arguments
@@ -1326,20 +1340,15 @@ eliminate_unnecessary_stmts (void)
 	  if (gimple_plf (stmt, STMT_NECESSARY)
 	      && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
 		  || (is_gimple_call (stmt)
-		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
+		      && operator_delete_candidate_p (gimple_call_fndecl (as_a <gcall *> (stmt))))))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) > 0)
+	      tree ptr = gimple_call_arg (stmt, 0);
+	      if (TREE_CODE (ptr) == SSA_NAME)
 		{
-		  tree ptr = gimple_call_arg (stmt, 0);
-		  if (TREE_CODE (ptr) == SSA_NAME)
-		    {
-		      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
-		      if (!gimple_nop_p (def_stmt)
-			  && !gimple_plf (def_stmt, STMT_NECESSARY))
-			gimple_set_plf (stmt, STMT_NECESSARY, false);
-		    }
+		  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+		  if (!gimple_nop_p (def_stmt)
+		      && !gimple_plf (def_stmt, STMT_NECESSARY))
+		    gimple_set_plf (stmt, STMT_NECESSARY, false);
 		}
 	    }
 
@@ -1394,7 +1403,7 @@ eliminate_unnecessary_stmts (void)
 			       && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
 			       && !ALLOCA_FUNCTION_CODE_P
 			       (DECL_FUNCTION_CODE (call))))
-			  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
+			  && !operator_new_candidate_p (call))))
 		{
 		  something_changed = true;
 		  if (dump_file && (dump_flags & TDF_DETAILS))
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-06 15:35                                     ` [PATCH] Detect not-cloned new/delete operators " Martin Liška
@ 2019-08-06 15:59                                       ` Marc Glisse
  2019-08-07  9:31                                         ` Martin Liška
  2019-08-06 17:30                                       ` Martin Jambor
  1 sibling, 1 reply; 91+ messages in thread
From: Marc Glisse @ 2019-08-06 15:59 UTC (permalink / raw)
  To: Martin Liška
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Tue, 6 Aug 2019, Martin Liška wrote:

> Anyway, I'm sending patch that considers only such new/delete operators
> that are not a clone of an original type. That should make the current
> DCE code more solid.

DECL_IS_REPLACEABLE_OPERATOR_NEW_P seems to have been replaced with 
DECL_IS_OPERATOR_NEW_P. Is that on purpose?

I like your cleanup of having a single function to decide if this is the 
kind of operator new/delete DCE can handle, but you may have introduced 
long lines in the substitution.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-06 15:35                                     ` [PATCH] Detect not-cloned new/delete operators " Martin Liška
  2019-08-06 15:59                                       ` Marc Glisse
@ 2019-08-06 17:30                                       ` Martin Jambor
  2019-08-07  8:56                                         ` Martin Liška
  1 sibling, 1 reply; 91+ messages in thread
From: Martin Jambor @ 2019-08-06 17:30 UTC (permalink / raw)
  To: Martin Liška, Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka

Hi,

unfortunately I cannot look into the problem now and I don't have my
phone set up to review patches in a sane way, but to answer your
question below...


On Tue, Aug 06 2019, Martin Liška wrote:
> On 8/6/19 2:42 PM, Martin Liška wrote:

...

>> Hm, strange that the ISRA clones don't have n->clone_of set. It's created here:
>> 
...

>> 
>> @Martin, @Honza: Why do we not set clone_of in this transformation?
>
...node->clone_of is set only while a clone created in the true IPA
stages has no body on its own and shares the body with the
original. These clones form a tree and their clone_of is cleared when
they get a body.  IPA-SRA is not a true IPA pass and the clones it
creates are created with create_clone_with_body (or similarly named)
method which immediately gives them a body, so setting clone_of would be
wrong. (The new IPA-SRA is a true IPA pass and so its clones have phase
when their clone_of is set).

When an IPA-stage clone gets its body (when it is materialized),
node->former_clone_of gets set to the decl (as opposed to cgraph_node)
of the original node and hopefully create_clone_with_body sets it
too. Can you perhaps use that?

> If I'm correct cgraph_node::clone is used for inline clones only?
>

IPA-CP also creates clones, it does so by calling
cgraph_node::create_virtual_clone but that also sets clone_of.

Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-06 17:30                                       ` Martin Jambor
@ 2019-08-07  8:56                                         ` Martin Liška
  0 siblings, 0 replies; 91+ messages in thread
From: Martin Liška @ 2019-08-07  8:56 UTC (permalink / raw)
  To: Martin Jambor, Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka

On 8/6/19 7:02 PM, Martin Jambor wrote:
> Hi,
> 
> unfortunately I cannot look into the problem now and I don't have my
> phone set up to review patches in a sane way, but to answer your
> question below...

Thank you Martin for answer. It can definitely wait once you're back
at the office.

> 
> 
> On Tue, Aug 06 2019, Martin Liška wrote:
>> On 8/6/19 2:42 PM, Martin Liška wrote:
> 
> ...
> 
>>> Hm, strange that the ISRA clones don't have n->clone_of set. It's created here:
>>>
> ...
> 
>>>
>>> @Martin, @Honza: Why do we not set clone_of in this transformation?
>>
> ...node->clone_of is set only while a clone created in the true IPA
> stages has no body on its own and shares the body with the
> original. These clones form a tree and their clone_of is cleared when
> they get a body.  IPA-SRA is not a true IPA pass and the clones it
> creates are created with create_clone_with_body (or similarly named)
> method which immediately gives them a body, so setting clone_of would be
> wrong. (The new IPA-SRA is a true IPA pass and so its clones have phase
> when their clone_of is set).
> 
> When an IPA-stage clone gets its body (when it is materialized),
> node->former_clone_of gets set to the decl (as opposed to cgraph_node)
> of the original node and hopefully create_clone_with_body sets it
> too. Can you perhaps use that?
> 
>> If I'm correct cgraph_node::clone is used for inline clones only?
>>
> 
> IPA-CP also creates clones, it does so by calling
> cgraph_node::create_virtual_clone but that also sets clone_of.

Hm, I can see neither of cgraph_node::clone_of and cgraph_node::former_clone_of set
for my ISRA clone:

grep clone /tmp/node
  next_sibling_clone = <cgraph_node * 0x0>, 
  prev_sibling_clone = <cgraph_node * 0x0>, 
  clones = <cgraph_node * 0x0>, 
  clone_of = <cgraph_node * 0x0>, 
  former_clone_of = <tree 0x0>, 
  simdclone = 0x0, 
  simd_clones = <cgraph_node * 0x0>, 
  clone = {
  tm_clone = 0, 

Anyway, I'm planning to use DECL_ABSTRACT_ORIGIN here.

Martin

> 
> Martin
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-06 15:59                                       ` Marc Glisse
@ 2019-08-07  9:31                                         ` Martin Liška
  2019-08-07 10:15                                           ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-07  9:31 UTC (permalink / raw)
  To: Marc Glisse
  Cc: H.J. Lu, David Malcolm, GCC Patches, Richard Biener,
	dominik.infuehr, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 768 bytes --]

On 8/6/19 5:44 PM, Marc Glisse wrote:
> On Tue, 6 Aug 2019, Martin Liška wrote:
> 
>> Anyway, I'm sending patch that considers only such new/delete operators
>> that are not a clone of an original type. That should make the current
>> DCE code more solid.
> 
> DECL_IS_REPLACEABLE_OPERATOR_NEW_P seems to have been replaced with DECL_IS_OPERATOR_NEW_P. Is that on purpose?

Whoops, that was not intentional, thanks for heads up.

> 
> I like your cleanup of having a single function to decide if this is the kind of operator new/delete DCE can handle, but you may have introduced long lines in the substitution.
> 

Long lines should be fixed now as well.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Detect-not-cloned-new-delete-operators-in-DCE.patch --]
[-- Type: text/x-patch, Size: 7245 bytes --]

From 6ccff415a8931558cf7f1a01b34daec999e9f5af Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 6 Aug 2019 16:14:48 +0200
Subject: [PATCH] Detect not-cloned new/delete operators in DCE.

gcc/ChangeLog:

2019-08-06  Martin Liska  <mliska@suse.cz>

	* gimple.c (gimple_call_operator_delete_p): Remove.
	* gimple.h (gimple_call_operator_delete_p): Likewise.
	* tree-ssa-dce.c (operator_new_candidate_p): New.
	(operator_delete_candidate_p): Likewise.
	(mark_stmt_if_obviously_necessary): Use operator_new_candidate_p
	and operator_delete_candidate_p in order to detect operators
	that are not not clones.
	(mark_all_reaching_defs_necessary_1): Likewise.
	(propagate_necessity): Likewise.
	(eliminate_unnecessary_stmts): Likewise.
---
 gcc/gimple.c       | 12 ---------
 gcc/gimple.h       |  1 -
 gcc/tree-ssa-dce.c | 63 ++++++++++++++++++++++++++++------------------
 3 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..684b8831b4d 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2707,18 +2707,6 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   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
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..7a1e1f49099 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1548,7 +1548,6 @@ 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_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/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index afb7bd9dedc..66eb085b65f 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -114,6 +114,25 @@ static bool cfg_altered;
 /* When non-NULL holds map from basic block index into the postorder.  */
 static int *bb_postorder;
 
+/* Return true when FNDECL is a new operator and not a clone.  */
+
+static bool
+operator_new_candidate_p (tree fndecl)
+{
+  return (fndecl != NULL_TREE
+	  && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
+	  && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE);
+}
+
+/* Return true when FNDECL is a delete operator and not a clone.  */
+
+static bool
+operator_delete_candidate_p (tree fndecl)
+{
+  return (fndecl != NULL_TREE
+	  && DECL_IS_OPERATOR_DELETE_P (fndecl)
+	  && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE);
+}
 
 /* True if we should treat any stmt with a vdef as necessary.  */
 
@@ -248,7 +267,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	if (callee != NULL_TREE
 	    && flag_allocation_dce
-	    && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+	    && operator_new_candidate_p (callee))
 	  return;
 
 	/* Most, but not all function calls are required.  Function calls that
@@ -613,8 +632,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 	  }
 
       if (callee != NULL_TREE
-	  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-	      || DECL_IS_OPERATOR_DELETE_P (callee)))
+	  && (operator_new_candidate_p (callee)
+	      || operator_delete_candidate_p (callee)))
 	return false;
     }
 
@@ -800,21 +819,18 @@ propagate_necessity (bool aggressive)
 	     which feed this statement's uses as necessary.  */
 	  ssa_op_iter iter;
 	  tree use;
+	  tree fndecl;
 
 	  /* If this is a call to free which is directly fed by an
 	     allocation function do not mark that necessary through
 	     processing the argument.  */
 	  bool is_delete_operator
 	    = (is_gimple_call (stmt)
-	       && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+	       && (fndecl = gimple_call_fndecl (as_a <gcall *> (stmt)))
+	       && operator_delete_candidate_p (fndecl));
 	  if (is_delete_operator
 	      || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) == 0)
-		continue;
-
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
 	      tree def_callee;
@@ -827,7 +843,7 @@ propagate_necessity (bool aggressive)
 		       && (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)))
+		      || operator_new_candidate_p (def_callee)))
 		{
 		  /* Delete operators can have alignment and (or) size as next
 		     arguments.  When being a SSA_NAME, they must be marked
@@ -900,8 +916,8 @@ propagate_necessity (bool aggressive)
 		continue;
 
 	      if (callee != NULL_TREE
-		  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-		      || DECL_IS_OPERATOR_DELETE_P (callee)))
+		  && (operator_new_candidate_p (callee)
+		      || operator_delete_candidate_p (callee)))
 		continue;
 
 	      /* Calls implicitly load from memory, their arguments
@@ -1313,6 +1329,7 @@ eliminate_unnecessary_stmts (void)
       auto_bitmap debug_seen;
       for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi)
 	{
+	  tree fndecl;
 	  stmt = gsi_stmt (gsi);
 
 	  psi = gsi;
@@ -1326,20 +1343,16 @@ eliminate_unnecessary_stmts (void)
 	  if (gimple_plf (stmt, STMT_NECESSARY)
 	      && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
 		  || (is_gimple_call (stmt)
-		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
+		      && (fndecl = gimple_call_fndecl (as_a <gcall *> (stmt)))
+		      && operator_delete_candidate_p (fndecl))))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) > 0)
+	      tree ptr = gimple_call_arg (stmt, 0);
+	      if (TREE_CODE (ptr) == SSA_NAME)
 		{
-		  tree ptr = gimple_call_arg (stmt, 0);
-		  if (TREE_CODE (ptr) == SSA_NAME)
-		    {
-		      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
-		      if (!gimple_nop_p (def_stmt)
-			  && !gimple_plf (def_stmt, STMT_NECESSARY))
-			gimple_set_plf (stmt, STMT_NECESSARY, false);
-		    }
+		  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+		  if (!gimple_nop_p (def_stmt)
+		      && !gimple_plf (def_stmt, STMT_NECESSARY))
+		    gimple_set_plf (stmt, STMT_NECESSARY, false);
 		}
 	    }
 
@@ -1394,7 +1407,7 @@ eliminate_unnecessary_stmts (void)
 			       && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
 			       && !ALLOCA_FUNCTION_CODE_P
 			       (DECL_FUNCTION_CODE (call))))
-			  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
+			  && !operator_new_candidate_p (call))))
 		{
 		  something_changed = true;
 		  if (dump_file && (dump_flags & TDF_DETAILS))
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-06 14:07                                   ` Martin Liška
  2019-08-06 15:35                                     ` [PATCH] Detect not-cloned new/delete operators " Martin Liška
@ 2019-08-07  9:54                                     ` Richard Biener
  2019-08-07 11:36                                       ` Martin Liška
  1 sibling, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-08-07  9:54 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Tue, Aug 6, 2019 at 2:42 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/5/19 3:46 PM, Marc Glisse wrote:
> > On Mon, 5 Aug 2019, Martin Liška wrote:
> >
> >> You are right. It can really lead to confusion of the DCE.
> >>
> >> What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate operators
> >> that were somehow modified by an IPA optimization.
> >
> > Looks similar to the cgraph_node->clone_of that Richard was talking about. I have no idea which one would be best.
>
>
> Hm, strange that the ISRA clones don't have n->clone_of set. It's created here:
>
> #0  cgraph_node::create (decl=<function_decl 0x7ffff721c300 _ZN1AdlEPvd.isra.0>) at /home/marxin/Programming/gcc/gcc/profile-count.h:751
> #1  0x0000000000bc8342 in cgraph_node::create_version_clone (this=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, new_decl=<optimized out>, redirect_callers=..., bbs_to_copy=0x0, suffix=0x1b74427 "isra") at /home/marxin/Programming/gcc/gcc/cgraphclones.c:960
> #2  0x0000000000bc9b9a in cgraph_node::create_version_clone_with_body (this=this@entry=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, redirect_callers=redirect_callers@entry=..., tree_map=tree_map@entry=0x0, args_to_skip=args_to_skip@entry=0x0,
>     skip_return=skip_return@entry=false, bbs_to_copy=bbs_to_copy@entry=0x0, new_entry_block=<optimized out>, suffix=<optimized out>, target_attributes=<optimized out>) at /home/marxin/Programming/gcc/gcc/cgraphclones.c:1071
> #3  0x00000000010e4611 in modify_function (adjustments=..., node=<cgraph_node * 0x7ffff7208000 "operator delete"/64>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5493
> #4  ipa_early_sra () at /home/marxin/Programming/gcc/gcc/tree-sra.c:5731
> #5  (anonymous namespace)::pass_early_ipa_sra::execute (this=<optimized out>) at /home/marxin/Programming/gcc/gcc/tree-sra.c:5778
>
> @Martin, @Honza: Why do we not set clone_of in this transformation?
>
> >
> >> Do you believe it will be sufficient?
> >
> > In DCE only consider the operator delete that are not clones? (possibly the same for operator new? I don't know how much we can change the return value of a function in a clone) I guess that should work, and it wouldn't impact the common case with default, global operator new/delete.
>
> I tent to limit that the only cgraph nodes that are not clones. I'm going to prepare a patch for it.

I think the simplest way to achieve this is to not copy, aka clear,
DECL_IS_OPERATOR_* when cloning and removing arguments
(cloning for a constant align argument should be OK for example, as is
for a constant address).  Or simply always when cloning.

Richard.

> >
> > An alternative would be to clear the DECL_IS_OPERATOR_DELETE flag when creating a clone (possibly only if it modified the first parameter?). There is probably not much information in the fact that a function that doesn't even take a pointer used to be an operator delete.
> >
> >
> > By the way, I just thought of something, now that we handle class-specific operator new/delete (but you could do the same with the global replacable ones as well):
> >
> > #include <stdio.h>
> > int count = 0;
> > struct A {
> >   __attribute__((malloc,noinline))
> >   static void* operator new(unsigned long sz){++count;return ::operator new(sz);}
> >   static void operator delete(void* ptr){--count;::operator delete(ptr);}
> > };
> > int main(){
> >   delete new A;
> >   printf("%d\n",count);
> > }
> >
> > If we do not inline anything, we can remove the pair and nothing touches count. If we inline both new and delete, we can then remove the inner pair instead, count increases and decreases, fine. If we inline only one of them, and DCE the mismatched pair new/delete, we get something inconsistent (count is -1).
> >
> > This seems to indicate we should check that the new and delete match somehow...
> >
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Detect not-cloned new/delete operators in DCE.
  2019-08-07  9:31                                         ` Martin Liška
@ 2019-08-07 10:15                                           ` Richard Biener
  0 siblings, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-08-07 10:15 UTC (permalink / raw)
  To: Martin Liška
  Cc: Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Wed, Aug 7, 2019 at 10:56 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/6/19 5:44 PM, Marc Glisse wrote:
> > On Tue, 6 Aug 2019, Martin Liška wrote:
> >
> >> Anyway, I'm sending patch that considers only such new/delete operators
> >> that are not a clone of an original type. That should make the current
> >> DCE code more solid.
> >
> > DECL_IS_REPLACEABLE_OPERATOR_NEW_P seems to have been replaced with DECL_IS_OPERATOR_NEW_P. Is that on purpose?
>
> Whoops, that was not intentional, thanks for heads up.
>
> >
> > I like your cleanup of having a single function to decide if this is the kind of operator new/delete DCE can handle, but you may have introduced long lines in the substitution.
> >
>
> Long lines should be fixed now as well.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>
> Ready to be installed?

As said in the other thread I prefer you unsed DECL_IS_OPERATOR_* when
cloning.  As much as
I dislike void memcpy (int yeah, double foo); be represented as
BUILT_IN_MEMCPY I dislike
an operator that doesn't follow its signature as such.

If you go as far as looking at the abstract origin you could figure
the original param position
by looking at the to-be-DCEd operator invocations DECL_ARGUMENTS, look at _its_
abstract origin and match that up when walking the operators abstract
origin DECL_ARGUMENTS...

But I think this is all hardly worth the trouble.

Richard.

> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-07  9:54                                     ` [PATCH] Handle new operators with no arguments " Richard Biener
@ 2019-08-07 11:36                                       ` Martin Liška
  2019-08-07 11:51                                         ` Jakub Jelinek
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-07 11:36 UTC (permalink / raw)
  To: Richard Biener
  Cc: Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]

On 8/7/19 11:51 AM, Richard Biener wrote:
> I think the simplest way to achieve this is to not copy, aka clear,
> DECL_IS_OPERATOR_* when cloning and removing arguments
> (cloning for a constant align argument should be OK for example, as is
> for a constant address).  Or simply always when cloning.

Ok, then I'm suggesting following tested patch.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-When-cloning-set-operator-new-delete-to-false.patch --]
[-- Type: text/x-patch, Size: 1434 bytes --]

From b7ed2c7c208e96ecff77a0127570a858a486c0b8 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Wed, 7 Aug 2019 12:00:58 +0200
Subject: [PATCH] When cloning set operator new/delete to false.

gcc/ChangeLog:

2019-08-07  Martin Liska  <mliska@suse.cz>

	* cgraphclones.c (set_new_clone_decl_and_node_flags): Drop
	IS_OPERATOR_NEW and IS_OPERATOR_DELETE.
	(create_version_clone_with_body): Likewise.
---
 gcc/cgraphclones.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index fd867ecac91..28cf2ecc411 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -248,6 +248,8 @@ set_new_clone_decl_and_node_flags (cgraph_node *new_node)
   DECL_VIRTUAL_P (new_node->decl) = 0;
   DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0;
   DECL_STATIC_DESTRUCTOR (new_node->decl) = 0;
+  DECL_SET_IS_OPERATOR_NEW (new_node->decl, 0);
+  DECL_SET_IS_OPERATOR_DELETE (new_node->decl, 0);
 
   new_node->externally_visible = 0;
   new_node->local.local = 1;
@@ -1065,6 +1067,8 @@ cgraph_node::create_version_clone_with_body
   /* When the old decl was a con-/destructor make sure the clone isn't.  */
   DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
   DECL_STATIC_DESTRUCTOR (new_decl) = 0;
+  DECL_SET_IS_OPERATOR_NEW (new_decl, 0);
+  DECL_SET_IS_OPERATOR_DELETE (new_decl, 0);
 
   /* Create the new version's call-graph node.
      and update the edges of the new node. */
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-07 11:36                                       ` Martin Liška
@ 2019-08-07 11:51                                         ` Jakub Jelinek
  2019-08-07 12:06                                           ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Jakub Jelinek @ 2019-08-07 11:51 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
> On 8/7/19 11:51 AM, Richard Biener wrote:
> > I think the simplest way to achieve this is to not copy, aka clear,
> > DECL_IS_OPERATOR_* when cloning and removing arguments
> > (cloning for a constant align argument should be OK for example, as is
> > for a constant address).  Or simply always when cloning.
> 
> Ok, then I'm suggesting following tested patch.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
way invalidate that too, i.e. shouldn't it be just 
  FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;
instead?  On the other side, if the cloning doesn't change arguments in any
way, do we still want to clear those flags?

	Jakub

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-07 11:51                                         ` Jakub Jelinek
@ 2019-08-07 12:06                                           ` Martin Liška
  2019-08-07 14:35                                             ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-07 12:06 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Biener, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On 8/7/19 12:51 PM, Jakub Jelinek wrote:
> On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
>> On 8/7/19 11:51 AM, Richard Biener wrote:
>>> I think the simplest way to achieve this is to not copy, aka clear,
>>> DECL_IS_OPERATOR_* when cloning and removing arguments
>>> (cloning for a constant align argument should be OK for example, as is
>>> for a constant address).  Or simply always when cloning.
>>
>> Ok, then I'm suggesting following tested patch.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
> way invalidate that too, i.e. shouldn't it be just 
>   FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;

Well, how are lambdas involved in the new/delete DCE here? Lambdas with removed
arguments should not interfere here.

> instead?  On the other side, if the cloning doesn't change arguments in any
> way, do we still want to clear those flags?

Well, I would consider it safer to drop it always.

Martin

> 
> 	Jakub
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-07 12:06                                           ` Martin Liška
@ 2019-08-07 14:35                                             ` Richard Biener
  2019-08-08  9:01                                               ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Richard Biener @ 2019-08-07 14:35 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jakub Jelinek, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Wed, Aug 7, 2019 at 2:04 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/7/19 12:51 PM, Jakub Jelinek wrote:
> > On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
> >> On 8/7/19 11:51 AM, Richard Biener wrote:
> >>> I think the simplest way to achieve this is to not copy, aka clear,
> >>> DECL_IS_OPERATOR_* when cloning and removing arguments
> >>> (cloning for a constant align argument should be OK for example, as is
> >>> for a constant address).  Or simply always when cloning.
> >>
> >> Ok, then I'm suggesting following tested patch.
> >>
> >> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >
> > What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
> > way invalidate that too, i.e. shouldn't it be just
> >   FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;
>
> Well, how are lambdas involved in the new/delete DCE here? Lambdas with removed
> arguments should not interfere here.

But for coverage where we do

  gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
                       && !DECL_FUNCTION_VERSIONED (current_function_decl)
                       && !DECL_LAMBDA_FUNCTION_P (current_function_decl));

all clones should be considered artificial?

Anyway, your patch is OK, we can think about lambdas separately.  Can you
simplify the DCE code after the patch?

Thanks,
Richard.

> > instead?  On the other side, if the cloning doesn't change arguments in any
> > way, do we still want to clear those flags?
>
> Well, I would consider it safer to drop it always.
>
> Martin
>
> >
> >       Jakub
> >
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-07 14:35                                             ` Richard Biener
@ 2019-08-08  9:01                                               ` Martin Liška
  2019-08-15 11:06                                                 ` Martin Liška
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-08  9:01 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

[-- Attachment #1: Type: text/plain, Size: 1923 bytes --]

On 8/7/19 4:12 PM, Richard Biener wrote:
> On Wed, Aug 7, 2019 at 2:04 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 8/7/19 12:51 PM, Jakub Jelinek wrote:
>>> On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
>>>> On 8/7/19 11:51 AM, Richard Biener wrote:
>>>>> I think the simplest way to achieve this is to not copy, aka clear,
>>>>> DECL_IS_OPERATOR_* when cloning and removing arguments
>>>>> (cloning for a constant align argument should be OK for example, as is
>>>>> for a constant address).  Or simply always when cloning.
>>>>
>>>> Ok, then I'm suggesting following tested patch.
>>>>
>>>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>>
>>> What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
>>> way invalidate that too, i.e. shouldn't it be just
>>>   FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;
>>
>> Well, how are lambdas involved in the new/delete DCE here? Lambdas with removed
>> arguments should not interfere here.
> 
> But for coverage where we do
> 
>   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
>                        && !DECL_FUNCTION_VERSIONED (current_function_decl)
>                        && !DECL_LAMBDA_FUNCTION_P (current_function_decl));
> 
> all clones should be considered artificial?

Well, from coverage perspective most of them are fine.

> 
> Anyway, your patch is OK, we can think about lambdas separately.  Can you
> simplify the DCE code after the patch?

I installed the patch and I'm sending the follow up cleanup.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

> 
> Thanks,
> Richard.
> 
>>> instead?  On the other side, if the cloning doesn't change arguments in any
>>> way, do we still want to clear those flags?
>>
>> Well, I would consider it safer to drop it always.
>>
>> Martin
>>
>>>
>>>       Jakub
>>>
>>


[-- Attachment #2: 0001-Clean-up-dead-condition-for-operators-in-DCE.patch --]
[-- Type: text/x-patch, Size: 1983 bytes --]

From 9da5bd0a2c81a20807caf9cc6915971067b021c3 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 8 Aug 2019 09:58:34 +0200
Subject: [PATCH] Clean up dead condition for operators in DCE.

gcc/ChangeLog:

2019-08-08  Martin Liska  <mliska@suse.cz>

	* tree-ssa-dce.c (propagate_necessity): We can't reach now
	operators with no arguments.
	(eliminate_unnecessary_stmts): Likewise here.
---
 gcc/tree-ssa-dce.c | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index afb7bd9dedc..80d5f5c30f7 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -810,11 +810,6 @@ propagate_necessity (bool aggressive)
 	  if (is_delete_operator
 	      || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) == 0)
-		continue;
-
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
 	      tree def_callee;
@@ -1328,18 +1323,13 @@ eliminate_unnecessary_stmts (void)
 		  || (is_gimple_call (stmt)
 		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
 	    {
-	      /* It can happen that a user delete operator has the pointer
-		 argument optimized out already.  */
-	      if (gimple_call_num_args (stmt) > 0)
+	      tree ptr = gimple_call_arg (stmt, 0);
+	      if (TREE_CODE (ptr) == SSA_NAME)
 		{
-		  tree ptr = gimple_call_arg (stmt, 0);
-		  if (TREE_CODE (ptr) == SSA_NAME)
-		    {
-		      gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
-		      if (!gimple_nop_p (def_stmt)
-			  && !gimple_plf (def_stmt, STMT_NECESSARY))
-			gimple_set_plf (stmt, STMT_NECESSARY, false);
-		    }
+		  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr);
+		  if (!gimple_nop_p (def_stmt)
+		      && !gimple_plf (def_stmt, STMT_NECESSARY))
+		    gimple_set_plf (stmt, STMT_NECESSARY, false);
 		}
 	    }
 
-- 
2.22.0


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-08  9:01                                               ` Martin Liška
@ 2019-08-15 11:06                                                 ` Martin Liška
  2019-08-15 11:35                                                   ` Richard Biener
  0 siblings, 1 reply; 91+ messages in thread
From: Martin Liška @ 2019-08-15 11:06 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

PING^1

On 8/8/19 10:43 AM, Martin Liška wrote:
> On 8/7/19 4:12 PM, Richard Biener wrote:
>> On Wed, Aug 7, 2019 at 2:04 PM Martin Liška <mliska@suse.cz> wrote:
>>>
>>> On 8/7/19 12:51 PM, Jakub Jelinek wrote:
>>>> On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
>>>>> On 8/7/19 11:51 AM, Richard Biener wrote:
>>>>>> I think the simplest way to achieve this is to not copy, aka clear,
>>>>>> DECL_IS_OPERATOR_* when cloning and removing arguments
>>>>>> (cloning for a constant align argument should be OK for example, as is
>>>>>> for a constant address).  Or simply always when cloning.
>>>>>
>>>>> Ok, then I'm suggesting following tested patch.
>>>>>
>>>>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>>>
>>>> What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
>>>> way invalidate that too, i.e. shouldn't it be just
>>>>   FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;
>>>
>>> Well, how are lambdas involved in the new/delete DCE here? Lambdas with removed
>>> arguments should not interfere here.
>>
>> But for coverage where we do
>>
>>   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
>>                        && !DECL_FUNCTION_VERSIONED (current_function_decl)
>>                        && !DECL_LAMBDA_FUNCTION_P (current_function_decl));
>>
>> all clones should be considered artificial?
> 
> Well, from coverage perspective most of them are fine.
> 
>>
>> Anyway, your patch is OK, we can think about lambdas separately.  Can you
>> simplify the DCE code after the patch?
> 
> I installed the patch and I'm sending the follow up cleanup.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Thanks,
> Martin
> 
>>
>> Thanks,
>> Richard.
>>
>>>> instead?  On the other side, if the cloning doesn't change arguments in any
>>>> way, do we still want to clear those flags?
>>>
>>> Well, I would consider it safer to drop it always.
>>>
>>> Martin
>>>
>>>>
>>>>       Jakub
>>>>
>>>
> 

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] Handle new operators with no arguments in DCE.
  2019-08-15 11:06                                                 ` Martin Liška
@ 2019-08-15 11:35                                                   ` Richard Biener
  0 siblings, 0 replies; 91+ messages in thread
From: Richard Biener @ 2019-08-15 11:35 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jakub Jelinek, Marc Glisse, H.J. Lu, David Malcolm, GCC Patches,
	dominik.infuehr, Jan Hubicka, Martin Jambor

On Thu, Aug 15, 2019 at 12:47 PM Martin Liška <mliska@suse.cz> wrote:
>
> PING^1

OK

> On 8/8/19 10:43 AM, Martin Liška wrote:
> > On 8/7/19 4:12 PM, Richard Biener wrote:
> >> On Wed, Aug 7, 2019 at 2:04 PM Martin Liška <mliska@suse.cz> wrote:
> >>>
> >>> On 8/7/19 12:51 PM, Jakub Jelinek wrote:
> >>>> On Wed, Aug 07, 2019 at 12:44:28PM +0200, Martin Liška wrote:
> >>>>> On 8/7/19 11:51 AM, Richard Biener wrote:
> >>>>>> I think the simplest way to achieve this is to not copy, aka clear,
> >>>>>> DECL_IS_OPERATOR_* when cloning and removing arguments
> >>>>>> (cloning for a constant align argument should be OK for example, as is
> >>>>>> for a constant address).  Or simply always when cloning.
> >>>>>
> >>>>> Ok, then I'm suggesting following tested patch.
> >>>>>
> >>>>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >>>>
> >>>> What about LAMBDA_FUNCTION, doesn't cloning which changes arguments in any
> >>>> way invalidate that too, i.e. shouldn't it be just
> >>>>   FUNCTION_DECL_DECL_TYPE (new_node->decl) = NONE;
> >>>
> >>> Well, how are lambdas involved in the new/delete DCE here? Lambdas with removed
> >>> arguments should not interfere here.
> >>
> >> But for coverage where we do
> >>
> >>   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
> >>                        && !DECL_FUNCTION_VERSIONED (current_function_decl)
> >>                        && !DECL_LAMBDA_FUNCTION_P (current_function_decl));
> >>
> >> all clones should be considered artificial?
> >
> > Well, from coverage perspective most of them are fine.
> >
> >>
> >> Anyway, your patch is OK, we can think about lambdas separately.  Can you
> >> simplify the DCE code after the patch?
> >
> > I installed the patch and I'm sending the follow up cleanup.
> >
> > Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >
> > Ready to be installed?
> > Thanks,
> > Martin
> >
> >>
> >> Thanks,
> >> Richard.
> >>
> >>>> instead?  On the other side, if the cloning doesn't change arguments in any
> >>>> way, do we still want to clear those flags?
> >>>
> >>> Well, I would consider it safer to drop it always.
> >>>
> >>> Martin
> >>>
> >>>>
> >>>>       Jakub
> >>>>
> >>>
> >
>

^ permalink raw reply	[flat|nested] 91+ messages in thread

end of thread, other threads:[~2019-08-15 11:24 UTC | newest]

Thread overview: 91+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-21 11:35 [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Dominik Inführ
2017-11-21 17:13 ` Jeff Law
2017-11-21 17:36   ` Dominik Inführ
2017-11-21 17:45     ` Jeff Law
2017-11-22 10:40   ` Martin Jambor
2017-11-22 18:03     ` Jeff Law
2017-11-22  9:33 ` Richard Biener
2017-11-22 10:41   ` Jakub Jelinek
2017-11-27  9:57     ` Dominik Inführ
2017-11-27 10:48       ` Jakub Jelinek
2017-11-27 17:04       ` Jeff Law
2017-11-28 11:55         ` Richard Biener
2017-11-28 14:48           ` Jakub Jelinek
2017-11-29  8:13       ` Martin Sebor
2017-11-29  9:33         ` Jakub Jelinek
2017-11-29 16:29           ` Martin Sebor
2017-11-29 16:53             ` David Malcolm
2017-11-29 17:01               ` Andrew Pinski
2018-05-13 17:19               ` Marc Glisse
2019-07-02 11:49                 ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Liška
2019-07-02 11:50                   ` [PATCH 2/2] Extend DCE to remove unnecessary new/delete-pairs (PR c++/23383) Martin Liška
2019-08-02 21:34                     ` H.J. Lu
2019-08-05  6:44                       ` [PATCH] Handle new operators with no arguments in DCE Martin Liška
2019-08-05  7:08                         ` Marc Glisse
2019-08-05  9:53                           ` Martin Liška
2019-08-05 11:57                             ` Marc Glisse
2019-08-05 12:52                               ` Martin Liška
2019-08-05 13:46                                 ` Marc Glisse
2019-08-06 14:07                                   ` Martin Liška
2019-08-06 15:35                                     ` [PATCH] Detect not-cloned new/delete operators " Martin Liška
2019-08-06 15:59                                       ` Marc Glisse
2019-08-07  9:31                                         ` Martin Liška
2019-08-07 10:15                                           ` Richard Biener
2019-08-06 17:30                                       ` Martin Jambor
2019-08-07  8:56                                         ` Martin Liška
2019-08-07  9:54                                     ` [PATCH] Handle new operators with no arguments " Richard Biener
2019-08-07 11:36                                       ` Martin Liška
2019-08-07 11:51                                         ` Jakub Jelinek
2019-08-07 12:06                                           ` Martin Liška
2019-08-07 14:35                                             ` Richard Biener
2019-08-08  9:01                                               ` Martin Liška
2019-08-15 11:06                                                 ` Martin Liška
2019-08-15 11:35                                                   ` Richard Biener
2019-08-05 12:13                         ` Richard Biener
2019-07-02 16:02                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Martin Sebor
2019-07-02 17:15                   ` Marc Glisse
2019-07-03 15:03                     ` Martin Liška
2019-07-03 16:44                       ` Richard Biener
2019-07-04 22:21                         ` Marc Glisse
2019-07-08 13:02                           ` Martin Liška
2019-07-08 22:00                             ` Jason Merrill
2019-07-09  2:28                             ` Marc Glisse
2019-07-09  7:52                               ` Marc Glisse
2019-07-09  8:49                                 ` Martin Liška
2019-07-09 10:22                                   ` Marc Glisse
2019-07-09 21:02                                     ` Jason Merrill
2019-07-11  6:48                                       ` Martin Liška
2019-07-22 14:00                                         ` Martin Liška
2019-07-24 19:05                                         ` Jeff Law
2019-07-25 10:24                                           ` Richard Biener
2019-07-25  2:17                                         ` Marc Glisse
2019-07-25  8:34                                           ` Martin Liška
2019-07-25 12:21                                             ` Marc Glisse
2019-07-25 13:50                                               ` Martin Liška
2019-07-25 15:41                                                 ` Martin Liška
2019-07-28 21:50                                                   ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Martin Liška
2019-07-29 10:03                                                     ` Richard Biener
2019-07-29 10:54                                                       ` Martin Liška
2019-07-29 14:40                                                         ` Richard Biener
2019-07-30  7:48                                                           ` Martin Liška
2019-07-30  8:09                                                             ` Martin Liška
2019-07-30  8:42                                                               ` Richard Biener
2019-07-30 10:20                                                                 ` Martin Liška
2019-07-30 10:28                                                                   ` Richard Biener
2019-07-30 12:08                                                                   ` Marc Glisse
2019-07-30 12:12                                                                     ` Martin Liška
2019-07-30 13:14                                                                       ` Marc Glisse
2019-07-30 13:41                                                                         ` Martin Liška
2019-07-30 14:37                                                                           ` Marc Glisse
2019-07-31  8:42                                                                             ` [PATCH] Mark necessary 2nd and later args for delete op Martin Liška
2019-07-31 10:24                                                                               ` Richard Biener
2019-07-31 10:00                                                                           ` [PATCH] Remove also 2nd argument for unused delete operator (PR tree-optimization/91270) Richard Biener
2019-07-29  9:59                                                   ` [PATCH 1/2] Come up with function_decl_type and use it in tree_function_decl Richard Biener
2017-11-29 18:05             ` [RFC][PATCH] Extend DCE to remove unnecessary new/delete-pairs Richard Biener
2017-12-04 12:20             ` Trevor Saunders
2017-12-01  1:24           ` Jeff Law
2017-12-01  1:23         ` Jeff Law
2017-11-22 13:03 ` Nathan Sidwell
2017-11-22 14:18   ` Richard Biener
2017-11-22 14:45     ` Nathan Sidwell
2017-11-22 21:45 ` Marc Glisse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).