Использование кода JL LLVM для кодирования программы для вызова кода C ++ - PullRequest
4 голосов
/ 15 марта 2012

В моем проекте есть библиотека 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-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"

Первая проблема заключается в том, как выделить item из LLVM. Я знаю, как создавать StructType s и добавлять к ним поля, но я не хочу параллельного размещения классов C ++ - это утомительно и подвержено ошибкам.

Идея, которую я получил, состояла в том, чтобы просто добавить char[sizeof(T)] в качестве единственного поля в StructType для типа класса C ++:

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, но пытаюсь построить Function объект, используя 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 );

но verifyModule() все еще жалуется на меня, потому что, очевидно, в LLVM нет автоматического приведения к void* типам. Как я могу решить эту проблему?

1 Ответ

5 голосов
/ 21 марта 2012

Оказывается, что использование char[sizeof(T)] является разумным способом для получения StructType s правильного размера - по крайней мере еще один человек из списка рассылки LLVM делает это.

Что касается "Тип параметра вызова не соответствует сигнатуре функции!" ошибки, решение которых состоит в том, чтобы все thunks использовали void* и использовали static_cast s внутри. При передаче аргументов в thunks, используйте функцию CreateBitCast() IRBuilder (поскольку приведение к void не является автоматическим в LLVM).

...