//===------ OrcTestCommon.h - Utilities for Orc Unit Tests ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Common utilities for the Orc unit tests. // //===----------------------------------------------------------------------===// #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H #define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/TypeBuilder.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" #include namespace llvm { namespace orc { // CoreAPIsStandardTest that saves a bunch of boilerplate by providing the // following: // // (1) ES -- An ExecutionSession // (2) Foo, Bar, Baz, Qux -- SymbolStringPtrs for strings "foo", "bar", "baz", // and "qux" respectively. // (3) FooAddr, BarAddr, BazAddr, QuxAddr -- Dummy addresses. Guaranteed // distinct and non-null. // (4) FooSym, BarSym, BazSym, QuxSym -- JITEvaluatedSymbols with FooAddr, // BarAddr, BazAddr, and QuxAddr respectively. All with default strong, // linkage and non-hidden visibility. // (5) V -- A JITDylib associated with ES. class CoreAPIsBasedStandardTest : public testing::Test { protected: std::shared_ptr SSP = std::make_shared(); ExecutionSession ES{SSP}; JITDylib &JD = ES.createJITDylib("JD"); SymbolStringPtr Foo = ES.getSymbolStringPool().intern("foo"); SymbolStringPtr Bar = ES.getSymbolStringPool().intern("bar"); SymbolStringPtr Baz = ES.getSymbolStringPool().intern("baz"); SymbolStringPtr Qux = ES.getSymbolStringPool().intern("qux"); static const JITTargetAddress FooAddr = 1U; static const JITTargetAddress BarAddr = 2U; static const JITTargetAddress BazAddr = 3U; static const JITTargetAddress QuxAddr = 4U; JITEvaluatedSymbol FooSym = JITEvaluatedSymbol(FooAddr, JITSymbolFlags::Exported); JITEvaluatedSymbol BarSym = JITEvaluatedSymbol(BarAddr, JITSymbolFlags::Exported); JITEvaluatedSymbol BazSym = JITEvaluatedSymbol(BazAddr, JITSymbolFlags::Exported); JITEvaluatedSymbol QuxSym = JITEvaluatedSymbol(QuxAddr, JITSymbolFlags::Exported); }; } // end namespace orc class OrcNativeTarget { public: static void initialize() { if (!NativeTargetInitialized) { InitializeNativeTarget(); InitializeNativeTargetAsmParser(); InitializeNativeTargetAsmPrinter(); NativeTargetInitialized = true; } } private: static bool NativeTargetInitialized; }; // Base class for Orc tests that will execute code. class OrcExecutionTest { public: OrcExecutionTest() { // Initialize the native target if it hasn't been done already. OrcNativeTarget::initialize(); // Try to select a TargetMachine for the host. TM.reset(EngineBuilder().selectTarget()); if (TM) { // If we found a TargetMachine, check that it's one that Orc supports. const Triple& TT = TM->getTargetTriple(); // Bail out for windows platforms. We do not support these yet. if ((TT.getArch() != Triple::x86_64 && TT.getArch() != Triple::x86) || TT.isOSWindows()) return; // Target can JIT? SupportsJIT = TM->getTarget().hasJIT(); // Use ability to create callback manager to detect whether Orc // has indirection support on this platform. This way the test // and Orc code do not get out of sync. SupportsIndirection = !!orc::createLocalCompileCallbackManager(TT, ES, 0); } }; protected: orc::ExecutionSession ES; LLVMContext Context; std::unique_ptr TM; bool SupportsJIT = false; bool SupportsIndirection = false; }; class ModuleBuilder { public: ModuleBuilder(LLVMContext &Context, StringRef Triple, StringRef Name); template Function* createFunctionDecl(StringRef Name) { return Function::Create( TypeBuilder::get(M->getContext()), GlobalValue::ExternalLinkage, Name, M.get()); } Module* getModule() { return M.get(); } const Module* getModule() const { return M.get(); } std::unique_ptr takeModule() { return std::move(M); } private: std::unique_ptr M; }; // Dummy struct type. struct DummyStruct { int X[256]; }; // TypeBuilder specialization for DummyStruct. template class TypeBuilder { public: static StructType *get(LLVMContext &Context) { return StructType::get( TypeBuilder[256], XCompile>::get(Context)); } }; template class MockBaseLayer { public: using ModuleHandleT = HandleT; using AddModuleSignature = Expected(ModuleT M, std::shared_ptr R); using RemoveModuleSignature = Error(ModuleHandleT H); using FindSymbolSignature = JITSymbol(const std::string &Name, bool ExportedSymbolsOnly); using FindSymbolInSignature = JITSymbol(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsONly); using EmitAndFinalizeSignature = Error(ModuleHandleT H); std::function addModuleImpl; std::function removeModuleImpl; std::function findSymbolImpl; std::function findSymbolInImpl; std::function emitAndFinalizeImpl; Expected addModule(ModuleT M, std::shared_ptr R) { assert(addModuleImpl && "addModule called, but no mock implementation was provided"); return addModuleImpl(std::move(M), std::move(R)); } Error removeModule(ModuleHandleT H) { assert(removeModuleImpl && "removeModule called, but no mock implementation was provided"); return removeModuleImpl(H); } JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { assert(findSymbolImpl && "findSymbol called, but no mock implementation was provided"); return findSymbolImpl(Name, ExportedSymbolsOnly); } JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { assert(findSymbolInImpl && "findSymbolIn called, but no mock implementation was provided"); return findSymbolInImpl(H, Name, ExportedSymbolsOnly); } Error emitAndFinaliez(ModuleHandleT H) { assert(emitAndFinalizeImpl && "emitAndFinalize called, but no mock implementation was provided"); return emitAndFinalizeImpl(H); } }; class ReturnNullJITSymbol { public: template JITSymbol operator()(Args...) const { return nullptr; } }; template class DoNothingAndReturn { public: DoNothingAndReturn(ReturnT Ret) : Ret(std::move(Ret)) {} template void operator()(Args...) const { return Ret; } private: ReturnT Ret; }; template <> class DoNothingAndReturn { public: template void operator()(Args...) const { } }; } // namespace llvm #endif