Загрузка и выполнение битового кода API LLVM C ++ - PullRequest
0 голосов
/ 24 апреля 2020

Я ищу полный пример, который описывает использование LLVM C ++ API, в частности загрузку функции из файла битового кода (не опечатки, они называют его битовым кодом), запуск его и получение результатов. Я изучил этот пост и пытаюсь перенести его на C ++, но я пытаюсь понять, как создавать различные необходимые экземпляры, особенно механизм исполнения. Я использую clang -c -emit-llvm file.c для компиляции файла C в файл битового кода .bc LLVM. Команда clang -S -emit-llvm file.c также работает и генерирует текстовый файл .ll. Кажется, что функция parseIRFile может загружать оба.

Это то, что я имею до сих пор:

LLVMContext context;
SMDiagnostic error;
unique_ptr<Module> mod = parseIRFile(StringRef(pathToLlOrBcFile), error, context);

Мне не нужно использовать JIT, я в порядке с базой c переводчик на данный момент; но я sh заставлю его работать с MCJIT или как там его потом.

Спасибо @arnt за то, что я заметил, что на самом деле использовал текстовый формат IR; Я изменил Makefile и приложение C ++, чтобы отразить тот факт, что .ll и .b c могут быть проанализированы одной и той же функцией.

1 Ответ

1 голос
/ 24 апреля 2020

Я использую llvm-devel.x86_64 9.0.1-5.fc31 в Fedora 31. Полный код ниже.

main. cc (Это приложение C ++, которое загружает битовый код LLVM)

#include <iostream>

#include <llvm/IR/Module.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>

using std::unique_ptr;
using std::cout;
using std::endl;

using llvm::Module;
using llvm::SMDiagnostic;
using llvm::LLVMContext;
using llvm::parseIRFile;
using llvm::StringRef;
using llvm::ExecutionEngine;
using llvm::EngineBuilder;
using llvm::ArrayRef;
using llvm::GenericValue;
using llvm::Function;

int main(int argc, char const *argv[]) {
  LLVMContext context;
  SMDiagnostic error;
  unique_ptr<Module> mod = parseIRFile(StringRef("hosted.bc" /* .ll files also work */), error, context);
  ExecutionEngine *executionEngine = EngineBuilder(std::move(mod)).setEngineKind(llvm::EngineKind::Interpreter).create();
  Function *add = executionEngine->FindFunctionNamed(StringRef("add"));
  GenericValue param1, param2;
  param1.FloatVal = 5.5;
  param2.FloatVal = 2.7;
  GenericValue params[] = { param1, param2 };
  ArrayRef<GenericValue> args = ArrayRef<GenericValue>(params, 2);
  GenericValue result = executionEngine->runFunction(add, args);
  cout << param1.FloatVal << " + " << param2.FloatVal << " = " << result.FloatVal << endl;
}

hosted. c (Это приложение C, которое я собираю в файл .bc с clang)

float add(float a, float b) {
  return a + b;
}

Makefile (используется для компиляции собственного приложения и байт-кода LLVM, который будет размещен в нем)

app.o: main.cc
    g++ main.cc -lLLVM -o app.o

hosted.bc: hosted.c
    clang -c -emit-llvm hosted.c

clean:
    rm app.o
    rm hosted.bc

.PHONY: clean

Вывод (компиляция и запуск)

[dario@localhost llvm-cpp-first]$ make hosted.bc && make && ./app.o 
clang -c -emit-llvm hosted.c
g++ main.cc -lLLVM -o app.o
5.5 + 2.7 = 8.2
...