llvm-party-12.1.0: src/LLVM/Internal/FFI/OrcJITC.cpp
#include <iostream>
#include <memory>
#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
#include <llvm/ExecutionEngine/Orc/Core.h>
#include <llvm/ExecutionEngine/Orc/ExecutionUtils.h>
#include <llvm/ExecutionEngine/Orc/Mangling.h>
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
#include <llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm/IR/Module.h>
#include <llvm-c/Core.h>
#include <llvm-c/Orc.h>
#include "LLVM/Internal/FFI/OrcJIT.h"
#include "LLVM/Internal/FFI/Target.hpp"
using namespace llvm;
using namespace orc;
#define SYMBOL_CASE(x) \
static_assert((unsigned)LLVMJITSymbolFlag##x == \
(unsigned)llvm::JITSymbolFlags::FlagNames::x, \
"JITSymbolFlag values should agree");
LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(SYMBOL_CASE)
static JITSymbolFlags unwrap(LLVMJITSymbolFlags_ f) {
JITSymbolFlags flags = JITSymbolFlags::None;
#define ENUM_CASE(x) \
if (f & LLVMJITSymbolFlag##x) \
flags |= JITSymbolFlags::x;
LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(ENUM_CASE)
#undef ENUM_CASE
return flags;
}
static LLVMJITSymbolFlags_ wrap(JITSymbolFlags f) {
unsigned r = 0;
#define ENUM_CASE(x) \
if (f & JITSymbolFlags::x) \
r |= (unsigned)LLVMJITSymbolFlag##x;
LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(ENUM_CASE)
#undef ENUM_CASE
return LLVMJITSymbolFlags_(r);
}
extern "C" {
// ExecutionSession
ExecutionSession *LLVM_Hs_createExecutionSession() {
return new ExecutionSession();
}
void LLVM_Hs_disposeExecutionSession(ExecutionSession *es) {
delete es;
}
void LLVM_Hs_ExecutionSession_endSession(ExecutionSession *es) {
if (Error err = es->endSession()) {
llvm::errs() << err << "\n";
// FIXME: Better error handling
exit(1);
}
}
// Thread-safe context
ThreadSafeContext* LLVM_Hs_createThreadSafeContext() {
return new ThreadSafeContext(std::make_unique<LLVMContext>());
}
void LLVM_Hs_disposeThreadSafeContext(ThreadSafeContext* ctx) {
delete ctx;
}
// Thread-safe module
// TODO: Figure out a way to do this without cloning the module
// The cloning is inspired by the code in llvm::orc::cloneToNewContext
ThreadSafeModule* LLVM_Hs_cloneAsThreadSafeModule(LLVMModuleRef m) {
Module* module = unwrap(m);
SmallVector<char,1> bitcode;
BitcodeWriter writer(bitcode);
writer.writeModule(*module);
writer.writeSymtab();
writer.writeStrtab();
ThreadSafeContext clone_context(std::make_unique<LLVMContext>());
MemoryBufferRef bitcode_ref(StringRef(bitcode.data(), bitcode.size()), "clone bitcode");
std::unique_ptr<Module> cloned_module = cantFail(
parseBitcodeFile(bitcode_ref, *clone_context.getContext()));
cloned_module->setModuleIdentifier(module->getName());
return new ThreadSafeModule(std::move(cloned_module), std::move(clone_context));
}
void LLVM_Hs_disposeThreadSafeModule(ThreadSafeModule* module) {
delete module;
}
// Object layer
ObjectLayer* LLVM_Hs_createRTDyldObjectLinkingLayer(ExecutionSession* es) {
return new RTDyldObjectLinkingLayer(*es, []() {
return std::make_unique<SectionMemoryManager>();
});
}
ObjectLayer* LLVM_Hs_createObjectLinkingLayer(ExecutionSession* es) {
return new ObjectLinkingLayer(*es, std::make_unique<jitlink::InProcessMemoryManager>());
}
void LLVM_Hs_ObjectLayerAddObjectFile(ObjectLayer* ol, JITDylib* dylib, const char* path) {
ExitOnError ExitOnErr;
if (auto errorOrBuffer = MemoryBuffer::getFile(path)) {
ExitOnErr(ol->add(*dylib, std::move(errorOrBuffer.get())));
} else exit(1);
}
void LLVM_Hs_disposeObjectLayer(ObjectLayer* ol) {
delete ol;
}
// Compile layer
IRLayer* LLVM_Hs_createIRCompileLayer(ExecutionSession* es, ObjectLayer* baseLayer, LLVMTargetMachineRef tm) {
return new IRCompileLayer(*es, *baseLayer, std::make_unique<SimpleCompiler>(SimpleCompiler(*unwrap(tm))));
}
void LLVM_Hs_disposeIRLayer(IRLayer* il) {
delete il;
}
void LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_forCurrentProcess(JITDylib* dylib, LLVMTargetDataRef dataLayout) {
auto dataLayoutCpp = *unwrap(dataLayout);
ExitOnError ExitOnErr;
dylib->addGenerator(
ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
dataLayoutCpp.getGlobalPrefix())));
}
void LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_load(JITDylib* dylib, LLVMTargetDataRef dataLayout, const char* name) {
auto dataLayoutCpp = *unwrap(dataLayout);
ExitOnError ExitOnErr;
dylib->addGenerator(
ExitOnErr(orc::DynamicLibrarySearchGenerator::Load(
name, dataLayoutCpp.getGlobalPrefix())));
}
void LLVM_Hs_JITDylib_defineAbsoluteSymbols(
JITDylib* dylib, unsigned num_symbols, const SymbolStringPtr** names, const JITEvaluatedSymbol** symbols) {
orc::SymbolMap map;
for (unsigned i = 0; i < num_symbols; ++i) {
map[*names[i]] = *symbols[i];
}
if (Error err = dylib->define(orc::absoluteSymbols(std::move(map)))) {
llvm::errs() << err << "\n";
// FIXME: Better error handling
exit(1);
}
}
// Warning: This consumes the module.
void LLVM_Hs_IRLayer_addModule(ThreadSafeModule* tsm, JITDylib* dylib, LLVMTargetDataRef dataLayout, IRLayer* il) {
auto dataLayoutCpp = *unwrap(dataLayout);
tsm->withModuleDo([&](auto& module) {
if (module.getDataLayout().isDefault()) {
module.setDataLayout(dataLayoutCpp);
}
});
if (Error err = il->add(*dylib, std::move(*tsm))) {
llvm::errs() << err << "\n";
// FIXME: Better error handling
exit(1);
}
}
JITDylib* LLVM_Hs_ExecutionSession_createJITDylib(ExecutionSession* es, const char* name) {
if (auto dylibOrErr = es->createJITDylib(name)) {
auto& dylib = *dylibOrErr;
return &dylib;
} else {
Error err = dylibOrErr.takeError();
llvm::errs() << err << "\n";
// FIXME: Better error handling
exit(1);
}
}
Expected<JITEvaluatedSymbol>* LLVM_Hs_ExecutionSession_lookupSymbol(
ExecutionSession* es, JITDylib* dylib,
MangleAndInterner* mangler, const char* name) {
// Printing here will show unresolved symbols.
// es->dump(llvm::errs());
return new Expected<JITEvaluatedSymbol>(es->lookup({dylib}, (*mangler)(name)));
}
uint64_t LLVM_Hs_getExpectedJITEvaluatedSymbolAddress(
Expected<JITEvaluatedSymbol>* symbolPtr,
char** errMsg) {
auto& symbol = *symbolPtr;
*errMsg = nullptr;
if (symbol) {
return symbol->getAddress();
} else {
*errMsg = strdup(toString(symbol.takeError()).c_str());
return 0;
}
}
LLVMJITSymbolFlags_ LLVM_Hs_getExpectedJITEvaluatedSymbolFlags(
Expected<JITEvaluatedSymbol>* symbolPtr) {
auto& symbol = *symbolPtr;
if (!symbol) {
return LLVMJITSymbolFlagHasError;
}
return wrap(symbol->getFlags());
}
JITEvaluatedSymbol* LLVM_Hs_createJITEvaluatedSymbol(uint64_t ptr, LLVMJITSymbolFlags_ flags) {
return new JITEvaluatedSymbol(ptr, unwrap(flags));
}
void LLVM_Hs_disposeJITEvaluatedSymbol(JITEvaluatedSymbol* symbol) {
delete symbol;
}
void LLVM_Hs_disposeExpectedJITEvaluatedSymbol(Expected<JITEvaluatedSymbol>* symbol) {
delete symbol;
}
MangleAndInterner* LLVM_Hs_createMangleAndInterner(ExecutionSession* es,
LLVMTargetDataRef dl) {
return new MangleAndInterner(*es, *unwrap(dl));
}
void LLVM_Hs_disposeMangleAndInterner(MangleAndInterner* mangler) {
delete mangler;
}
SymbolStringPtr* LLVM_Hs_MangleAndInterner_call(MangleAndInterner* mangler, const char* name) {
return new SymbolStringPtr((*mangler)(name));
}
const char* LLVM_Hs_SymbolStringPtr_c_str(SymbolStringPtr* ptr) {
return (*(*ptr)).data();
}
void LLVM_Hs_disposeSymbolStringPtr(SymbolStringPtr* ptr) {
delete ptr;
}
}