On Tue, Nov 19, 2024 at 11:23:31AM +0100, Jakub Jelinek wrote:
> On Tue, Nov 19, 2024 at 10:25:16AM +0100, Richard Biener wrote:
> > I think it's pretty clear and easy to describe to users what "m " and 
> > what "mC" do.  But with "pure" this is an odd intermediate state.  For both
> > "m " and "mP" you suggest above the new/delete might modify their
> > global state but as you can't rely on the new/delete pair to prevail
> > you cannot rely on the modification to happen.  But how do you explain
> > that
> 
> If we are willing to make the default not strictly conforming (i.e.
> basically revert PR101480 by default and make the GCC 11.1/11.2 behavior
> the default and allow -fno-sane-operators-new-delete to change to GCC
> 11.3/14.* behavior), I can live with it.
> But we need to make the documentation clear that the default is not strictly
> conforming.

Here is a modified version of the patch to do that.

Or do we want to set the default based on -std= option (-std=gnu* implies
-fassume-sane-operators-new-delete, -std=c++* implies
-fno-assume-sane-operators-new-delete)?  Though, not sure what to do for
LTO then.

2024-11-19  Jakub Jelinek  <ja...@redhat.com>

        PR c++/110137
        PR middle-end/101480
gcc/
        * doc/invoke.texi (-fassume-sane-operators-new-delete,
        -fno-assume-sane-operators-new-delete): Document.
        * gimple.cc (gimple_call_fnspec): Handle
        -f{,no-}assume-sane-operators-new-delete.
gcc/c-family/
        * c.opt (fassume-sane-operators-new-delete): New option.
gcc/testsuite/
        * g++.dg/tree-ssa/pr110137-1.C: New test.
        * g++.dg/tree-ssa/pr110137-2.C: New test.
        * g++.dg/tree-ssa/pr110137-3.C: New test.
        * g++.dg/torture/pr10148.C: Add -fno-assume-sane-operators-new-delete
        as dg-additional-options.

--- gcc/doc/invoke.texi.jj      2024-11-19 10:23:59.145145887 +0100
+++ gcc/doc/invoke.texi 2024-11-19 12:07:13.942789378 +0100
@@ -213,7 +213,9 @@ in the following sections.
 @item C++ Language Options
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control
--faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new
+-faligned-new=@var{n}  -fargs-in-order=@var{n}
+-fno-assume-sane-operators-new-delete
+-fchar8_t  -fcheck-new
 -fconcepts  -fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n}
 -fconstexpr-loop-limit=@var{n}  -fconstexpr-ops-limit=@var{n}
 -fno-elide-constructors
@@ -3163,6 +3165,35 @@ but few users will need to override the
 
 This flag is enabled by default for @option{-std=c++17}.
 
+@opindex fno-assume-sane-operators-new-delete
+@opindex fassume-sane-operators-new-delete
+@item -fno-assume-sane-operators-new
+The C++ standard allows replacing the global @code{new}, @code{new[]},
+@code{delete} and @code{delete[]} operators, though a lot of C++ programs
+don't replace them and just use the implementation provided version.
+Furthermore, the C++ standard allows omitting those calls if they are
+made from new or delete expressions (and by extension the same is
+assumed if @code{__builtin_operator_new} or @code{__builtin_operator_delete}
+functions are used).
+This option allows control over some optimizations around calls
+to those operators.
+With @code{-fassume-sane-operators-new-delete} option GCC may assume that
+calls to the replaceable global operators from new or delete expressions or
+from @code{__builtin_operator_new} or @code{__builtin_operator_delete} calls
+don't read or modify any global variables or variables whose address could
+escape to the operators (global state; except for @code{errno} for the
+@code{new} and @code{new[]} operators).
+This allows most optimizations across those calls and is something that
+the implementation provided operators satisfy unless @code{malloc}
+implementation details are observable in the code or unless @code{malloc}
+hooks are used, but might not be satisfied if a program replaces those
+operators.  This behavior is enabled by default.
+With @code{-fno-assume-sane-operators-new-delete} option GCC must
+assume all these calls (whether from new or delete expressions or called
+directly) may read and write global state unless proven otherwise (e.g.@:
+when GCC compiles their implementation).  Use this option if those
+operators are or may be replaced and code needs to expect such behavior.
+
 @opindex fchar8_t
 @opindex fno-char8_t
 @item -fchar8_t
--- gcc/gimple.cc.jj    2024-11-16 10:22:38.386770817 +0100
+++ gcc/gimple.cc       2024-11-19 11:45:33.386136116 +0100
@@ -1600,12 +1600,22 @@ gimple_call_fnspec (const gcall *stmt)
       && DECL_IS_OPERATOR_DELETE_P (fndecl)
       && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
       && gimple_call_from_new_or_delete (stmt))
-    return ". o ";
+    {
+      if (flag_assume_sane_operators_new_delete)
+       return ".co ";
+      else
+       return ". o ";
+    }
   /* Similarly operator new can be treated as malloc.  */
   if (fndecl
       && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
       && gimple_call_from_new_or_delete (stmt))
-    return "m ";
+    {
+      if (flag_assume_sane_operators_new_delete)
+       return "mC";
+      else
+       return "m ";
+    }
   return "";
 }
 
--- gcc/c-family/c.opt.jj       2024-11-18 09:05:00.182283546 +0100
+++ gcc/c-family/c.opt  2024-11-19 11:31:29.381038177 +0100
@@ -1690,6 +1690,10 @@ fasm
 C ObjC C++ ObjC++ Var(flag_no_asm, 0)
 Recognize the \"asm\" keyword.
 
