Lang Hames 7da63426ac Re-apply "[ORC] Unify task dispatch across ExecutionSession..." with more fixes.
This re-applies 6094b3b7db7, which was reverted in e7efd37c229 (and before that
in 1effa19de24) due to bot failures.

The test failures were fixed by having SelfExecutorProcessControl use an
InPlaceTaskDispatcher by default, rather than a DynamicThreadPoolTaskDispatcher.
This shouldn't be necessary (and indicates a concurrency issue elsewhere), but
InPlaceTaskDispatcher is a less surprising default, and better matches the
existing behavior (compilation on current thread by default), so the change
seems reasonable. I've filed https://github.com/llvm/llvm-project/issues/89870
to investigate the concurrency issue as a follow-up.

Coding my way home: 6.25133S 127.94177W
2024-04-23 23:11:37 -08:00

175 lines
5.4 KiB
C++

//===------ OrcTestCommon.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 the Orc unit tests.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H
#define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"
#include <memory>
namespace llvm {
namespace orc {
// CoreAPIsStandardTest that saves a bunch of boilerplate by providing the
// following:
//
// (1) ES -- An ExecutionSession
// (2) Foo, Bar, Baz, Qux -- SymbolStringPtrs for strings "foo", "bar", "baz",
// and "qux" respectively.
// (3) FooAddr, BarAddr, BazAddr, QuxAddr -- Dummy addresses. Guaranteed
// distinct and non-null.
// (4) FooSym, BarSym, BazSym, QuxSym -- JITEvaluatedSymbols with FooAddr,
// BarAddr, BazAddr, and QuxAddr respectively. All with default strong,
// linkage and non-hidden visibility.
// (5) V -- A JITDylib associated with ES.
class CoreAPIsBasedStandardTest : public testing::Test {
public:
~CoreAPIsBasedStandardTest() {
if (auto Err = ES.endSession())
ES.reportError(std::move(Err));
}
protected:
class OverridableDispatcher : public InPlaceTaskDispatcher {
public:
OverridableDispatcher(CoreAPIsBasedStandardTest &Parent) : Parent(Parent) {}
void dispatch(std::unique_ptr<Task> T) override;
private:
CoreAPIsBasedStandardTest &Parent;
};
std::unique_ptr<llvm::orc::ExecutorProcessControl>
makeEPC(std::shared_ptr<SymbolStringPool> SSP);
std::shared_ptr<SymbolStringPool> SSP = std::make_shared<SymbolStringPool>();
ExecutionSession ES{makeEPC(SSP)};
JITDylib &JD = ES.createBareJITDylib("JD");
SymbolStringPtr Foo = ES.intern("foo");
SymbolStringPtr Bar = ES.intern("bar");
SymbolStringPtr Baz = ES.intern("baz");
SymbolStringPtr Qux = ES.intern("qux");
static constexpr ExecutorAddr FooAddr{1};
static constexpr ExecutorAddr BarAddr{2};
static constexpr ExecutorAddr BazAddr{3};
static constexpr ExecutorAddr QuxAddr{4};
ExecutorSymbolDef FooSym{FooAddr, JITSymbolFlags::Exported};
ExecutorSymbolDef BarSym{BarAddr, JITSymbolFlags::Exported};
ExecutorSymbolDef BazSym{BazAddr, JITSymbolFlags::Exported};
ExecutorSymbolDef QuxSym{QuxAddr, JITSymbolFlags::Exported};
unique_function<void(std::unique_ptr<Task>)> DispatchOverride;
};
} // end namespace orc
class OrcNativeTarget {
public:
static void initialize() {
if (!NativeTargetInitialized) {
InitializeNativeTarget();
InitializeNativeTargetAsmParser();
InitializeNativeTargetAsmPrinter();
NativeTargetInitialized = true;
}
}
private:
static bool NativeTargetInitialized;
};
class SimpleMaterializationUnit : public orc::MaterializationUnit {
public:
using MaterializeFunction =
std::function<void(std::unique_ptr<orc::MaterializationResponsibility>)>;
using DiscardFunction =
std::function<void(const orc::JITDylib &, orc::SymbolStringPtr)>;
using DestructorFunction = std::function<void()>;
SimpleMaterializationUnit(
orc::SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize,
orc::SymbolStringPtr InitSym = nullptr,
DiscardFunction Discard = DiscardFunction(),
DestructorFunction Destructor = DestructorFunction())
: MaterializationUnit(
Interface(std::move(SymbolFlags), std::move(InitSym))),
Materialize(std::move(Materialize)), Discard(std::move(Discard)),
Destructor(std::move(Destructor)) {}
~SimpleMaterializationUnit() override {
if (Destructor)
Destructor();
}
StringRef getName() const override { return "<Simple>"; }
void
materialize(std::unique_ptr<orc::MaterializationResponsibility> R) override {
Materialize(std::move(R));
}
void discard(const orc::JITDylib &JD,
const orc::SymbolStringPtr &Name) override {
if (Discard)
Discard(JD, std::move(Name));
else
llvm_unreachable("Discard not supported");
}
private:
MaterializeFunction Materialize;
DiscardFunction Discard;
DestructorFunction Destructor;
};
class ModuleBuilder {
public:
ModuleBuilder(LLVMContext &Context, StringRef Triple,
StringRef Name);
Function *createFunctionDecl(FunctionType *FTy, StringRef Name) {
return Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M.get());
}
Module* getModule() { return M.get(); }
const Module* getModule() const { return M.get(); }
std::unique_ptr<Module> takeModule() { return std::move(M); }
private:
std::unique_ptr<Module> M;
};
// Dummy struct type.
struct DummyStruct {
int X[256];
};
inline StructType *getDummyStructTy(LLVMContext &Context) {
return StructType::get(ArrayType::get(Type::getInt32Ty(Context), 256));
}
} // namespace llvm
#endif