Use the LLVM JIT code to encode the program to call C code

My project has a C library, and I want to allow users to use JIT through a certain programming language to call the functions in the library. For simplicity, suppose the library has the following classes: < p>

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. One way to call C functions is to wrap them in a C thunk:

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 question is how to get from LLVM Assign items. I know how to create StructTypes and add words to them Paragraph, but I don’t want to be parallel to the C-type layout-it is tedious and error-prone.

The idea I get is just to add a char [sizeof(T)] as the only field of the C-type StructType:

StructType *const llvm_item_type = StructType::create( llvm_ctx, "item" );
vector 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 think, because it is a StructType, the alignment is correct and the size of sizeof(item) is correct. Would that be useful? Is there a better way?

The second problem is that, unlike the C class hierarchy, there is no inheritance relationship between StructType. If I create a Function that accepts llvm_iterator_type but try to use llvm_singleton_iterator_type to build a Function object, the LLVM verifyModule() function will Complain to me:

The call parameter type does not match the function signature!

Then 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 );

However, verifyModule() still complains to me because obviously, there is no automatic conversion to void * in LLVM. How can I solve this problem?

It turns out that using char [sizeof(T)] is a reasonable way to make StructTypes the correct size – At least one other person from the LLVM mailing list did this.

As for the “call parameter type does not match the function signature!” error, the solution is to make all thunks use void * and use it in it static_casts. When passing parameters to thunk, please use the CreateBitCast()IRBuilder function (because in LLVM, casts-tovoid is not automatic).

My project has one C library, I want to allow users to use JIT through a certain programming language to call the functions in the library. For simplicity, suppose the library has the following classes:

 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. One way to call C functions is to wrap them in a C thunk:

extern "C" {

void thunk_item_M_new( item *addr) {
new( addr) item;
}

void thunk_singleton_iterator_M_new( singleton_iterator *addr, i tem *i) {
new( addr) singleton_iterator( *i );
}

bool thunk_iterator_M_next( item_iterator *that, item *result) {
return that ->next( result );
}

} // extern "C"

The first question is how to allocate items from LLVM. I know how to create StructTypes And add fields to them, but I don’t want to be parallel to the C class layout-this is tedious and error-prone.

The idea I get is just to add a char [sizeof(T)] as the StructType of the C class type The only field of :

StructType *const llvm_item_type = StructType::create( llvm_ctx, "item" );
vector 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 *constptr_type = llvm_item_type ::getUnqual( llvm_item_type );

I think, because it is a StructType, the alignment is correct, and the size of sizeof(item) is correct. Would that be useful? Is there a better way?

The second problem is that, unlike the C class hierarchy, there is no inheritance relationship between StructType. If I create a Function that accepts llvm_iterator_type but try to use llvm_singleton_iterator_type to build a Function object, the LLVM verifyModule() function will Complain to me:

The call parameter type does not match the function signature!

Then 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 );

However, verifyModule() still complains to me because obviously, there is no automatic conversion to void * in LLVM. How can I solve this problem?

It turns out that using char [sizeof(T)] is a reasonable way to make StructTypes the correct size-at least one other person from the LLVM mailing list does this .

As for the “call parameter type does not match the function signature!” error, the solution is to make all thunks use void * and use static_casts in them. When passing parameters to the thunk, please use CreateBitCast ()IRBuilder function (because casts-tovoid is not automatic in LLVM).

Leave a Comment

Your email address will not be published.