Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Thread safe wrappers and utilities for Module and LLVMContext.
10
//
11
//===----------------------------------------------------------------------===//
12
 
13
#ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H
14
#define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H
15
 
16
#include "llvm/IR/LLVMContext.h"
17
#include "llvm/IR/Module.h"
18
#include "llvm/Support/Compiler.h"
19
 
20
#include <functional>
21
#include <memory>
22
#include <mutex>
23
 
24
namespace llvm {
25
namespace orc {
26
 
27
/// An LLVMContext together with an associated mutex that can be used to lock
28
/// the context to prevent concurrent access by other threads.
29
class ThreadSafeContext {
30
private:
31
  struct State {
32
    State(std::unique_ptr<LLVMContext> Ctx) : Ctx(std::move(Ctx)) {}
33
 
34
    std::unique_ptr<LLVMContext> Ctx;
35
    std::recursive_mutex Mutex;
36
  };
37
 
38
public:
39
  // RAII based lock for ThreadSafeContext.
40
  class [[nodiscard]] Lock {
41
  public:
42
    Lock(std::shared_ptr<State> S) : S(std::move(S)), L(this->S->Mutex) {}
43
 
44
  private:
45
    std::shared_ptr<State> S;
46
    std::unique_lock<std::recursive_mutex> L;
47
  };
48
 
49
  /// Construct a null context.
50
  ThreadSafeContext() = default;
51
 
52
  /// Construct a ThreadSafeContext from the given LLVMContext.
53
  ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)
54
      : S(std::make_shared<State>(std::move(NewCtx))) {
55
    assert(S->Ctx != nullptr &&
56
           "Can not construct a ThreadSafeContext from a nullptr");
57
  }
58
 
59
  /// Returns a pointer to the LLVMContext that was used to construct this
60
  /// instance, or null if the instance was default constructed.
61
  LLVMContext *getContext() { return S ? S->Ctx.get() : nullptr; }
62
 
63
  /// Returns a pointer to the LLVMContext that was used to construct this
64
  /// instance, or null if the instance was default constructed.
65
  const LLVMContext *getContext() const { return S ? S->Ctx.get() : nullptr; }
66
 
67
  Lock getLock() const {
68
    assert(S && "Can not lock an empty ThreadSafeContext");
69
    return Lock(S);
70
  }
71
 
72
private:
73
  std::shared_ptr<State> S;
74
};
75
 
76
/// An LLVM Module together with a shared ThreadSafeContext.
77
class ThreadSafeModule {
78
public:
79
  /// Default construct a ThreadSafeModule. This results in a null module and
80
  /// null context.
81
  ThreadSafeModule() = default;
82
 
83
  ThreadSafeModule(ThreadSafeModule &&Other) = default;
84
 
85
  ThreadSafeModule &operator=(ThreadSafeModule &&Other) {
86
    // We have to explicitly define this move operator to copy the fields in
87
    // reverse order (i.e. module first) to ensure the dependencies are
88
    // protected: The old module that is being overwritten must be destroyed
89
    // *before* the context that it depends on.
90
    // We also need to lock the context to make sure the module tear-down
91
    // does not overlap any other work on the context.
92
    if (M) {
93
      auto L = TSCtx.getLock();
94
      M = nullptr;
95
    }
96
    M = std::move(Other.M);
97
    TSCtx = std::move(Other.TSCtx);
98
    return *this;
99
  }
100
 
101
  /// Construct a ThreadSafeModule from a unique_ptr<Module> and a
102
  /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
103
  /// given context.
104
  ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx)
105
      : M(std::move(M)), TSCtx(std::move(Ctx)) {}
106
 
107
  /// Construct a ThreadSafeModule from a unique_ptr<Module> and an
108
  /// existing ThreadSafeContext.
109
  ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx)
110
      : M(std::move(M)), TSCtx(std::move(TSCtx)) {}
111
 
112
  ~ThreadSafeModule() {
113
    // We need to lock the context while we destruct the module.
114
    if (M) {
115
      auto L = TSCtx.getLock();
116
      M = nullptr;
117
    }
118
  }
119
 
120
  /// Boolean conversion: This ThreadSafeModule will evaluate to true if it
121
  /// wraps a non-null module.
122
  explicit operator bool() const {
123
    if (M) {
124
      assert(TSCtx.getContext() &&
125
             "Non-null module must have non-null context");
126
      return true;
127
    }
128
    return false;
129
  }
130
 
131
  /// Locks the associated ThreadSafeContext and calls the given function
132
  /// on the contained Module.
133
  template <typename Func> decltype(auto) withModuleDo(Func &&F) {
134
    assert(M && "Can not call on null module");
135
    auto Lock = TSCtx.getLock();
136
    return F(*M);
137
  }
138
 
139
  /// Locks the associated ThreadSafeContext and calls the given function
140
  /// on the contained Module.
141
  template <typename Func> decltype(auto) withModuleDo(Func &&F) const {
142
    assert(M && "Can not call on null module");
143
    auto Lock = TSCtx.getLock();
144
    return F(*M);
145
  }
146
 
147
  /// Locks the associated ThreadSafeContext and calls the given function,
148
  /// passing the contained std::unique_ptr<Module>. The given function should
149
  /// consume the Module.
150
  template <typename Func> decltype(auto) consumingModuleDo(Func &&F) {
151
    auto Lock = TSCtx.getLock();
152
    return F(std::move(M));
153
  }
154
 
155
  /// Get a raw pointer to the contained module without locking the context.
156
  Module *getModuleUnlocked() { return M.get(); }
157
 
158
  /// Get a raw pointer to the contained module without locking the context.
159
  const Module *getModuleUnlocked() const { return M.get(); }
160
 
161
  /// Returns the context for this ThreadSafeModule.
162
  ThreadSafeContext getContext() const { return TSCtx; }
163
 
164
private:
165
  std::unique_ptr<Module> M;
166
  ThreadSafeContext TSCtx;
167
};
168
 
169
using GVPredicate = std::function<bool(const GlobalValue &)>;
170
using GVModifier = std::function<void(GlobalValue &)>;
171
 
172
/// Clones the given module on to a new context.
173
ThreadSafeModule
174
cloneToNewContext(const ThreadSafeModule &TSMW,
175
                  GVPredicate ShouldCloneDef = GVPredicate(),
176
                  GVModifier UpdateClonedDefSource = GVModifier());
177
 
178
} // End namespace orc
179
} // End namespace llvm
180
 
181
#endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULE_H