blob: 8e1273ed91198e08854edb6153dfe3a4d1dacb86 [file] [log] [blame]
//===---- 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<std::unique_ptr<TestResources>>
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<char, 0> ObjBuffer;
raw_svector_ostream ObjStream;
MCTargetOptions Options;
std::unique_ptr<MCRegisterInfo> MRI;
std::unique_ptr<MCAsmInfo> MAI;
std::unique_ptr<MCInstrInfo> MCII;
std::unique_ptr<MCSubtargetInfo> STI;
MCObjectFileInfo MOFI;
std::unique_ptr<MCContext> AsCtx;
std::unique_ptr<MCStreamer> MOS;
std::unique_ptr<MCContext> DisCtx;
std::unique_ptr<const MCDisassembler> Dis;
};
class TestJITLinkContext : public jitlink::JITLinkContext {
public:
using TestCaseFunction = std::function<void(jitlink::AtomGraph &)>;
using NotifyResolvedFunction = std::function<void(jitlink::AtomGraph &G)>;
using NotifyFinalizedFunction = std::function<void(
std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>)>;
TestJITLinkContext(TestResources &TR, TestCaseFunction TestCase);
StringMap<JITEvaluatedSymbol> &externals() { return Externals; }
TestJITLinkContext &
setNotifyResolved(NotifyResolvedFunction NotifyResolved);
TestJITLinkContext &
setNotifyFinalized(NotifyFinalizedFunction NotifyFinalized);
TestJITLinkContext &
setMemoryManager(std::unique_ptr<jitlink::JITLinkMemoryManager> MM);
jitlink::JITLinkMemoryManager &getMemoryManager() override;
MemoryBufferRef getObjectBuffer() const override;
void notifyFailed(Error Err) override;
void
lookup(const DenseSet<StringRef> &Symbols,
jitlink::JITLinkAsyncLookupContinuation LookupContinuation) override;
void notifyResolved(jitlink::AtomGraph &G) override;
void notifyFinalized(
std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> A) override;
Error modifyPassConfig(const Triple &TT,
jitlink::PassConfiguration &Config) override;
private:
TestResources &TR;
TestCaseFunction TestCase;
NotifyResolvedFunction NotifyResolved;
NotifyFinalizedFunction NotifyFinalized;
std::unique_ptr<MemoryBuffer> ObjBuffer;
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr;
StringMap<JITEvaluatedSymbol> 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<std::unique_ptr<TestResources>>
getTestResources(StringRef AsmSrc, StringRef Triple, bool PIC,
bool LargeCodeModel, MCTargetOptions Options) const {
return TestResources::Create(AsmSrc, Triple, PIC, LargeCodeModel,
std::move(Options));
}
template <typename T>
static Expected<T> readInt(jitlink::AtomGraph &G, jitlink::DefinedAtom &A,
size_t Offset = 0) {
if (Offset + sizeof(T) > A.getContent().size())
return make_error<StringError>("Reading past end of atom content",
inconvertibleErrorCode());
return support::endian::read<T, 1>(A.getContent().data() + Offset,
G.getEndianness());
}
template <typename T>
static Expected<T> readInt(jitlink::AtomGraph &G, StringRef AtomName,
size_t Offset = 0) {
auto DA = G.findDefinedAtomByName(AtomName);
if (!DA)
return DA.takeError();
return readInt<T>(G, *DA);
}
static Expected<std::pair<MCInst, size_t>>
disassemble(const MCDisassembler &Dis, jitlink::DefinedAtom &Atom,
size_t Offset = 0);
static Expected<int64_t> decodeImmediateOperand(const MCDisassembler &Dis,
jitlink::DefinedAtom &Atom,
size_t OpIdx,
size_t Offset = 0);
static jitlink::Atom &atom(jitlink::AtomGraph &G, StringRef Name) {
return G.getAtomByName(Name);
}
static jitlink::DefinedAtom &definedAtom(jitlink::AtomGraph &G,
StringRef Name) {
return G.getDefinedAtomByName(Name);
}
static JITTargetAddress atomAddr(jitlink::AtomGraph &G, StringRef Name) {
return atom(G, Name).getAddress();
}
template <typename PredT>
static size_t countEdgesMatching(jitlink::DefinedAtom &DA,
const PredT &Pred) {
return std::count_if(DA.edges().begin(), DA.edges().end(), Pred);
}
template <typename PredT>
static size_t countEdgesMatching(jitlink::AtomGraph &G, StringRef Name,
const PredT &Pred) {
return countEdgesMatching(definedAtom(G, Name), Pred);
}
private:
static bool AreTargetsInitialized;
void initializeLLVMTargets();
DenseMap<StringRef, JITEvaluatedSymbol> Externals;
};
} // end namespace llvm
#endif