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
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 =
713 llvm::lower_bound(impl->sortedRegisteredOperations, dialectName,
714 [](const RegisteredOperationName &lhs, StringRef rhs) {
715 return lhs.getDialect().getNamespace() < rhs;
716 });
717
718 if (lowerBound == impl->sortedRegisteredOperations.end() ||
719 lowerBound->getDialect().getNamespace() != dialectName)
721
722 auto *upperBound = std::upper_bound(
723 lowerBound, impl->sortedRegisteredOperations.end(), dialectName,
724 [](StringRef lhs, const RegisteredOperationName &rhs) {
725 return lhs < rhs.getDialect().getNamespace();
726 });
727
728 size_t count = std::distance(lowerBound, upperBound);
729 return ArrayRef(&*lowerBound, count);
730}
731
733 return RegisteredOperationName::lookup(name, this).has_value();
734}
735
736void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
737 auto &impl = context->getImpl();
738 assert(impl.multiThreadedExecutionContext == 0 &&
739 "Registering a new type kind while in a multi-threaded execution "
740 "context");
741 auto *newInfo =
742 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
743 AbstractType(std::move(typeInfo));
744 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
745 llvm::report_fatal_error("Dialect Type already registered.");
746 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
747 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
748 " is already registered.");
749}
750
752 auto &impl = context->getImpl();
753 assert(impl.multiThreadedExecutionContext == 0 &&
754 "Registering a new attribute kind while in a multi-threaded execution "
755 "context");
756 auto *newInfo =
757 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
758 AbstractAttribute(std::move(attrInfo));
759 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
760 llvm::report_fatal_error("Dialect Attribute already registered.");
761 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
762 llvm::report_fatal_error("Dialect Attribute with name " +
763 newInfo->getName() + " is already registered.");
764}
765
766//===----------------------------------------------------------------------===//
767// AbstractAttribute
768//===----------------------------------------------------------------------===//
769
770/// Get the dialect that registered the attribute with the provided typeid.
771const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
772 MLIRContext *context) {
773 const AbstractAttribute *abstract = lookupMutable(typeID, context);
774 if (!abstract)
775 llvm::report_fatal_error("Trying to create an Attribute that was not "
776 "registered in this MLIRContext.");
777 return *abstract;
778}
779
780AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
781 MLIRContext *context) {
782 auto &impl = context->getImpl();
783 return impl.registeredAttributes.lookup(typeID);
784}
785
786std::optional<std::reference_wrapper<const AbstractAttribute>>
787AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
788 MLIRContextImpl &impl = context->getImpl();
789 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
790
791 if (!type)
792 return std::nullopt;
793 return {*type};
794}
795
796//===----------------------------------------------------------------------===//
797// OperationName
798//===----------------------------------------------------------------------===//
799
804
805OperationName::OperationName(StringRef name, MLIRContext *context) {
806 MLIRContextImpl &ctxImpl = context->getImpl();
807
808 // Check for an existing name in read-only mode.
809 bool isMultithreadingEnabled = context->isMultithreadingEnabled();
810 if (isMultithreadingEnabled) {
811 // Check the registered info map first. In the overwhelmingly common case,
812 // the entry will be in here and it also removes the need to acquire any
813 // locks.
814 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
815 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
816 impl = registeredIt->second.impl;
817 return;
818 }
819
820 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
821 auto it = ctxImpl.operations.find(name);
822 if (it != ctxImpl.operations.end()) {
823 impl = it->second.get();
824 return;
825 }
826 }
827
828 // Acquire a writer-lock so that we can safely create the new instance.
829 ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
830
831 auto it = ctxImpl.operations.try_emplace(name);
832 if (it.second) {
833 auto nameAttr = StringAttr::get(context, name);
834 it.first->second = std::make_unique<UnregisteredOpModel>(
835 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
837 }
838 impl = it.first->second.get();
839}
840
842 if (Dialect *dialect = getDialect())
843 return dialect->getNamespace();
844 return getStringRef().split('.').first;
845}
846
847LogicalResult
855
858 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
859}
863 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
864 p.printGenericOp(op);
865}
866LogicalResult
870LogicalResult
874
875std::optional<Attribute>
877 StringRef name) {
878 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
879 if (!dict)
880 return std::nullopt;
881 if (Attribute attr = dict.get(name))
882 return attr;
883 return std::nullopt;
884}
886 StringAttr name,
887 Attribute value) {
888 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
889 assert(dict);
890 NamedAttrList attrs(dict);
891 attrs.set(name, value);
892 *op->getPropertiesStorage().as<Attribute *>() =
893 attrs.getDictionary(op->getContext());
894}
906 OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
907 new (storage.as<Attribute *>()) Attribute();
908 if (init)
909 *storage.as<Attribute *>() = *init.as<Attribute *>();
910}
918 OperationName opName, OpaqueProperties properties, Attribute attr,
920 *properties.as<Attribute *>() = attr;
921 return success();
922}
935llvm::hash_code
937 return llvm::hash_combine(*prop.as<Attribute *>());
938}
939
940//===----------------------------------------------------------------------===//
941// RegisteredOperationName
942//===----------------------------------------------------------------------===//
943
944std::optional<RegisteredOperationName>
946 auto &impl = ctx->getImpl();
947 auto it = impl.registeredOperations.find(typeID);
948 if (it != impl.registeredOperations.end())
949 return it->second;
950 return std::nullopt;
951}
952
953std::optional<RegisteredOperationName>
955 auto &impl = ctx->getImpl();
956 auto it = impl.registeredOperationsByName.find(name);
957 if (it != impl.registeredOperationsByName.end())
958 return it->getValue();
959 return std::nullopt;
960}
961
963 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
964 ArrayRef<StringRef> attrNames) {
965 RegisteredOperationName::Impl *impl = ownedImpl.get();
966 MLIRContext *ctx = impl->getDialect()->getContext();
967 auto &ctxImpl = ctx->getImpl();
968 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
969 "registering a new operation kind while in a multi-threaded execution "
970 "context");
971
972 // Register the attribute names of this operation.
973 MutableArrayRef<StringAttr> cachedAttrNames;
974 if (!attrNames.empty()) {
975 cachedAttrNames = MutableArrayRef<StringAttr>(
976 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
977 attrNames.size()),
978 attrNames.size());
979 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
980 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
981 impl->attributeNames = cachedAttrNames;
982 }
983 StringRef name = impl->getName().strref();
984 // Insert the operation info if it doesn't exist yet.
985 ctxImpl.operations[name] = std::move(ownedImpl);
986
987 // Update the registered info for this operation.
988 auto emplaced = ctxImpl.registeredOperations.try_emplace(
989 impl->getTypeID(), RegisteredOperationName(impl));
990 assert(emplaced.second && "operation name registration must be successful");
991 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
993 (void)emplacedByName;
994 assert(emplacedByName.second &&
995 "operation name registration must be successful");
996
997 // Add emplaced operation name to the sorted operations container.
998 RegisteredOperationName &value = emplaced.first->second;
999 ctxImpl.sortedRegisteredOperations.insert(
1000 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1001 [](auto &lhs, auto &rhs) {
1002 return lhs.getIdentifier().strref() <
1003 rhs.getIdentifier().strref();
1004 }),
1005 value);
1006}
1007
1008//===----------------------------------------------------------------------===//
1009// AbstractType
1010//===----------------------------------------------------------------------===//
1011
1012const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1013 const AbstractType *type = lookupMutable(typeID, context);
1014 if (!type)
1015 llvm::report_fatal_error(
1016 "Trying to create a Type that was not registered in this MLIRContext.");
1017 return *type;
1018}
1019
1020AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1021 auto &impl = context->getImpl();
1022 return impl.registeredTypes.lookup(typeID);
1023}
1024
1025std::optional<std::reference_wrapper<const AbstractType>>
1026AbstractType::lookup(StringRef name, MLIRContext *context) {
1027 MLIRContextImpl &impl = context->getImpl();
1028 const AbstractType *type = impl.nameToType.lookup(name);
1029
1030 if (!type)
1031 return std::nullopt;
1032 return {*type};
1033}
1034
1035//===----------------------------------------------------------------------===//
1036// Type uniquing
1037//===----------------------------------------------------------------------===//
1038
1039/// Returns the storage uniquer used for constructing type storage instances.
1040/// This should not be used directly.
1042
1043BFloat16Type BFloat16Type::get(MLIRContext *context) {
1044 return context->getImpl().bf16Ty;
1045}
1046Float16Type Float16Type::get(MLIRContext *context) {
1047 return context->getImpl().f16Ty;
1048}
1049FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1050 return context->getImpl().tf32Ty;
1051}
1052Float32Type Float32Type::get(MLIRContext *context) {
1053 return context->getImpl().f32Ty;
1054}
1055Float64Type Float64Type::get(MLIRContext *context) {
1056 return context->getImpl().f64Ty;
1057}
1058Float80Type Float80Type::get(MLIRContext *context) {
1059 return context->getImpl().f80Ty;
1060}
1061Float128Type Float128Type::get(MLIRContext *context) {
1062 return context->getImpl().f128Ty;
1063}
1064
1065/// Get an instance of the IndexType.
1066IndexType IndexType::get(MLIRContext *context) {
1067 return context->getImpl().indexTy;
1068}
1069
1070/// Return an existing integer type instance if one is cached within the
1071/// context.
1072static IntegerType
1074 IntegerType::SignednessSemantics signedness,
1075 MLIRContext *context) {
1076 if (signedness != IntegerType::Signless)
1077 return IntegerType();
1078
1079 switch (width) {
1080 case 1:
1081 return context->getImpl().int1Ty;
1082 case 8:
1083 return context->getImpl().int8Ty;
1084 case 16:
1085 return context->getImpl().int16Ty;
1086 case 32:
1087 return context->getImpl().int32Ty;
1088 case 64:
1089 return context->getImpl().int64Ty;
1090 case 128:
1091 return context->getImpl().int128Ty;
1092 default:
1093 return IntegerType();
1094 }
1095}
1096
1097IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1098 IntegerType::SignednessSemantics signedness) {
1099 if (auto cached = getCachedIntegerType(width, signedness, context))
1100 return cached;
1101 return Base::get(context, width, signedness);
1102}
1103
1104IntegerType
1105IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1106 MLIRContext *context, unsigned width,
1107 SignednessSemantics signedness) {
1108 if (auto cached = getCachedIntegerType(width, signedness, context))
1109 return cached;
1110 return Base::getChecked(emitError, context, width, signedness);
1111}
1112
1113/// Get an instance of the NoneType.
1114NoneType NoneType::get(MLIRContext *context) {
1115 if (NoneType cachedInst = context->getImpl().noneType)
1116 return cachedInst;
1117 // Note: May happen when initializing the singleton attributes of the builtin
1118 // dialect.
1119 return Base::get(context);
1120}
1121
1122//===----------------------------------------------------------------------===//
1123// Attribute uniquing
1124//===----------------------------------------------------------------------===//
1125
1126/// Returns the storage uniquer used for constructing attribute storage
1127/// instances. This should not be used directly.
1129 return getImpl().attributeUniquer;
1130}
1131
1132/// Initialize the given attribute storage instance.
1133void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1134 MLIRContext *ctx,
1135 TypeID attrID) {
1137}
1138
1139BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1140 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1141}
1142
1143UnitAttr UnitAttr::get(MLIRContext *context) {
1144 return context->getImpl().unitAttr;
1145}
1146
1147UnknownLoc UnknownLoc::get(MLIRContext *context) {
1148 return context->getImpl().unknownLocAttr;
1149}
1150
1151DistinctAttrStorage *
1152detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1153 Attribute referencedAttr) {
1154 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1155}
1156
1157/// Return empty dictionary.
1158DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1159 return context->getImpl().emptyDictionaryAttr;
1160}
1161
1163 // Check for a dialect namespace prefix, if there isn't one we don't need to
1164 // do any additional initialization.
1165 auto dialectNamePair = value.split('.');
1166 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1167 return;
1168
1169 // If one exists, we check to see if this dialect is loaded. If it is, we set
1170 // the dialect now, if it isn't we record this storage for initialization
1171 // later if the dialect ever gets loaded.
1172 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1173 return;
1174
1175 MLIRContextImpl &impl = context->getImpl();
1176 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1177 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1178}
1179
1180/// Return an empty string.
1181StringAttr StringAttr::get(MLIRContext *context) {
1182 return context->getImpl().emptyStringAttr;
1183}
1184
1185//===----------------------------------------------------------------------===//
1186// AffineMap uniquing
1187//===----------------------------------------------------------------------===//
1188
1190 return getImpl().affineUniquer;
1191}
1192
1193AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1194 ArrayRef<AffineExpr> results,
1195 MLIRContext *context) {
1196 auto &impl = context->getImpl();
1197 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1198 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1199 symbolCount, results);
1200 return AffineMap(storage);
1201}
1202
1203/// Check whether the arguments passed to the AffineMap::get() are consistent.
1204/// This method checks whether the highest index of dimensional identifier
1205/// present in result expressions is less than `dimCount` and the highest index
1206/// of symbolic identifier present in result expressions is less than
1207/// `symbolCount`.
1208[[maybe_unused]] static bool
1209willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1210 ArrayRef<AffineExpr> results) {
1211 int64_t maxDimPosition = -1;
1212 int64_t maxSymbolPosition = -1;
1213 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1214 maxSymbolPosition);
1215 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1216 LDBG()
1217 << "maximum dimensional identifier position in result expression must "
1218 "be less than `dimCount` and maximum symbolic identifier position "
1219 "in result expression must be less than `symbolCount`";
1220 return false;
1221 }
1222 return true;
1223}
1224
1226 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1227}
1228
1229AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1230 MLIRContext *context) {
1231 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1232}
1233
1234AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1236 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1237 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1238}
1239
1240AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1241 ArrayRef<AffineExpr> results, MLIRContext *context) {
1242 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1243 return getImpl(dimCount, symbolCount, results, context);
1244}
1245
1246//===----------------------------------------------------------------------===//
1247// Integer Sets: these are allocated into the bump pointer, and are immutable.
1248// Unlike AffineMap's, these are uniqued only if they are small.
1249//===----------------------------------------------------------------------===//
1250
1251IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1252 ArrayRef<AffineExpr> constraints,
1253 ArrayRef<bool> eqFlags) {
1254 // The number of constraints can't be zero.
1255 assert(!constraints.empty());
1256 assert(constraints.size() == eqFlags.size());
1257
1258 auto &impl = constraints[0].getContext()->getImpl();
1259 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1260 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1261 return IntegerSet(storage);
1262}
1263
1264//===----------------------------------------------------------------------===//
1265// StorageUniquerSupport
1266//===----------------------------------------------------------------------===//
1267
1268/// Utility method to generate a callback that can be used to generate a
1269/// diagnostic when checking the construction invariants of a storage object.
1270/// This is defined out-of-line to avoid the need to include Location.h.
1271llvm::unique_function<InFlightDiagnostic()>
1273 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1274}
1275llvm::unique_function<InFlightDiagnostic()>
1277 return [=] { return emitError(loc); };
1278}
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:55
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:237
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
Definition Operation.h:929
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
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.