我的项目有一个C++库,我希望允许用户通过某种编程语言来JIT来调用所述库中的函数.为简单起见,假设库具有以下类:
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 );
// ...
};
Run Code Online (Sandbox Code Playgroud)
我知道LLVM对C++一无所知,调用C++函数的一种方法是将它们包装在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"
Run Code Online (Sandbox Code Playgroud)
第一个问题是如何item从LLVM 分配.我知道如何创建StructTypes并为它们添加字段,但我不想要与C++类布局并行 - 这很乏味且容易出错.
我得到的想法只是添加一个char[sizeof(T)]作为StructTypeC++类类型的唯一字段:
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 );
Run Code Online (Sandbox Code Playgroud)
我认为,因为它是一个StructType,对齐将是正确的,sizeof(item)并将得到正确的大小.那会有用吗?有没有更好的办法?
第二个问题是,与C++类层次结构不同,StructTypes 之间没有继承关系.如果我创建了Function一个llvm_iterator_type但是尝试Function使用a来构建对象llvm_singleton_iterator_type,那么LLVM verifyModule()函数会向我抱怨:
调用参数类型与函数签名不匹配!
那么我以为我只是void*到处使用:
Type *const llvm_void_type = Type::getVoidTy( llvm_ctx );
PointerType *const llvm_void_ptr_type = PointerType::getUnqual( llvm_void_type );
Run Code Online (Sandbox Code Playgroud)
但verifyModule()仍然抱怨我,因为显然,void*LLVM中没有自动转换类型.我怎么解决这个问题?
事实证明,使用char[sizeof(T)]是一种合理的方法来获得StructType正确的大小 - 至少LLVM邮件列表中的另一个人这样做.
至于"调用参数类型与函数签名不匹配!" 错误,解决方案只是让所有thunk使用void*并使用static_casts.将参数传递给thunk时,请使用该CreateBitCast() IRBuilder函数(因为void在LLVM中,casts-to 不是自动的).