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.

Reply via email to