On Tue, 19 Nov 2024, Jakub Jelinek wrote: > 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)?
I don't think we want to do that. I didn't yet suggest to make -Ofast to change it, not to introduce a -ffast-math like flag to the frontend(s) (or a -fstrict). > Though, not sure what to do for > LTO then. With LTO the complication is going to be there anyway - since the fnspec isn't on the actual calls function type. So mixing TUs with different setting is bogus. You probably want to mark the flag Optimization so we have it per function. We'd then have to refuse inlining of functions with incompatible flag_assume_sane_operators_new_delete setting into each other as well. Alternatively keep a global setting and have lto-wrapper merge the flag conservatively. Richard. > > 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 > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)