#include "llvm-c/Core.h"
#include "llvm-c/Error.h"
#include "llvm-c/IRReader.h"
#include "llvm-c/Initialization.h"
#include "llvm-c/LLJIT.h"
#include "llvm-c/Support.h"
#include "llvm-c/Target.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
int handleError(LLVMErrorRef Err) {
char *ErrMsg = LLVMGetErrorMessage(Err);
fprintf(stderr, "Error: %s\n", ErrMsg);
LLVMDisposeErrorMessage(ErrMsg);
return 1;
}
const char FooMod[] = " define i32 @foo_body() { \n"
" entry: \n"
" ret i32 1 \n"
" } \n";
const char BarMod[] = " define i32 @bar_body() { \n"
" entry: \n"
" ret i32 2 \n"
" } \n";
const char MainMod[] =
" define i32 @entry(i32 %argc) { \n"
" entry: \n"
" %and = and i32 %argc, 1 \n"
" %tobool = icmp eq i32 %and, 0 \n"
" br i1 %tobool, label %if.end, label %if.then \n"
" \n"
" if.then: \n"
" %call = tail call i32 @foo() \n"
" br label %return \n"
" \n"
" if.end: \n"
" %call1 = tail call i32 @bar() \n"
" br label %return \n"
" \n"
" return: \n"
" %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
" ret i32 %retval.0 \n"
" } \n"
" \n"
" declare i32 @foo() \n"
" declare i32 @bar() \n";
LLVMErrorRef applyDataLayout(void *Ctx, LLVMModuleRef M) {
LLVMSetDataLayout(M, LLVMOrcLLJITGetDataLayoutStr((LLVMOrcLLJITRef)Ctx));
return LLVMErrorSuccess;
}
LLVMErrorRef parseExampleModule(const char *Source, size_t Len,
const char *Name,
LLVMOrcThreadSafeModuleRef *TSM) {
LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
LLVMMemoryBufferRef MB =
LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 1);
LLVMModuleRef M;
char *ErrMsg;
if (LLVMParseIRInContext(Ctx, MB, &M, &ErrMsg)) {
LLVMErrorRef Err = LLVMCreateStringError(ErrMsg);
LLVMDisposeMessage(ErrMsg);
return Err;
}
*TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
LLVMOrcDisposeThreadSafeContext(TSCtx);
return LLVMErrorSuccess;
}
void Destroy(void *Ctx) {}
void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) {
int MainResult = 0;
size_t NumSymbols;
LLVMOrcSymbolStringPoolEntryRef *Symbols =
LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols);
assert(NumSymbols == 1);
LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx;
LLVMOrcSymbolStringPoolEntryRef Sym = Symbols[0];
LLVMOrcThreadSafeModuleRef TSM = 0;
LLVMErrorRef Err;
LLVMOrcSymbolStringPoolEntryRef FooBody =
LLVMOrcLLJITMangleAndIntern(J, "foo_body");
LLVMOrcSymbolStringPoolEntryRef BarBody =
LLVMOrcLLJITMangleAndIntern(J, "bar_body");
if (Sym == FooBody) {
if ((Err = parseExampleModule(FooMod, strlen(FooMod), "foo-mod", &TSM))) {
MainResult = handleError(Err);
goto cleanup;
}
} else if (Sym == BarBody) {
if ((Err = parseExampleModule(BarMod, strlen(BarMod), "bar-mod", &TSM))) {
MainResult = handleError(Err);
goto cleanup;
}
} else {
MainResult = 1;
goto cleanup;
}
assert(TSM);
if ((Err = LLVMOrcThreadSafeModuleWithModuleDo(TSM, &applyDataLayout, Ctx))) {
MainResult = handleError(Err);
goto cleanup;
}
cleanup:
LLVMOrcReleaseSymbolStringPoolEntry(BarBody);
LLVMOrcReleaseSymbolStringPoolEntry(FooBody);
LLVMOrcDisposeSymbols(Symbols);
if (MainResult == 1) {
LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
LLVMOrcDisposeMaterializationResponsibility(MR);
} else {
LLVMOrcIRTransformLayerRef IRLayer = LLVMOrcLLJITGetIRTransformLayer(J);
LLVMOrcIRTransformLayerEmit(IRLayer, MR, TSM);
}
}
int main(int argc, char *argv[]) {
int MainResult = 0;
LLVMParseCommandLineOptions(argc, (const char **)argv, "");
LLVMInitializeCore(LLVMGetGlobalPassRegistry());
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMOrcLLJITRef J;
const char *TargetTriple;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
MainResult = handleError(Err);
goto llvm_shutdown;
}
TargetTriple = LLVMOrcLLJITGetTripleString(J);
}
{
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
LLVMErrorRef Err;
LLVMOrcThreadSafeModuleRef MainTSM;
if ((Err = parseExampleModule(MainMod, strlen(MainMod), "main-mod",
&MainTSM))) {
MainResult = handleError(Err);
goto jit_cleanup;
}
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {
LLVMOrcDisposeThreadSafeModule(MainTSM);
MainResult = handleError(Err);
goto jit_cleanup;
}
}
LLVMJITSymbolFlags Flags = {
LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
LLVMOrcCSymbolFlagsMapPair FooSym = {
LLVMOrcLLJITMangleAndIntern(J, "foo_body"), Flags};
LLVMOrcCSymbolFlagsMapPair BarSym = {
LLVMOrcLLJITMangleAndIntern(J, "bar_body"), Flags};
{
LLVMOrcMaterializationUnitRef FooMU =
LLVMOrcCreateCustomMaterializationUnit("FooMU", J, &FooSym, 1, NULL,
&Materialize, NULL, &Destroy);
LLVMOrcMaterializationUnitRef BarMU =
LLVMOrcCreateCustomMaterializationUnit("BarMU", J, &BarSym, 1, NULL,
&Materialize, NULL, &Destroy);
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
LLVMOrcJITDylibDefine(MainJD, FooMU);
LLVMOrcJITDylibDefine(MainJD, BarMU);
}
LLVMOrcIndirectStubsManagerRef ISM =
LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
LLVMOrcLazyCallThroughManagerRef LCTM;
{
LLVMErrorRef Err;
LLVMOrcExecutionSessionRef ES = LLVMOrcLLJITGetExecutionSession(J);
if ((Err = LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple, ES, 0,
&LCTM))) {
LLVMOrcDisposeIndirectStubsManager(ISM);
MainResult = handleError(Err);
goto jit_cleanup;
}
}
LLVMOrcCSymbolAliasMapPair ReExports[2] = {
{LLVMOrcLLJITMangleAndIntern(J, "foo"),
{LLVMOrcLLJITMangleAndIntern(J, "foo_body"), Flags}},
{LLVMOrcLLJITMangleAndIntern(J, "bar"),
{LLVMOrcLLJITMangleAndIntern(J, "bar_body"), Flags}},
};
{
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
LLVMOrcMaterializationUnitRef MU =
LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);
LLVMOrcJITDylibDefine(MainJD, MU);
}
LLVMOrcJITTargetAddress EntryAddr;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {
MainResult = handleError(Err);
goto cleanup;
}
}
int32_t (*Entry)(int32_t) = (int32_t(*)(int32_t))EntryAddr;
int32_t Result = Entry(argc);
printf("--- Result ---\n");
printf("entry(%i) = %i\n", argc, Result);
cleanup : {
LLVMOrcDisposeIndirectStubsManager(ISM);
LLVMOrcDisposeLazyCallThroughManager(LCTM);
}
jit_cleanup:
{
LLVMErrorRef Err;
if ((Err = LLVMOrcDisposeLLJIT(J))) {
int NewFailureResult = handleError(Err);
if (MainResult == 0)
MainResult = NewFailureResult;
}
}
llvm_shutdown:
LLVMShutdown();
return MainResult;
}