#include "llvm/ADT/SmallVector.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"
namespace orc {
-/// Simple compile functor: Takes a single IR module and returns an
-/// ObjectFile.
+/// Simple compile functor: Takes a single IR module and returns an ObjectFile.
+/// This compiler supports a single compilation thread and LLVMContext only.
+/// For multithreaded compilation, use MultiThreadedSimpleCompiler below.
class SimpleCompiler {
-private:
- class SmallVectorMemoryBuffer : public MemoryBuffer {
- public:
- SmallVectorMemoryBuffer(SmallVector<char, 0> Buffer)
- : Buffer(std::move(Buffer)) {
- init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
- false);
- }
-
- BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
-
- private:
- SmallVector<char, 0> Buffer;
- };
-
public:
using CompileResult = std::unique_ptr<MemoryBuffer>;
ObjectCache *ObjCache = nullptr;
};
+/// A thread-safe version of SimpleCompiler.
+///
+/// This class creates a new TargetMachine and SimpleCompiler instance for each
+/// compile.
+class MultiThreadedSimpleCompiler {
+public:
+ MultiThreadedSimpleCompiler(JITTargetMachineBuilder JTMB,
+ ObjectCache *ObjCache = nullptr)
+ : JTMB(std::move(JTMB)), ObjCache(ObjCache) {}
+
+ void setObjectCache(ObjectCache *ObjCache) { this->ObjCache = ObjCache; }
+
+ std::unique_ptr<MemoryBuffer> operator()(Module &M) {
+ auto TM = cantFail(JTMB.createTargetMachine());
+ SimpleCompiler C(*TM, ObjCache);
+ return C(M);
+ }
+
+private:
+ JITTargetMachineBuilder JTMB;
+ ObjectCache *ObjCache = nullptr;
+};
+
} // end namespace orc
} // end namespace llvm
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/Cloning.h"
using namespace llvm;
using namespace llvm::orc;
R.delegate(symbolAliases(std::move(Aliases)));
}
-static std::unique_ptr<Module> extractGlobals(Module &M) {
- // FIXME: Add alias support.
+static std::unique_ptr<Module>
+extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix,
+ function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) {
+ SmallVector<char, 1> ClonedModuleBuffer;
- auto GlobalsModule = llvm::make_unique<Module>(
- (M.getName() + ".globals").str(), M.getContext());
- GlobalsModule->setDataLayout(M.getDataLayout());
-
- ValueToValueMapTy VMap;
+ {
+ std::set<GlobalValue *> ClonedDefsInSrc;
+ ValueToValueMapTy VMap;
+ auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
+ if (ShouldCloneDefinition(GV)) {
+ ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
+ return true;
+ }
+ return false;
+ });
+
+ for (auto *GV : ClonedDefsInSrc) {
+ // Delete the definition and bump the linkage in the source module.
+ if (isa<Function>(GV)) {
+ auto &F = *cast<Function>(GV);
+ F.deleteBody();
+ F.setPersonalityFn(nullptr);
+ } else if (isa<GlobalVariable>(GV)) {
+ cast<GlobalVariable>(GV)->setInitializer(nullptr);
+ } else
+ llvm_unreachable("Unsupported global type");
+
+ GV->setLinkage(GlobalValue::ExternalLinkage);
+ }
- for (auto &GV : M.globals())
- if (!GV.isDeclaration() && !VMap.count(&GV))
- cloneGlobalVariableDecl(*GlobalsModule, GV, &VMap);
+ BitcodeWriter BCWriter(ClonedModuleBuffer);
- // Clone the module flags.
- cloneModuleFlagsMetadata(*GlobalsModule, M, VMap);
+ BCWriter.writeModule(*Tmp);
+ BCWriter.writeSymtab();
+ BCWriter.writeStrtab();
+ }
- auto Materializer = createLambdaValueMaterializer([&](Value *V) -> Value * {
- if (auto *F = dyn_cast<Function>(V))
- return cloneFunctionDecl(*GlobalsModule, *F);
- return nullptr;
- });
+ MemoryBufferRef ClonedModuleBufferRef(
+ StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
+ "cloned module buffer");
- // Move the global variable initializers.
- for (auto &GV : M.globals()) {
- if (!GV.isDeclaration())
- moveGlobalVariableInitializer(GV, VMap, &Materializer);
- GV.setInitializer(nullptr);
- }
+ auto ClonedModule =
+ cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext));
+ ClonedModule->setModuleIdentifier((M.getName() + Suffix).str());
+ return ClonedModule;
+}
- return GlobalsModule;
+static std::unique_ptr<Module> extractGlobals(Module &M,
+ LLVMContext &NewContext) {
+ return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) {
+ return isa<GlobalVariable>(GV);
+ });
}
namespace llvm {
// original function definitions in the target VSO. All other
// symbols should be looked up in the backing resolver.
- // Find the functions that have been requested.
auto RequestedSymbols = R.getRequestedSymbols();
- // Extract them into a new module.
- auto ExtractedFunctionsModule =
- Parent.extractFunctions(*M, RequestedSymbols, SymbolToDefinition);
+ // Extract the requested functions into a new module.
+ std::unique_ptr<Module> ExtractedFunctionsModule;
+ if (!RequestedSymbols.empty()) {
+ std::string Suffix;
+ std::set<const GlobalValue *> FunctionsToClone;
+ for (auto &Name : RequestedSymbols) {
+ auto I = SymbolToDefinition.find(Name);
+ assert(I != SymbolToDefinition.end() && I->second != nullptr &&
+ "Should have a non-null definition");
+ FunctionsToClone.insert(I->second);
+ Suffix += ".";
+ Suffix += *Name;
+ }
+
+ std::lock_guard<std::mutex> Lock(SourceModuleMutex);
+ ExtractedFunctionsModule =
+ extractAndClone(*M, Parent.GetAvailableContext(), Suffix,
+ [&](const GlobalValue *GV) -> bool {
+ return FunctionsToClone.count(GV);
+ });
+ }
// Build a new ExtractingIRMaterializationUnit to delegate the unrequested
// symbols to.
std::move(DelegatedSymbolToDefinition), Parent, BackingResolver));
}
- Parent.emitExtractedFunctionsModule(
- std::move(R), std::move(ExtractedFunctionsModule), BackingResolver);
+ if (ExtractedFunctionsModule)
+ Parent.emitExtractedFunctionsModule(
+ std::move(R), std::move(ExtractedFunctionsModule), BackingResolver);
}
void discard(const VSO &V, SymbolStringPtr Name) override {
"ExtractingIRMaterializationUnit");
}
+ mutable std::mutex SourceModuleMutex;
CompileOnDemandLayer2 &Parent;
std::shared_ptr<SymbolResolver> BackingResolver;
};
extractAliases(R, *M, Mangle);
- auto GlobalsModule = extractGlobals(*M);
+ auto GlobalsModule = extractGlobals(*M, GetAvailableContext());
// Delete the bodies of any available externally functions, rename the
// rest, and build the compile callbacks.
if (F.hasAvailableExternallyLinkage()) {
F.deleteBody();
+ F.setPersonalityFn(nullptr);
continue;
}
F.setName(F.getName() + "$body");
auto StubDecl = cloneFunctionDecl(*M, F);
StubDecl->setName(StubUnmangledName);
+ StubDecl->setPersonalityFn(nullptr);
+ StubDecl->setLinkage(GlobalValue::ExternalLinkage);
F.replaceAllUsesWith(StubDecl);
+
auto StubName = Mangle(StubUnmangledName);
auto BodyName = Mangle(F.getName());
if (auto CallbackAddr = CCMgr.getCompileCallback(
return *I->second;
}
-std::unique_ptr<Module> CompileOnDemandLayer2::extractFunctions(
- Module &M, const SymbolNameSet &SymbolNames,
- const SymbolNameToDefinitionMap &SymbolToDefinition) {
- assert(!SymbolNames.empty() && "Can not extract an empty function set");
-
- std::string ExtractedModName;
- {
- raw_string_ostream ExtractedModNameStream(ExtractedModName);
- ExtractedModNameStream << M.getName();
- for (auto &Name : SymbolNames)
- ExtractedModNameStream << "." << *Name;
- }
-
- auto ExtractedFunctionsModule =
- llvm::make_unique<Module>(ExtractedModName, GetAvailableContext());
- ExtractedFunctionsModule->setDataLayout(M.getDataLayout());
-
- ValueToValueMapTy VMap;
-
- auto Materializer = createLambdaValueMaterializer([&](Value *V) -> Value * {
- GlobalValue *NewGV = nullptr;
- if (auto *F = dyn_cast<Function>(V))
- NewGV = cloneFunctionDecl(*ExtractedFunctionsModule, *F);
- else if (auto *GV = dyn_cast<GlobalVariable>(V))
- NewGV = cloneGlobalVariableDecl(*ExtractedFunctionsModule, *GV);
-
- if (NewGV)
- NewGV->setLinkage(GlobalValue::ExternalLinkage);
- return NewGV;
- });
-
- std::vector<std::pair<Function *, Function *>> OrigToNew;
- for (auto &FunctionName : SymbolNames) {
- assert(SymbolToDefinition.count(FunctionName) &&
- "No definition for symbol");
- auto *OrigF = cast<Function>(SymbolToDefinition.find(FunctionName)->second);
- auto *NewF = cloneFunctionDecl(*ExtractedFunctionsModule, *OrigF, &VMap);
- OrigToNew.push_back(std::make_pair(OrigF, NewF));
- }
-
- for (auto &KV : OrigToNew)
- moveFunctionBody(*KV.first, VMap, &Materializer, KV.second);
-
- return ExtractedFunctionsModule;
-}
-
void CompileOnDemandLayer2::emitExtractedFunctionsModule(
MaterializationResponsibility R, std::unique_ptr<Module> M,
std::shared_ptr<SymbolResolver> Resolver) {