//===---- JITLinkTestCommon.h - Utilities for Orc Unit Tests ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Common utilities for JITLink unit tests. // //===----------------------------------------------------------------------===// #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKTESTCOMMON_H #define LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKTESTCOMMON_H #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/Endian.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "gtest/gtest.h" namespace llvm { class JITLinkTestCommon { public: class TestResources { public: static Expected> Create(StringRef AsmSrc, StringRef TripleStr, bool PIC, bool LargeCodeModel, MCTargetOptions Options); MemoryBufferRef getTestObjectBufferRef() const; const MCDisassembler &getDisassembler() const { return *Dis; } private: TestResources(StringRef AsmSrc, StringRef TripleStr, bool PIC, bool LargeCodeModel, MCTargetOptions Options, Error &Err); Error initializeTripleSpecifics(Triple &TT); void initializeTestSpecifics(StringRef AsmSource, const Triple &TT, bool PIC, bool LargeCodeModel); const Target *TheTarget = nullptr; SourceMgr SrcMgr; SmallVector ObjBuffer; raw_svector_ostream ObjStream; MCTargetOptions Options; std::unique_ptr MRI; std::unique_ptr MAI; std::unique_ptr MCII; std::unique_ptr STI; MCObjectFileInfo MOFI; std::unique_ptr AsCtx; std::unique_ptr MOS; std::unique_ptr DisCtx; std::unique_ptr Dis; }; class TestJITLinkContext : public jitlink::JITLinkContext { public: using TestCaseFunction = std::function; using NotifyResolvedFunction = std::function; using NotifyFinalizedFunction = std::function)>; TestJITLinkContext(TestResources &TR, TestCaseFunction TestCase); StringMap &externals() { return Externals; } TestJITLinkContext & setNotifyResolved(NotifyResolvedFunction NotifyResolved); TestJITLinkContext & setNotifyFinalized(NotifyFinalizedFunction NotifyFinalized); TestJITLinkContext & setMemoryManager(std::unique_ptr MM); jitlink::JITLinkMemoryManager &getMemoryManager() override; MemoryBufferRef getObjectBuffer() const override; void notifyFailed(Error Err) override; void lookup( const DenseSet &Symbols, std::unique_ptr LC) override; void notifyResolved(jitlink::LinkGraph &G) override; void notifyFinalized( std::unique_ptr A) override; Error modifyPassConfig(const Triple &TT, jitlink::PassConfiguration &Config) override; private: TestResources &TR; TestCaseFunction TestCase; NotifyResolvedFunction NotifyResolved; NotifyFinalizedFunction NotifyFinalized; std::unique_ptr ObjBuffer; std::unique_ptr MemMgr; StringMap Externals; }; JITLinkTestCommon(); /// Get TestResources for this target/test. /// /// If this method fails it is likely because the target is not supported in /// this build. The test should bail out without failing (possibly logging a /// diagnostic). Expected> getTestResources(StringRef AsmSrc, StringRef Triple, bool PIC, bool LargeCodeModel, MCTargetOptions Options) const { return TestResources::Create(AsmSrc, Triple, PIC, LargeCodeModel, std::move(Options)); } template static Expected readInt(jitlink::LinkGraph &G, jitlink::Block &B, size_t Offset = 0) { if (Offset + sizeof(T) > B.getSize()) return make_error("Reading past end of block content", inconvertibleErrorCode()); return support::endian::read(B.getContent().data() + Offset, G.getEndianness()); } template static Expected readInt(jitlink::LinkGraph &G, StringRef SymbolName, size_t Offset = 0) { for (auto *Sym : G.defined_symbols()) { if (Sym->getName() == SymbolName) return readInt(G, Sym->getBlock(), Sym->getOffset() + Offset); } return make_error("Symbol \"" + SymbolName + "\" not found", inconvertibleErrorCode()); } static Expected> disassemble(const MCDisassembler &Dis, jitlink::Block &B, size_t Offset = 0); static Expected decodeImmediateOperand(const MCDisassembler &Dis, jitlink::Block &B, size_t OpIdx, size_t Offset = 0); static jitlink::Symbol &symbol(jitlink::LinkGraph &G, StringRef Name) { for (auto *Sym : G.defined_symbols()) if (Sym->getName() == Name) return *Sym; for (auto *Sym : G.external_symbols()) if (Sym->getName() == Name) return *Sym; for (auto *Sym : G.absolute_symbols()) if (Sym->getName() == Name) return *Sym; llvm_unreachable("Name must reference a symbol"); } static JITTargetAddress symbolAddr(jitlink::LinkGraph &G, StringRef Name) { return symbol(G, Name).getAddress(); } template static size_t countEdgesMatching(jitlink::Block &B, const PredT &Pred) { return std::count_if(B.edges().begin(), B.edges().end(), Pred); } template static size_t countEdgesMatching(jitlink::LinkGraph &G, StringRef Name, const PredT &Pred) { return countEdgesMatching(symbol(G, Name), Pred); } private: static bool AreTargetsInitialized; void initializeLLVMTargets(); DenseMap Externals; }; } // end namespace llvm #endif