Message ID | 1372693018.1789.110.camel@surprise |
---|---|
State | New |
Headers | show |
On Mon, 2013-07-01 at 11:36 -0400, David Malcolm wrote: Sorry, I forgot the ChangeLog entries: gcc/ 2013-07-01 David Malcolm <dmalcolm@redhat.com> * doc/extend.texi (Type Attributes): Document new "force_static" attribute. gcc/cp/ 2013-07-01 David Malcolm <dmalcolm@redhat.com> * cp-tree.h (struct lang_type_class): Add force_static bitfield. (CLASSTYPE_FORCE_STATIC): New macro. * decl.c (grokfndecl): Silently discard "const" on methods within a "force_static" class. (grokdeclarator): Implement the effect of the "force_static" attribute. * ptree.c (cxx_print_type): Indicate when a class has been marked with "force_static". * tree.c (cxx_attribute_table): Add an entry for a new "force_static" attribute. (handle_force_static_attribute): New. gcc/testsuite/ 2013-07-01 David Malcolm <dmalcolm@redhat.com> New "force_static" attribute. * g++.dg/ext/force_static/attribute.C: New. * g++.dg/ext/force_static/callsite.C: Likewise. * g++.dg/ext/force_static/const.C: Likewise. * g++.dg/ext/force_static/ctor.C: Likewise. * g++.dg/ext/force_static/dtor.C: Likewise. * g++.dg/ext/force_static/method.C: Likewise. * g++.dg/ext/force_static/not-a-class.C: Likewise. * g++.dg/ext/force_static/struct.C: Likewise. * g++.dg/ext/force_static/trailing.C: Likewise. * g++.dg/ext/force_static/vfunc.C: Likewise.
On Mon, Jul 1, 2013 at 10:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: > My plan for removal of global variables in gcc 4.9 [1] calls for several > hundred new classes, which will be singletons in a classic monolithic > build, but have multiple instances in a shared-library build. > > In order to avoid the register pressure of passing a redundant "this" > pointer around for the classic case, I've been looking at optimizing > singletons. > > I'm attaching an optimization for this: a new "force_static" attribute > for the C++ frontend, which when added to a class implicitly adds > "static" to all members of said class. This gives a way of avoiding a > "this" pointer in the classic build (in stages 2 and 3, once the > attribute is recognized), whilst supporting it in a shared-library > build, with relatively little boilerplate, preprocessor hackery or > syntactic differences. > > See: > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization > for more information on how this would be used in GCC itself. Hi David, I am still a little bit confused by this. Help me out: 1. if we don't need to pass `this', why should we ever find ourselves to writing functions that need one in the first place? How do shared libraries get into this water? 2. regarding your comment about constexpr. If you think that is useful you can add it to gnu++03 as __constexpr__ and use it, following the pattern suggested by RTH. 3. Is it that GCC does not know how to optimize objects of empty classes? > > With this optimization, the generated machine code *with classes* (with > "methods" and "fields") is identical to that with just functions and > global variables (apart from the ordering of the functions/"methods" > within the .text sections of their respective .o files). [2] > > FWIW I've also been looking at another approach: > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization > which is even lower boilerplate, though I don't have that working yet; > it touches the internals of classes and methods much more deeply. > > BTW, I'm not 100% sold on "force_static" as the name of the attribute; > would "implicit_static" be a better name? (the latter is growing on me). > > Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases > have the same results as an unpatched build, and all new testcases pass > (using r200562 as the baseline). > > Dave > [1] See http://gcc.gnu.org/ml/gcc/2013-06/msg00215.html > [2] I've written an "asmdiff" tool to help check this: > https://github.com/davidmalcolm/asmdiff
On Mon, 1 Jul 2013, Gabriel Dos Reis wrote: > On Mon, Jul 1, 2013 at 10:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: >> My plan for removal of global variables in gcc 4.9 [1] calls for several >> hundred new classes, which will be singletons in a classic monolithic >> build, but have multiple instances in a shared-library build. >> >> In order to avoid the register pressure of passing a redundant "this" >> pointer around for the classic case, I've been looking at optimizing >> singletons. >> >> I'm attaching an optimization for this: a new "force_static" attribute >> for the C++ frontend, which when added to a class implicitly adds >> "static" to all members of said class. This gives a way of avoiding a >> "this" pointer in the classic build (in stages 2 and 3, once the >> attribute is recognized), whilst supporting it in a shared-library >> build, with relatively little boilerplate, preprocessor hackery or >> syntactic differences. >> >> See: >> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization >> for more information on how this would be used in GCC itself. > > Hi David, > > I am still a little bit confused by this. Help me out: > 1. if we don't need to pass `this', why should we ever find > ourselves to writing functions that need one in the first place? > How do shared libraries get into this water? In theory, there is always this regular class with data and member functions that use *this. However, for traditional use (not in a library), there will be a single global instance of this class. For optimization purposes, it seems better in that case to make all members (variables and functions) static to let the compiler use a constant address instead of passing "this" around. I don't know exactly how hard it would be for the compiler to do this optimization without the force_static hint, but it would need to detect that there is only ever one object created (using -fwhole-program? visibility?). Or to clone the member functions for each global instance if it is always clear on which one the function is called (but how do you determine it is worth it?). > 3. Is it that GCC does not know how to optimize objects of empty classes? GCC indeed isn't very good at that (partially because of the ABI), but I don't think that's the point here. >> With this optimization, the generated machine code *with classes* (with >> "methods" and "fields") is identical to that with just functions and >> global variables (apart from the ordering of the functions/"methods" >> within the .text sections of their respective .o files). [2] >> >> FWIW I've also been looking at another approach: >> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization >> which is even lower boilerplate, though I don't have that working yet; >> it touches the internals of classes and methods much more deeply. >> >> BTW, I'm not 100% sold on "force_static" as the name of the attribute; >> would "implicit_static" be a better name? (the latter is growing on me). >> >> Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases >> have the same results as an unpatched build, and all new testcases pass >> (using r200562 as the baseline). >> >> Dave >> [1] See http://gcc.gnu.org/ml/gcc/2013-06/msg00215.html >> [2] I've written an "asmdiff" tool to help check this: >> https://github.com/davidmalcolm/asmdiff
On Tue, Jul 2, 2013 at 1:16 AM, Marc Glisse <marc.glisse@inria.fr> wrote: > On Mon, 1 Jul 2013, Gabriel Dos Reis wrote: > >> On Mon, Jul 1, 2013 at 10:36 AM, David Malcolm <dmalcolm@redhat.com> >> wrote: >>> >>> My plan for removal of global variables in gcc 4.9 [1] calls for several >>> hundred new classes, which will be singletons in a classic monolithic >>> build, but have multiple instances in a shared-library build. >>> >>> In order to avoid the register pressure of passing a redundant "this" >>> pointer around for the classic case, I've been looking at optimizing >>> singletons. >>> >>> I'm attaching an optimization for this: a new "force_static" attribute >>> for the C++ frontend, which when added to a class implicitly adds >>> "static" to all members of said class. This gives a way of avoiding a >>> "this" pointer in the classic build (in stages 2 and 3, once the >>> attribute is recognized), whilst supporting it in a shared-library >>> build, with relatively little boilerplate, preprocessor hackery or >>> syntactic differences. >>> >>> See: >>> >>> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization >>> for more information on how this would be used in GCC itself. >> >> >> Hi David, >> >> I am still a little bit confused by this. Help me out: >> 1. if we don't need to pass `this', why should we ever find >> ourselves to writing functions that need one in the first place? >> How do shared libraries get into this water? > > > In theory, there is always this regular class with data and member functions > that use *this. However, for traditional use (not in a library), there will > be a single global instance of this class. For optimization purposes, it > seems better in that case to make all members (variables and functions) > static to let the compiler use a constant address instead of passing "this" > around. Thanks, Marc! From the description, I have the impression you are saying that the class is essentially a singleton class. Is that right? Sorry, I am still confused about what the problem is and why we need this solution -- I read several times David's links but I can't get my head around the fundamental problem. > > I don't know exactly how hard it would be for the compiler to do this > optimization without the force_static hint, but it would need to detect that > there is only ever one object created (using -fwhole-program? visibility?). > Or to clone the member functions for each global instance if it is always > clear on which one the function is called (but how do you determine it is > worth it?). > > >> 3. Is it that GCC does not know how to optimize objects of empty >> classes? > > > GCC indeed isn't very good at that (partially because of the ABI), but I > don't think that's the point here. > > >>> With this optimization, the generated machine code *with classes* (with >>> "methods" and "fields") is identical to that with just functions and >>> global variables (apart from the ordering of the functions/"methods" >>> within the .text sections of their respective .o files). [2] >>> >>> FWIW I've also been looking at another approach: >>> >>> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization >>> which is even lower boilerplate, though I don't have that working yet; >>> it touches the internals of classes and methods much more deeply. >>> >>> BTW, I'm not 100% sold on "force_static" as the name of the attribute; >>> would "implicit_static" be a better name? (the latter is growing on me). >>> >>> Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases >>> have the same results as an unpatched build, and all new testcases pass >>> (using r200562 as the baseline). >>> >>> Dave >>> [1] See http://gcc.gnu.org/ml/gcc/2013-06/msg00215.html >>> [2] I've written an "asmdiff" tool to help check this: >>> https://github.com/davidmalcolm/asmdiff > > > -- > Marc Glisse
On Tue, 2013-07-02 at 06:37 -0500, Gabriel Dos Reis wrote: > On Tue, Jul 2, 2013 at 1:16 AM, Marc Glisse <marc.glisse@inria.fr> wrote: > > On Mon, 1 Jul 2013, Gabriel Dos Reis wrote: > > > >> On Mon, Jul 1, 2013 at 10:36 AM, David Malcolm <dmalcolm@redhat.com> > >> wrote: > >>> > >>> My plan for removal of global variables in gcc 4.9 [1] calls for several > >>> hundred new classes, which will be singletons in a classic monolithic > >>> build, but have multiple instances in a shared-library build. > >>> > >>> In order to avoid the register pressure of passing a redundant "this" > >>> pointer around for the classic case, I've been looking at optimizing > >>> singletons. > >>> > >>> I'm attaching an optimization for this: a new "force_static" attribute > >>> for the C++ frontend, which when added to a class implicitly adds > >>> "static" to all members of said class. This gives a way of avoiding a > >>> "this" pointer in the classic build (in stages 2 and 3, once the > >>> attribute is recognized), whilst supporting it in a shared-library > >>> build, with relatively little boilerplate, preprocessor hackery or > >>> syntactic differences. > >>> > >>> See: > >>> > >>> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization > >>> for more information on how this would be used in GCC itself. > >> > >> > >> Hi David, > >> > >> I am still a little bit confused by this. Help me out: > >> 1. if we don't need to pass `this', why should we ever find > >> ourselves to writing functions that need one in the first place? > >> How do shared libraries get into this water? > > > > > > In theory, there is always this regular class with data and member functions > > that use *this. However, for traditional use (not in a library), there will > > be a single global instance of this class. For optimization purposes, it > > seems better in that case to make all members (variables and functions) > > static to let the compiler use a constant address instead of passing "this" > > around. > > Thanks, Marc! > > From the description, I have the impression you are saying that the class > is essentially a singleton class. Is that right? > > Sorry, I am still confused about what the problem is and why we need this > solution -- I read several times David's links but I can't get my head > around the fundamental problem. Sorry about that. I want to rework the internals of GCC so that they become thread-safe, embeddable as a library inside another program. For example, a web browser may want to compile JavaScript to machine code: each tab within the browser could be running on a separate thread within one process, and each may want to create "compilation contexts" that turn javascript into gimple, say, create a dedicated optimization pipeline (perhaps with some custom passes), and send the gimple+pipeline to the GCC-as-a-shared-library to get machine code back. [well, assembler, but binutils-as-a-library is currently out-of-scope for my plan]. Given that this could all be happening on different threads, we could just have one big mutex to avoid interference, but the better approach is to isolate all of the state inside GCC so each compilation context gets its own world of state. Ideally there would be no global variables internally in gcc, but currently there are about 3500 of them. I want to provide the above, but I don't want to slow down the current use-case of GCC: the family of monolithic binaries. For example, simply building as a shared library slows things down, since you'd have have to build gcc as position-independent code, which itself incurs a slowdown. So I envisage a "--enable-shared" configuration switch to opt-in to the shared library code, but I want as minimize the difference between the two cases. The natural way to eliminate the various globals is to group logically-related global variables into classes, together with the functions that operate on them, as methods. For example, the callgraph-related code could be placed into a new "class callgraph", the pass-management code into a new "class pipeline", the garbage-collector internals into a new "class gc_heap", etc. The various passes with state typically get their own classes. I estimate about 300 such classes. Each client of gcc (e.g. each tab in a web browser) would have its own context pointer into the GCC shared library, a handle to one "parallel universe" of state, independent of all other such parallel universes. Much of GCC's existing functions would become methods of one of the above classes. For example, most of the functions in cgraph.c, cgraphbuild.c, cgraphclones.c and cgraphunit.c would become methods of a "class callgraph" (much of these methods would be private); each parallel universe of state would have its own callgraph instance. The graph of internal functions implementing the callgraph code become a graph of *methods*, passing around a "this" pointer. This should give us a relatively smooth transition path from the current code to such a parallel-universe world, but there is a performance concern: thousands of callsites throughout the compiler would gain a "this" parameter that gets silently passed around, and dereferenced throughout the code when reading/writing data which would have been a global in an old version of gcc. We'd have hundreds of these new classes which would be regular classes when configured --with-shared, but these classes are all singletons when configured --without-shared: the "this" pointer is redundant in this latter configuration (as is the case for a conventional build of gcc, as binaries). The purpose of the attribute is to provide a way to write code as regular classes, but have a relatively simple way of eliminating all of the "this" uses in the --without-shared build, thus trivially making the performance characteristics of the new gcc with --without-shared be the same as the old gcc. Hence we get relatively clean code (IMHO), the ability to have multiple independent compilation contexts in a thread-safe gcc shared library, and the same code shared with a non-shared-library gcc that has the same performance characteristics as an existing version of gcc. Hope the above makes more sense Dave
On Tue, 2013-07-02 at 08:16 +0200, Marc Glisse wrote: > On Mon, 1 Jul 2013, Gabriel Dos Reis wrote: > > > On Mon, Jul 1, 2013 at 10:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: > >> My plan for removal of global variables in gcc 4.9 [1] calls for several > >> hundred new classes, which will be singletons in a classic monolithic > >> build, but have multiple instances in a shared-library build. > >> > >> In order to avoid the register pressure of passing a redundant "this" > >> pointer around for the classic case, I've been looking at optimizing > >> singletons. > >> > >> I'm attaching an optimization for this: a new "force_static" attribute > >> for the C++ frontend, which when added to a class implicitly adds > >> "static" to all members of said class. This gives a way of avoiding a > >> "this" pointer in the classic build (in stages 2 and 3, once the > >> attribute is recognized), whilst supporting it in a shared-library > >> build, with relatively little boilerplate, preprocessor hackery or > >> syntactic differences. > >> > >> See: > >> http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization > >> for more information on how this would be used in GCC itself. > > > > Hi David, > > > > I am still a little bit confused by this. Help me out: > > 1. if we don't need to pass `this', why should we ever find > > ourselves to writing functions that need one in the first place? > > How do shared libraries get into this water? > > In theory, there is always this regular class with data and member > functions that use *this. However, for traditional use (not in a library), > there will be a single global instance of this class. For optimization > purposes, it seems better in that case to make all members (variables and > functions) static to let the compiler use a constant address instead of > passing "this" around. Exactly (assuming that by "constant address" you're referring to the address of each member variable, when it becomes static). > I don't know exactly how hard it would be for the compiler to do this > optimization without the force_static hint, but it would need to detect > that there is only ever one object created (using -fwhole-program? > visibility?). Or to clone the member functions for each global instance if > it is always clear on which one the function is called (but how do you > determine it is worth it?). It may work when the class is confined to a single TU, but in the general case such an approach would also require building the compiler with LTO to get back to the old performance, which might be a significant imposition (e.g. needing plenty of RAM, for starters). > > > 3. Is it that GCC does not know how to optimize objects of empty classes? > > GCC indeed isn't very good at that (partially because of the ABI), but I > don't think that's the point here. Right, the objects would only be empty when marked with "force_static". [...]
On Tue, 2 Jul 2013, David Malcolm wrote: > So I envisage a "--enable-shared" configuration switch to opt-in to the > shared library code, but I want as minimize the difference between the > two cases. --enable-host-shared or --enable-shared-gcc or some other such option name, please, not plain --enable-shared with currently refers to the libraries built for the target. Whether the target libraries should be shared libraries is a choice completely independent of whether to build GCC itself as a shared library (or libraries? - since you have lots of separate front ends that don't currently expect to be linked together, although actually making it possible to link them together is probably only a few days' work).
On Mon, Jul 1, 2013 at 8:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: > My plan for removal of global variables in gcc 4.9 [1] calls for several > hundred new classes, which will be singletons in a classic monolithic > build, but have multiple instances in a shared-library build. > > In order to avoid the register pressure of passing a redundant "this" > pointer around for the classic case, I've been looking at optimizing > singletons. > > I'm attaching an optimization for this: a new "force_static" attribute > for the C++ frontend, which when added to a class implicitly adds > "static" to all members of said class. This gives a way of avoiding a > "this" pointer in the classic build (in stages 2 and 3, once the > attribute is recognized), whilst supporting it in a shared-library > build, with relatively little boilerplate, preprocessor hackery or > syntactic differences. > > See: > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization > for more information on how this would be used in GCC itself. > > With this optimization, the generated machine code *with classes* (with > "methods" and "fields") is identical to that with just functions and > global variables (apart from the ordering of the functions/"methods" > within the .text sections of their respective .o files). [2] > > FWIW I've also been looking at another approach: > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization > which is even lower boilerplate, though I don't have that working yet; > it touches the internals of classes and methods much more deeply. > > BTW, I'm not 100% sold on "force_static" as the name of the attribute; > would "implicit_static" be a better name? (the latter is growing on me). > > Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases > have the same results as an unpatched build, and all new testcases pass > (using r200562 as the baseline). I am not a big fan of adding another extension to GCC. Especially one where the documentation does not describe all the interactions with templates or all of the C++ features. Also Why can't we use some preprocess tricks instead of adding this extension? Thanks, Andrew Pinski > > Dave > [1] See http://gcc.gnu.org/ml/gcc/2013-06/msg00215.html > [2] I've written an "asmdiff" tool to help check this: > https://github.com/davidmalcolm/asmdiff
On Tue, 2013-07-02 at 13:54 -0700, Andrew Pinski wrote: > On Mon, Jul 1, 2013 at 8:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: > > My plan for removal of global variables in gcc 4.9 [1] calls for several > > hundred new classes, which will be singletons in a classic monolithic > > build, but have multiple instances in a shared-library build. > > > > In order to avoid the register pressure of passing a redundant "this" > > pointer around for the classic case, I've been looking at optimizing > > singletons. > > > > I'm attaching an optimization for this: a new "force_static" attribute > > for the C++ frontend, which when added to a class implicitly adds > > "static" to all members of said class. This gives a way of avoiding a > > "this" pointer in the classic build (in stages 2 and 3, once the > > attribute is recognized), whilst supporting it in a shared-library > > build, with relatively little boilerplate, preprocessor hackery or > > syntactic differences. > > > > See: > > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization > > for more information on how this would be used in GCC itself. > > > > With this optimization, the generated machine code *with classes* (with > > "methods" and "fields") is identical to that with just functions and > > global variables (apart from the ordering of the functions/"methods" > > within the .text sections of their respective .o files). [2] > > > > FWIW I've also been looking at another approach: > > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization > > which is even lower boilerplate, though I don't have that working yet; > > it touches the internals of classes and methods much more deeply. > > > > BTW, I'm not 100% sold on "force_static" as the name of the attribute; > > would "implicit_static" be a better name? (the latter is growing on me). > > > > Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases > > have the same results as an unpatched build, and all new testcases pass > > (using r200562 as the baseline). > > I am not a big fan of adding another extension to GCC. Especially one > where the documentation does not describe all the interactions with > templates or all of the C++ features. Right; it doesn't support templates yet, and reviewing my own patch it looks like the interaction with ctors and dtors could use some work, at least. (sorry) I think a renaming to "implicit_static" may help, so I'll do that in the next iteration. Are there other aspects that would need documentation/improvement for you to be happier with this? Out of interest, how do you feel about the alternate "singleton" attribute proposed in my plan: http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization (I have only a partially-working implementation of this other attribute). > Also Why can't we use some > preprocess tricks instead of adding this extension? FWIW I initially did go down the preprocessor route: see http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#other-ways-to-optimize-singletons but doing so involves a *lot* of macros: every member function and variable needs to be marked with "MAYBE_STATIC". The advantage of the attribute is that the macro markings can be done per-class rather than per-member, for (waving hands) an order-of-magnitude fewer macro uses. Thanks Dave
On Tue, 2013-07-02 at 20:49 +0000, Joseph S. Myers wrote: > On Tue, 2 Jul 2013, David Malcolm wrote: > > > So I envisage a "--enable-shared" configuration switch to opt-in to the > > shared library code, but I want as minimize the difference between the > > two cases. > > --enable-host-shared or --enable-shared-gcc or some other such option > name, please, not plain --enable-shared with currently refers to the > libraries built for the target. Whether the target libraries should be > shared libraries is a choice completely independent of whether to build > GCC itself as a shared library Good catch; thanks. I've added a note on this to my plan doc. [1] > (or libraries? - since you have lots of > separate front ends that don't currently expect to be linked together, > although actually making it possible to link them together is probably > only a few days' work). I think a lot of this will be dependent on Andrew's big frontend vs backend cleanup, but yes, multiple libraries would be much nicer. Thanks Dave [1] https://github.com/davidmalcolm/gcc-global-state/commit/a5bf16116a6da217981a9c94f8f999fec995dfc7
On Tue, Jul 2, 2013 at 2:09 PM, David Malcolm <dmalcolm@redhat.com> wrote: > On Tue, 2013-07-02 at 13:54 -0700, Andrew Pinski wrote: >> On Mon, Jul 1, 2013 at 8:36 AM, David Malcolm <dmalcolm@redhat.com> wrote: >> > My plan for removal of global variables in gcc 4.9 [1] calls for several >> > hundred new classes, which will be singletons in a classic monolithic >> > build, but have multiple instances in a shared-library build. >> > >> > In order to avoid the register pressure of passing a redundant "this" >> > pointer around for the classic case, I've been looking at optimizing >> > singletons. >> > >> > I'm attaching an optimization for this: a new "force_static" attribute >> > for the C++ frontend, which when added to a class implicitly adds >> > "static" to all members of said class. This gives a way of avoiding a >> > "this" pointer in the classic build (in stages 2 and 3, once the >> > attribute is recognized), whilst supporting it in a shared-library >> > build, with relatively little boilerplate, preprocessor hackery or >> > syntactic differences. >> > >> > See: >> > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#another-singleton-removal-optimization >> > for more information on how this would be used in GCC itself. >> > >> > With this optimization, the generated machine code *with classes* (with >> > "methods" and "fields") is identical to that with just functions and >> > global variables (apart from the ordering of the functions/"methods" >> > within the .text sections of their respective .o files). [2] >> > >> > FWIW I've also been looking at another approach: >> > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization >> > which is even lower boilerplate, though I don't have that working yet; >> > it touches the internals of classes and methods much more deeply. >> > >> > BTW, I'm not 100% sold on "force_static" as the name of the attribute; >> > would "implicit_static" be a better name? (the latter is growing on me). >> > >> > Successfully bootstrapped on x86_64-unknown-linux-gnu; all old testcases >> > have the same results as an unpatched build, and all new testcases pass >> > (using r200562 as the baseline). >> >> I am not a big fan of adding another extension to GCC. Especially one >> where the documentation does not describe all the interactions with >> templates or all of the C++ features. > > Right; it doesn't support templates yet, and reviewing my own patch it > looks like the interaction with ctors and dtors could use some work, at > least. (sorry) > > I think a renaming to "implicit_static" may help, so I'll do that in the > next iteration. > > Are there other aspects that would need documentation/improvement for > you to be happier with this? > > Out of interest, how do you feel about the alternate "singleton" > attribute proposed in my plan: > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#a-singleton-removal-optimization > (I have only a partially-working implementation of this other > attribute). > >> Also Why can't we use some >> preprocess tricks instead of adding this extension? > > FWIW I initially did go down the preprocessor route: see > http://dmalcolm.fedorapeople.org/gcc/global-state/singletons.html#other-ways-to-optimize-singletons > but doing so involves a *lot* of macros: every member function and > variable needs to be marked with "MAYBE_STATIC". > > The advantage of the attribute is that the macro markings can be done > per-class rather than per-member, for (waving hands) an > order-of-magnitude fewer macro uses. I think the per-class method is just going to get messy in the sense you have to go back and find the attribute. In the per-member it is easier to find and easier to see. If you want to go this route, I think you should go and propose this to the C++ standard committee first :). Thanks, Andrew > > Thanks > Dave >
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2931ac5..17cf35e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1416,6 +1416,7 @@ struct GTY(()) lang_type_class { unsigned has_complex_move_assign : 1; unsigned has_constexpr_ctor : 1; unsigned is_final : 1; + unsigned force_static : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -1424,7 +1425,7 @@ struct GTY(()) lang_type_class { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 2; + unsigned dummy : 1; tree primary_base; vec<tree_pair_s, va_gc> *vcall_indices; @@ -1536,6 +1537,10 @@ struct GTY((variable_size)) lang_type { #define CLASSTYPE_FINAL(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->is_final) +/* Nonzero means that NODE (a class type) has the force_static + attribute. */ +#define CLASSTYPE_FORCE_STATIC(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->force_static) /* Nonzero means that this _CLASSTYPE node overloads operator=(X&). */ #define TYPE_HAS_COPY_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_copy_assign) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9eb1d12..d12b2a8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7575,10 +7575,24 @@ grokfndecl (tree ctype, { if (quals) { - error (ctype - ? G_("static member function %qD cannot have cv-qualifier") - : G_("non-member function %qD cannot have cv-qualifier"), - decl); + if (ctype) + { + if (CLASS_TYPE_P (ctype) && CLASSTYPE_FORCE_STATIC (ctype)) + /* It's useful to be able to mark methods of force_static + classes as "const" etc so that we can toggle the + presence of the "force_static" attribute without needing + to remove the const qualifiers. + + Silently discard such markings. */ + ; + else + error (G_("static member function %qD cannot have" + " cv-qualifier"), + decl); + } + else + error (G_("non-member function %qD cannot have cv-qualifier"), + decl); quals = TYPE_UNQUALIFIED; } @@ -9243,7 +9257,9 @@ grokdeclarator (const cp_declarator *declarator, explicitp = decl_spec_seq_has_spec_p (declspecs, ds_explicit); storage_class = declspecs->storage_class; - if (storage_class == sc_static) + if (storage_class == sc_static + || (current_class_type && + CLASSTYPE_FORCE_STATIC (current_class_type))) staticp = 1 + (decl_context == FIELD); if (virtualp && staticp == 2) diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index f4ca003..f4e5cd0 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -165,6 +165,8 @@ cxx_print_type (FILE *file, tree node, int indent) fprintf (file, " interface-only"); if (CLASSTYPE_INTERFACE_UNKNOWN (node)) fprintf (file, " interface-unknown"); + if (CLASSTYPE_FORCE_STATIC (node)) + fprintf (file, " force_static"); } } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8524f6c..b5d5879 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -47,6 +47,7 @@ static tree handle_java_interface_attribute (tree *, tree, tree, int, bool *); static tree handle_com_interface_attribute (tree *, tree, tree, int, bool *); static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *); static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *); +static tree handle_force_static_attribute (tree *, tree, tree, int, bool *); /* If REF is an lvalue, returns the kind of lvalue that REF is. Otherwise, returns clk_none. */ @@ -3157,6 +3158,8 @@ const struct attribute_spec cxx_attribute_table[] = handle_init_priority_attribute, false }, { "abi_tag", 1, -1, false, false, false, handle_abi_tag_attribute, true }, + { "force_static", 0, 0, false, true, false, + handle_force_static_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -3378,6 +3381,39 @@ handle_abi_tag_attribute (tree* node, tree name, tree args, return NULL_TREE; } +/* Handle a "force_static" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_force_static_attribute (tree* node, + tree name, + tree /*args*/, + int /*flags*/, + bool* /*no_add_attrs*/) +{ + if (!CLASS_TYPE_P (*node)) + { + warning (OPT_Wattributes, "%qE attribute can only be applied " + "to class definitions", name); + return NULL_TREE; + } + + /* The attribute affects how decls within the class body are grokked. + If the attribute is seen after the body of the class has been handled, + it's too late. */ + if (TYPE_FIELDS (*node)) + { + warning (OPT_Wattributes, + ("%qE attribute must be applied after the class keyword," + " not after the closing brace"), + name); + return NULL_TREE; + } + + CLASSTYPE_FORCE_STATIC (*node) = 1; + + return NULL_TREE; +} + /* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the thing pointed to by the constant. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6ce26ef..6d33191 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5539,6 +5539,46 @@ and caught in another, the class must have default visibility. Otherwise the two shared objects are unable to use the same typeinfo node and exception handling will break. +@item force_static +In C++, a class or struct can be marked with the ``force_static'' attribute +to make it easier to implement singletons. + +This implicitly adds the ``static'' keyword to all methods and data, so +that the methods lose the implicit ``this'' that they would otherwise +have, thus allowing for more efficient generated code. + +The attribute must appear between the ``class'' or ``struct'' keyword and +the name of the type; it may not appear between the closing parenthesis +of the body of the type and the trailing semicolon. + +@smallexample +class __attribute__((force_static)) foo +@{ +public: + void some_method (); + +private: + int some_field; +@}; + +/* Instances of the type can still be created, but they become empty. */ +extern foo the_foo; + +/* Any instances share the same data, as if there was just one + instance. */ +int foo::some_field; + +void bar (void) +@{ + /* You can invoke methods on such a class... */ + the_foo.some_method (); + + /* ...where the attribute makes the above be implicitly equivalent to + this: */ + foo::some_method (); +@} +@end smallexample + @end table To specify multiple attributes, separate them by commas within the diff --git a/gcc/testsuite/g++.dg/ext/force_static/attribute.C b/gcc/testsuite/g++.dg/ext/force_static/attribute.C new file mode 100644 index 0000000..5f315e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/attribute.C @@ -0,0 +1,7 @@ +class __attribute__((force_static)) foo +{ +private: + int i; +}; + +int foo::i; diff --git a/gcc/testsuite/g++.dg/ext/force_static/callsite.C b/gcc/testsuite/g++.dg/ext/force_static/callsite.C new file mode 100644 index 0000000..3a11884 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/callsite.C @@ -0,0 +1,19 @@ +// { dg-options "-fdump-tree-original" } + +class __attribute__((force_static)) foo +{ +public: + int some_method (int i); + +private: + int some_field; +}; + +int test_callsite () +{ + extern foo the_foo; + return the_foo.some_method (42); +} + +// { dg-final { scan-tree-dump "foo::some_method" "original" } } +// { dg-final { cleanup-tree-dump original } } diff --git a/gcc/testsuite/g++.dg/ext/force_static/const.C b/gcc/testsuite/g++.dg/ext/force_static/const.C new file mode 100644 index 0000000..5f2581f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/const.C @@ -0,0 +1,7 @@ +class __attribute__((force_static)) foo +{ +public: + /* It's harmless to have a "const" qualifier on a method of + such a class. */ + void bar () const; +}; diff --git a/gcc/testsuite/g++.dg/ext/force_static/ctor.C b/gcc/testsuite/g++.dg/ext/force_static/ctor.C new file mode 100644 index 0000000..7d499ec --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/ctor.C @@ -0,0 +1,5 @@ +class __attribute__((force_static)) foo +{ +public: + foo(); /* { dg-error "constructor cannot be static member function" } */ +}; diff --git a/gcc/testsuite/g++.dg/ext/force_static/dtor.C b/gcc/testsuite/g++.dg/ext/force_static/dtor.C new file mode 100644 index 0000000..a62ba57 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/dtor.C @@ -0,0 +1,5 @@ +class __attribute__((force_static)) foo +{ +public: + ~foo(); /* { dg-error "destructor cannot be static member function" } */ +}; diff --git a/gcc/testsuite/g++.dg/ext/force_static/method.C b/gcc/testsuite/g++.dg/ext/force_static/method.C new file mode 100644 index 0000000..b94de84 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/method.C @@ -0,0 +1,19 @@ +// { dg-options "-fdump-tree-original" } + +class __attribute__((force_static)) foo +{ +public: + int some_method (int i); + +private: + int some_field; +}; + +int foo::some_method (int i) +{ + some_field += i; + return some_field; +} + +// { dg-final { scan-tree-dump-not "this" "original" } } +// { dg-final { cleanup-tree-dump original } } diff --git a/gcc/testsuite/g++.dg/ext/force_static/not-a-class.C b/gcc/testsuite/g++.dg/ext/force_static/not-a-class.C new file mode 100644 index 0000000..0cda06c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/not-a-class.C @@ -0,0 +1 @@ +int i __attribute__((force_static)); /* { dg-warning "'force_static' attribute can only be applied to class definitions" } */ diff --git a/gcc/testsuite/g++.dg/ext/force_static/struct.C b/gcc/testsuite/g++.dg/ext/force_static/struct.C new file mode 100644 index 0000000..8ba5a50 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/struct.C @@ -0,0 +1,6 @@ +struct __attribute__((force_static)) foo +{ + int i; +}; + +int foo::i; diff --git a/gcc/testsuite/g++.dg/ext/force_static/trailing.C b/gcc/testsuite/g++.dg/ext/force_static/trailing.C new file mode 100644 index 0000000..b6dfa2f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/trailing.C @@ -0,0 +1,3 @@ +class foo +{ +} __attribute__((force_static)); /* { dg-warning "'force_static' attribute must be applied after the class keyword, not after the closing brace" } */ diff --git a/gcc/testsuite/g++.dg/ext/force_static/vfunc.C b/gcc/testsuite/g++.dg/ext/force_static/vfunc.C new file mode 100644 index 0000000..b0da35d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/force_static/vfunc.C @@ -0,0 +1,5 @@ +class __attribute__((force_static)) foo +{ +public: + virtual void bar (); /* { dg-error "member 'bar' cannot be declared both virtual and static" } */ +};