List valid pairs for new and delete operators.
authorMartin Liska <mliska@suse.cz>
Thu, 16 Apr 2020 13:39:22 +0000 (15:39 +0200)
committerMartin Liska <mliska@suse.cz>
Thu, 16 Apr 2020 13:39:22 +0000 (15:39 +0200)
PR c++/94314
* cgraphclones.c (set_new_clone_decl_and_node_flags): Drop
DECL_IS_REPLACEABLE_OPERATOR during cloning.
* tree-ssa-dce.c (valid_new_delete_pair_p): New function.
(propagate_necessity): Check operator names.

PR c++/94314
* g++.dg/pr94314.C: Do not use dg-additional-options
and remove not needed stdio.h include.
* g++.dg/pr94314-2.C: Likewise.
* g++.dg/pr94314-3.C: Likewise.
* g++.dg/pr94314-4.C: New test.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
gcc/ChangeLog
gcc/cgraphclones.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr94314-2.C
gcc/testsuite/g++.dg/pr94314-3.C
gcc/testsuite/g++.dg/pr94314-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/pr94314.C
gcc/tree-ssa-dce.c

index 74dbeeb44c6a87cc50362db4d45e5fa196073672..9e499ec9c86c800f506b0327ce4e6cb3e4bfc357 100644 (file)
@@ -1,3 +1,12 @@
+2020-04-16  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/94314
+       * cgraphclones.c (set_new_clone_decl_and_node_flags): Drop
+       DECL_IS_REPLACEABLE_OPERATOR during cloning.
+       * tree-ssa-dce.c (valid_new_delete_pair_p): New function.
+       (propagate_necessity): Check operator names.
+
 2020-04-16  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR rtl-optimization/94605
index c73b8f810f0f0c896de1ebfdd13494a6d352f45b..8f541a28b6ec5ca922dbbc26d0e3de9ffb87b88f 100644 (file)
@@ -165,6 +165,7 @@ set_new_clone_decl_and_node_flags (cgraph_node *new_node)
   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);
+  DECL_IS_REPLACEABLE_OPERATOR (new_node->decl) = 0;
 
   new_node->externally_visible = 0;
   new_node->local = 1;
@@ -1030,6 +1031,7 @@ cgraph_node::create_version_clone_with_body
   DECL_STATIC_DESTRUCTOR (new_decl) = 0;
   DECL_SET_IS_OPERATOR_NEW (new_decl, 0);
   DECL_SET_IS_OPERATOR_DELETE (new_decl, 0);
+  DECL_IS_REPLACEABLE_OPERATOR (new_decl) = 0;
 
   /* Create the new version's call-graph node.
      and update the edges of the new node. */
index 756f1d759e6427fe6b20a9a59548ba39f19fa614..94d2312022de30db844246c5e3b28d6727a46f93 100644 (file)
@@ -1,3 +1,13 @@
+2020-04-16  Martin Liska  <mliska@suse.cz>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/94314
+       * g++.dg/pr94314.C: Do not use dg-additional-options
+       and remove not needed stdio.h include.
+       * g++.dg/pr94314-2.C: Likewise.
+       * g++.dg/pr94314-3.C: Likewise.
+       * g++.dg/pr94314-4.C: New test.
+
 2020-04-16  Patrick Palka  <ppalka@redhat.com>
 
        PR c++/94475
index 36b93ed6d4d3601e9bb35cafe6e6861c4cd0fce7..998ce6017673a3b2ce0ca4f6cd67b2cdac65b7b9 100644 (file)
@@ -1,9 +1,6 @@
 /* PR c++/94314.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-cddce-details" } */
-/* { dg-additional-options "-fdelete-null-pointer-checks" } */
-
-#include <stdio.h>
+/* { dg-options "-O2 -fdump-tree-cddce-details -fdelete-null-pointer-checks" } */
 
 struct A
 {
index 575ba9d8ad86f4a2141faaeb07299fbdb3f08c8f..846a5d6a3d81e87846e838160d2d559e78d1ddd4 100644 (file)
@@ -1,9 +1,6 @@
 /* PR c++/94314.  */
 /* { dg-do run } */
-/* { dg-options "-O2 --param early-inlining-insns=100 -fdump-tree-cddce-details" } */
-/* { dg-additional-options "-fdelete-null-pointer-checks" } */
-
-#include <stdio.h>
+/* { dg-options "-O2 --param early-inlining-insns=100 -fdump-tree-cddce-details -fdelete-null-pointer-checks" } */
 
 volatile int idx;
 
diff --git a/gcc/testsuite/g++.dg/pr94314-4.C b/gcc/testsuite/g++.dg/pr94314-4.C
new file mode 100644 (file)
index 0000000..d097f29
--- /dev/null
@@ -0,0 +1,30 @@
+/* PR c++/94314.  */
+/* { dg-do run { target c++11 } } */
+/* { dg-options "-O2 -fdump-tree-cddce-details -fdelete-null-pointer-checks" } */
+
+int count = 0;
+
+__attribute__((malloc, noinline)) void* operator new[](__SIZE_TYPE__ sz) {
+  ++count;
+  return ::operator new(sz);
+}
+
+void operator delete[](void* ptr) noexcept {
+  --count;
+  ::operator delete(ptr);
+}
+
+void operator delete[](void* ptr, __SIZE_TYPE__ sz) noexcept {
+  --count;
+  ::operator delete(ptr, sz);
+}
+
+int main() {
+  delete[] new int[1];
+  if (count != 0)
+    __builtin_abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "Deleting : operator delete" "cddce1"} } */
index 86e651d10ba6cb34389655fd0358141c188638e8..4e5ae122e9fe1b870359b9021a5450532c11f0c1 100644 (file)
@@ -1,9 +1,6 @@
 /* PR c++/94314.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-cddce-details" } */
