2

During some research across the internet and Stackoverflow the only example on how to execute IR code during runtime was this one on SO. I have now compiled llvm and clang with Visual Studio 2012 and I was able to compile some source files I want to use to for "scripting" extensions with clang File.cpp -S -emit-llvm -O3 such that the output was the usual IR code like

; ModuleID = '.\Test.cpp'
target datalayout = "/* ... */"
target triple = "i686-pc-win32"
define i32 @test() #0 {
  ret i32 43
}
attributes #0 = { nounwind /* ... */ }

The post I referred to is really old and I would like to know two things:

  1. How does one initialize an engine and execute such code (using C++) during runtime with llvm 3.2? Are still the same calls used for it?
  2. During compilation a huge amount of libs were created. How do I know which ones have to be linked?

My code which works and could need some optimization

#include <iostream>
#include <llvm/IR/LLVMContext.h>
#include <llvm/ADT/Triple.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/CodeGen/LinkAllCodegenComponents.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/Interpreter.h>
#include <llvm/ExecutionEngine/JIT.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/ExecutionEngine/JITMemoryManager.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/Debug.h>
#include <llvm/Support/DynamicLibrary.h>
#include <llvm/Support/Format.h>
#include <llvm/Support/IRReader.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/Support/Memory.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/PluginLoader.h>
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Process.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/raw_ostream.h>

#pragma comment(lib, "LLVMMCJIT.lib")
#pragma comment(lib, "LLVMInterpreter.lib")
#pragma comment(lib, "LLVMBitReader.lib")
#pragma comment(lib, "LLVMAsmParser.lib")
#pragma comment(lib, "LLVMX86CodeGen.lib")
#pragma comment(lib, "LLVMX86AsmParser.lib")
#pragma comment(lib, "LLVMX86Disassembler.lib")
#pragma comment(lib, "LLVMJIT.lib")
#pragma comment(lib, "LLVMAsmPrinter.lib")
#pragma comment(lib, "LLVMSelectionDAG.lib")
#pragma comment(lib, "LLVMX86Desc.lib")
#pragma comment(lib, "LLVMExecutionEngine.lib")
#pragma comment(lib, "LLVMRuntimeDyld.lib")
#pragma comment(lib, "LLVMMCParser.lib")
#pragma comment(lib, "LLVMCodeGen.lib")
#pragma comment(lib, "LLVMX86AsmPrinter.lib")
#pragma comment(lib, "LLVMX86Info.lib")
#pragma comment(lib, "LLVMObjCARCOpts.lib")
#pragma comment(lib, "LLVMScalarOpts.lib")
#pragma comment(lib, "LLVMX86Utils.lib")
#pragma comment(lib, "LLVMInstCombine.lib")
#pragma comment(lib, "LLVMTransformUtils.lib")
#pragma comment(lib, "LLVMipa.lib")
#pragma comment(lib, "LLVMAnalysis.lib")
#pragma comment(lib, "LLVMTarget.lib")
#pragma comment(lib, "LLVMCore.lib")
#pragma comment(lib, "LLVMMC.lib")
#pragma comment(lib, "LLVMObject.lib")
#pragma comment(lib, "LLVMSupport.lib")

using namespace llvm;

int main(int argc, char **argv) {
    InitializeNativeTarget();
    LLVMContext &context = getGlobalContext();
    ExecutionEngine *ee;
    SMDiagnostic diag;
    Module *m = ParseIRFile("Script.s", diag, context);
    if(!m) {
        diag.print("LLVMSandbox", errs());
        return 1;
    }
    m->MaterializeAllPermanently();
    ee = EngineBuilder(m).create();
    Function *func = ee->FindFunctionNamed("main");
    typedef int (*PFN)();
    PFN pfn = reinterpret_cast<PFN>(ee->getPointerToFunction(func));
    int i = pfn();
    std::cout << i;
    std::cin.get();
    delete ee;
    return 0;
}
Community
  • 1
  • 1
Christian Ivicevic
  • 10,071
  • 7
  • 39
  • 74

1 Answers1

4

LLVM is evolving at a break-neck pace and is difficult to keep up with. Therefore, the best way to find code that keeps working while LLVM keeps moving forward is look at code that is built and tested with LLVM.

In this case, you need the lli tool (tools/lli in the code). It's a generic "executor" for LLVM IR, using either the interpreter or one of the JIT engines. It should work on Windows as well. You can use it both as an example for instantiating all the required LLVM machinery (in terms of C++ code) and building a new stand-alone tool (you can mimic it's makefile or CMakeLists.txt)

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
  • I was able to adapt the code from `lli` and the one I linked to for the newest version and with some more help I got in the IRC it works. Although I have now a huge amount of includes and libs I am probably not going to check which ones I can remove or not because I will encapsulate everything in a DLL and this doesn't need so much optimization. Thank you again. – Christian Ivicevic Feb 26 '13 at 18:48
  • @ChristianIvicevic: why do you worry about includes and libs? The linker should clean things up for you. That said, when JITing IR you eventually end up using most of the LLVM libs. The largest for-size optimization is disabling targets you don't plan to cross-compile to. – Eli Bendersky Feb 26 '13 at 22:41
  • It's just that don't like having so many unnecessary includes which make a file larger than it has to be. – Christian Ivicevic Feb 26 '13 at 22:48