[LLVMdev] Offset to C++ structure members
Eli Friedman
eli.friedman at gmail.com
Tue Oct 2 15:40:02 PDT 2012
On Tue, Oct 2, 2012 at 3:28 PM, Paul J. Lucas <paul at lucasmail.org> wrote:
> On Oct 2, 2012, at 2:34 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>
>> On Tue, Oct 2, 2012 at 11:33 AM, Paul J. Lucas <paul at lucasmail.org> wrote:
>>
>>> 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.
>
> Oh! I just tried it and it works. :-)
>
>>>> 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?
>
> Because if I can create a thunk to do that, I can just as easily create a thunk to provide a "setter" for the struct member (something I'd prefer not to do).
>
> I'm trying to compute the offset "inline" in the LLVM code rather than (a) have to create yet another C thunk and (b) call it.
>
>>>> 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.
>
> Hmmmm.... I just changed:
>
> s/int ai/string as/
> s/&S::b/&S::as/
>
> and the code still works. The offset is 0 which is what you'd expect with class 'A' being a public virtual (shared) base class.
The offset of as is 0 given an A*, but not given an S*. If you handle
that already, it's okay, I guess.
-Eli
More information about the llvm-dev
mailing list