This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: TREE_UNCHANGING?


>>>>> "Jason" == Jason Merrill <jason@redhat.com> writes:

> I would like to be able to tell the backend that the vtable for a class
> object will never change, regardless of anything else we might or might not
> know about that object, so we can hoist vtable lookups out of loops.

Tangent:

While setting TREE_CONSTANT does the trick for normal virtual function
calls, it isn't enough for calls through a pointer-to-member function.
This turns out to be because the loop optimizer isn't clever enough to
hoist the complicated code for resolving a pmf, which involves a test and
jump.

I've whipped up a C analog below; this testcase takes 50% longer to run
with -O2 than with -O2 -fno-inline, because of the const function
optimization.  If we inline, we lose that information; there ought to be a
way to express the same thing for inlined/open-coded routines.

I thought about using a libcall block, but that seems to be specific to
calls.  Any reason not to use it for an arbitrary block of code with
defined inputs and output?  <hack, hack> Nope, doesn't work.  loop still
looks at the individual insns, and doesn't think it can move some of the
internal sets.

Does the AST optimizer branch support anything like this?

typedef void (*pfn_type)();

typedef struct PMF {
  union {
    pfn_type pfn;
    int idx;
  } u;
  // ignored for this example
  int delta;
} PMF;

typedef struct A {
  pfn_type* vptr;
} A;

static inline pfn_type extract_pfn (A* ap, PMF pmf) __attribute__ ((const));
static inline pfn_type extract_pfn (A* ap, PMF pmf)
{
  if (pmf.u.idx & 1)
    {
      // virtual; get the pointer from the vtable.
      int idx = pmf.u.idx - 1;
      void *pos = ((void *)ap->vptr) + idx;
      return *(pfn_type *)pos;
    }
  else
    // non-virtual
    return pmf.u.pfn;
}

void f (A* ap, PMF pmf)
{
  int i;
  for (i = 0; i < 500000000; ++i)
    {
      extract_pfn (ap, pmf) ();
    }
}

void g() {}

pfn_type vtable[] = { g };

int main()
{
  A a = { vtable };
  PMF pmf_nonv = { g, 0 };
  PMF pmf_virt = { (pfn_type)1, 0 };
  f (&a, pmf_nonv);
  f (&a, pmf_virt);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]