#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/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(); auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) { consumeError(EPC.takeError()); GTEST_SKIP(); } auto DLOrErr = JTMB->getDefaultDataLayoutForTarget(); if (!DLOrErr) { consumeError(DLOrErr.takeError()); GTEST_SKIP(); } ES = std::make_unique(std::move(*EPC)); JD = &ES->createBareJITDylib("main"); ObjLinkingLayer = std::make_unique( *ES, std::make_unique(16384)); DL = std::make_unique(std::move(*DLOrErr)); auto TM = JTMB->createTargetMachine(); if (!TM) { consumeError(TM.takeError()); GTEST_SKIP(); } auto CompileFunction = std::make_unique(std::move(*TM)); CompileLayer = std::make_unique(*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 ES; std::unique_ptr ObjLinkingLayer; std::unique_ptr CompileLayer; std::unique_ptr ROLayer; std::unique_ptr 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(*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(&I)) { Value *RetValue = ConstantInt::get(M.getContext(), APInt(32, 53)); Ret->setOperand(0, RetValue); } } } } }); return Error::success(); }); EXPECT_THAT_ERROR(ROLayer->reigsterRuntimeFunctions(*JD), Succeeded()); ThreadSafeContext Ctx(std::make_unique()); auto M = std::make_unique("
", *Ctx.getContext()); M->setTargetTriple(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(); for (size_t I = 0; I <= ReOptimizeLayer::CallCountThreshold; I++) EXPECT_EQ(FuncPtr(), 42); EXPECT_EQ(FuncPtr(), 53); }