Using LLVM JIT code to encode a program to invoke C ++ code

My project has a C ++ library that I want to allow the user to use with some programming language so that JIT'd call functions in the specified library. For simplicity, suppose the library has classes such as:

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 know that LLVM knows nothing 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 extract item from LLVM. I know how to create StructType and add fields to them, but I don’t want the parallel layout of the C ++ class to be tedious and error-prone.

The idea I got is to simply add char[sizeof(T)] as the only field for 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 since this is a StructType , alignment would be correct, and sizeof(item) would get the correct size. Will this work? Is there a better way?

The second problem is that, unlike the C ++ class hierarchy, there is no inheritance relationship between StructType s. If I create a Function that accepts llvm_iterator_type but tries to build a Function object using llvm_singleton_iterator_type , the LLVM verifyModule() function complains about me:

The call parameter type does not match the function signature!

So, I thought I was just using void* everywhere:

 Type *const llvm_void_type = Type::getVoidTy( llvm_ctx ); PointerType *const llvm_void_ptr_type = PointerType::getUnqual( llvm_void_type ); 

but verifyModule() is still complaining about me because there seems to be no automatic casting to void* types in LLVM. How can I solve this problem?

+4
source share
1 answer

It turns out that using char[sizeof(T)] is a smart way to get the StructType right size β€” at least one person on the LLVM mailing list does this.

Regarding "The type of the call parameter does not match the function signature!" bugs, the solution for this is to just use all the void* tricks and use static_cast inside. When passing arguments to tricks, use the CreateBitCast() IRBuilder (since casts-to void are not automatic in LLVM).

+5
source

Source: https://habr.com/ru/post/1401497/


All Articles