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 "llvm/Config/llvm-config.h"
16#include <functional>
17#include <memory>
18#include <vector>
19
20namespace llvm {
21class ThreadPoolInterface;
22} // namespace llvm
23
24namespace mlir {
25namespace tracing {
26class Action;
27}
29class Dialect;
30class DialectRegistry;
31class DynamicDialect;
33class Location;
34class MLIRContextImpl;
36class StorageUniquer;
37class IRUnit;
38namespace remark::detail {
39class RemarkEngine;
40} // namespace remark::detail
41
42/// MLIRContext is the top-level object for a collection of MLIR operations. It
43/// holds immortal uniqued objects like types, and the tables used to unique
44/// them.
45///
46/// MLIRContext gets a redundant "MLIR" prefix because otherwise it ends up with
47/// a very generic name ("Context") and because it is uncommon for clients to
48/// interact with it.
49///
50/// The context wrap some multi-threading facilities, and in particular by
51/// default it will implicitly create a thread pool.
52/// This can be undesirable if multiple context exists at the same time or if a
53/// process will be long-lived and create and destroy contexts.
54/// To control better thread spawning, an externally owned ThreadPool can be
55/// injected in the context. For example:
56///
57/// llvm::DefaultThreadPool myThreadPool;
58/// while (auto *request = nextCompilationRequests()) {
59/// MLIRContext ctx(registry, MLIRContext::Threading::DISABLED);
60/// ctx.setThreadPool(myThreadPool);
61/// processRequest(request, cxt);
62/// }
63///
64/// Clients that manage their own threads can enable thread-safe context access
65/// without creating a thread pool or enabling parallel execution within MLIR.
66/// Required dialects must be loaded before accessing the context concurrently:
67///
68/// MLIRContext ctx(registry, MLIRContext::Threading::DISABLED);
69/// ctx.enableThreadSafeLocking();
70///
72public:
73 enum class Threading { DISABLED, ENABLED };
74 /// Create a new Context.
75 explicit MLIRContext(Threading multithreading = Threading::ENABLED);
76 explicit MLIRContext(const DialectRegistry &registry,
77 Threading multithreading = Threading::ENABLED);
79
80 /// Return information about all IR dialects loaded in the context.
81 std::vector<Dialect *> getLoadedDialects();
82
83 /// Return the dialect registry associated with this context.
85
86 /// Append the contents of the given dialect registry to the registry
87 /// associated with this context.
88 void appendDialectRegistry(const DialectRegistry &registry);
89
90 /// Return information about all available dialects in the registry in this
91 /// context.
92 std::vector<StringRef> getAvailableDialects();
93
94 /// Get a registered IR dialect with the given namespace. If an exact match is
95 /// not found, then return nullptr.
96 Dialect *getLoadedDialect(StringRef name);
97
98 /// Get a registered IR dialect for the given derived dialect type. The
99 /// derived type must provide a static 'getDialectNamespace' method.
100 template <typename T>
102 return static_cast<T *>(getLoadedDialect(T::getDialectNamespace()));
103 }
104
105 /// Get (or create) a dialect for the given derived dialect type. The derived
106 /// type must provide a static 'getDialectNamespace' method.
107 template <typename T>
109 return static_cast<T *>(
110 getOrLoadDialect(T::getDialectNamespace(), TypeID::get<T>(), [this]() {
111 std::unique_ptr<T> dialect(new T(this));
112 return dialect;
113 }));
114 }
115
116 /// Load a dialect in the context.
117 template <typename Dialect>
118 void loadDialect() {
119 // Do not load the dialect if it is currently loading. This can happen if a
120 // dialect initializer triggers loading the same dialect recursively.
121 if (!isDialectLoading(Dialect::getDialectNamespace()))
123 }
124
125 /// Load a list dialects in the context.
126 template <typename Dialect, typename OtherDialect, typename... MoreDialects>
127 void loadDialect() {
129 loadDialect<OtherDialect, MoreDialects...>();
130 }
131
132 /// Get (or create) a dynamic dialect for the given name.
134 getOrLoadDynamicDialect(StringRef dialectNamespace,
135 function_ref<void(DynamicDialect *)> ctor);
136
137 /// Load all dialects available in the registry in this context.
139
140 /// Get (or create) a dialect for the given derived dialect name.
141 /// The dialect will be loaded from the registry if no dialect is found.
142 /// If no dialect is loaded for this name and none is available in the
143 /// registry, returns nullptr.
144 Dialect *getOrLoadDialect(StringRef name);
145
146 /// Return true if we allow to create operation for unregistered dialects.
147 [[nodiscard]] bool allowsUnregisteredDialects();
148
149 /// Enables creating operations in unregistered dialects.
150 /// This option is **heavily discouraged**: it is convenient during testing
151 /// but it is not a good practice to use it in production code. Some system
152 /// invariants can be broken (like loading a dialect after creating
153 /// operations) without being caught by assertions or other means.
154 void allowUnregisteredDialects(bool allow = true);
155
156 /// Begins a transient scope on the context, freezing the current state (all
157 /// loaded dialects, registered operations, types, attributes, affine
158 /// expressions, and singletons) as the base state. Subsequent types,
159 /// attributes, and expressions allocated will belong to the transient layer.
160 ///
161 /// Preconditions:
162 /// - The context must not already be in a transient scope.
163 /// - Must be called from a single-threaded execution context.
164 /// - Loading dialects, modifying dialect registries, or mutating base
165 /// storage instances is not supported while in a transient scope.
166 void beginTransientScope();
167
168 /// Ends the transient scope and resets the context to the base state, pruning
169 /// all types, attributes, affine expressions, distinct attributes, and
170 /// unregistered operations created during the transient scope.
171 ///
172 /// Preconditions:
173 /// - The context must be in a transient scope.
174 /// - There must be no remaining IR (operations, blocks, regions,
175 /// values) referencing the transient types/attributes.
176 /// - Must be called from a single-threaded execution context.
177 void endTransientScope();
178
179 /// Returns true if the context is currently in a transient scope.
180 bool isInTransientScope() const;
181
182 /// RAII scope guard that calls beginTransientScope() on construction and
183 /// endTransientScope() on destruction. Provides exception-safe and
184 /// forgetting-proof transient scope management.
186 public:
187 explicit TransientScope(MLIRContext &ctx) : ctx(ctx) {
188 ctx.beginTransientScope();
189 }
190 ~TransientScope() { ctx.endTransientScope(); }
191
194
195 private:
196 MLIRContext &ctx;
197 };
198
199 /// Return true if multi-threading is enabled by the context.
200 /// This controls parallel execution within MLIR. Use
201 /// isThreadSafeLockingEnabled() to query locking for context access.
202#if LLVM_ENABLE_THREADS
204#else
205 bool isMultithreadingEnabled() { return false; }
206#endif
207
208 /// Set the flag specifying if multi-threading is disabled by the context.
209 /// Enabling multi-threading also enables thread-safe locking. Disabling it
210 /// also disables thread-safe locking, which can be re-enabled independently
211 /// with enableThreadSafeLocking().
212 /// The command line debugging flag `--mlir-disable-threading` is overriding
213 /// this call and making it a no-op!
214 void disableMultithreading(bool disable = true);
215 void enableMultithreading(bool enable = true) {
216 disableMultithreading(!enable);
217 }
218
219 /// Return true if thread-safe locking is enabled for context access.
220 /// This does not imply that parallel execution within MLIR is enabled.
221#if LLVM_ENABLE_THREADS
223#else
224 bool isThreadSafeLockingEnabled() { return false; }
225#endif
226
227 /// Enable thread-safe locking for context access, including
228 /// uniquing types, attributes, affine expressions, and operation names.
229 /// This does not create a thread pool or change isMultithreadingEnabled().
230 /// For example, clients using their own threads can construct a context with
231 /// Threading::DISABLED and then call enableThreadSafeLocking().
232 ///
233 /// Disabling multi-threading also disables locking. This method must be
234 /// called when no other threads are accessing the context. Dialects
235 /// must still be loaded before accessing the context concurrently.
236 /// Unlike enableMultithreading(), this is not overridden by the debugging
237 /// flag --mlir-disable-threading.
239
240 /// Set a new thread pool to be used in this context. This method requires
241 /// that multithreading is disabled for this context prior to the call. This
242 /// allows to share a thread pool across multiple contexts, as well as
243 /// decoupling the lifetime of the threads from the contexts. The thread pool
244 /// must outlive the context. Multi-threading will be enabled as part of this
245 /// method.
246 /// The command line debugging flag `--mlir-disable-threading` will still
247 /// prevent threading from being enabled and threading won't be enabled after
248 /// this call in this case.
249 void setThreadPool(llvm::ThreadPoolInterface &pool);
250
251 /// Return the number of threads used by the thread pool in this context. The
252 /// number of computed hardware threads can change over the lifetime of a
253 /// process based on affinity changes, so users should use the number of
254 /// threads actually in the thread pool for dispatching work. Returns 1 if
255 /// multithreading is disabled.
256 unsigned getNumThreads();
257
258 /// Return the thread pool used by this context. This method requires that
259 /// multithreading be enabled within the context, and should generally not be
260 /// used directly. Users should instead prefer the threading utilities within
261 /// Threading.h.
262 llvm::ThreadPoolInterface &getThreadPool();
263
264 /// Return true if we should attach the operation to diagnostics emitted via
265 /// Operation::emit.
267
268 /// Set the flag specifying if we should attach the operation to diagnostics
269 /// emitted via Operation::emit.
270 void printOpOnDiagnostic(bool enable);
271
272 /// Return true if we should attach the current stacktrace to diagnostics when
273 /// emitted.
275
276 /// Set the flag specifying if we should attach the current stacktrace when
277 /// emitting diagnostics.
278 void printStackTraceOnDiagnostic(bool enable);
279
280 /// Return a sorted array containing the information about all registered
281 /// operations.
283
284 /// Return a sorted array containing the information for registered operations
285 /// filtered by dialect name.
287 getRegisteredOperationsByDialect(StringRef dialectName);
288
289 /// Return true if this operation name is registered in this context.
290 bool isOperationRegistered(StringRef name);
291
292 // This is effectively private given that only MLIRContext.cpp can see the
293 // MLIRContextImpl type.
295 const MLIRContextImpl &getImpl() const { return *impl; }
296
297 /// Returns the diagnostic engine for this context.
299
300 /// Returns the remark engine for this context, or nullptr if none has been
301 /// set.
303
304 /// Set the remark engine for this context.
305 void setRemarkEngine(std::unique_ptr<remark::detail::RemarkEngine> engine);
306
307 /// Returns the storage uniquer used for creating affine constructs.
309
310 /// Returns the storage uniquer used for constructing type storage instances.
311 /// This should not be used directly.
313
314 /// Returns the storage uniquer used for constructing attribute storage
315 /// instances. This should not be used directly.
317
318 /// These APIs are tracking whether the context will be used in a
319 /// multithreading environment: this has no effect other than enabling
320 /// assertions on misuses of some APIs.
323
324 /// Get a dialect for the provided namespace and TypeID: abort the program if
325 /// a dialect exist for this namespace with different TypeID. If a dialect has
326 /// not been loaded for this namespace/TypeID yet, use the provided ctor to
327 /// create one on the fly and load it. Returns a pointer to the dialect owned
328 /// by the context.
329 /// The use of this method is in general discouraged in favor of
330 /// 'getOrLoadDialect<DialectClass>()'.
331 Dialect *getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
332 function_ref<std::unique_ptr<Dialect>()> ctor);
333
334 /// Returns a hash of the registry of the context that may be used to give
335 /// a rough indicator of if the state of the context registry has changed. The
336 /// context registry correlates to loaded dialects and their entities
337 /// (attributes, operations, types, etc.).
338 llvm::hash_code getRegistryHash();
339
340 //===--------------------------------------------------------------------===//
341 // Action API
342 //===--------------------------------------------------------------------===//
343
344 /// Signatures for the action handler that can be registered with the context.
345 using HandlerTy =
346 std::function<void(function_ref<void()>, const tracing::Action &)>;
347
348 /// Register a handler for handling actions that are dispatched through this
349 /// context. A nullptr handler can be set to disable a previously set handler.
350 void registerActionHandler(HandlerTy handler);
351
352 /// Return a reference to the currently registered action handler. Its target
353 /// can be used to gain access to the handler's state, if any.
354 const HandlerTy &getActionHandler() const;
356
357 /// Return true if a valid ActionHandler is set.
358 bool hasActionHandler();
359
360 /// Dispatch the provided action to the handler if any, or just execute it.
361 void executeAction(function_ref<void()> actionFn,
362 const tracing::Action &action) {
363 if (LLVM_UNLIKELY(hasActionHandler()))
364 executeActionInternal(actionFn, action);
365 else
366 actionFn();
367 }
368
369 /// Dispatch the provided action to the handler if any, or just execute it.
370 template <typename ActionTy, typename... Args>
371 void executeAction(function_ref<void()> actionFn, ArrayRef<IRUnit> irUnits,
372 Args &&...args) {
373 if (LLVM_UNLIKELY(hasActionHandler()))
374 executeActionInternal<ActionTy, Args...>(actionFn, irUnits,
375 std::forward<Args>(args)...);
376 else
377 actionFn();
378 }
379
380private:
381 /// Return true if the given dialect is currently loading.
382 bool isDialectLoading(StringRef dialectNamespace);
383
384 /// Internal helper for the dispatch method.
385 void executeActionInternal(function_ref<void()> actionFn,
386 const tracing::Action &action);
387
388 /// Internal helper for the dispatch method. We get here after checking that
389 /// there is a handler, for the purpose of keeping this code out-of-line. and
390 /// avoid calling the ctor for the Action unnecessarily.
391 template <typename ActionTy, typename... Args>
392 LLVM_ATTRIBUTE_NOINLINE void
393 executeActionInternal(function_ref<void()> actionFn, ArrayRef<IRUnit> irUnits,
394 Args &&...args) {
395 executeActionInternal(actionFn,
396 ActionTy(irUnits, std::forward<Args>(args)...));
397 }
398
399 const std::unique_ptr<MLIRContextImpl> impl;
400
401 MLIRContext(const MLIRContext &) = delete;
402 void operator=(const MLIRContext &) = delete;
403};
404
405//===----------------------------------------------------------------------===//
406// MLIRContext CommandLine Options
407//===----------------------------------------------------------------------===//
408
409/// Register a set of useful command-line options that can be used to configure
410/// various flags within the MLIRContext. These flags are used when constructing
411/// an MLIR context for initialization.
413
414} // namespace mlir
415
416#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.
void enableThreadSafeLocking()
Enable thread-safe locking for context access, including uniquing types, attributes,...
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 isThreadSafeLockingEnabled()
Return true if thread-safe locking is enabled for context access.
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 isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
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.
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:229
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:155