MLIR 24.0.0git
MLIRContext.h
Go to the documentation of this file.
1//===- MLIRContext.h - MLIR Global Context Class ----------------*- 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#ifndef MLIR_IR_MLIRCONTEXT_H
10#define MLIR_IR_MLIRCONTEXT_H
11
12#include "mlir/Support/LLVM.h"
13#include "mlir/Support/TypeID.h"
14#include "llvm/ADT/ArrayRef.h"
15#include <functional>
16#include <memory>
17#include <vector>
18
19namespace llvm {
20class ThreadPoolInterface;
21} // namespace llvm
22
23namespace mlir {
24namespace tracing {
25class Action;
26}
28class Dialect;
29class DialectRegistry;
30class DynamicDialect;
32class Location;
33class MLIRContextImpl;
35class StorageUniquer;
36class IRUnit;
37namespace remark::detail {
38class RemarkEngine;
39} // namespace remark::detail
40
41/// MLIRContext is the top-level object for a collection of MLIR operations. It
42/// holds immortal uniqued objects like types, and the tables used to unique
43/// them.
44///
45/// MLIRContext gets a redundant "MLIR" prefix because otherwise it ends up with
46/// a very generic name ("Context") and because it is uncommon for clients to
47/// interact with it.
48///
49/// The context wrap some multi-threading facilities, and in particular by
50/// default it will implicitly create a thread pool.
51/// This can be undesirable if multiple context exists at the same time or if a
52/// process will be long-lived and create and destroy contexts.
53/// To control better thread spawning, an externally owned ThreadPool can be
54/// injected in the context. For example:
55///
56/// llvm::DefaultThreadPool myThreadPool;
57/// while (auto *request = nextCompilationRequests()) {
58/// MLIRContext ctx(registry, MLIRContext::Threading::DISABLED);
59/// ctx.setThreadPool(myThreadPool);
60/// processRequest(request, cxt);
61/// }
62///
64public:
65 enum class Threading { DISABLED, ENABLED };
66 /// Create a new Context.
67 explicit MLIRContext(Threading multithreading = Threading::ENABLED);
68 explicit MLIRContext(const DialectRegistry &registry,
69 Threading multithreading = Threading::ENABLED);
71
72 /// Return information about all IR dialects loaded in the context.
73 std::vector<Dialect *> getLoadedDialects();
74
75 /// Return the dialect registry associated with this context.
77
78 /// Append the contents of the given dialect registry to the registry
79 /// associated with this context.
80 void appendDialectRegistry(const DialectRegistry &registry);
81
82 /// Return information about all available dialects in the registry in this
83 /// context.
84 std::vector<StringRef> getAvailableDialects();
85
86 /// Get a registered IR dialect with the given namespace. If an exact match is
87 /// not found, then return nullptr.
88 Dialect *getLoadedDialect(StringRef name);
89
90 /// Get a registered IR dialect for the given derived dialect type. The
91 /// derived type must provide a static 'getDialectNamespace' method.
92 template <typename T>
94 return static_cast<T *>(getLoadedDialect(T::getDialectNamespace()));
95 }
96
97 /// Get (or create) a dialect for the given derived dialect type. The derived
98 /// type must provide a static 'getDialectNamespace' method.
99 template <typename T>
101 return static_cast<T *>(
102 getOrLoadDialect(T::getDialectNamespace(), TypeID::get<T>(), [this]() {
103 std::unique_ptr<T> dialect(new T(this));
104 return dialect;
105 }));
106 }
107
108 /// Load a dialect in the context.
109 template <typename Dialect>
110 void loadDialect() {
111 // Do not load the dialect if it is currently loading. This can happen if a
112 // dialect initializer triggers loading the same dialect recursively.
113 if (!isDialectLoading(Dialect::getDialectNamespace()))
115 }
116
117 /// Load a list dialects in the context.
118 template <typename Dialect, typename OtherDialect, typename... MoreDialects>
119 void loadDialect() {
121 loadDialect<OtherDialect, MoreDialects...>();
122 }
123
124 /// Get (or create) a dynamic dialect for the given name.
126 getOrLoadDynamicDialect(StringRef dialectNamespace,
127 function_ref<void(DynamicDialect *)> ctor);
128
129 /// Load all dialects available in the registry in this context.
131
132 /// Get (or create) a dialect for the given derived dialect name.
133 /// The dialect will be loaded from the registry if no dialect is found.
134 /// If no dialect is loaded for this name and none is available in the
135 /// registry, returns nullptr.
136 Dialect *getOrLoadDialect(StringRef name);
137
138 /// Return true if we allow to create operation for unregistered dialects.
139 [[nodiscard]] bool allowsUnregisteredDialects();
140
141 /// Enables creating operations in unregistered dialects.
142 /// This option is **heavily discouraged**: it is convenient during testing
143 /// but it is not a good practice to use it in production code. Some system
144 /// invariants can be broken (like loading a dialect after creating
145 /// operations) without being caught by assertions or other means.
146 void allowUnregisteredDialects(bool allow = true);
147
148 /// Begins a transient scope on the context, freezing the current state (all
149 /// loaded dialects, registered operations, types, attributes, affine
150 /// expressions, and singletons) as the base state. Subsequent types,
151 /// attributes, and expressions allocated will belong to the transient layer.
152 ///
153 /// Preconditions:
154 /// - The context must not already be in a transient scope.
155 /// - Must be called from a single-threaded execution context.
156 /// - Loading dialects, modifying dialect registries, or mutating base
157 /// storage instances is not supported while in a transient scope.
158 void beginTransientScope();
159
160 /// Ends the transient scope and resets the context to the base state, pruning
161 /// all types, attributes, affine expressions, distinct attributes, and
162 /// unregistered operations created during the transient scope.
163 ///
164 /// Preconditions:
165 /// - The context must be in a transient scope.
166 /// - There must be no remaining IR (operations, blocks, regions,
167 /// values) referencing the transient types/attributes.
168 /// - Must be called from a single-threaded execution context.
169 void endTransientScope();
170
171 /// Returns true if the context is currently in a transient scope.
172 bool isInTransientScope() const;
173
174 /// RAII scope guard that calls beginTransientScope() on construction and
175 /// endTransientScope() on destruction. Provides exception-safe and
176 /// forgetting-proof transient scope management.
178 public:
179 explicit TransientScope(MLIRContext &ctx) : ctx(ctx) {
180 ctx.beginTransientScope();
181 }
182 ~TransientScope() { ctx.endTransientScope(); }
183
186
187 private:
188 MLIRContext &ctx;
189 };
190
191 /// Return true if multi-threading is enabled by the context.
193
194 /// Set the flag specifying if multi-threading is disabled by the context.
195 /// The command line debugging flag `--mlir-disable-threading` is overriding
196 /// this call and making it a no-op!
197 void disableMultithreading(bool disable = true);
198 void enableMultithreading(bool enable = true) {
199 disableMultithreading(!enable);
200 }
201
202 /// Set a new thread pool to be used in this context. This method requires
203 /// that multithreading is disabled for this context prior to the call. This
204 /// allows to share a thread pool across multiple contexts, as well as
205 /// decoupling the lifetime of the threads from the contexts. The thread pool
206 /// must outlive the context. Multi-threading will be enabled as part of this
207 /// method.
208 /// The command line debugging flag `--mlir-disable-threading` will still
209 /// prevent threading from being enabled and threading won't be enabled after
210 /// this call in this case.
211 void setThreadPool(llvm::ThreadPoolInterface &pool);
212
213 /// Return the number of threads used by the thread pool in this context. The
214 /// number of computed hardware threads can change over the lifetime of a
215 /// process based on affinity changes, so users should use the number of
216 /// threads actually in the thread pool for dispatching work. Returns 1 if
217 /// multithreading is disabled.
218 unsigned getNumThreads();
219
220 /// Return the thread pool used by this context. This method requires that
221 /// multithreading be enabled within the context, and should generally not be
222 /// used directly. Users should instead prefer the threading utilities within
223 /// Threading.h.
224 llvm::ThreadPoolInterface &getThreadPool();
225
226 /// Return true if we should attach the operation to diagnostics emitted via
227 /// Operation::emit.
229
230 /// Set the flag specifying if we should attach the operation to diagnostics
231 /// emitted via Operation::emit.
232 void printOpOnDiagnostic(bool enable);
233
234 /// Return true if we should attach the current stacktrace to diagnostics when
235 /// emitted.
237
238 /// Set the flag specifying if we should attach the current stacktrace when
239 /// emitting diagnostics.
240 void printStackTraceOnDiagnostic(bool enable);
241
242 /// Return a sorted array containing the information about all registered
243 /// operations.
245
246 /// Return a sorted array containing the information for registered operations
247 /// filtered by dialect name.
249 getRegisteredOperationsByDialect(StringRef dialectName);
250
251 /// Return true if this operation name is registered in this context.
252 bool isOperationRegistered(StringRef name);
253
254 // This is effectively private given that only MLIRContext.cpp can see the
255 // MLIRContextImpl type.
257 const MLIRContextImpl &getImpl() const { return *impl; }
258
259 /// Returns the diagnostic engine for this context.
261
262 /// Returns the remark engine for this context, or nullptr if none has been
263 /// set.
265
266 /// Set the remark engine for this context.
267 void setRemarkEngine(std::unique_ptr<remark::detail::RemarkEngine> engine);
268
269 /// Returns the storage uniquer used for creating affine constructs.
271
272 /// Returns the storage uniquer used for constructing type storage instances.
273 /// This should not be used directly.
275
276 /// Returns the storage uniquer used for constructing attribute storage
277 /// instances. This should not be used directly.
279
280 /// These APIs are tracking whether the context will be used in a
281 /// multithreading environment: this has no effect other than enabling
282 /// assertions on misuses of some APIs.
285
286 /// Get a dialect for the provided namespace and TypeID: abort the program if
287 /// a dialect exist for this namespace with different TypeID. If a dialect has
288 /// not been loaded for this namespace/TypeID yet, use the provided ctor to
289 /// create one on the fly and load it. Returns a pointer to the dialect owned
290 /// by the context.
291 /// The use of this method is in general discouraged in favor of
292 /// 'getOrLoadDialect<DialectClass>()'.
293 Dialect *getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
294 function_ref<std::unique_ptr<Dialect>()> ctor);
295
296 /// Returns a hash of the registry of the context that may be used to give
297 /// a rough indicator of if the state of the context registry has changed. The
298 /// context registry correlates to loaded dialects and their entities
299 /// (attributes, operations, types, etc.).
300 llvm::hash_code getRegistryHash();
301
302 //===--------------------------------------------------------------------===//
303 // Action API
304 //===--------------------------------------------------------------------===//
305
306 /// Signatures for the action handler that can be registered with the context.
307 using HandlerTy =
308 std::function<void(function_ref<void()>, const tracing::Action &)>;
309
310 /// Register a handler for handling actions that are dispatched through this
311 /// context. A nullptr handler can be set to disable a previously set handler.
312 void registerActionHandler(HandlerTy handler);
313
314 /// Return a reference to the currently registered action handler. Its target
315 /// can be used to gain access to the handler's state, if any.
316 const HandlerTy &getActionHandler() const;
318
319 /// Return true if a valid ActionHandler is set.
320 bool hasActionHandler();
321
322 /// Dispatch the provided action to the handler if any, or just execute it.
323 void executeAction(function_ref<void()> actionFn,
324 const tracing::Action &action) {
325 if (LLVM_UNLIKELY(hasActionHandler()))
326 executeActionInternal(actionFn, action);
327 else
328 actionFn();
329 }
330
331 /// Dispatch the provided action to the handler if any, or just execute it.
332 template <typename ActionTy, typename... Args>
333 void executeAction(function_ref<void()> actionFn, ArrayRef<IRUnit> irUnits,
334 Args &&...args) {
335 if (LLVM_UNLIKELY(hasActionHandler()))
336 executeActionInternal<ActionTy, Args...>(actionFn, irUnits,
337 std::forward<Args>(args)...);
338 else
339 actionFn();
340 }
341
342private:
343 /// Return true if the given dialect is currently loading.
344 bool isDialectLoading(StringRef dialectNamespace);
345
346 /// Internal helper for the dispatch method.
347 void executeActionInternal(function_ref<void()> actionFn,
348 const tracing::Action &action);
349
350 /// Internal helper for the dispatch method. We get here after checking that
351 /// there is a handler, for the purpose of keeping this code out-of-line. and
352 /// avoid calling the ctor for the Action unnecessarily.
353 template <typename ActionTy, typename... Args>
354 LLVM_ATTRIBUTE_NOINLINE void
355 executeActionInternal(function_ref<void()> actionFn, ArrayRef<IRUnit> irUnits,
356 Args &&...args) {
357 executeActionInternal(actionFn,
358 ActionTy(irUnits, std::forward<Args>(args)...));
359 }
360
361 const std::unique_ptr<MLIRContextImpl> impl;
362
363 MLIRContext(const MLIRContext &) = delete;
364 void operator=(const MLIRContext &) = delete;
365};
366
367//===----------------------------------------------------------------------===//
368// MLIRContext CommandLine Options
369//===----------------------------------------------------------------------===//
370
371/// Register a set of useful command-line options that can be used to configure
372/// various flags within the MLIRContext. These flags are used when constructing
373/// an MLIR context for initialization.
375
376} // namespace mlir
377
378#endif // MLIR_IR_MLIRCONTEXT_H
This class is the main interface for diagnostics.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
A dialect that can be defined at runtime.
IRUnit is a union of the different types of IR objects that constitute the IR structure (other than T...
Definition Unit.h:28
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This is the implementation of the MLIRContext class, using the pImpl idiom.
TransientScope(const TransientScope &)=delete
TransientScope & operator=(const TransientScope &)=delete
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
bool shouldPrintStackTraceOnDiagnostic()
Return true if we should attach the current stacktrace to diagnostics when emitted.
unsigned getNumThreads()
Return the number of threads used by the thread pool in this context.
bool isInTransientScope() const
Returns true if the context is currently in a transient scope.
bool isOperationRegistered(StringRef name)
Return true if this operation name is registered in this context.
MLIRContext(Threading multithreading=Threading::ENABLED)
Create a new Context.
void disableMultithreading(bool disable=true)
Set the flag specifying if multi-threading is disabled by the context.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
void printStackTraceOnDiagnostic(bool enable)
Set the flag specifying if we should attach the current stacktrace when emitting diagnostics.
bool hasActionHandler()
Return true if a valid ActionHandler is set.
void setRemarkEngine(std::unique_ptr< remark::detail::RemarkEngine > engine)
Set the remark engine for this context.
void setThreadPool(llvm::ThreadPoolInterface &pool)
Set a new thread pool to be used in this context.
void executeAction(function_ref< void()> actionFn, const tracing::Action &action)
Dispatch the provided action to the handler if any, or just execute it.
const HandlerTy & getActionHandler() const
Return a reference to the currently registered action handler.
void enableMultithreading(bool enable=true)
remark::detail::RemarkEngine * getRemarkEngine()
Returns the remark engine for this context, or nullptr if none has been set.
std::vector< Dialect * > getLoadedDialects()
Return information about all IR dialects loaded in the context.
ArrayRef< RegisteredOperationName > getRegisteredOperationsByDialect(StringRef dialectName)
Return a sorted array containing the information for registered operations filtered by dialect name.
void printOpOnDiagnostic(bool enable)
Set the flag specifying if we should attach the operation to diagnostics emitted via Operation::emit.
void executeAction(function_ref< void()> actionFn, ArrayRef< IRUnit > irUnits, Args &&...args)
Dispatch the provided action to the handler if any, or just execute it.
void registerActionHandler(HandlerTy handler)
Register a handler for handling actions that are dispatched through this context.
ArrayRef< RegisteredOperationName > getRegisteredOperations()
Return a sorted array containing the information about all registered operations.
llvm::hash_code getRegistryHash()
Returns a hash of the registry of the context that may be used to give a rough indicator of if the st...
void enterMultiThreadedExecution()
These APIs are tracking whether the context will be used in a multithreading environment: this has no...
const DialectRegistry & getDialectRegistry()
Return the dialect registry associated with this context.
void loadDialect()
Load a dialect in the context.
DynamicDialect * getOrLoadDynamicDialect(StringRef dialectNamespace, function_ref< void(DynamicDialect *)> ctor)
Get (or create) a dynamic dialect for the given name.
const MLIRContextImpl & getImpl() const
StorageUniquer & getAttributeUniquer()
Returns the storage uniquer used for constructing attribute storage instances.
StorageUniquer & getAffineUniquer()
Returns the storage uniquer used for creating affine constructs.
void endTransientScope()
Ends the transient scope and resets the context to the base state, pruning all types,...
std::function< void(function_ref< void()>, const tracing::Action &)> HandlerTy
Signatures for the action handler that can be registered with the context.
StorageUniquer & getTypeUniquer()
Returns the storage uniquer used for constructing type storage instances.
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
std::vector< StringRef > getAvailableDialects()
Return information about all available dialects in the registry in this context.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
void loadDialect()
Load a list dialects in the context.
MLIRContextImpl & getImpl()
void exitMultiThreadedExecution()
bool shouldPrintOpOnDiagnostic()
Return true if we should attach the operation to diagnostics emitted via Operation::emit.
void beginTransientScope()
Begins a transient scope on the context, freezing the current state (all loaded dialects,...
void loadAllAvailableDialects()
Load all dialects available in the registry in this context.
T * getLoadedDialect()
Get a registered IR dialect for the given derived dialect type.
Definition MLIRContext.h:93
This is a "type erased" representation of a registered operation.
A utility class to get or create instances of "storage classes".
This class provides an efficient unique identifier for a specific C++ type.
Definition TypeID.h:107
static TypeID get()
Construct a type info object for the given type T.
Definition TypeID.h:245
An action is a specific action that is to be taken by the compiler, that can be toggled and controlle...
Definition Action.h:38
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:227
Include the generated interface declarations.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147