Reputation: 7123
My project has a C++ library that I want to allow the user to use via some programming language to be JIT'd to call functions in said library. For the sake of simplicity, assume the library has classes like:
class item {
public:
item();
item( int );
~item();
// ...
};
class item_iterator {
public:
virtual ~item_iterator();
virtual bool next( item *result ) = 0;
};
class singleton_iterator : public item_iterator {
public:
singleton_iterator( item const &i );
// ...
};
I'm aware that LLVM doesn't know anything about C++ and that one way to call C++ functions is to wrap them in C thunks:
extern "C" {
void thunk_item_M_new( item *addr ) {
new( addr ) item;
}
void thunk_singleton_iterator_M_new( singleton_iterator *addr, item *i ) {
new( addr ) singleton_iterator( *i );
}
bool thunk_iterator_M_next( item_iterator *that, item *result ) {
return that->next( result );
}
} // extern "C"
The first problem is how to allocate an item
from LLVM. I know how to create StructType
s and add fields to them, but I don't want to have to parallel the C++ class layout -- that's tedious and error-prone.
The idea I got was simply to add a char[sizeof(T)]
as the only field to a StructType
for a C++ class type:
StructType *const llvm_item_type = StructType::create( llvm_ctx, "item" );
vector<Type*> llvm_struct_types;
llvm_struct_types.push_back( ArrayType::get( IntegerType::get( llvm_ctx, 8 ), sizeof( item ) ) );
llvm_item_type->setBody( llvm_struct_types, false );
PointerType *const llvm_item_ptr_type = PointerType::getUnqual( llvm_item_type );
I would think that, because it's a StructType
, the alignment would be correct and the sizeof(item)
would get the size right. Will that work? Is there a better way?
The second problem is that, unlike the C++ class hierarchy, there's no inheritance relationship between StructType
s. If I create a Function
that takes an llvm_iterator_type
but try to build a Function
object using an llvm_singleton_iterator_type
, the LLVM verifyModule()
function complains at me:
Call parameter type does not match function signature!
So then I thought I'd simply use void*
everywhere:
Type *const llvm_void_type = Type::getVoidTy( llvm_ctx );
PointerType *const llvm_void_ptr_type = PointerType::getUnqual( llvm_void_type );
but verifyModule()
still complains at me because, apparently, there's no automatic casting to void*
types in LLVM. How can I solve this problem?
Upvotes: 4
Views: 1162
Reputation: 7123
It turns out that using char[sizeof(T)]
is a reasonable way to gets StructType
s to be the correct size -- at least one other person from the LLVM mailing list does this.
As for the "Call parameter type does not match function signature!" errors, a solution to that is simply to have all thunks use void*
and use static_cast
s inside. When passing arguments to the thunks, use the CreateBitCast()
IRBuilder
function (since casts-tovoid
are not automatic in LLVM).
Upvotes: 5