On 8/8/07, Michael Matz <[EMAIL PROTECTED]> wrote:
> So those tree expressions would live throughout the middle-end and only
> then become lowered to RTL directly?  I'm not sure that's worthwhile.
> E.g. I'm not sure why there's a need to really get rid of the
> expand_constant langhook.  It's only important that it isn't called too
> late, i.e. ideally during gimplification.  It seems it only makes use of
> type information which should be available at that time, so if it
> currently is called too late (interfering with LTO in the future) it
> should be possible to move it earlier.

You're correct.  It is possible to remove the expand_constant language
hook without supporting pointers to members in the middle end.  In
fact, I submitted such a patch back in March
(http://gcc.gnu.org/ml/gcc-patches/2007-03/msg01819.html).  The
various follow-up emails illustrate some of the reasons why migrating
pointers to members to the middle end is a good thing (at least for
C++).

It would have been more accurate for me to describe the language hooks
removal as a jumping off point.  Strictly speaking, the middle end
migration is only necessary for language hook removal if the C++
maintainers won't approve my patch.  :)

That said, I think there is real value in moving pointers to members
to the middle end.  Keep reading.

> I have a conceptual problem with moving pointer to members into the
> middle-end: my mental model of what the middle-end should be concerned
> about is complete expressions/constants/types, like adding two numbers,
> accessing an integer two words away from that address (i.e. you see I
> already sort of decompose structures in my mental model).  Pointers to
> members is a very different beast: they can't be accessed without a real
> object, yet they can be stored into objects themself (sort of an
> incomplete memory reference).  If anything they simply resemble offsets
> (perhaps variable ones), so you might perhaps model them as such.
> Conversions between them sometimes requires adjustments to 'this',
> resulting in real operations (the delta field of the struct, how pointer
> to member values are currently modelled).  IMHO it would be wrong if we
> wouldn't make those adjustments explicit in the middle end.

I think the primary purpose of the middle end is to provide a
representation which captures the semantics of a program at a
sufficiently high level to enable efficient optimization.  COMPLEX_CST
and COMPLEX_TYPE are a good example.  In theory, the middle end has
enough information to optimize complex arithmetic based solely on the
constituent operations on real and imaginary components, but it's
easier to deal with the complex number as an atomic unit.

Similarly, consider the following code fragment:

  struct S { virtual void f(); };
  typedef void (S::*P)(void);
  const P p = &S::f, NULL;
 void g(S s) {
   (s.*p)();
 }

GCC should be able to optimize g() to call s.S::f() directly.  In
theory, it can optimize out the null pointer to member check, the
virtual bit check, and the vtable lookup, but that's a lot of work.
Right now, GCC can't do it.

> So, why do you think you need the PTRMEM_TYPE in the middle end?  And why
> the PTRMEM_CST (i.e. why couldn't it be lowered to some explicit constant
> during gimplificaton)?  Same for PTRMEM_PLUS_EXPR, why is (PTR_)PLUS_EXPR
> not enough, if the semantic is only to add the integer argument to the
> pointer argument (is that even an operation which can be done to pointers
> to members?)?  Also PTRMEM_REF seems to equivalent to a normal
> COMPONENT_REF, just that the second operand is a funny "offset"
> specification instead of a simple field decl.

The implementation is certainly negotiable.  That's part of why I sent
out this email.

For pointers to data members, PTRMEM_CST doesn't give much information
that isn't already provided by integers of OFFSET_TYPE (It does
explicitly indicate NULL pointers to members, which offsets do not.
In fact, GCC currently handles NULL pointer to member casts
incorrectly, as it fails to preserve NULLs).  However, for pointers to
member functions, it bypasses the need to decode an
architecture-dependent virtual bit, and replaces the virtual function
offset with FUNCTION_DECL, which means we don't need to decode vtable
lookups in order to inline function calls.

PTRMEM_PLUS_EXPR is supposed to represent casts (CAST_EXPR didn't seem
appropriate, but I could be convinced otherwise).  It expands to a
conditional which propagates NULL or increments the offset.  I don't
think PTR_PLUS_EXPR checks for NULL, and it's designed to increment
pointers.  A pointer to data member expands to an offset, and a
pointer to member function expands to a fairly complex structure.  In
fact, for some architectures, the offset field is shifted, so
PTRMEM_PLUS_EXPR (p, 1), would actually have to add 2 to the offset.

Take a look at the expand_ptrmemfunc_cst() and build_ptrmemfunc1()
calls inside cplus_expand_constant().  Now reverse that to see the
amount of work that PTRMEM_REF needs to perform.

> Ugh, I wouldn't like that either.  I have the feeling that it would drag
> too much specifics of C++ into the middle end.  After all e.g. the virtual
> tables have to follow a certain layout according to the C++ ABI, which
> needn't be the right one for other languages.  I think you need only one
> feature, namely given a definite class type and an offset into the
> vtable, what definite FUNCTION_DECL that corresponds too.  I can't think
> of many places where you'd like to have this information, as the most
> interesting user of it would be the inliner.  There aren't that many
> transformations which make a former indefinite class type definite, and
> most of them can be done when the C++ frontend is still around to ask.

Yes.  That's all I really need.  If that can be done without pulling
in to much of the virtual function machinery, I'd be very happy
indeed.  :)

Ollie

Reply via email to