123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===----------- ThreadSafeModule.h -- Layer interfaces ---------*- 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
- //
- //===----------------------------------------------------------------------===//
- //
- // Thread safe wrappers and utilities for Module and LLVMContext.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
- #define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/Support/Compiler.h"
- #include <functional>
- #include <memory>
- #include <mutex>
- namespace llvm {
- namespace orc {
- /// An LLVMContext together with an associated mutex that can be used to lock
- /// the context to prevent concurrent access by other threads.
- class ThreadSafeContext {
- private:
- struct State {
- State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {}
- std::unique_ptr<LLVMContext> Ctx;
- std::recursive_mutex Mutex;
- };
- public:
- // RAII based lock for ThreadSafeContext.
- class LLVM_NODISCARD Lock {
- public:
- Lock(std::shared_ptr<State> S) : S(std::move(S)), L(this->S->Mutex) {}
- private:
- std::shared_ptr<State> S;
- std::unique_lock<std::recursive_mutex> L;
- };
- /// Construct a null context.
- ThreadSafeContext() = default;
- /// Construct a ThreadSafeContext from the given LLVMContext.
- ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)
- : S(std::make_shared<State>(std::move(NewCtx))) {
- assert(S->Ctx != nullptr &&
- "Can not construct a ThreadSafeContext from a nullptr");
- }
- /// Returns a pointer to the LLVMContext that was used to construct this
- /// instance, or null if the instance was default constructed.
- LLVMContext *getContext() { return S ? S->Ctx.get() : nullptr; }
- /// Returns a pointer to the LLVMContext that was used to construct this
- /// instance, or null if the instance was default constructed.
- const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; }
- Lock getLock() const {
- assert(S && "Can not lock an empty ThreadSafeContext");
- return Lock(S);
- }
- private:
- std::shared_ptr<State> S;
- };
- /// An LLVM Module together with a shared ThreadSafeContext.
- class ThreadSafeModule {
- public:
- /// Default construct a ThreadSafeModule. This results in a null module and
- /// null context.
- ThreadSafeModule() = default;
- ThreadSafeModule(ThreadSafeModule &&Other) = default;
- ThreadSafeModule &operator=(ThreadSafeModule &&Other) {
- // We have to explicitly define this move operator to copy the fields in
- // reverse order (i.e. module first) to ensure the dependencies are
- // protected: The old module that is being overwritten must be destroyed
- // *before* the context that it depends on.
- // We also need to lock the context to make sure the module tear-down
- // does not overlap any other work on the context.
- if (M) {
- auto L = TSCtx.getLock();
- M = nullptr;
- }
- M = std::move(Other.M);
- TSCtx = std::move(Other.TSCtx);
- return *this;
- }
- /// Construct a ThreadSafeModule from a unique_ptr<Module> and a
- /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
- /// given context.
- ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx)
- : M(std::move(M)), TSCtx(std::move(Ctx)) {}
- /// Construct a ThreadSafeModule from a unique_ptr<Module> and an
- /// existing ThreadSafeContext.
- ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx)
- : M(std::move(M)), TSCtx(std::move(TSCtx)) {}
- ~ThreadSafeModule() {
- // We need to lock the context while we destruct the module.
- if (M) {
- auto L = TSCtx.getLock();
- M = nullptr;
- }
- }
- /// Boolean conversion: This ThreadSafeModule will evaluate to true if it
- /// wraps a non-null module.
- explicit operator bool() const {
- if (M) {
- assert(TSCtx.getContext() &&
- "Non-null module must have non-null context");
- return true;
- }
- return false;
- }
- /// Locks the associated ThreadSafeContext and calls the given function
- /// on the contained Module.
- template <typename Func> decltype(auto) withModuleDo(Func &&F) {
- assert(M && "Can not call on null module");
- auto Lock = TSCtx.getLock();
- return F(*M);
- }
- /// Locks the associated ThreadSafeContext and calls the given function
- /// on the contained Module.
- template <typename Func> decltype(auto) withModuleDo(Func &&F) const {
- auto Lock = TSCtx.getLock();
- return F(*M);
- }
- /// Get a raw pointer to the contained module without locking the context.
- Module *getModuleUnlocked() { return M.get(); }
- /// Get a raw pointer to the contained module without locking the context.
- const Module *getModuleUnlocked() const { return M.get(); }
- /// Returns the context for this ThreadSafeModule.
- ThreadSafeContext getContext() const { return TSCtx; }
- private:
- std::unique_ptr<Module> M;
- ThreadSafeContext TSCtx;
- };
- using GVPredicate = std::function<bool(const GlobalValue &)>;
- using GVModifier = std::function<void(GlobalValue &)>;
- /// Clones the given module on to a new context.
- ThreadSafeModule
- cloneToNewContext(const ThreadSafeModule &TSMW,
- GVPredicate ShouldCloneDef = GVPredicate(),
- GVModifier UpdateClonedDefSource = GVModifier());
- } // End namespace orc
- } // End namespace llvm
- #endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|