
This removes ThreadSafeContext::Lock, ThreadSafeContext::getLock, and ThreadSafeContext::getContext, and replaces them with a ThreadSafeContext::withContextDo method (and const override). The new method can be used to access an existing ThreadSafeContext-wrapped LLVMContext in a safe way: ThreadSafeContext TSCtx = ... ; TSCtx.withContextDo([](LLVMContext *Ctx) { // this closure has exclusive access to Ctx. }); The new API enforces correct locking, whereas the old APIs relied on manual locking (which almost no in-tree code preformed, relying instead on incidental exclusive access to the ThreadSafeContext).
191 lines
6.4 KiB
C++
191 lines
6.4 KiB
C++
#include "llvm/ExecutionEngine/Orc/ReOptimizeLayer.h"
|
|
#include "OrcTestCommon.h"
|
|
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
|
|
#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
|
|
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
|
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
|
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/IRPartitionLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h"
|
|
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
|
|
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h"
|
|
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/Support/CodeGen.h"
|
|
#include "llvm/TargetParser/Host.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
using namespace llvm::jitlink;
|
|
|
|
class ReOptimizeLayerTest : public testing::Test {
|
|
public:
|
|
~ReOptimizeLayerTest() {
|
|
if (ES)
|
|
if (auto Err = ES->endSession())
|
|
ES->reportError(std::move(Err));
|
|
}
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
auto JTMB = JITTargetMachineBuilder::detectHost();
|
|
// Bail out if we can not detect the host.
|
|
if (!JTMB) {
|
|
consumeError(JTMB.takeError());
|
|
GTEST_SKIP();
|
|
}
|
|
|
|
// COFF-ARM64 is not supported yet
|
|
auto Triple = JTMB->getTargetTriple();
|
|
if (Triple.isOSBinFormatCOFF() && Triple.isAArch64())
|
|
GTEST_SKIP();
|
|
|
|
// SystemZ is not supported yet.
|
|
if (Triple.isSystemZ())
|
|
GTEST_SKIP();
|
|
|
|
// 32-bit X86 is not supported yet.
|
|
if (Triple.isX86() && Triple.isArch32Bit())
|
|
GTEST_SKIP();
|
|
|
|
if (Triple.isPPC())
|
|
GTEST_SKIP();
|
|
|
|
// RISC-V is not supported yet
|
|
if (Triple.isRISCV())
|
|
GTEST_SKIP();
|
|
|
|
// ARM is not supported yet.
|
|
if (Triple.isARM())
|
|
GTEST_SKIP();
|
|
|
|
auto EPC = SelfExecutorProcessControl::Create();
|
|
if (!EPC) {
|
|
consumeError(EPC.takeError());
|
|
GTEST_SKIP();
|
|
}
|
|
|
|
auto DLOrErr = JTMB->getDefaultDataLayoutForTarget();
|
|
if (!DLOrErr) {
|
|
consumeError(DLOrErr.takeError());
|
|
GTEST_SKIP();
|
|
}
|
|
|
|
auto PageSize = sys::Process::getPageSize();
|
|
if (!PageSize) {
|
|
consumeError(PageSize.takeError());
|
|
GTEST_SKIP();
|
|
}
|
|
|
|
ES = std::make_unique<ExecutionSession>(std::move(*EPC));
|
|
JD = &ES->createBareJITDylib("main");
|
|
ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(
|
|
*ES, std::make_unique<InProcessMemoryManager>(*PageSize));
|
|
DL = std::make_unique<DataLayout>(std::move(*DLOrErr));
|
|
|
|
auto TM = JTMB->createTargetMachine();
|
|
if (!TM) {
|
|
consumeError(TM.takeError());
|
|
GTEST_SKIP();
|
|
}
|
|
auto CompileFunction =
|
|
std::make_unique<TMOwningSimpleCompiler>(std::move(*TM));
|
|
CompileLayer = std::make_unique<IRCompileLayer>(*ES, *ObjLinkingLayer,
|
|
std::move(CompileFunction));
|
|
}
|
|
|
|
Error addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM) {
|
|
assert(TSM && "Can not add null module");
|
|
|
|
TSM.withModuleDo([&](Module &M) { M.setDataLayout(*DL); });
|
|
|
|
return ROLayer->add(std::move(RT), std::move(TSM));
|
|
}
|
|
|
|
JITDylib *JD{nullptr};
|
|
std::unique_ptr<ExecutionSession> ES;
|
|
std::unique_ptr<ObjectLinkingLayer> ObjLinkingLayer;
|
|
std::unique_ptr<IRCompileLayer> CompileLayer;
|
|
std::unique_ptr<ReOptimizeLayer> ROLayer;
|
|
std::unique_ptr<DataLayout> DL;
|
|
};
|
|
|
|
static Function *createRetFunction(Module *M, StringRef Name,
|
|
uint32_t ReturnCode) {
|
|
Function *Result = Function::Create(
|
|
FunctionType::get(Type::getInt32Ty(M->getContext()), {}, false),
|
|
GlobalValue::ExternalLinkage, Name, M);
|
|
|
|
BasicBlock *BB = BasicBlock::Create(M->getContext(), Name, Result);
|
|
IRBuilder<> Builder(M->getContext());
|
|
Builder.SetInsertPoint(BB);
|
|
|
|
Value *RetValue = ConstantInt::get(M->getContext(), APInt(32, ReturnCode));
|
|
Builder.CreateRet(RetValue);
|
|
return Result;
|
|
}
|
|
|
|
TEST_F(ReOptimizeLayerTest, BasicReOptimization) {
|
|
MangleAndInterner Mangle(*ES, *DL);
|
|
|
|
auto &EPC = ES->getExecutorProcessControl();
|
|
EXPECT_THAT_ERROR(JD->define(absoluteSymbols(
|
|
{{Mangle("__orc_rt_jit_dispatch"),
|
|
{EPC.getJITDispatchInfo().JITDispatchFunction,
|
|
JITSymbolFlags::Exported}},
|
|
{Mangle("__orc_rt_jit_dispatch_ctx"),
|
|
{EPC.getJITDispatchInfo().JITDispatchContext,
|
|
JITSymbolFlags::Exported}},
|
|
{Mangle("__orc_rt_reoptimize_tag"),
|
|
{ExecutorAddr(), JITSymbolFlags::Exported}}})),
|
|
Succeeded());
|
|
|
|
auto RM = JITLinkRedirectableSymbolManager::Create(*ObjLinkingLayer);
|
|
EXPECT_THAT_ERROR(RM.takeError(), Succeeded());
|
|
|
|
ROLayer = std::make_unique<ReOptimizeLayer>(*ES, *DL, *CompileLayer, **RM);
|
|
ROLayer->setReoptimizeFunc(
|
|
[&](ReOptimizeLayer &Parent,
|
|
ReOptimizeLayer::ReOptMaterializationUnitID MUID, unsigned CurVerison,
|
|
ResourceTrackerSP OldRT, ThreadSafeModule &TSM) {
|
|
TSM.withModuleDo([&](Module &M) {
|
|
for (auto &F : M) {
|
|
if (F.isDeclaration())
|
|
continue;
|
|
for (auto &B : F) {
|
|
for (auto &I : B) {
|
|
if (ReturnInst *Ret = dyn_cast<ReturnInst>(&I)) {
|
|
Value *RetValue =
|
|
ConstantInt::get(M.getContext(), APInt(32, 53));
|
|
Ret->setOperand(0, RetValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return Error::success();
|
|
});
|
|
EXPECT_THAT_ERROR(ROLayer->reigsterRuntimeFunctions(*JD), Succeeded());
|
|
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("<main>", *Ctx);
|
|
M->setTargetTriple(Triple(sys::getProcessTriple()));
|
|
|
|
(void)createRetFunction(M.get(), "main", 42);
|
|
|
|
EXPECT_THAT_ERROR(addIRModule(JD->getDefaultResourceTracker(),
|
|
ThreadSafeModule(std::move(M), std::move(Ctx))),
|
|
Succeeded());
|
|
|
|
auto Result = cantFail(ES->lookup({JD}, Mangle("main")));
|
|
auto FuncPtr = Result.getAddress().toPtr<int (*)()>();
|
|
for (size_t I = 0; I <= ReOptimizeLayer::CallCountThreshold; I++)
|
|
EXPECT_EQ(FuncPtr(), 42);
|
|
EXPECT_EQ(FuncPtr(), 53);
|
|
}
|