-/* { dg-additional-options "-fdelete-null-pointer-checks" } */
-
-#include <stdio.h>
+/* { dg-options "-O2 -fdump-tree-cddce-details -fdelete-null-pointer-checks" } */
 
 struct A
 {
index fd5f24c746ca0359fdf5f883bfefeaf87e473848..757cfad5b5e18da3c4b6ca75a19235c0a648bb40 100644 (file)
@@ -646,6 +646,77 @@ degenerate_phi_p (gimple *phi)
   return true;
 }
 
+/* Return that NEW_CALL and DELETE_CALL are a valid pair of new
+   and delete  operators.  */
+
+static bool
+valid_new_delete_pair_p (gimple *new_call, gimple *delete_call)
+{
+  tree new_asm = DECL_ASSEMBLER_NAME (gimple_call_fndecl (new_call));
+  tree delete_asm = DECL_ASSEMBLER_NAME (gimple_call_fndecl (delete_call));
+  const char *new_name = IDENTIFIER_POINTER (new_asm);
+  const char *delete_name = IDENTIFIER_POINTER (delete_asm);
+  unsigned int new_len = IDENTIFIER_LENGTH (new_asm);
+  unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm);
+
+  if (new_len < 5 || delete_len < 6)
+    return false;
+  if (new_name[0] == '_')
+    ++new_name, --new_len;
+  if (new_name[0] == '_')
+    ++new_name, --new_len;
+  if (delete_name[0] == '_')
+    ++delete_name, --delete_len;
+  if (delete_name[0] == '_')
+    ++delete_name, --delete_len;
+  if (new_len < 4 || delete_len < 5)
+    return false;
+  /* *_len is now just the length after initial underscores.  */
+  if (new_name[0] != 'Z' || new_name[1] != 'n')
+    return false;
+  if (delete_name[0] != 'Z' || delete_name[1] != 'd')
+    return false;
+  /* _Znw must match _Zdl, _Zna must match _Zda.  */
+  if ((new_name[2] != 'w' || delete_name[2] != 'l')
+      && (new_name[2] != 'a' || delete_name[2] != 'a'))
+    return false;
+  /* 'j', 'm' and 'y' correspond to size_t.  */
+  if (new_name[3] != 'j' && new_name[3] != 'm' && new_name[3] != 'y')
+    return false;
+  if (delete_name[3] != 'P' || delete_name[4] != 'v')
+    return false;
+  if (new_len == 4
+      || (new_len == 18 && !memcmp (new_name + 4, "RKSt9nothrow_t", 14)))
+    {
+      /* _ZnXY or _ZnXYRKSt9nothrow_t matches
+        _ZdXPv, _ZdXPvY and _ZdXPvRKSt9nothrow_t.  */
+      if (delete_len == 5)
+       return true;
+      if (delete_len == 6 && delete_name[5] == new_name[3])
+       return true;
+      if (delete_len == 19 && !memcmp (delete_name + 5, "RKSt9nothrow_t", 14))
+       return true;
+    }
+  else if ((new_len == 19 && !memcmp (new_name + 4, "St11align_val_t", 15))
+          || (new_len == 33
+              && !memcmp (new_name + 4, "St11align_val_tRKSt9nothrow_t", 29)))
+    {
+      /* _ZnXYSt11align_val_t or _ZnXYSt11align_val_tRKSt9nothrow_t matches
+        _ZdXPvSt11align_val_t or _ZdXPvYSt11align_val_t or  or
+        _ZdXPvSt11align_val_tRKSt9nothrow_t.  */
+      if (delete_len == 20 && !memcmp (delete_name + 5, "St11align_val_t", 15))
+       return true;
+      if (delete_len == 21
+         && delete_name[5] == new_name[3]
+         && !memcmp (delete_name + 6, "St11align_val_t", 15))
+       return true;
+      if (delete_len == 34
+         && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29))
+       return true;
+    }
+  return false;
+}
+
 /* 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
@@ -824,16 +895,23 @@ propagate_necessity (bool aggressive)
                           || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
                      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
                {
-                 /* 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)
-                   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);
-                     }
+                 if (is_delete_operator)
+                   {
+                     if (!valid_new_delete_pair_p (def_stmt, stmt))
+                       mark_operand_necessary (gimple_call_arg (stmt, 0));
+
+                     /* Delete operators can have alignment and (or) size
+                        as next arguments.  When being a SSA_NAME, they
+                        must be marked as necessary.  */
+                     if (gimple_call_num_args (stmt) >= 2)
+                       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;
                }