使用LLVM JIT代码编码程序以调用C++代码

4

我的项目有一个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 );
  // ...
};

我知道LLVM对C++一无所知,调用C++函数的一种方式是将它们包装在C语言函数中:

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"

第一个问题是如何从LLVM分配一个item。我知道如何创建StructType并向其添加字段,但我不想与C++类布局并行--这很繁琐且容易出错。
我的想法很简单,就是为C++类类型的StructType添加一个唯一的char[sizeof(T)]作为唯一的字段:
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 );

我认为,由于它是一个StructType,所以对齐方式应该是正确的,sizeof(item)会得到正确的大小。这样行吗?有更好的方法吗?
第二个问题是,与C++类层次结构不同,StructType之间没有继承关系。如果我创建一个Function,它需要一个llvm_iterator_type,但尝试使用llvm_singleton_iterator_type构建一个Function对象,LLVM的verifyModule()函数会抱怨: 调用参数类型与函数签名不匹配! 所以我想到了简单地在所有地方使用void*
Type *const llvm_void_type = Type::getVoidTy( llvm_ctx );
PointerType *const llvm_void_ptr_type = PointerType::getUnqual( llvm_void_type );

但是verifyModule()仍然抱怨我,因为在LLVM中显然没有对void*类型进行自动转换。 我该如何解决这个问题?

1个回答

5

原来使用char[sizeof(T)]是使得StructType具有正确大小的合理方法——至少LLVM邮件列表中有另一位用户这样做。

对于"调用参数类型与函数签名不匹配!"错误,一个解决方法是让所有thunk使用void*,并在内部使用static_cast。当向thunk传递参数时,使用CreateBitCast() IRBuilder函数(因为在LLVM中转换为void不是自动的)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接