Hi, On Thu, 3 Nov 2011, Jakub Jelinek wrote:
> > It's possible. At expansion time the clobbers expand to nothing, so > > those regions theoretically are mergeable with outer regions, but we > > don't have EH cleanups on RTL anymore. > > That is unfortunate. Can't EH cleanups be taught about these stmts and > optimize them as if those clobbering stmts weren't present? I.e. > similarly to the VTA first rule, don't base decisions on their presence, > and just take them into account when doing the transformation if decided > it should be done? Perhaps that's possible, though I don't immediately see how in the general case; I don't want to tackle this as part of the patch unless absolutely required. Let's take a typical example: # cat x.cc struct A { A(); ~A(); int i[10];}; extern void callme (int*); int foo (int cond) { if (cond) { A a; callme (a.i); } } That's gimplified like so: # cat x.cc.004.gimple int foo(int) (int cond) { { if (cond != 0) goto <D.2113>; else goto <D.2114>; <D.2113>: { struct A a; try { A::A (&a); try { callme (&a.i); //1 } finally { A::~A (&a); //2 } //3 } finally { a = {}; } } goto <D.2115>; <D.2114>: <D.2115>: } } There are three exits of the scope that must somehow reach the clobber, callme can throw, the dtor can throw, and the fall thru. Right now ehcleanup does this: After removal of unreachable regions: Eh tree: 1 cleanup land:{1,<L4>} 3 must_not_throw 2 cleanup land:{2,<L3>} int foo(int) (int cond) { struct A a; <bb 2>: if (cond_1(D) != 0) goto <bb 3>; else goto <bb 7>; <bb 3>: A::A (&a); <bb 4>: callme (&a.i); <bb 5>: A::~A (&a); <bb 6>: a ={v} {}; <bb 7>: return; <L3>: A::~A (&a); resx 2 <L4>: a ={v} {}; resx 1 } L4 is the landing pad that is reached by resx 2 and by the throwing dtor. Now, suppose we would be somehow removing that region. We need places to put the clobber to, we can't move it upward, because while the edge L3->L4 is explicit (and we could move the clobber there) the edge bb5->L4 isn't. In this specific case we could notice that resx1 actually is the outermost resume, hence only will leave the function and therefore the clobber is useless (as in, moving them down actually removes them from the function body). But suppose the whole code above would itself be contained in some other region to which the resx1 would lead. We could move the clobber there (and to the fall thru path that skips that region, which is the case with catch region), that it safe (outer cleanup regions are always outer or following scopes, and moving clobber outwards or lower is conservatively correct), but extends the life area of the variables in question. > > That's possible I guess, but is it worth it? A file compiled with g++ is > > completely fine in requiring the c++ personality. Disabling this for some > > special cases just seems like a hack. > > It is important, for several tools the size of .eh_frame section matters a > lot (e.g. when you need to pin all the .eh_frame/.eh_frame_hdr > sections into memory for kernel unwinding). I suppose I could disable generating the clobbers for the outermost scopes (hence no outer try/finally pair), which requires extending the inliner to generate those clobbers at inlining time. The other possibility would be removing the clobbers (all of them) right before ehcleanup2 (shortly before expand) and somehow remember the edges over which the variables die. That seems a bit fragile as there are some more passes between them that fiddle with edges. Ciao, Michael.