xref: /llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ThreadSafeModule.h (revision ae331245b730a2c91ecc227c4cb1198d2b3ad94e)
18d76c711SLang Hames //===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===//
28d76c711SLang Hames //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68d76c711SLang Hames //
78d76c711SLang Hames //===----------------------------------------------------------------------===//
88d76c711SLang Hames //
98d76c711SLang Hames // Thread safe wrappers and utilities for Module and LLVMContext.
108d76c711SLang Hames //
118d76c711SLang Hames //===----------------------------------------------------------------------===//
128d76c711SLang Hames 
13aa5c09beSKazu Hirata #ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H
14aa5c09beSKazu Hirata #define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H
158d76c711SLang Hames 
168d76c711SLang Hames #include "llvm/IR/LLVMContext.h"
178d76c711SLang Hames #include "llvm/IR/Module.h"
185ad09de9SLang Hames #include "llvm/Support/Compiler.h"
198d76c711SLang Hames 
20867587f8SLang Hames #include <functional>
21867587f8SLang Hames #include <memory>
227e38be47SLang Hames #include <mutex>
237e38be47SLang Hames 
248d76c711SLang Hames namespace llvm {
258d76c711SLang Hames namespace orc {
268d76c711SLang Hames 
278d76c711SLang Hames /// An LLVMContext together with an associated mutex that can be used to lock
288d76c711SLang Hames /// the context to prevent concurrent access by other threads.
298d76c711SLang Hames class ThreadSafeContext {
308d76c711SLang Hames private:
318d76c711SLang Hames   struct State {
StateState324328ea34SLang Hames     State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {}
338d76c711SLang Hames 
348d76c711SLang Hames     std::unique_ptr<LLVMContext> Ctx;
358d76c711SLang Hames     std::recursive_mutex Mutex;
368d76c711SLang Hames   };
378d76c711SLang Hames 
388d76c711SLang Hames public:
398d76c711SLang Hames   // RAII based lock for ThreadSafeContext.
40fa66789dSFangrui Song   class [[nodiscard]] Lock {
414328ea34SLang Hames   public:
Lock(std::shared_ptr<State> S)426f0ac30aSBenjamin Kramer     Lock(std::shared_ptr<State> S) : S(std::move(S)), L(this->S->Mutex) {}
434328ea34SLang Hames 
448d76c711SLang Hames   private:
458d76c711SLang Hames     std::shared_ptr<State> S;
466f0ac30aSBenjamin Kramer     std::unique_lock<std::recursive_mutex> L;
478d76c711SLang Hames   };
488d76c711SLang Hames 
498d76c711SLang Hames   /// Construct a null context.
508d76c711SLang Hames   ThreadSafeContext() = default;
518d76c711SLang Hames 
528d76c711SLang Hames   /// Construct a ThreadSafeContext from the given LLVMContext.
ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)538d76c711SLang Hames   ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)
548d76c711SLang Hames       : S(std::make_shared<State>(std::move(NewCtx))) {
558d76c711SLang Hames     assert(S->Ctx != nullptr &&
568d76c711SLang Hames            "Can not construct a ThreadSafeContext from a nullptr");
578d76c711SLang Hames   }
588d76c711SLang Hames 
598d76c711SLang Hames   /// Returns a pointer to the LLVMContext that was used to construct this
608d76c711SLang Hames   /// instance, or null if the instance was default constructed.
getContext()614328ea34SLang Hames   LLVMContext *getContext() { return S ? S->Ctx.get() : nullptr; }
628d76c711SLang Hames 
633e709d5fSLang Hames   /// Returns a pointer to the LLVMContext that was used to construct this
643e709d5fSLang Hames   /// instance, or null if the instance was default constructed.
getContext()653e709d5fSLang Hames   const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; }
663e709d5fSLang Hames 
getLock()67809e9d1eSLang Hames   Lock getLock() const {
688d76c711SLang Hames     assert(S && "Can not lock an empty ThreadSafeContext");
698d76c711SLang Hames     return Lock(S);
708d76c711SLang Hames   }
718d76c711SLang Hames 
728d76c711SLang Hames private:
738d76c711SLang Hames   std::shared_ptr<State> S;
748d76c711SLang Hames };
758d76c711SLang Hames 
768d76c711SLang Hames /// An LLVM Module together with a shared ThreadSafeContext.
778d76c711SLang Hames class ThreadSafeModule {
788d76c711SLang Hames public:
798d76c711SLang Hames   /// Default construct a ThreadSafeModule. This results in a null module and
808d76c711SLang Hames   /// null context.
818d76c711SLang Hames   ThreadSafeModule() = default;
828d76c711SLang Hames 
835ad09de9SLang Hames   ThreadSafeModule(ThreadSafeModule &&Other) = default;
845ad09de9SLang Hames 
855ad09de9SLang Hames   ThreadSafeModule &operator=(ThreadSafeModule &&Other) {
865ad09de9SLang Hames     // We have to explicitly define this move operator to copy the fields in
875ad09de9SLang Hames     // reverse order (i.e. module first) to ensure the dependencies are
885ad09de9SLang Hames     // protected: The old module that is being overwritten must be destroyed
895ad09de9SLang Hames     // *before* the context that it depends on.
9028d596c3SLang Hames     // We also need to lock the context to make sure the module tear-down
9128d596c3SLang Hames     // does not overlap any other work on the context.
9228d596c3SLang Hames     if (M) {
93809e9d1eSLang Hames       auto L = TSCtx.getLock();
9428d596c3SLang Hames       M = nullptr;
9528d596c3SLang Hames     }
965ad09de9SLang Hames     M = std::move(Other.M);
975ad09de9SLang Hames     TSCtx = std::move(Other.TSCtx);
985ad09de9SLang Hames     return *this;
995ad09de9SLang Hames   }
1005ad09de9SLang Hames 
1018d76c711SLang Hames   /// Construct a ThreadSafeModule from a unique_ptr<Module> and a
1028d76c711SLang Hames   /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
1038d76c711SLang Hames   /// given context.
ThreadSafeModule(std::unique_ptr<Module> M,std::unique_ptr<LLVMContext> Ctx)1045ad09de9SLang Hames   ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx)
105cf0949aaSLang Hames       : M(std::move(M)), TSCtx(std::move(Ctx)) {}
1068d76c711SLang Hames 
107cf0949aaSLang Hames   /// Construct a ThreadSafeModule from a unique_ptr<Module> and an
108cf0949aaSLang Hames   /// existing ThreadSafeContext.
ThreadSafeModule(std::unique_ptr<Module> M,ThreadSafeContext TSCtx)1095ad09de9SLang Hames   ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx)
110cf0949aaSLang Hames       : M(std::move(M)), TSCtx(std::move(TSCtx)) {}
1118d76c711SLang Hames 
~ThreadSafeModule()112cf0949aaSLang Hames   ~ThreadSafeModule() {
113cf0949aaSLang Hames     // We need to lock the context while we destruct the module.
114cf0949aaSLang Hames     if (M) {
115809e9d1eSLang Hames       auto L = TSCtx.getLock();
116cf0949aaSLang Hames       M = nullptr;
117cf0949aaSLang Hames     }
118cf0949aaSLang Hames   }
119cf0949aaSLang Hames 
120cf0949aaSLang Hames   /// Boolean conversion: This ThreadSafeModule will evaluate to true if it
121cf0949aaSLang Hames   /// wraps a non-null module.
122809e9d1eSLang Hames   explicit operator bool() const {
1238d76c711SLang Hames     if (M) {
1244328ea34SLang Hames       assert(TSCtx.getContext() &&
1254328ea34SLang Hames              "Non-null module must have non-null context");
1268d76c711SLang Hames       return true;
1278d76c711SLang Hames     }
1288d76c711SLang Hames     return false;
1298d76c711SLang Hames   }
1308d76c711SLang Hames 
131809e9d1eSLang Hames   /// Locks the associated ThreadSafeContext and calls the given function
132809e9d1eSLang Hames   /// on the contained Module.
decltype(auto)133fb45968eSJustin Lebar   template <typename Func> decltype(auto) withModuleDo(Func &&F) {
134809e9d1eSLang Hames     assert(M && "Can not call on null module");
135809e9d1eSLang Hames     auto Lock = TSCtx.getLock();
136809e9d1eSLang Hames     return F(*M);
137809e9d1eSLang Hames   }
138809e9d1eSLang Hames 
139809e9d1eSLang Hames   /// Locks the associated ThreadSafeContext and calls the given function
140809e9d1eSLang Hames   /// on the contained Module.
decltype(auto)141fb45968eSJustin Lebar   template <typename Func> decltype(auto) withModuleDo(Func &&F) const {
1420bf85d7dSLang Hames     assert(M && "Can not call on null module");
143809e9d1eSLang Hames     auto Lock = TSCtx.getLock();
144809e9d1eSLang Hames     return F(*M);
145809e9d1eSLang Hames   }
146809e9d1eSLang Hames 
1470bf85d7dSLang Hames   /// Locks the associated ThreadSafeContext and calls the given function,
1480bf85d7dSLang Hames   /// passing the contained std::unique_ptr<Module>. The given function should
1490bf85d7dSLang Hames   /// consume the Module.
decltype(auto)150*ae331245SLang Hames   template <typename Func> decltype(auto) consumingModuleDo(Func &&F) {
1510bf85d7dSLang Hames     auto Lock = TSCtx.getLock();
1520bf85d7dSLang Hames     return F(std::move(M));
1530bf85d7dSLang Hames   }
1540bf85d7dSLang Hames 
155809e9d1eSLang Hames   /// Get a raw pointer to the contained module without locking the context.
getModuleUnlocked()156809e9d1eSLang Hames   Module *getModuleUnlocked() { return M.get(); }
157809e9d1eSLang Hames 
158809e9d1eSLang Hames   /// Get a raw pointer to the contained module without locking the context.
getModuleUnlocked()159809e9d1eSLang Hames   const Module *getModuleUnlocked() const { return M.get(); }
160809e9d1eSLang Hames 
161809e9d1eSLang Hames   /// Returns the context for this ThreadSafeModule.
getContext()162809e9d1eSLang Hames   ThreadSafeContext getContext() const { return TSCtx; }
163809e9d1eSLang Hames 
1648d76c711SLang Hames private:
1655ad09de9SLang Hames   std::unique_ptr<Module> M;
166cf0949aaSLang Hames   ThreadSafeContext TSCtx;
1678d76c711SLang Hames };
1688d76c711SLang Hames 
1698d76c711SLang Hames using GVPredicate = std::function<bool(const GlobalValue &)>;
1708d76c711SLang Hames using GVModifier = std::function<void(GlobalValue &)>;
1718d76c711SLang Hames 
1728d76c711SLang Hames /// Clones the given module on to a new context.
1738d76c711SLang Hames ThreadSafeModule
174f12db8cfSStefan Gränitz cloneToNewContext(const ThreadSafeModule &TSMW,
1758d76c711SLang Hames                   GVPredicate ShouldCloneDef = GVPredicate(),
1768d76c711SLang Hames                   GVModifier UpdateClonedDefSource = GVModifier());
1778d76c711SLang Hames 
1788d76c711SLang Hames } // End namespace orc
1798d76c711SLang Hames } // End namespace llvm
1808d76c711SLang Hames 
181aa5c09beSKazu Hirata #endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H
182