+fassume-sane-operators-new-delete
+C++ ObjC++ LTO Var(flag_assume_sane_operators_new_delete) Init(1)
+Assume C++ replaceable global operators new, new[], delete, delete[] don't 
read or write visible global state.
+
 ; Define extra predefined macros for use in libgcc.
 fbuilding-libgcc
 C ObjC C++ ObjC++ Undocumented Var(flag_building_libgcc)
--- gcc/testsuite/g++.dg/tree-ssa/pr110137-1.C.jj       2024-11-19 
11:30:24.866947846 +0100
+++ gcc/testsuite/g++.dg/tree-ssa/pr110137-1.C  2024-11-19 11:52:27.996287689 
+0100
@@ -0,0 +1,74 @@
+// PR c++/110137
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "q = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "t = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
+// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
+
+int i, j, k, l, m, n, o, q, r, s, t, u;
+
+void *
+foo ()
+{
+  i = 1;
+  j = 2;
+  void *p = ::operator new (32);
+  j = 3;
+  k = i;
+  return p;
+}
+
+void
+bar (void *p)
+{
+  l = 1;
+  m = 2;
+  ::operator delete (p);
+  m = 3;
+  n = l;
+}
+
+int *
+baz ()
+{
+  o = 1;
+  q = 2;
+  int *p = new int;
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+qux (int *p)
+{
+  s = 1;
+  t = 2;
+  delete p;
+  t = 3;
+  u = s;
+}
+
+void *
+corge ()
+{
+  o = 1;
+  q = 2;
+  void *p = __builtin_operator_new (32);
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+waldo (void *p)
+{
+  s = 1;
+  t = 2;
+  __builtin_operator_delete (p);
+  t = 3;
+  u = s;
+}
--- gcc/testsuite/g++.dg/tree-ssa/pr110137-2.C.jj       2024-11-19 
11:30:24.866947846 +0100
+++ gcc/testsuite/g++.dg/tree-ssa/pr110137-2.C  2024-11-19 11:52:18.473422017 
+0100
@@ -0,0 +1,74 @@
+// PR c++/110137
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-optimized -fassume-sane-operators-new-delete" 
}
+// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "q = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "t = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
+// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
+
+int i, j, k, l, m, n, o, q, r, s, t, u;
+
+void *
+foo ()
+{
+  i = 1;
+  j = 2;
+  void *p = ::operator new (32);
+  j = 3;
+  k = i;
+  return p;
+}
+
+void
+bar (void *p)
+{
+  l = 1;
+  m = 2;
+  ::operator delete (p);
+  m = 3;
+  n = l;
+}
+
+int *
+baz ()
+{
+  o = 1;
+  q = 2;
+  int *p = new int;
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+qux (int *p)
+{
+  s = 1;
+  t = 2;
+  delete p;
+  t = 3;
+  u = s;
+}
+
+void *
+corge ()
+{
+  o = 1;
+  q = 2;
+  void *p = __builtin_operator_new (32);
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+waldo (void *p)
+{
+  s = 1;
+  t = 2;
+  __builtin_operator_delete (p);
+  t = 3;
+  u = s;
+}
--- gcc/testsuite/g++.dg/tree-ssa/pr110137-3.C.jj       2024-11-19 
11:30:24.866947846 +0100
+++ gcc/testsuite/g++.dg/tree-ssa/pr110137-3.C  2024-11-19 11:30:24.866947846 
+0100
@@ -0,0 +1,76 @@
+// PR c++/110137
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-optimized 
-fno-assume-sane-operators-new-delete" }
+// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
+// { dg-final { scan-tree-dump-times "q = 2;" 2 "optimized" } } */
+// { dg-final { scan-tree-dump-times "t = 2;" 2 "optimized" } } */
+// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "n = 1;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "r = 1;" "optimized" } } */
+// { dg-final { scan-tree-dump-not "u = 1;" "optimized" } } */
+
+int i, j, k, l, m, n, o, q, r, s, t, u;
+
+void *
+foo ()
+{
+  i = 1;
+  j = 2;
+  void *p = ::operator new (32);
+  j = 3;
+  k = i;
+  return p;
+}
+
+void
+bar (void *p)
+{
+  l = 1;
+  m = 2;
+  ::operator delete (p);
+  m = 3;
+  n = l;
+}
+
+int *
+baz ()
+{
+  o = 1;
+  q = 2;
+  int *p = new int;
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+qux (int *p)
+{
+  s = 1;
+  t = 2;
+  delete p;
+  t = 3;
+  u = s;
+}
+
+void *
+corge ()
+{
+  o = 1;
+  q = 2;
+  void *p = __builtin_operator_new (32);
+  q = 3;
+  r = o;
+  return p;
+}
+
+void
+waldo (void *p)
+{
+  s = 1;
+  t = 2;
+  __builtin_operator_delete (p);
+  t = 3;
+  u = s;
+}
--- gcc/testsuite/g++.dg/torture/pr10148.C.jj   2024-09-13 16:09:39.744357235 
+0200
+++ gcc/testsuite/g++.dg/torture/pr10148.C      2024-11-19 11:59:39.308203533 
+0100
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } 
} */
+/* { dg-additional-options "-fno-assume-sane-operators-new-delete" } */
 
 #include <stdlib.h>
 #include <assert.h>


        Jakub

Reply via email to