blob: 5c90532d897aa0fc7d58a957725c5a7b8f0eaa26 [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::LinkGraph &)>;
using NotifyResolvedFunction = std::function<void(jitlink::LinkGraph &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,
std::unique_ptr<jitlink::JITLinkAsyncLookupContinuation> LC) override;
void notifyResolved(jitlink::LinkGraph &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::LinkGraph &G, jitlink::Block &B,
size_t Offset = 0) {
if (Offset + sizeof(T) > B.getSize())
return make_error<StringError>("Reading past end of block content",
inconvertibleErrorCode());
return support::endian::read<T, 1>(B.getContent().data() + Offset,
G.getEndianness());
}
template <typename T>
static Expected<T> readInt(jitlink::LinkGraph &G, StringRef SymbolName,
size_t Offset = 0) {
for (auto *Sym : G.defined_symbols()) {
if (Sym->getName() == SymbolName)
return readInt<T>(G, Sym->getBlock(), Sym->getOffset() + Offset);
}
return make_error<StringError>("Symbol \"" + SymbolName + "\" not found",
inconvertibleErrorCode());
}
static Expected<std::pair<MCInst, size_t>>
disassemble(const MCDisassembler &Dis, jitlink::Block &B, size_t Offset = 0);
static Expected<int64_t> 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 <typename PredT>
static size_t countEdgesMatching(jitlink::Block &B, const PredT &Pred) {
return std::count_if(B.edges().begin(), B.edges().end(), Pred);
}
template <typename PredT>
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<StringRef, JITEvaluatedSymbol> Externals;
};
} // end namespace llvm
#endif