MLIR 23.0.0git
MLIRContext.cpp
Go to the documentation of this file.
1//===- MLIRContext.cpp - MLIR Type Classes --------------------------------===//
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
10#include "AffineExprDetail.h"
11#include "AffineMapDetail.h"
12#include "AttributeDetail.h"
13#include "IntegerSetDetail.h"
14#include "TypeDetail.h"
15#include "mlir/IR/Action.h"
16#include "mlir/IR/AffineExpr.h"
17#include "mlir/IR/AffineMap.h"
18#include "mlir/IR/Attributes.h"
21#include "mlir/IR/Diagnostics.h"
22#include "mlir/IR/Dialect.h"
24#include "mlir/IR/IntegerSet.h"
25#include "mlir/IR/Location.h"
28#include "mlir/IR/Remarks.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/Twine.h"
31#include "llvm/Support/Allocator.h"
32#include "llvm/Support/CommandLine.h"
33#include "llvm/Support/Compiler.h"
34#include "llvm/Support/DebugLog.h"
35#include "llvm/Support/ManagedStatic.h"
36#include "llvm/Support/Mutex.h"
37#include "llvm/Support/RWMutex.h"
38#include "llvm/Support/ThreadPool.h"
39#include "llvm/Support/raw_ostream.h"
40#include <memory>
41#include <optional>
42
43#define DEBUG_TYPE "mlircontext"
44
45using namespace mlir;
46using namespace mlir::detail;
47
48//===----------------------------------------------------------------------===//
49// MLIRContext CommandLine Options
50//===----------------------------------------------------------------------===//
51
52namespace {
53/// This struct contains command line options that can be used to initialize
54/// various bits of an MLIRContext. This uses a struct wrapper to avoid the need
55/// for global command line options.
56struct MLIRContextOptions {
57 llvm::cl::opt<bool> disableThreading{
58 "mlir-disable-threading",
59 llvm::cl::desc("Disable multi-threading within MLIR, overrides any "
60 "further call to MLIRContext::enableMultiThreading()")};
61
62 llvm::cl::opt<bool> printOpOnDiagnostic{
63 "mlir-print-op-on-diagnostic",
64 llvm::cl::desc("When a diagnostic is emitted on an operation, also print "
65 "the operation as an attached note"),
66 llvm::cl::init(true)};
67
68 llvm::cl::opt<bool> printStackTraceOnDiagnostic{
69 "mlir-print-stacktrace-on-diagnostic",
70 llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "
71 "as an attached note")};
72};
73} // namespace
74
75static llvm::ManagedStatic<MLIRContextOptions> clOptions;
76
78#if LLVM_ENABLE_THREADS != 0
79 return clOptions.isConstructed() && clOptions->disableThreading;
80#else
81 return true;
82#endif
83}
84
85/// Register a set of useful command-line options that can be used to configure
86/// various flags within the MLIRContext. These flags are used when constructing
87/// an MLIR context for initialization.
89 // Make sure that the options struct has been initialized.
90 *clOptions;
91}
92
93//===----------------------------------------------------------------------===//
94// Locking Utilities
95//===----------------------------------------------------------------------===//
96
97namespace {
98/// Utility writer lock that takes a runtime flag that specifies if we really
99/// need to lock.
100struct ScopedWriterLock {
101 ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)
102 : mutex(shouldLock ? &mutexParam : nullptr) {
103 if (mutex)
104 mutex->lock();
105 }
106 ~ScopedWriterLock() {
107 if (mutex)
108 mutex->unlock();
109 }
110 llvm::sys::SmartRWMutex<true> *mutex;
111};
112} // namespace
113
114//===----------------------------------------------------------------------===//
115// MLIRContextImpl
116//===----------------------------------------------------------------------===//
117
118namespace mlir {
119/// This is the implementation of the MLIRContext class, using the pImpl idiom.
120/// This class is completely private to this file, so everything is public.
122public:
123 //===--------------------------------------------------------------------===//
124 // Remark
125 //===--------------------------------------------------------------------===//
126 std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;
127
128 //===--------------------------------------------------------------------===//
129 // Debugging
130 //===--------------------------------------------------------------------===//
131
132 /// An action handler for handling actions that are dispatched through this
133 /// context.
134 std::function<void(function_ref<void()>, const tracing::Action &)>
136
137 //===--------------------------------------------------------------------===//
138 // Diagnostics
139 //===--------------------------------------------------------------------===//
141
142 //===--------------------------------------------------------------------===//
143 // Options
144 //===--------------------------------------------------------------------===//
145
146 /// In most cases, creating operation in unregistered dialect is not desired
147 /// and indicate a misconfiguration of the compiler. This option enables to
148 /// detect such use cases
150
151 /// Enable support for multi-threading within MLIR.
153
154 /// Track if we are currently executing in a threaded execution environment
155 /// (like the pass-manager): this is only a debugging feature to help reducing
156 /// the chances of data races one some context APIs.
157#ifndef NDEBUG
158 std::atomic<int> multiThreadedExecutionContext{0};
159#endif
160
161 /// If the operation should be attached to diagnostics printed via the
162 /// Operation::emit methods.
164
165 /// If the current stack trace should be attached when emitting diagnostics.
167
168 //===--------------------------------------------------------------------===//
169 // Other
170 //===--------------------------------------------------------------------===//
171
172 /// This points to the ThreadPool used when processing MLIR tasks in parallel.
173 /// It can't be nullptr when multi-threading is enabled. Otherwise if
174 /// multi-threading is disabled, and the threadpool wasn't externally provided
175 /// using `setThreadPool`, this will be nullptr.
176 llvm::ThreadPoolInterface *threadPool = nullptr;
177
178 /// In case where the thread pool is owned by the context, this ensures
179 /// destruction with the context.
180 std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
181
182 /// An allocator used for AbstractAttribute and AbstractType objects.
183 llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
184
185 /// This is a mapping from operation name to the operation info describing it.
186 llvm::StringMap<std::unique_ptr<OperationName::Impl>> operations;
187
188 /// A vector of operation info specifically for registered operations.
190 llvm::StringMap<RegisteredOperationName> registeredOperationsByName;
191
192 /// This is a sorted container of registered operations for a deterministic
193 /// and efficient `getRegisteredOperations` implementation.
195
196 /// This is a list of dialects that are created referring to this context.
197 /// The MLIRContext owns the objects. These need to be declared after the
198 /// registered operations to ensure correct destruction order.
201
202 /// A mutex used when accessing operation information.
203 llvm::sys::SmartRWMutex<true> operationInfoMutex;
204
205 //===--------------------------------------------------------------------===//
206 // Affine uniquing
207 //===--------------------------------------------------------------------===//
208
209 // Affine expression, map and integer set uniquing.
211
212 //===--------------------------------------------------------------------===//
213 // Type uniquing
214 //===--------------------------------------------------------------------===//
215
218
219 /// This is a mapping from type name to the abstract type describing it.
220 /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.
221 /// As this map needs to be populated before `StringAttr` is loaded, we
222 /// cannot use `StringAttr` as the key. The context does not take ownership
223 /// of the key, so the `StringRef` must outlive the context.
225
226 /// Cached Type Instances.
227 BFloat16Type bf16Ty;
228 Float16Type f16Ty;
229 FloatTF32Type tf32Ty;
230 Float32Type f32Ty;
231 Float64Type f64Ty;
232 Float80Type f80Ty;
233 Float128Type f128Ty;
234 IndexType indexTy;
236 NoneType noneType;
237
238 //===--------------------------------------------------------------------===//
239 // Attribute uniquing
240 //===--------------------------------------------------------------------===//
241
244
245 /// This is a mapping from attribute name to the abstract attribute describing
246 /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a
247 /// name.
248 /// As this map needs to be populated before `StringAttr` is loaded, we
249 /// cannot use `StringAttr` as the key. The context does not take ownership
250 /// of the key, so the `StringRef` must outlive the context.
252
253 /// Cached Attribute Instances.
255 UnitAttr unitAttr;
256 UnknownLoc unknownLocAttr;
257 DictionaryAttr emptyDictionaryAttr;
258 StringAttr emptyStringAttr;
259
260 /// Map of string attributes that may reference a dialect, that are awaiting
261 /// that dialect to be loaded.
265
266 /// A distinct attribute allocator that allocates every time since the
267 /// address of the distinct attribute storage serves as unique identifier. The
268 /// allocator is thread safe and frees the allocated storage after its
269 /// destruction.
271
272public:
275 if (threadingIsEnabled) {
276 ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
278 }
279 }
281 for (auto typeMapping : registeredTypes)
282 typeMapping.second->~AbstractType();
283 for (auto attrMapping : registeredAttributes)
284 attrMapping.second->~AbstractAttribute();
285 }
286};
287} // namespace mlir
288
291
293 : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
295 // Initialize values based on the command line flags if they were provided.
296 if (clOptions.isConstructed()) {
297 printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
298 printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
299 }
300
301 // Pre-populate the registry.
302 registry.appendTo(impl->dialectsRegistry);
303
304 // Ensure the builtin dialect is always pre-loaded.
306
307 // Initialize several common attributes and types to avoid the need to lock
308 // the context when accessing them.
309
310 //// Types.
311 /// Floating-point Types.
312 impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
313 impl->f16Ty = TypeUniquer::get<Float16Type>(this);
315 impl->f32Ty = TypeUniquer::get<Float32Type>(this);
316 impl->f64Ty = TypeUniquer::get<Float64Type>(this);
317 impl->f80Ty = TypeUniquer::get<Float80Type>(this);
318 impl->f128Ty = TypeUniquer::get<Float128Type>(this);
319 /// Index Type.
320 impl->indexTy = TypeUniquer::get<IndexType>(this);
321 /// Integer Types.
322 impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
323 impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
324 impl->int16Ty =
325 TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
326 impl->int32Ty =
327 TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
328 impl->int64Ty =
329 TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
330 impl->int128Ty =
331 TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
332 /// None Type.
333 impl->noneType = TypeUniquer::get<NoneType>(this);
334
335 //// Attributes.
336 //// Note: These must be registered after the types as they may generate one
337 //// of the above types internally.
338 /// Unknown Location Attribute.
339 impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
340 /// Bool Attributes.
341 impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
342 impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
343 /// Unit Attribute.
344 impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
345 /// The empty dictionary attribute.
346 impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
347 /// The empty string attribute.
348 impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
349
350 // Register the affine storage objects with the uniquer.
351 impl->affineUniquer
352 .registerParametricStorageType<AffineBinaryOpExprStorage>();
353 impl->affineUniquer
354 .registerParametricStorageType<AffineConstantExprStorage>();
355 impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
356 impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
357 impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
358}
359
361 // finalize remark engine before destroying anything else.
362 impl->remarkEngine.reset();
363}
364
365/// Copy the specified array of elements into memory managed by the provided
366/// bump pointer allocator. This assumes the elements are all PODs.
367template <typename T>
368static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
369 ArrayRef<T> elements) {
370 auto result = allocator.Allocate<T>(elements.size());
371 llvm::uninitialized_copy(elements, result);
372 return ArrayRef<T>(result, elements.size());
373}
374
375//===----------------------------------------------------------------------===//
376// Action Handling
377//===----------------------------------------------------------------------===//
378
380 getImpl().actionHandler = std::move(handler);
381}
382
386
390
391/// Dispatch the provided action to the handler if any, or just execute it.
392void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
393 const tracing::Action &action) {
394 assert(getImpl().actionHandler);
395 getImpl().actionHandler(actionFn, action);
396}
397
399
400//===----------------------------------------------------------------------===//
401// Diagnostic Handlers
402//===----------------------------------------------------------------------===//
403
404/// Returns the diagnostic engine for this context.
406
407//===----------------------------------------------------------------------===//
408// Remark Handlers
409//===----------------------------------------------------------------------===//
410
412 std::unique_ptr<remark::detail::RemarkEngine> engine) {
413 getImpl().remarkEngine = std::move(engine);
414}
415
419
420//===----------------------------------------------------------------------===//
421// Dialect and Operation Registration
422//===----------------------------------------------------------------------===//
423
425 if (registry.isSubsetOf(impl->dialectsRegistry))
426 return;
427
428 assert(impl->multiThreadedExecutionContext == 0 &&
429 "appending to the MLIRContext dialect registry while in a "
430 "multi-threaded execution context");
431 registry.appendTo(impl->dialectsRegistry);
432
433 // For the already loaded dialects, apply any possible extensions immediately.
434 registry.applyExtensions(this);
435}
436
438 return impl->dialectsRegistry;
439}
440
441/// Return information about all registered IR dialects.
442std::vector<Dialect *> MLIRContext::getLoadedDialects() {
443 std::vector<Dialect *> result;
444 result.reserve(impl->loadedDialects.size());
445 for (auto &dialect : impl->loadedDialects)
446 result.push_back(dialect.second.get());
447 llvm::array_pod_sort(result.begin(), result.end(),
448 [](Dialect *const *lhs, Dialect *const *rhs) -> int {
449 return (*lhs)->getNamespace() < (*rhs)->getNamespace();
450 });
451 return result;
452}
453std::vector<StringRef> MLIRContext::getAvailableDialects() {
454 std::vector<StringRef> result;
455 for (auto dialect : impl->dialectsRegistry.getRegisteredDialectNames())
456 result.push_back(dialect);
457 return result;
458}
459
460/// Get a registered IR dialect with the given namespace. If none is found,
461/// then return nullptr.
463 // Dialects are sorted by name, so we can use binary search for lookup.
464 auto it = impl->loadedDialects.find(name);
465 return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
466}
467
469 Dialect *dialect = getLoadedDialect(name);
470 if (dialect)
471 return dialect;
473 impl->dialectsRegistry.getDialectAllocator(name);
474 return allocator ? allocator(this) : nullptr;
475}
476
477/// Get a dialect for the provided namespace and TypeID: abort the program if a
478/// dialect exist for this namespace with different TypeID. Returns a pointer to
479/// the dialect owned by the context.
480Dialect *
481MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
482 function_ref<std::unique_ptr<Dialect>()> ctor) {
483 auto &impl = getImpl();
484 // Get the correct insertion position sorted by namespace.
485 auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
486
487 if (dialectIt.second) {
488 LDBG() << "Load new dialect in Context " << dialectNamespace;
489#ifndef NDEBUG
490 if (impl.multiThreadedExecutionContext != 0)
491 llvm::report_fatal_error(
492 "Loading a dialect (" + dialectNamespace +
493 ") while in a multi-threaded execution context (maybe "
494 "the PassManager): this can indicate a "
495 "missing `dependentDialects` in a pass for example.");
496#endif // NDEBUG
497 // loadedDialects entry is initialized to nullptr, indicating that the
498 // dialect is currently being loaded. Re-lookup the address in
499 // loadedDialects because the table might have been rehashed by recursive
500 // dialect loading in ctor().
501 std::unique_ptr<Dialect> &dialectOwned =
502 impl.loadedDialects[dialectNamespace] = ctor();
503 Dialect *dialect = dialectOwned.get();
504 assert(dialect && "dialect ctor failed");
505
506 // Refresh all the identifiers dialect field, this catches cases where a
507 // dialect may be loaded after identifier prefixed with this dialect name
508 // were already created.
509 auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
510 if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
511 for (StringAttrStorage *storage : stringAttrsIt->second)
512 storage->referencedDialect = dialect;
513 impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
514 }
515
516 // Apply any extensions to this newly loaded dialect.
517 impl.dialectsRegistry.applyExtensions(dialect);
518 return dialect;
519 }
520
521#ifndef NDEBUG
522 if (dialectIt.first->second == nullptr)
523 llvm::report_fatal_error(
524 "Loading (and getting) a dialect (" + dialectNamespace +
525 ") while the same dialect is still loading: use loadDialect instead "
526 "of getOrLoadDialect.");
527#endif // NDEBUG
528
529 // Abort if dialect with namespace has already been registered.
530 std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
531 if (dialect->getTypeID() != dialectID)
532 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
533 "' has already been registered");
534
535 return dialect.get();
536}
537
538bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
539 auto it = getImpl().loadedDialects.find(dialectNamespace);
540 // nullptr indicates that the dialect is currently being loaded.
541 return it != getImpl().loadedDialects.end() && it->second == nullptr;
542}
543
545 StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
546 auto &impl = getImpl();
547 // Get the correct insertion position sorted by namespace.
548 auto dialectIt = impl.loadedDialects.find(dialectNamespace);
549
550 if (dialectIt != impl.loadedDialects.end()) {
551 if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
552 return dynDialect;
553 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
554 "' has already been registered");
555 }
556
557 LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
558#ifndef NDEBUG
559 if (impl.multiThreadedExecutionContext != 0)
560 llvm::report_fatal_error(
561 "Loading a dynamic dialect (" + dialectNamespace +
562 ") while in a multi-threaded execution context (maybe "
563 "the PassManager): this can indicate a "
564 "missing `dependentDialects` in a pass for example.");
565#endif
566
567 auto name = StringAttr::get(this, dialectNamespace);
568 auto *dialect = new DynamicDialect(name, this);
569 (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
570 ctor(dialect);
571 return std::unique_ptr<DynamicDialect>(dialect);
572 });
573 // This is the same result as `getOrLoadDialect` (if it didn't failed),
574 // since it has the same TypeID, and TypeIDs are unique.
575 return dialect;
576}
577
579 for (StringRef name : getAvailableDialects())
580 getOrLoadDialect(name);
581}
582
584 llvm::hash_code hash(0);
585 // Factor in number of loaded dialects, attributes, operations, types.
586 hash = llvm::hash_combine(hash, impl->loadedDialects.size());
587 hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
588 hash = llvm::hash_combine(hash, impl->registeredOperations.size());
589 hash = llvm::hash_combine(hash, impl->registeredTypes.size());
590 return hash;
591}
592
594 return impl->allowUnregisteredDialects;
595}
596
598 assert(impl->multiThreadedExecutionContext == 0 &&
599 "changing MLIRContext `allow-unregistered-dialects` configuration "
600 "while in a multi-threaded execution context");
601 impl->allowUnregisteredDialects = allowing;
602}
603
604/// Return true if multi-threading is enabled by the context.
606 return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
607}
608
609/// Set the flag specifying if multi-threading is disabled by the context.
611 // This API can be overridden by the global debugging flag
612 // --mlir-disable-threading
614 return;
615 assert(impl->multiThreadedExecutionContext == 0 &&
616 "changing MLIRContext `disable-threading` configuration while "
617 "in a multi-threaded execution context");
618
619 impl->threadingIsEnabled = !disable;
620
621 // Update the threading mode for each of the uniquers.
622 impl->affineUniquer.disableMultithreading(disable);
623 impl->attributeUniquer.disableMultithreading(disable);
624 impl->typeUniquer.disableMultithreading(disable);
625
626 // Destroy thread pool (stop all threads) if it is no longer needed, or create
627 // a new one if multithreading was re-enabled.
628 if (disable) {
629 // If the thread pool is owned, explicitly set it to nullptr to avoid
630 // keeping a dangling pointer around. If the thread pool is externally
631 // owned, we don't do anything.
632 if (impl->ownedThreadPool) {
633 assert(impl->threadPool);
634 impl->threadPool = nullptr;
635 impl->ownedThreadPool.reset();
636 }
637 } else if (!impl->threadPool) {
638 // The thread pool isn't externally provided.
639 assert(!impl->ownedThreadPool);
640 impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
641 impl->threadPool = impl->ownedThreadPool.get();
642 }
643}
644
645void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
646 assert(!isMultithreadingEnabled() &&
647 "expected multi-threading to be disabled when setting a ThreadPool");
648 impl->threadPool = &pool;
649 impl->ownedThreadPool.reset();
651}
652
655 assert(impl->threadPool &&
656 "multi-threading is enabled but threadpool not set");
657 return impl->threadPool->getMaxConcurrency();
658 }
659 // No multithreading or active thread pool. Return 1 thread.
660 return 1;
661}
662
663llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
664 assert(isMultithreadingEnabled() &&
665 "expected multi-threading to be enabled within the context");
666 assert(impl->threadPool &&
667 "multi-threading is enabled but threadpool not set");
668 return *impl->threadPool;
669}
670
672#ifndef NDEBUG
673 ++impl->multiThreadedExecutionContext;
674#endif
675}
677#ifndef NDEBUG
678 --impl->multiThreadedExecutionContext;
679#endif
680}
681
682/// Return true if we should attach the operation to diagnostics emitted via
683/// Operation::emit.
685 return impl->printOpOnDiagnostic;
686}
687
688/// Set the flag specifying if we should attach the operation to diagnostics
689/// emitted via Operation::emit.
691 assert(impl->multiThreadedExecutionContext == 0 &&
692 "changing MLIRContext `print-op-on-diagnostic` configuration while in "
693 "a multi-threaded execution context");
694 impl->printOpOnDiagnostic = enable;
695}
696
697/// Return true if we should attach the current stacktrace to diagnostics when
698/// emitted.
700 return impl->printStackTraceOnDiagnostic;
701}
702
703/// Set the flag specifying if we should attach the current stacktrace when
704/// emitting diagnostics.
706 assert(impl->multiThreadedExecutionContext == 0 &&
707 "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
708 "while in a multi-threaded execution context");
709 impl->printStackTraceOnDiagnostic = enable;
710}
711
712/// Return information about all registered operations.
714 return impl->sortedRegisteredOperations;
715}
716
717/// Return information for registered operations by dialect.
720 auto *lowerBound =
721 llvm::lower_bound(impl->sortedRegisteredOperations, dialectName,
722 [](const RegisteredOperationName &lhs, StringRef rhs) {
723 return lhs.getDialect().getNamespace() < rhs;
724 });
725
726 if (lowerBound == impl->sortedRegisteredOperations.end() ||
727 lowerBound->getDialect().getNamespace() != dialectName)
729
730 auto *upperBound = std::upper_bound(
731 lowerBound, impl->sortedRegisteredOperations.end(), dialectName,
732 [](StringRef lhs, const RegisteredOperationName &rhs) {
733 return lhs < rhs.getDialect().getNamespace();
734 });
735
736 size_t count = std::distance(lowerBound, upperBound);
737 return ArrayRef(&*lowerBound, count);
738}
739
741 return RegisteredOperationName::lookup(name, this).has_value();
742}
743
744void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
745 auto &impl = context->getImpl();
746 assert(impl.multiThreadedExecutionContext == 0 &&
747 "Registering a new type kind while in a multi-threaded execution "
748 "context");
749 auto *newInfo =
750 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
751 AbstractType(std::move(typeInfo));
752 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
753 llvm::report_fatal_error("Dialect Type already registered.");
754 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
755 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
756 " is already registered.");
757}
758
760 auto &impl = context->getImpl();
761 assert(impl.multiThreadedExecutionContext == 0 &&
762 "Registering a new attribute kind while in a multi-threaded execution "
763 "context");
764 auto *newInfo =
765 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
766 AbstractAttribute(std::move(attrInfo));
767 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
768 llvm::report_fatal_error("Dialect Attribute already registered.");
769 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
770 llvm::report_fatal_error("Dialect Attribute with name " +
771 newInfo->getName() + " is already registered.");
772}
773
774//===----------------------------------------------------------------------===//
775// AbstractAttribute
776//===----------------------------------------------------------------------===//
777
778/// Get the dialect that registered the attribute with the provided typeid.
779const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
780 MLIRContext *context) {
781 const AbstractAttribute *abstract = lookupMutable(typeID, context);
782 if (!abstract)
783 llvm::report_fatal_error("Trying to create an Attribute that was not "
784 "registered in this MLIRContext.");
785 return *abstract;
786}
787
788AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
789 MLIRContext *context) {
790 auto &impl = context->getImpl();
791 return impl.registeredAttributes.lookup(typeID);
792}
793
794std::optional<std::reference_wrapper<const AbstractAttribute>>
795AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
796 MLIRContextImpl &impl = context->getImpl();
797 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
798
799 if (!type)
800 return std::nullopt;
801 return {*type};
802}
803
804//===----------------------------------------------------------------------===//
805// OperationName
806//===----------------------------------------------------------------------===//
807
812
813OperationName::OperationName(StringRef name, MLIRContext *context) {
814 MLIRContextImpl &ctxImpl = context->getImpl();
815
816 // Check for an existing name in read-only mode.
817 bool isMultithreadingEnabled = context->isMultithreadingEnabled();
818 if (isMultithreadingEnabled) {
819 // Check the registered info map first. In the overwhelmingly common case,
820 // the entry will be in here and it also removes the need to acquire any
821 // locks.
822 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
823 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
824 impl = registeredIt->second.impl;
825 return;
826 }
827
828 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
829 auto it = ctxImpl.operations.find(name);
830 if (it != ctxImpl.operations.end()) {
831 impl = it->second.get();
832 return;
833 }
834 }
835
836 // Acquire a writer-lock so that we can safely create the new instance.
837 ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
838
839 auto it = ctxImpl.operations.try_emplace(name);
840 if (it.second) {
841 auto nameAttr = StringAttr::get(context, name);
842 it.first->second = std::make_unique<UnregisteredOpModel>(
843 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
845 }
846 impl = it.first->second.get();
847}
848
850 if (Dialect *dialect = getDialect())
851 return dialect->getNamespace();
852 return getStringRef().split('.').first;
853}
854
855LogicalResult
863
866 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
867}
871 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
872 p.printGenericOp(op);
873}
874LogicalResult
878LogicalResult
882
883std::optional<Attribute>
885 StringRef name) {
886 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
887 if (!dict)
888 return std::nullopt;
889 if (Attribute attr = dict.get(name))
890 return attr;
891 return std::nullopt;
892}
894 StringAttr name,
895 Attribute value) {
896 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
897 assert(dict);
898 NamedAttrList attrs(dict);
899 attrs.set(name, value);
900 *op->getPropertiesStorage().as<Attribute *>() =
901 attrs.getDictionary(op->getContext());
902}
914 PropertyRef storage,
915 PropertyRef init) {
916 new (storage.as<Attribute *>()) Attribute();
917 if (init)
918 *storage.as<Attribute *>() = *init.as<Attribute *>();
919}
926 OperationName opName, PropertyRef properties, Attribute attr,
928 *properties.as<Attribute *>() = attr;
929 return success();
930}
943llvm::hash_code
945 return llvm::hash_combine(*prop.as<Attribute *>());
946}
947
948//===----------------------------------------------------------------------===//
949// RegisteredOperationName
950//===----------------------------------------------------------------------===//
951
952std::optional<RegisteredOperationName>
954 auto &impl = ctx->getImpl();
955 auto it = impl.registeredOperations.find(typeID);
956 if (it != impl.registeredOperations.end())
957 return it->second;
958 return std::nullopt;
959}
960
961std::optional<RegisteredOperationName>
963 auto &impl = ctx->getImpl();
964 auto it = impl.registeredOperationsByName.find(name);
965 if (it != impl.registeredOperationsByName.end())
966 return it->getValue();
967 return std::nullopt;
968}
969
971 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
972 ArrayRef<StringRef> attrNames) {
973 RegisteredOperationName::Impl *impl = ownedImpl.get();
974 MLIRContext *ctx = impl->getDialect()->getContext();
975 auto &ctxImpl = ctx->getImpl();
976 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
977 "registering a new operation kind while in a multi-threaded execution "
978 "context");
979
980 // Register the attribute names of this operation.
981 MutableArrayRef<StringAttr> cachedAttrNames;
982 if (!attrNames.empty()) {
983 cachedAttrNames = MutableArrayRef<StringAttr>(
984 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
985 attrNames.size()),
986 attrNames.size());
987 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
988 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
989 impl->attributeNames = cachedAttrNames;
990 }
991 StringRef name = impl->getName().strref();
992 // Insert the operation info if it doesn't exist yet.
993 ctxImpl.operations[name] = std::move(ownedImpl);
994
995 // Update the registered info for this operation.
996 auto emplaced = ctxImpl.registeredOperations.try_emplace(
997 impl->getTypeID(), RegisteredOperationName(impl));
998 assert(emplaced.second && "operation name registration must be successful");
999 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
1001 (void)emplacedByName;
1002 assert(emplacedByName.second &&
1003 "operation name registration must be successful");
1004
1005 // Add emplaced operation name to the sorted operations container.
1006 RegisteredOperationName &value = emplaced.first->second;
1007 ctxImpl.sortedRegisteredOperations.insert(
1008 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1009 [](auto &lhs, auto &rhs) {
1010 return lhs.getIdentifier().strref() <
1011 rhs.getIdentifier().strref();
1012 }),
1013 value);
1014}
1015
1016//===----------------------------------------------------------------------===//
1017// AbstractType
1018//===----------------------------------------------------------------------===//
1019
1020const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1021 const AbstractType *type = lookupMutable(typeID, context);
1022 if (!type)
1023 llvm::report_fatal_error(
1024 "Trying to create a Type that was not registered in this MLIRContext.");
1025 return *type;
1026}
1027
1028AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1029 auto &impl = context->getImpl();
1030 return impl.registeredTypes.lookup(typeID);
1031}
1032
1033std::optional<std::reference_wrapper<const AbstractType>>
1034AbstractType::lookup(StringRef name, MLIRContext *context) {
1035 MLIRContextImpl &impl = context->getImpl();
1036 const AbstractType *type = impl.nameToType.lookup(name);
1037
1038 if (!type)
1039 return std::nullopt;
1040 return {*type};
1041}
1042
1043//===----------------------------------------------------------------------===//
1044// Type uniquing
1045//===----------------------------------------------------------------------===//
1046
1047/// Returns the storage uniquer used for constructing type storage instances.
1048/// This should not be used directly.
1050
1051BFloat16Type BFloat16Type::get(MLIRContext *context) {
1052 return context->getImpl().bf16Ty;
1053}
1054Float16Type Float16Type::get(MLIRContext *context) {
1055 return context->getImpl().f16Ty;
1056}
1057FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1058 return context->getImpl().tf32Ty;
1059}
1060Float32Type Float32Type::get(MLIRContext *context) {
1061 return context->getImpl().f32Ty;
1062}
1063Float64Type Float64Type::get(MLIRContext *context) {
1064 return context->getImpl().f64Ty;
1065}
1066Float80Type Float80Type::get(MLIRContext *context) {
1067 return context->getImpl().f80Ty;
1068}
1069Float128Type Float128Type::get(MLIRContext *context) {
1070 return context->getImpl().f128Ty;
1071}
1072
1073/// Get an instance of the IndexType.
1074IndexType IndexType::get(MLIRContext *context) {
1075 return context->getImpl().indexTy;
1076}
1077
1078/// Return an existing integer type instance if one is cached within the
1079/// context.
1080static IntegerType
1082 IntegerType::SignednessSemantics signedness,
1083 MLIRContext *context) {
1084 if (signedness != IntegerType::Signless)
1085 return IntegerType();
1086
1087 switch (width) {
1088 case 1:
1089 return context->getImpl().int1Ty;
1090 case 8:
1091 return context->getImpl().int8Ty;
1092 case 16:
1093 return context->getImpl().int16Ty;
1094 case 32:
1095 return context->getImpl().int32Ty;
1096 case 64:
1097 return context->getImpl().int64Ty;
1098 case 128:
1099 return context->getImpl().int128Ty;
1100 default:
1101 return IntegerType();
1102 }
1103}
1104
1105IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1106 IntegerType::SignednessSemantics signedness) {
1107 if (auto cached = getCachedIntegerType(width, signedness, context))
1108 return cached;
1109 return Base::get(context, width, signedness);
1110}
1111
1112IntegerType
1113IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1114 MLIRContext *context, unsigned width,
1115 SignednessSemantics signedness) {
1116 if (auto cached = getCachedIntegerType(width, signedness, context))
1117 return cached;
1118 return Base::getChecked(emitError, context, width, signedness);
1119}
1120
1121/// Get an instance of the NoneType.
1122NoneType NoneType::get(MLIRContext *context) {
1123 if (NoneType cachedInst = context->getImpl().noneType)
1124 return cachedInst;
1125 // Note: May happen when initializing the singleton attributes of the builtin
1126 // dialect.
1127 return Base::get(context);
1128}
1129
1130//===----------------------------------------------------------------------===//
1131// Attribute uniquing
1132//===----------------------------------------------------------------------===//
1133
1134/// Returns the storage uniquer used for constructing attribute storage
1135/// instances. This should not be used directly.
1137 return getImpl().attributeUniquer;
1138}
1139
1140/// Initialize the given attribute storage instance.
1141void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1142 MLIRContext *ctx,
1143 TypeID attrID) {
1145}
1146
1147BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1148 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1149}
1150
1151UnitAttr UnitAttr::get(MLIRContext *context) {
1152 return context->getImpl().unitAttr;
1153}
1154
1155UnknownLoc UnknownLoc::get(MLIRContext *context) {
1156 return context->getImpl().unknownLocAttr;
1157}
1158
1159DistinctAttrStorage *
1160detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1161 Attribute referencedAttr) {
1162 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1163}
1164
1165/// Return empty dictionary.
1166DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1167 return context->getImpl().emptyDictionaryAttr;
1168}
1169
1171 // Check for a dialect namespace prefix, if there isn't one we don't need to
1172 // do any additional initialization.
1173 auto dialectNamePair = value.split('.');
1174 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1175 return;
1176
1177 // If one exists, we check to see if this dialect is loaded. If it is, we set
1178 // the dialect now, if it isn't we record this storage for initialization
1179 // later if the dialect ever gets loaded.
1180 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1181 return;
1182
1183 MLIRContextImpl &impl = context->getImpl();
1184 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1185 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1186}
1187
1188/// Return an empty string.
1189StringAttr StringAttr::get(MLIRContext *context) {
1190 return context->getImpl().emptyStringAttr;
1191}
1192
1193//===----------------------------------------------------------------------===//
1194// AffineMap uniquing
1195//===----------------------------------------------------------------------===//
1196
1198 return getImpl().affineUniquer;
1199}
1200
1201AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1202 ArrayRef<AffineExpr> results,
1203 MLIRContext *context) {
1204 auto &impl = context->getImpl();
1205 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1206 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1207 symbolCount, results);
1208 return AffineMap(storage);
1209}
1210
1211/// Check whether the arguments passed to the AffineMap::get() are consistent.
1212/// This method checks whether the highest index of dimensional identifier
1213/// present in result expressions is less than `dimCount` and the highest index
1214/// of symbolic identifier present in result expressions is less than
1215/// `symbolCount`.
1216[[maybe_unused]] static bool
1217willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1218 ArrayRef<AffineExpr> results) {
1219 int64_t maxDimPosition = -1;
1220 int64_t maxSymbolPosition = -1;
1221 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1222 maxSymbolPosition);
1223 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1224 LDBG()
1225 << "maximum dimensional identifier position in result expression must "
1226 "be less than `dimCount` and maximum symbolic identifier position "
1227 "in result expression must be less than `symbolCount`";
1228 return false;
1229 }
1230 return true;
1231}
1232
1234 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1235}
1236
1237AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1238 MLIRContext *context) {
1239 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1240}
1241
1242AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1244 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1245 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1246}
1247
1248AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1249 ArrayRef<AffineExpr> results, MLIRContext *context) {
1250 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1251 return getImpl(dimCount, symbolCount, results, context);
1252}
1253
1254//===----------------------------------------------------------------------===//
1255// Integer Sets: these are allocated into the bump pointer, and are immutable.
1256// Unlike AffineMap's, these are uniqued only if they are small.
1257//===----------------------------------------------------------------------===//
1258
1259IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1260 ArrayRef<AffineExpr> constraints,
1261 ArrayRef<bool> eqFlags) {
1262 // The number of constraints can't be zero.
1263 assert(!constraints.empty());
1264 assert(constraints.size() == eqFlags.size());
1265
1266 auto &impl = constraints[0].getContext()->getImpl();
1267 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1268 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1269 return IntegerSet(storage);
1270}
1271
1272//===----------------------------------------------------------------------===//
1273// StorageUniquerSupport
1274//===----------------------------------------------------------------------===//
1275
1276/// Utility method to generate a callback that can be used to generate a
1277/// diagnostic when checking the construction invariants of a storage object.
1278/// This is defined out-of-line to avoid the need to include Location.h.
1279llvm::unique_function<InFlightDiagnostic()>
1281 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1282}
1283llvm::unique_function<InFlightDiagnostic()>
1285 return [=] { return emitError(loc); };
1286}
return success()
static llvm::ManagedStatic< DebugCounterOptions > clOptions
static size_t hash(const T &value)
Local helper to compute std::hash for a value.
Definition IRCore.cpp:56
lhs
static bool willBeValidAffineMap(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > results)
Check whether the arguments passed to the AffineMap::get() are consistent.
static bool isThreadingGloballyDisabled()
static ArrayRef< T > copyArrayRefInto(llvm::BumpPtrAllocator &allocator, ArrayRef< T > elements)
Copy the specified array of elements into memory managed by the provided bump pointer allocator.
static IntegerType getCachedIntegerType(unsigned width, IntegerType::SignednessSemantics signedness, MLIRContext *context)
Return an existing integer type instance if one is cached within the context.
This class contains all of the static information common to all instances of a registered Attribute.
static const AbstractAttribute & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract attribute in the MLIRContext and return a reference to it.
This class contains all of the static information common to all instances of a registered Type.
Definition TypeSupport.h:30
static const AbstractType & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract type in the MLIRContext and return a reference to it.
Base type for affine expression.
Definition AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
constexpr AffineMap()=default
Base storage class appearing in an attribute.
void initializeAbstractAttribute(const AbstractAttribute &abstractAttr)
Set the abstract attribute for this storage instance.
Attributes are known-constant values of operations.
Definition Attributes.h:25
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static BoolAttr get(MLIRContext *context, bool value)
This class is the main interface for diagnostics.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool isSubsetOf(const DialectRegistry &rhs) const
Returns true if the current registry is a subset of 'rhs', i.e.
Definition Dialect.cpp:343
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition Dialect.cpp:269
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
void addType(TypeID typeID, AbstractType &&typeInfo)
Register a type instance with this dialect.
void addAttribute(TypeID typeID, AbstractAttribute &&attrInfo)
Register an attribute instance with this dialect.
A dialect that can be defined at runtime.
This class represents a diagnostic that is inflight and set to be reported.
constexpr IntegerSet()=default
static IntegerSet get(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > constraints, ArrayRef< bool > eqFlags)
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.
llvm::ThreadPoolInterface * threadPool
This points to the ThreadPool used when processing MLIR tasks in parallel.
DictionaryAttr emptyDictionaryAttr
bool printStackTraceOnDiagnostic
If the current stack trace should be attached when emitting diagnostics.
llvm::DenseMap< StringRef, AbstractAttribute * > nameToAttribute
This is a mapping from attribute name to the abstract attribute describing it.
DenseMap< StringRef, std::unique_ptr< Dialect > > loadedDialects
This is a list of dialects that are created referring to this context.
llvm::DenseMap< TypeID, RegisteredOperationName > registeredOperations
A vector of operation info specifically for registered operations.
BoolAttr falseAttr
Cached Attribute Instances.
llvm::sys::SmartRWMutex< true > operationInfoMutex
A mutex used when accessing operation information.
BFloat16Type bf16Ty
Cached Type Instances.
DenseMap< StringRef, SmallVector< StringAttrStorage * > > dialectReferencingStrAttrs
llvm::StringMap< RegisteredOperationName > registeredOperationsByName
std::atomic< int > multiThreadedExecutionContext
Track if we are currently executing in a threaded execution environment (like the pass-manager): this...
std::function< void(function_ref< void()>, const tracing::Action &)> actionHandler
An action handler for handling actions that are dispatched through this context.
bool allowUnregisteredDialects
In most cases, creating operation in unregistered dialect is not desired and indicate a misconfigurat...
llvm::sys::SmartMutex< true > dialectRefStrAttrMutex
Map of string attributes that may reference a dialect, that are awaiting that dialect to be loaded.
llvm::DenseMap< StringRef, AbstractType * > nameToType
This is a mapping from type name to the abstract type describing it.
StorageUniquer typeUniquer
bool printOpOnDiagnostic
If the operation should be attached to diagnostics printed via the Operation::emit methods.
llvm::BumpPtrAllocator abstractDialectSymbolAllocator
An allocator used for AbstractAttribute and AbstractType objects.
DenseMap< TypeID, AbstractType * > registeredTypes
StorageUniquer affineUniquer
DiagnosticEngine diagEngine
std::unique_ptr< remark::detail::RemarkEngine > remarkEngine
DenseMap< TypeID, AbstractAttribute * > registeredAttributes
llvm::StringMap< std::unique_ptr< OperationName::Impl > > operations
This is a mapping from operation name to the operation info describing it.
std::unique_ptr< llvm::ThreadPoolInterface > ownedThreadPool
In case where the thread pool is owned by the context, this ensures destruction with the context.
SmallVector< RegisteredOperationName, 0 > sortedRegisteredOperations
This is a sorted container of registered operations for a deterministic and efficient getRegisteredOp...
DistinctAttributeAllocator distinctAttributeAllocator
A distinct attribute allocator that allocates every time since the address of the distinct attribute ...
MLIRContextImpl(bool threadingIsEnabled)
StorageUniquer attributeUniquer
DialectRegistry dialectsRegistry
bool threadingIsEnabled
Enable support for multi-threading within MLIR.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
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 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.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
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.
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 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.
DynamicDialect * getOrLoadDynamicDialect(StringRef dialectNamespace, function_ref< void(DynamicDialect *)> ctor)
Get (or create) a dynamic dialect for the given name.
StorageUniquer & getAttributeUniquer()
Returns the storage uniquer used for constructing attribute storage instances.
StorageUniquer & getAffineUniquer()
Returns the storage uniquer used for creating affine constructs.
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.
MLIRContextImpl & getImpl()
void exitMultiThreadedExecution()
bool shouldPrintOpOnDiagnostic()
Return true if we should attach the operation to diagnostics emitted via Operation::emit.
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
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printGenericOp(Operation *op, bool printOpName=true)=0
Print the entire operation with the default generic assembly form.
StringAttr name
The name of the operation.
TypeID typeID
The unique identifier of the derived Op class.
Impl(StringRef, Dialect *dialect, TypeID typeID, detail::InterfaceMap interfaceMap)
Dialect * dialect
The following fields are only populated when the operation is registered.
detail::InterfaceMap interfaceMap
A map of interfaces that were registered to this operation.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
OperationName(StringRef name, MLIRContext *context)
StringRef getDialectNamespace() const
Return the name of the dialect this operation is registered to.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
MLIRContext * getContext()
Return the context this operation is associated with.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
Definition Operation.h:926
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given 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
static T get(MLIRContext *ctx, Args &&...args)
Get an uniqued instance of an attribute T.
An allocator for distinct attribute storage instances.
DistinctAttrStorage * allocate(Attribute referencedAttr)
This class provides an efficient mapping between a given Interface type, and a particular implementat...
An action is a specific action that is to be taken by the compiler, that can be toggled and controlle...
Definition Action.h:38
AttrTypeReplacer.
llvm::unique_function< InFlightDiagnostic()> getDefaultDiagnosticEmitFn(MLIRContext *ctx)
Utility method to generate a callback that can be used to generate a diagnostic when checking the con...
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
static void getMaxDimAndSymbol(ArrayRef< AffineExprContainer > exprsList, int64_t &maxDim, int64_t &maxSym)
Calculates maximum dimension and symbol positions from the expressions in exprsLists and stores them ...
Definition AffineMap.h:697
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
function_ref< Dialect *(MLIRContext *)> DialectAllocatorFunctionRef
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) final
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
llvm::hash_code hashProperties(PropertyRef) final
void initProperties(OperationName opName, PropertyRef storage, PropertyRef init) final
OperationName::ParseAssemblyFn getParseAssemblyFn() final
LogicalResult verifyRegionInvariants(Operation *) final
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) final
Implementation for properties.
void getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) final
LogicalResult setPropertiesFromAttr(OperationName, PropertyRef, Attribute, function_ref< InFlightDiagnostic()> emitError) final
void populateDefaultAttrs(const OperationName &, NamedAttrList &) final
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final
LogicalResult verifyInvariants(Operation *) final
void populateDefaultProperties(OperationName opName, PropertyRef properties) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(PropertyRef, PropertyRef) final
void copyProperties(PropertyRef, PropertyRef) final
A binary operation appearing in an affine expression.
An integer constant appearing in affine expression.
A dimensional or symbolic identifier appearing in an affine expression.
StringRef value
The raw string value.
Dialect * referencedDialect
If the string value contains a dialect namespace prefix (e.g.
void initialize(MLIRContext *context)
Initialize the storage given an MLIRContext.
static T get(MLIRContext *ctx, Args &&...args)
Get an uniqued instance of a type T.