Functions that are CSEable but not pure

Jason Merrill jason@redhat.com
Wed Oct 3 19:00:00 GMT 2012


In C++ there is a common idiom called "initialize on first use".  In its 
simplest form it looks like

int& lazy_i()
{
   static int i = init;
   return i;
}

If the initialization is expensive or order-sensitive, this is a useful 
alternative to initialization on load 
(http://www.parashift.com/c++-faq/static-init-order-on-first-use.html).

An interesting property of such functions is that they only have 
side-effects the first time they are called, so subsequent calls can be 
optimized away to just use the return value of the first call.

Currently there is no way to express this in GCC so that the optimizers 
know that multiple calls are redundant.  Marking the function as pure 
causes calls to be CSEd as desired, but also asserts that the first call 
has no side-effects, which is not the case.

My implementation of dynamic initialization of TLS variables as mandated 
by the C++11 and OpenMP standards uses this idiom implicitly, so I'd 
really like to be able to optimize away multiple calls.

Right now we have the following ECF flags (among others):

const = no read, no write, no side-effects, cseable
pure = no write, no side-effects, cseable
novops = no read, no write
looping_const_or_pure = wait, actually there are side-effects

Seems like the difference between novops and looping_const_or_pure is 
whether calls are subject to CSE.  Is that right?

Rather than checking these flag bundles, it seems to me that we ought to 
break them up into

no reads
no writes
no side-effects
cseable side-effects

So const      would be noread|nowrite|noside
    pure       would be nowrite|noside
const|looping would be noread|nowrite|cseside
pure|looping  would be nowrite|cseside
    novops     would be noread|nowrite

and the behavior I want would be just cseside.

Does this make sense?  Anyone more familiar with this area of the code 
want to implement it for me?  :}

Jason



More information about the Gcc mailing list