MLIR 22.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
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
383/// Dispatch the provided action to the handler if any, or just execute it.
384void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
385 const tracing::Action &action) {
386 assert(getImpl().actionHandler);
387 getImpl().actionHandler(actionFn, action);
388}
389
391
392//===----------------------------------------------------------------------===//
393// Diagnostic Handlers
394//===----------------------------------------------------------------------===//
395
396/// Returns the diagnostic engine for this context.
398
399//===----------------------------------------------------------------------===//
400// Remark Handlers
401//===----------------------------------------------------------------------===//
402
404 std::unique_ptr<remark::detail::RemarkEngine> engine) {
405 getImpl().remarkEngine = std::move(engine);
406}
407
411
412//===----------------------------------------------------------------------===//
413// Dialect and Operation Registration
414//===----------------------------------------------------------------------===//
415
417 if (registry.isSubsetOf(impl->dialectsRegistry))
418 return;
419
420 assert(impl->multiThreadedExecutionContext == 0 &&
421 "appending to the MLIRContext dialect registry while in a "
422 "multi-threaded execution context");
423 registry.appendTo(impl->dialectsRegistry);
424
425 // For the already loaded dialects, apply any possible extensions immediately.
426 registry.applyExtensions(this);
427}
428
430 return impl->dialectsRegistry;
431}
432
433/// Return information about all registered IR dialects.
434std::vector<Dialect *> MLIRContext::getLoadedDialects() {
435 std::vector<Dialect *> result;
436 result.reserve(impl->loadedDialects.size());
437 for (auto &dialect : impl->loadedDialects)
438 result.push_back(dialect.second.get());
439 llvm::array_pod_sort(result.begin(), result.end(),
440 [](Dialect *const *lhs, Dialect *const *rhs) -> int {
441 return (*lhs)->getNamespace() < (*rhs)->getNamespace();
442 });
443 return result;
444}
445std::vector<StringRef> MLIRContext::getAvailableDialects() {
446 std::vector<StringRef> result;
447 for (auto dialect : impl->dialectsRegistry.getDialectNames())
448 result.push_back(dialect);
449 return result;
450}
451
452/// Get a registered IR dialect with the given namespace. If none is found,
453/// then return nullptr.
455 // Dialects are sorted by name, so we can use binary search for lookup.
456 auto it = impl->loadedDialects.find(name);
457 return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
458}
459
461 Dialect *dialect = getLoadedDialect(name);
462 if (dialect)
463 return dialect;
465 impl->dialectsRegistry.getDialectAllocator(name);
466 return allocator ? allocator(this) : nullptr;
467}
468
469/// Get a dialect for the provided namespace and TypeID: abort the program if a
470/// dialect exist for this namespace with different TypeID. Returns a pointer to
471/// the dialect owned by the context.
472Dialect *
473MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
474 function_ref<std::unique_ptr<Dialect>()> ctor) {
475 auto &impl = getImpl();
476 // Get the correct insertion position sorted by namespace.
477 auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
478
479 if (dialectIt.second) {
480 LDBG() << "Load new dialect in Context " << dialectNamespace;
481#ifndef NDEBUG
482 if (impl.multiThreadedExecutionContext != 0)
483 llvm::report_fatal_error(
484 "Loading a dialect (" + dialectNamespace +
485 ") while in a multi-threaded execution context (maybe "
486 "the PassManager): this can indicate a "
487 "missing `dependentDialects` in a pass for example.");
488#endif // NDEBUG
489 // loadedDialects entry is initialized to nullptr, indicating that the
490 // dialect is currently being loaded. Re-lookup the address in
491 // loadedDialects because the table might have been rehashed by recursive
492 // dialect loading in ctor().
493 std::unique_ptr<Dialect> &dialectOwned =
494 impl.loadedDialects[dialectNamespace] = ctor();
495 Dialect *dialect = dialectOwned.get();
496 assert(dialect && "dialect ctor failed");
497
498 // Refresh all the identifiers dialect field, this catches cases where a
499 // dialect may be loaded after identifier prefixed with this dialect name
500 // were already created.
501 auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
502 if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
503 for (StringAttrStorage *storage : stringAttrsIt->second)
504 storage->referencedDialect = dialect;
505 impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
506 }
507
508 // Apply any extensions to this newly loaded dialect.
509 impl.dialectsRegistry.applyExtensions(dialect);
510 return dialect;
511 }
512
513#ifndef NDEBUG
514 if (dialectIt.first->second == nullptr)
515 llvm::report_fatal_error(
516 "Loading (and getting) a dialect (" + dialectNamespace +
517 ") while the same dialect is still loading: use loadDialect instead "
518 "of getOrLoadDialect.");
519#endif // NDEBUG
520
521 // Abort if dialect with namespace has already been registered.
522 std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
523 if (dialect->getTypeID() != dialectID)
524 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
525 "' has already been registered");
526
527 return dialect.get();
528}
529
530bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
531 auto it = getImpl().loadedDialects.find(dialectNamespace);
532 // nullptr indicates that the dialect is currently being loaded.
533 return it != getImpl().loadedDialects.end() && it->second == nullptr;
534}
535
537 StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
538 auto &impl = getImpl();
539 // Get the correct insertion position sorted by namespace.
540 auto dialectIt = impl.loadedDialects.find(dialectNamespace);
541
542 if (dialectIt != impl.loadedDialects.end()) {
543 if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
544 return dynDialect;
545 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
546 "' has already been registered");
547 }
548
549 LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
550#ifndef NDEBUG
551 if (impl.multiThreadedExecutionContext != 0)
552 llvm::report_fatal_error(
553 "Loading a dynamic dialect (" + dialectNamespace +
554 ") while in a multi-threaded execution context (maybe "
555 "the PassManager): this can indicate a "
556 "missing `dependentDialects` in a pass for example.");
557#endif
558
559 auto name = StringAttr::get(this, dialectNamespace);
560 auto *dialect = new DynamicDialect(name, this);
561 (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
562 ctor(dialect);
563 return std::unique_ptr<DynamicDialect>(dialect);
564 });
565 // This is the same result as `getOrLoadDialect` (if it didn't failed),
566 // since it has the same TypeID, and TypeIDs are unique.
567 return dialect;
568}
569
571 for (StringRef name : getAvailableDialects())
572 getOrLoadDialect(name);
573}
574
576 llvm::hash_code hash(0);
577 // Factor in number of loaded dialects, attributes, operations, types.
578 hash = llvm::hash_combine(hash, impl->loadedDialects.size());
579 hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
580 hash = llvm::hash_combine(hash, impl->registeredOperations.size());
581 hash = llvm::hash_combine(hash, impl->registeredTypes.size());
582 return hash;
583}
584
586 return impl->allowUnregisteredDialects;
587}
588
590 assert(impl->multiThreadedExecutionContext == 0 &&
591 "changing MLIRContext `allow-unregistered-dialects` configuration "
592 "while in a multi-threaded execution context");
593 impl->allowUnregisteredDialects = allowing;
594}
595
596/// Return true if multi-threading is enabled by the context.
598 return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
599}
600
601/// Set the flag specifying if multi-threading is disabled by the context.
603 // This API can be overridden by the global debugging flag
604 // --mlir-disable-threading
606 return;
607 assert(impl->multiThreadedExecutionContext == 0 &&
608 "changing MLIRContext `disable-threading` configuration while "
609 "in a multi-threaded execution context");
610
611 impl->threadingIsEnabled = !disable;
612
613 // Update the threading mode for each of the uniquers.
614 impl->affineUniquer.disableMultithreading(disable);
615 impl->attributeUniquer.disableMultithreading(disable);
616 impl->typeUniquer.disableMultithreading(disable);
617
618 // Destroy thread pool (stop all threads) if it is no longer needed, or create
619 // a new one if multithreading was re-enabled.
620 if (disable) {
621 // If the thread pool is owned, explicitly set it to nullptr to avoid
622 // keeping a dangling pointer around. If the thread pool is externally
623 // owned, we don't do anything.
624 if (impl->ownedThreadPool) {
625 assert(impl->threadPool);
626 impl->threadPool = nullptr;
627 impl->ownedThreadPool.reset();
628 }
629 } else if (!impl->threadPool) {
630 // The thread pool isn't externally provided.
631 assert(!impl->ownedThreadPool);
632 impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
633 impl->threadPool = impl->ownedThreadPool.get();
634 }
635}
636
637void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
638 assert(!isMultithreadingEnabled() &&
639 "expected multi-threading to be disabled when setting a ThreadPool");
640 impl->threadPool = &pool;
641 impl->ownedThreadPool.reset();
643}
644
647 assert(impl->threadPool &&
648 "multi-threading is enabled but threadpool not set");
649 return impl->threadPool->getMaxConcurrency();
650 }
651 // No multithreading or active thread pool. Return 1 thread.
652 return 1;
653}
654
655llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
656 assert(isMultithreadingEnabled() &&
657 "expected multi-threading to be enabled within the context");
658 assert(impl->threadPool &&
659 "multi-threading is enabled but threadpool not set");
660 return *impl->threadPool;
661}
662
664#ifndef NDEBUG
665 ++impl->multiThreadedExecutionContext;
666#endif
667}
669#ifndef NDEBUG
670 --impl->multiThreadedExecutionContext;
671#endif
672}
673
674/// Return true if we should attach the operation to diagnostics emitted via
675/// Operation::emit.
677 return impl->printOpOnDiagnostic;
678}
679
680/// Set the flag specifying if we should attach the operation to diagnostics
681/// emitted via Operation::emit.
683 assert(impl->multiThreadedExecutionContext == 0 &&
684 "changing MLIRContext `print-op-on-diagnostic` configuration while in "
685 "a multi-threaded execution context");
686 impl->printOpOnDiagnostic = enable;
687}
688
689/// Return true if we should attach the current stacktrace to diagnostics when
690/// emitted.
692 return impl->printStackTraceOnDiagnostic;
693}
694
695/// Set the flag specifying if we should attach the current stacktrace when
696/// emitting diagnostics.
698 assert(impl->multiThreadedExecutionContext == 0 &&
699 "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
700 "while in a multi-threaded execution context");
701 impl->printStackTraceOnDiagnostic = enable;
702}
703
704/// Return information about all registered operations.
706 return impl->sortedRegisteredOperations;
707}
708
709/// Return information for registered operations by dialect.
712 auto *lowerBound = llvm::lower_bound(
713 impl->sortedRegisteredOperations, dialectName, [](auto &lhs, auto &rhs) {
714 return lhs.getDialect().getNamespace().compare(rhs);
715 });
716
717 if (lowerBound == impl->sortedRegisteredOperations.end() ||
718 lowerBound->getDialect().getNamespace() != dialectName)
720
721 auto *upperBound =
722 std::upper_bound(lowerBound, impl->sortedRegisteredOperations.end(),
723 dialectName, [](auto &lhs, auto &rhs) {
724 return lhs.compare(rhs.getDialect().getNamespace());
725 });
726
727 size_t count = std::distance(lowerBound, upperBound);
728 return ArrayRef(&*lowerBound, count);
729}
730
732 return RegisteredOperationName::lookup(name, this).has_value();
733}
734
735void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
736 auto &impl = context->getImpl();
737 assert(impl.multiThreadedExecutionContext == 0 &&
738 "Registering a new type kind while in a multi-threaded execution "
739 "context");
740 auto *newInfo =
741 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
742 AbstractType(std::move(typeInfo));
743 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
744 llvm::report_fatal_error("Dialect Type already registered.");
745 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
746 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
747 " is already registered.");
748}
749
751 auto &impl = context->getImpl();
752 assert(impl.multiThreadedExecutionContext == 0 &&
753 "Registering a new attribute kind while in a multi-threaded execution "
754 "context");
755 auto *newInfo =
756 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
757 AbstractAttribute(std::move(attrInfo));
758 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
759 llvm::report_fatal_error("Dialect Attribute already registered.");
760 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
761 llvm::report_fatal_error("Dialect Attribute with name " +
762 newInfo->getName() + " is already registered.");
763}
764
765//===----------------------------------------------------------------------===//
766// AbstractAttribute
767//===----------------------------------------------------------------------===//
768
769/// Get the dialect that registered the attribute with the provided typeid.
770const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
771 MLIRContext *context) {
772 const AbstractAttribute *abstract = lookupMutable(typeID, context);
773 if (!abstract)
774 llvm::report_fatal_error("Trying to create an Attribute that was not "
775 "registered in this MLIRContext.");
776 return *abstract;
777}
778
779AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
780 MLIRContext *context) {
781 auto &impl = context->getImpl();
782 return impl.registeredAttributes.lookup(typeID);
783}
784
785std::optional<std::reference_wrapper<const AbstractAttribute>>
786AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
787 MLIRContextImpl &impl = context->getImpl();
788 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
789
790 if (!type)
791 return std::nullopt;
792 return {*type};
793}
794
795//===----------------------------------------------------------------------===//
796// OperationName
797//===----------------------------------------------------------------------===//
798
803
804OperationName::OperationName(StringRef name, MLIRContext *context) {
805 MLIRContextImpl &ctxImpl = context->getImpl();
806
807 // Check for an existing name in read-only mode.
808 bool isMultithreadingEnabled = context->isMultithreadingEnabled();
809 if (isMultithreadingEnabled) {
810 // Check the registered info map first. In the overwhelmingly common case,
811 // the entry will be in here and it also removes the need to acquire any
812 // locks.
813 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
814 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
815 impl = registeredIt->second.impl;
816 return;
817 }
818
819 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
820 auto it = ctxImpl.operations.find(name);
821 if (it != ctxImpl.operations.end()) {
822 impl = it->second.get();
823 return;
824 }
825 }
826
827 // Acquire a writer-lock so that we can safely create the new instance.
828 ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
829
830 auto it = ctxImpl.operations.try_emplace(name);
831 if (it.second) {
832 auto nameAttr = StringAttr::get(context, name);
833 it.first->second = std::make_unique<UnregisteredOpModel>(
834 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
836 }
837 impl = it.first->second.get();
838}
839
841 if (Dialect *dialect = getDialect())
842 return dialect->getNamespace();
843 return getStringRef().split('.').first;
844}
845
846LogicalResult
854
857 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
858}
862 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
863 p.printGenericOp(op);
864}
865LogicalResult
869LogicalResult
873
874std::optional<Attribute>
876 StringRef name) {
877 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
878 if (!dict)
879 return std::nullopt;
880 if (Attribute attr = dict.get(name))
881 return attr;
882 return std::nullopt;
883}
885 StringAttr name,
886 Attribute value) {
887 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
888 assert(dict);
889 NamedAttrList attrs(dict);
890 attrs.set(name, value);
891 *op->getPropertiesStorage().as<Attribute *>() =
892 attrs.getDictionary(op->getContext());
893}
905 OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
906 new (storage.as<Attribute *>()) Attribute();
907 if (init)
908 *storage.as<Attribute *>() = *init.as<Attribute *>();
909}
917 OperationName opName, OpaqueProperties properties, Attribute attr,
919 *properties.as<Attribute *>() = attr;
920 return success();
921}
934llvm::hash_code
936 return llvm::hash_combine(*prop.as<Attribute *>());
937}
938
939//===----------------------------------------------------------------------===//
940// RegisteredOperationName
941//===----------------------------------------------------------------------===//
942
943std::optional<RegisteredOperationName>
945 auto &impl = ctx->getImpl();
946 auto it = impl.registeredOperations.find(typeID);
947 if (it != impl.registeredOperations.end())
948 return it->second;
949 return std::nullopt;
950}
951
952std::optional<RegisteredOperationName>
954 auto &impl = ctx->getImpl();
955 auto it = impl.registeredOperationsByName.find(name);
956 if (it != impl.registeredOperationsByName.end())
957 return it->getValue();
958 return std::nullopt;
959}
960
962 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
963 ArrayRef<StringRef> attrNames) {
964 RegisteredOperationName::Impl *impl = ownedImpl.get();
965 MLIRContext *ctx = impl->getDialect()->getContext();
966 auto &ctxImpl = ctx->getImpl();
967 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
968 "registering a new operation kind while in a multi-threaded execution "
969 "context");
970
971 // Register the attribute names of this operation.
972 MutableArrayRef<StringAttr> cachedAttrNames;
973 if (!attrNames.empty()) {
974 cachedAttrNames = MutableArrayRef<StringAttr>(
975 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
976 attrNames.size()),
977 attrNames.size());
978 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
979 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
980 impl->attributeNames = cachedAttrNames;
981 }
982 StringRef name = impl->getName().strref();
983 // Insert the operation info if it doesn't exist yet.
984 ctxImpl.operations[name] = std::move(ownedImpl);
985
986 // Update the registered info for this operation.
987 auto emplaced = ctxImpl.registeredOperations.try_emplace(
988 impl->getTypeID(), RegisteredOperationName(impl));
989 assert(emplaced.second && "operation name registration must be successful");
990 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
992 (void)emplacedByName;
993 assert(emplacedByName.second &&
994 "operation name registration must be successful");
995
996 // Add emplaced operation name to the sorted operations container.
997 RegisteredOperationName &value = emplaced.first->second;
998 ctxImpl.sortedRegisteredOperations.insert(
999 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1000 [](auto &lhs, auto &rhs) {
1001 return lhs.getIdentifier().compare(
1002 rhs.getIdentifier());
1003 }),
1004 value);
1005}
1006
1007//===----------------------------------------------------------------------===//
1008// AbstractType
1009//===----------------------------------------------------------------------===//
1010
1011const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1012 const AbstractType *type = lookupMutable(typeID, context);
1013 if (!type)
1014 llvm::report_fatal_error(
1015 "Trying to create a Type that was not registered in this MLIRContext.");
1016 return *type;
1017}
1018
1019AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1020 auto &impl = context->getImpl();
1021 return impl.registeredTypes.lookup(typeID);
1022}
1023
1024std::optional<std::reference_wrapper<const AbstractType>>
1025AbstractType::lookup(StringRef name, MLIRContext *context) {
1026 MLIRContextImpl &impl = context->getImpl();
1027 const AbstractType *type = impl.nameToType.lookup(name);
1028
1029 if (!type)
1030 return std::nullopt;
1031 return {*type};
1032}
1033
1034//===----------------------------------------------------------------------===//
1035// Type uniquing
1036//===----------------------------------------------------------------------===//
1037
1038/// Returns the storage uniquer used for constructing type storage instances.
1039/// This should not be used directly.
1041
1042BFloat16Type BFloat16Type::get(MLIRContext *context) {
1043 return context->getImpl().bf16Ty;
1044}
1045Float16Type Float16Type::get(MLIRContext *context) {
1046 return context->getImpl().f16Ty;
1047}
1048FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1049 return context->getImpl().tf32Ty;
1050}
1051Float32Type Float32Type::get(MLIRContext *context) {
1052 return context->getImpl().f32Ty;
1053}
1054Float64Type Float64Type::get(MLIRContext *context) {
1055 return context->getImpl().f64Ty;
1056}
1057Float80Type Float80Type::get(MLIRContext *context) {
1058 return context->getImpl().f80Ty;
1059}
1060Float128Type Float128Type::get(MLIRContext *context) {
1061 return context->getImpl().f128Ty;
1062}
1063
1064/// Get an instance of the IndexType.
1065IndexType IndexType::get(MLIRContext *context) {
1066 return context->getImpl().indexTy;
1067}
1068
1069/// Return an existing integer type instance if one is cached within the
1070/// context.
1071static IntegerType
1073 IntegerType::SignednessSemantics signedness,
1074 MLIRContext *context) {
1075 if (signedness != IntegerType::Signless)
1076 return IntegerType();
1077
1078 switch (width) {
1079 case 1:
1080 return context->getImpl().int1Ty;
1081 case 8:
1082 return context->getImpl().int8Ty;
1083 case 16:
1084 return context->getImpl().int16Ty;
1085 case 32:
1086 return context->getImpl().int32Ty;
1087 case 64:
1088 return context->getImpl().int64Ty;
1089 case 128:
1090 return context->getImpl().int128Ty;
1091 default:
1092 return IntegerType();
1093 }
1094}
1095
1096IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1097 IntegerType::SignednessSemantics signedness) {
1098 if (auto cached = getCachedIntegerType(width, signedness, context))
1099 return cached;
1100 return Base::get(context, width, signedness);
1101}
1102
1103IntegerType
1104IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1105 MLIRContext *context, unsigned width,
1106 SignednessSemantics signedness) {
1107 if (auto cached = getCachedIntegerType(width, signedness, context))
1108 return cached;
1109 return Base::getChecked(emitError, context, width, signedness);
1110}
1111
1112/// Get an instance of the NoneType.
1113NoneType NoneType::get(MLIRContext *context) {
1114 if (NoneType cachedInst = context->getImpl().noneType)
1115 return cachedInst;
1116 // Note: May happen when initializing the singleton attributes of the builtin
1117 // dialect.
1118 return Base::get(context);
1119}
1120
1121//===----------------------------------------------------------------------===//
1122// Attribute uniquing
1123//===----------------------------------------------------------------------===//
1124
1125/// Returns the storage uniquer used for constructing attribute storage
1126/// instances. This should not be used directly.
1128 return getImpl().attributeUniquer;
1129}
1130
1131/// Initialize the given attribute storage instance.
1132void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1133 MLIRContext *ctx,
1134 TypeID attrID) {
1136}
1137
1138BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1139 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1140}
1141
1142UnitAttr UnitAttr::get(MLIRContext *context) {
1143 return context->getImpl().unitAttr;
1144}
1145
1146UnknownLoc UnknownLoc::get(MLIRContext *context) {
1147 return context->getImpl().unknownLocAttr;
1148}
1149
1150DistinctAttrStorage *
1151detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1152 Attribute referencedAttr) {
1153 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1154}
1155
1156/// Return empty dictionary.
1157DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1158 return context->getImpl().emptyDictionaryAttr;
1159}
1160
1162 // Check for a dialect namespace prefix, if there isn't one we don't need to
1163 // do any additional initialization.
1164 auto dialectNamePair = value.split('.');
1165 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1166 return;
1167
1168 // If one exists, we check to see if this dialect is loaded. If it is, we set
1169 // the dialect now, if it isn't we record this storage for initialization
1170 // later if the dialect ever gets loaded.
1171 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1172 return;
1173
1174 MLIRContextImpl &impl = context->getImpl();
1175 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1176 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1177}
1178
1179/// Return an empty string.
1180StringAttr StringAttr::get(MLIRContext *context) {
1181 return context->getImpl().emptyStringAttr;
1182}
1183
1184//===----------------------------------------------------------------------===//
1185// AffineMap uniquing
1186//===----------------------------------------------------------------------===//
1187
1189 return getImpl().affineUniquer;
1190}
1191
1192AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1193 ArrayRef<AffineExpr> results,
1194 MLIRContext *context) {
1195 auto &impl = context->getImpl();
1196 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1197 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1198 symbolCount, results);
1199 return AffineMap(storage);
1200}
1201
1202/// Check whether the arguments passed to the AffineMap::get() are consistent.
1203/// This method checks whether the highest index of dimensional identifier
1204/// present in result expressions is less than `dimCount` and the highest index
1205/// of symbolic identifier present in result expressions is less than
1206/// `symbolCount`.
1207[[maybe_unused]] static bool
1208willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1209 ArrayRef<AffineExpr> results) {
1210 int64_t maxDimPosition = -1;
1211 int64_t maxSymbolPosition = -1;
1212 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1213 maxSymbolPosition);
1214 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1215 LDBG()
1216 << "maximum dimensional identifier position in result expression must "
1217 "be less than `dimCount` and maximum symbolic identifier position "
1218 "in result expression must be less than `symbolCount`";
1219 return false;
1220 }
1221 return true;
1222}
1223
1225 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1226}
1227
1228AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1229 MLIRContext *context) {
1230 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1231}
1232
1233AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1235 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1236 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1237}
1238
1239AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1240 ArrayRef<AffineExpr> results, MLIRContext *context) {
1241 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1242 return getImpl(dimCount, symbolCount, results, context);
1243}
1244
1245//===----------------------------------------------------------------------===//
1246// Integer Sets: these are allocated into the bump pointer, and are immutable.
1247// Unlike AffineMap's, these are uniqued only if they are small.
1248//===----------------------------------------------------------------------===//
1249
1250IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1251 ArrayRef<AffineExpr> constraints,
1252 ArrayRef<bool> eqFlags) {
1253 // The number of constraints can't be zero.
1254 assert(!constraints.empty());
1255 assert(constraints.size() == eqFlags.size());
1256
1257 auto &impl = constraints[0].getContext()->getImpl();
1258 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1259 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1260 return IntegerSet(storage);
1261}
1262
1263//===----------------------------------------------------------------------===//
1264// StorageUniquerSupport
1265//===----------------------------------------------------------------------===//
1266
1267/// Utility method to generate a callback that can be used to generate a
1268/// diagnostic when checking the construction invariants of a storage object.
1269/// This is defined out-of-line to avoid the need to include Location.h.
1270llvm::unique_function<InFlightDiagnostic()>
1272 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1273}
1274llvm::unique_function<InFlightDiagnostic()>
1276 return [=] { return emitError(loc); };
1277}
return success()
static llvm::ManagedStatic< DebugCounterOptions > clOptions
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:320
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition Dialect.cpp:246
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.
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.
Simple wrapper around a void* in order to express generically how to pass in op properties through AP...
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:88
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:216
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
Definition Operation.h:900
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:126
function_ref< Dialect *(MLIRContext *)> DialectAllocatorFunctionRef
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) final
llvm::hash_code hashProperties(OpaqueProperties) final
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
void deleteProperties(OpaqueProperties) final
LogicalResult setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic()> emitError) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
void populateDefaultProperties(OperationName opName, OpaqueProperties properties) 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
void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init) final
void populateDefaultAttrs(const OperationName &, NamedAttrList &) final
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final
LogicalResult verifyInvariants(Operation *) final
void copyProperties(OpaqueProperties, OpaqueProperties) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(OpaqueProperties, OpaqueProperties) 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.