[LLVMdev] Offset to C++ structure members

Eli Friedman eli.friedman at gmail.com
Tue Oct 2 14:34:21 PDT 2012

On Tue, Oct 2, 2012 at 11:33 AM, Paul J. Lucas <paul at lucasmail.org> wrote:
> On Oct 1, 2012, at 9:58 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>> Using GEP on an i8* is a bit nicer to the optimizer, though, because
>> using ptrtoint/inttoptr has effects on alias analysis.
> My understanding is that, in order to use GEP, you have to provide the LLVM code with the struct layout, i.e., build a StructType object.  In my case, that struct is declared in C++ code already and, in order to use GEP, I'd have to replicate the struct layout (exactly as the C++ compiler would) in LLVM code -- something that I'd rather not do, not to mention that it's fairly "brittle" even if I could manage to get it right.  (Simple structs would probably be easy, but struct that have virtual functions or multiple base classes would be much harder.)

No, you don't have to... you can just use GEP on i8*'s.  The LLVM type
system doesn't have any semantic significance.

>> I'm not entirely sure how you're using mbr_offset_of
> Given 't', an instance of some class T, and some member T::m, find the integer offset in bytes from &t to &t.m.  This offset, when added to &t, should be &t.m.
> I'm using mbr_offset_of to get the C++ compiler to do the work of telling me what the correct offset is for the already existing struct.

If you can do that, why not just generate a thunk to perform the addressing?

>> but it's broken if there are any classes with virtual bases involved.
> Really?  This simple code works just fine:
>         struct A             { int ai; };
>         struct X : virtual A { int xi; };
>         struct Y : virtual A { int yi; };
>         struct S : X, Y {
>           string a;
>           string b;
>         };
>         template<class ClassType,class MbrType> inline
>         ptrdiff_t mbr_offset_of( MbrType ClassType::*p ) {
>           ClassType const *const c = static_cast<ClassType*>( nullptr );
>           return reinterpret_cast<ptrdiff_t>( &(c->*p) );
>         }
>         int main() {
>           ptrdiff_t offset = mbr_offset_of( &S::b );
>           S s;
>           string *p = (string*)((char*)&s + offset);
>           p->assign( "Hello, world!" );
>           cout << *p << endl;
>          return 0;
>         }

It starts to become an issue when you try to compute the offset to
e.g. A::ai in your example.

> Despite that, however, the equivalent code in LLVM (once I introduce a base class for S, even just ordinary inheritance), crashes.  I don't understand why, however.  I print out the offset, and it's the correct value that's getting added to the Pointer.

No idea what's happening here.


More information about the llvm-dev mailing list