MLIR 24.0.0git
MLIRContext.cpp
Go to the documentation of this file.
1//===- MLIRContext.cpp - MLIR Type Classes --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "AffineExprDetail.h"
11#include "AffineMapDetail.h"
12#include "AttributeDetail.h"
13#include "IntegerSetDetail.h"
14#include "TypeDetail.h"
15#include "mlir/IR/Action.h"
16#include "mlir/IR/AffineExpr.h"
17#include "mlir/IR/AffineMap.h"
18#include "mlir/IR/Attributes.h"
21#include "mlir/IR/Diagnostics.h"
22#include "mlir/IR/Dialect.h"
24#include "mlir/IR/IntegerSet.h"
25#include "mlir/IR/Location.h"
28#include "mlir/IR/Remarks.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/Twine.h"
31#include "llvm/Support/Allocator.h"
32#include "llvm/Support/CommandLine.h"
33#include "llvm/Support/Compiler.h"
34#include "llvm/Support/DebugLog.h"
35#include "llvm/Support/ManagedStatic.h"
36#include "llvm/Support/Mutex.h"
37#include "llvm/Support/RWMutex.h"
38#include "llvm/Support/ThreadPool.h"
39#include "llvm/Support/raw_ostream.h"
40#include <memory>
41#include <optional>
42
43#define DEBUG_TYPE "mlircontext"
44
45using namespace mlir;
46using namespace mlir::detail;
47
48//===----------------------------------------------------------------------===//
49// MLIRContext CommandLine Options
50//===----------------------------------------------------------------------===//
51
52namespace {
53/// This struct contains command line options that can be used to initialize
54/// various bits of an MLIRContext. This uses a struct wrapper to avoid the need
55/// for global command line options.
56struct MLIRContextOptions {
57 llvm::cl::opt<bool> disableThreading{
58 "mlir-disable-threading",
59 llvm::cl::desc("Disable multi-threading within MLIR, overrides any "
60 "further call to MLIRContext::enableMultiThreading()")};
61
62 llvm::cl::opt<bool> printOpOnDiagnostic{
63 "mlir-print-op-on-diagnostic",
64 llvm::cl::desc("When a diagnostic is emitted on an operation, also print "
65 "the operation as an attached note"),
66 llvm::cl::init(true)};
67
68 llvm::cl::opt<bool> printStackTraceOnDiagnostic{
69 "mlir-print-stacktrace-on-diagnostic",
70 llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "
71 "as an attached note")};
72};
73} // namespace
74
75static llvm::ManagedStatic<MLIRContextOptions> clOptions;
76
78#if LLVM_ENABLE_THREADS != 0
79 return clOptions.isConstructed() && clOptions->disableThreading;
80#else
81 return true;
82#endif
83}
84
85/// Register a set of useful command-line options that can be used to configure
86/// various flags within the MLIRContext. These flags are used when constructing
87/// an MLIR context for initialization.
89 // Make sure that the options struct has been initialized.
90 *clOptions;
91}
92
93//===----------------------------------------------------------------------===//
94// Locking Utilities
95//===----------------------------------------------------------------------===//
96
97namespace {
98/// Utility writer lock that takes a runtime flag that specifies if we really
99/// need to lock.
100struct ScopedWriterLock {
101 ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)
102 : mutex(shouldLock ? &mutexParam : nullptr) {
103 if (mutex)
104 mutex->lock();
105 }
106 ~ScopedWriterLock() {
107 if (mutex)
108 mutex->unlock();
109 }
110 llvm::sys::SmartRWMutex<true> *mutex;
111};
112} // namespace
113
114//===----------------------------------------------------------------------===//
115// MLIRContextImpl
116//===----------------------------------------------------------------------===//
117
118namespace mlir {
119/// This is the implementation of the MLIRContext class, using the pImpl idiom.
120/// This class is completely private to this file, so everything is public.
122public:
123 //===--------------------------------------------------------------------===//
124 // Remark
125 //===--------------------------------------------------------------------===//
126 std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;
127
128 //===--------------------------------------------------------------------===//
129 // Debugging
130 //===--------------------------------------------------------------------===//
131
132 /// An action handler for handling actions that are dispatched through this
133 /// context.
134 std::function<void(function_ref<void()>, const tracing::Action &)>
136
137 //===--------------------------------------------------------------------===//
138 // Diagnostics
139 //===--------------------------------------------------------------------===//
141
142 //===--------------------------------------------------------------------===//
143 // Options
144 //===--------------------------------------------------------------------===//
145
146 /// In most cases, creating operation in unregistered dialect is not desired
147 /// and indicate a misconfiguration of the compiler. This option enables to
148 /// detect such use cases
150
151 /// Enable support for multi-threading within MLIR.
153
154 /// Track if we are currently executing in a threaded execution environment
155 /// (like the pass-manager): this is only a debugging feature to help reducing
156 /// the chances of data races one some context APIs.
157#ifndef NDEBUG
158 std::atomic<int> multiThreadedExecutionContext{0};
159#endif
160
161 /// If the operation should be attached to diagnostics printed via the
162 /// Operation::emit methods.
164
165 /// If the current stack trace should be attached when emitting diagnostics.
167
168 //===--------------------------------------------------------------------===//
169 // Other
170 //===--------------------------------------------------------------------===//
171
172 /// This points to the ThreadPool used when processing MLIR tasks in parallel.
173 /// It can't be nullptr when multi-threading is enabled. Otherwise if
174 /// multi-threading is disabled, and the threadpool wasn't externally provided
175 /// using `setThreadPool`, this will be nullptr.
176 llvm::ThreadPoolInterface *threadPool = nullptr;
177
178 /// In case where the thread pool is owned by the context, this ensures
179 /// destruction with the context.
180 std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
181
182 /// An allocator used for AbstractAttribute and AbstractType objects.
183 llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
184
185 /// This is a mapping from operation name to the operation info describing it.
186 llvm::StringMap<std::unique_ptr<OperationName::Impl>> operations;
187
188 /// A vector of operation info specifically for registered operations.
190 llvm::StringMap<RegisteredOperationName> registeredOperationsByName;
191
192 /// This is a sorted container of registered operations for a deterministic
193 /// and efficient `getRegisteredOperations` implementation.
195
196 /// This is a list of dialects that are created referring to this context.
197 /// The MLIRContext owns the objects. These need to be declared after the
198 /// registered operations to ensure correct destruction order.
201
202 /// A mutex used when accessing operation information.
203 llvm::sys::SmartRWMutex<true> operationInfoMutex;
204
205 //===--------------------------------------------------------------------===//
206 // Affine uniquing
207 //===--------------------------------------------------------------------===//
208
209 // Affine expression, map and integer set uniquing.
211
212 //===--------------------------------------------------------------------===//
213 // Type uniquing
214 //===--------------------------------------------------------------------===//
215
218
219 /// This is a mapping from type name to the abstract type describing it.
220 /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.
221 /// As this map needs to be populated before `StringAttr` is loaded, we
222 /// cannot use `StringAttr` as the key. The context does not take ownership
223 /// of the key, so the `StringRef` must outlive the context.
225
226 /// Cached Type Instances.
227 BFloat16Type bf16Ty;
228 Float16Type f16Ty;
229 FloatTF32Type tf32Ty;
230 Float32Type f32Ty;
231 Float64Type f64Ty;
232 Float80Type f80Ty;
233 Float128Type f128Ty;
234 IndexType indexTy;
236 NoneType noneType;
237
238 //===--------------------------------------------------------------------===//
239 // Attribute uniquing
240 //===--------------------------------------------------------------------===//
241
244
245 /// This is a mapping from attribute name to the abstract attribute describing
246 /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a
247 /// name.
248 /// As this map needs to be populated before `StringAttr` is loaded, we
249 /// cannot use `StringAttr` as the key. The context does not take ownership
250 /// of the key, so the `StringRef` must outlive the context.
252
253 /// Cached Attribute Instances.
255 UnitAttr unitAttr;
256 UnknownLoc unknownLocAttr;
257 DictionaryAttr emptyDictionaryAttr;
258 StringAttr emptyStringAttr;
259
260 /// Map of string attributes that may reference a dialect, that are awaiting
261 /// that dialect to be loaded.
265
266 /// A distinct attribute allocator that allocates every time since the
267 /// address of the distinct attribute storage serves as unique identifier. The
268 /// allocator is thread safe and frees the allocated storage after its
269 /// destruction.
271
272 /// Bundled state dynamically allocated when in a transient scope.
274 /// Set of operation names in `operations` at snapshot time.
276
277 /// Number of entries in `dialectReferencingStrAttrs` per dialect at
278 /// snapshot time.
280 };
281 std::unique_ptr<TransientScopeState> transientState;
282
283public:
286 if (threadingIsEnabled) {
287 ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
289 }
290 }
292 for (auto typeMapping : registeredTypes)
293 typeMapping.second->~AbstractType();
294 for (auto attrMapping : registeredAttributes)
295 attrMapping.second->~AbstractAttribute();
296 }
297};
298} // namespace mlir
299
302
304 : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
306 // Initialize values based on the command line flags if they were provided.
307 if (clOptions.isConstructed()) {
308 printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
309 printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
310 }
311
312 // Pre-populate the registry.
313 registry.appendTo(impl->dialectsRegistry);
314
315 // Ensure the builtin dialect is always pre-loaded.
317
318 // Initialize several common attributes and types to avoid the need to lock
319 // the context when accessing them.
320
321 //// Types.
322 /// Floating-point Types.
323 impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
324 impl->f16Ty = TypeUniquer::get<Float16Type>(this);
326 impl->f32Ty = TypeUniquer::get<Float32Type>(this);
327 impl->f64Ty = TypeUniquer::get<Float64Type>(this);
328 impl->f80Ty = TypeUniquer::get<Float80Type>(this);
329 impl->f128Ty = TypeUniquer::get<Float128Type>(this);
330 /// Index Type.
331 impl->indexTy = TypeUniquer::get<IndexType>(this);
332 /// Integer Types.
333 impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
334 impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
335 impl->int16Ty =
336 TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
337 impl->int32Ty =
338 TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
339 impl->int64Ty =
340 TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
341 impl->int128Ty =
342 TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
343 /// None Type.
344 impl->noneType = TypeUniquer::get<NoneType>(this);
345
346 //// Attributes.
347 //// Note: These must be registered after the types as they may generate one
348 //// of the above types internally.
349 /// Unknown Location Attribute.
350 impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
351 /// Bool Attributes.
352 impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
353 impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
354 /// Unit Attribute.
355 impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
356 /// The empty dictionary attribute.
357 impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
358 /// The empty string attribute.
359 impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
360
361 // Register the affine storage objects with the uniquer.
362 impl->affineUniquer
363 .registerParametricStorageType<AffineBinaryOpExprStorage>();
364 impl->affineUniquer
365 .registerParametricStorageType<AffineConstantExprStorage>();
366 impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
367 impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
368 impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
369}
370
372 // finalize remark engine before destroying anything else.
373 impl->remarkEngine.reset();
374}
375
376/// Copy the specified array of elements into memory managed by the provided
377/// bump pointer allocator. This assumes the elements are all PODs.
378template <typename T>
379static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
380 ArrayRef<T> elements) {
381 auto result = allocator.Allocate<T>(elements.size());
382 llvm::uninitialized_copy(elements, result);
383 return ArrayRef<T>(result, elements.size());
384}
385
386//===----------------------------------------------------------------------===//
387// Action Handling
388//===----------------------------------------------------------------------===//
389
391 getImpl().actionHandler = std::move(handler);
392}
393
397
401
402/// Dispatch the provided action to the handler if any, or just execute it.
403void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
404 const tracing::Action &action) {
405 assert(getImpl().actionHandler);
406 getImpl().actionHandler(actionFn, action);
407}
408
410
411//===----------------------------------------------------------------------===//
412// Diagnostic Handlers
413//===----------------------------------------------------------------------===//
414
415/// Returns the diagnostic engine for this context.
417
418//===----------------------------------------------------------------------===//
419// Remark Handlers
420//===----------------------------------------------------------------------===//
421
423 std::unique_ptr<remark::detail::RemarkEngine> engine) {
424 getImpl().remarkEngine = std::move(engine);
425}
426
430
431//===----------------------------------------------------------------------===//
432// Dialect and Operation Registration
433//===----------------------------------------------------------------------===//
434
436 if (registry.isSubsetOf(impl->dialectsRegistry))
437 return;
438
439 assert(impl->multiThreadedExecutionContext == 0 &&
440 "appending to the MLIRContext dialect registry while in a "
441 "multi-threaded execution context");
442 assert(!impl->transientState &&
443 "cannot append to dialect registry while in a transient scope");
444
445 registry.appendTo(impl->dialectsRegistry);
446
447 // For the already loaded dialects, apply any possible extensions immediately.
448 registry.applyExtensions(this);
449}
450
452 return impl->dialectsRegistry;
453}
454
455/// Return information about all registered IR dialects.
456std::vector<Dialect *> MLIRContext::getLoadedDialects() {
457 std::vector<Dialect *> result;
458 result.reserve(impl->loadedDialects.size());
459 for (auto &dialect : impl->loadedDialects)
460 result.push_back(dialect.second.get());
461 llvm::array_pod_sort(result.begin(), result.end(),
462 [](Dialect *const *lhs, Dialect *const *rhs) -> int {
463 return (*lhs)->getNamespace() < (*rhs)->getNamespace();
464 });
465 return result;
466}
467std::vector<StringRef> MLIRContext::getAvailableDialects() {
468 std::vector<StringRef> result;
469 for (auto dialect : impl->dialectsRegistry.getRegisteredDialectNames())
470 result.push_back(dialect);
471 return result;
472}
473
474/// Get a registered IR dialect with the given namespace. If none is found,
475/// then return nullptr.
477 // Dialects are sorted by name, so we can use binary search for lookup.
478 auto it = impl->loadedDialects.find(name);
479 return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
480}
481
483 Dialect *dialect = getLoadedDialect(name);
484 if (dialect)
485 return dialect;
487 impl->dialectsRegistry.getDialectAllocator(name);
488 return allocator ? allocator(this) : nullptr;
489}
490
491/// Get a dialect for the provided namespace and TypeID: abort the program if a
492/// dialect exist for this namespace with different TypeID. Returns a pointer to
493/// the dialect owned by the context.
494Dialect *
495MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
496 function_ref<std::unique_ptr<Dialect>()> ctor) {
497 auto &impl = getImpl();
498 // Get the correct insertion position sorted by namespace.
499 auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
500
501 if (dialectIt.second) {
502 LDBG() << "Load new dialect in Context " << dialectNamespace;
503 assert(!impl.transientState &&
504 "cannot load new dialects while in a transient scope");
505#ifndef NDEBUG
506 if (impl.multiThreadedExecutionContext != 0)
507 llvm::report_fatal_error(
508 "Loading a dialect (" + dialectNamespace +
509 ") while in a multi-threaded execution context (maybe "
510 "the PassManager): this can indicate a "
511 "missing `dependentDialects` in a pass for example.");
512#endif // NDEBUG
513 // loadedDialects entry is initialized to nullptr, indicating that the
514 // dialect is currently being loaded. Re-lookup the address in
515 // loadedDialects because the table might have been rehashed by recursive
516 // dialect loading in ctor().
517 std::unique_ptr<Dialect> &dialectOwned =
518 impl.loadedDialects[dialectNamespace] = ctor();
519 Dialect *dialect = dialectOwned.get();
520 assert(dialect && "dialect ctor failed");
521
522 // Refresh all the identifiers dialect field, this catches cases where a
523 // dialect may be loaded after identifier prefixed with this dialect name
524 // were already created.
525 auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
526 if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
527 for (StringAttrStorage *storage : stringAttrsIt->second)
528 storage->referencedDialect = dialect;
529 impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
530 }
531
532 // Apply any extensions to this newly loaded dialect.
533 impl.dialectsRegistry.applyExtensions(dialect);
534 return dialect;
535 }
536
537#ifndef NDEBUG
538 if (dialectIt.first->second == nullptr)
539 llvm::report_fatal_error(
540 "Loading (and getting) a dialect (" + dialectNamespace +
541 ") while the same dialect is still loading: use loadDialect instead "
542 "of getOrLoadDialect.");
543#endif // NDEBUG
544
545 // Abort if dialect with namespace has already been registered.
546 std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
547 if (dialect->getTypeID() != dialectID)
548 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
549 "' has already been registered");
550
551 return dialect.get();
552}
553
554bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
555 auto it = getImpl().loadedDialects.find(dialectNamespace);
556 // nullptr indicates that the dialect is currently being loaded.
557 return it != getImpl().loadedDialects.end() && it->second == nullptr;
558}
559
561 StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
562 auto &impl = getImpl();
563 // Get the correct insertion position sorted by namespace.
564 auto dialectIt = impl.loadedDialects.find(dialectNamespace);
565
566 if (dialectIt != impl.loadedDialects.end()) {
567 if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
568 return dynDialect;
569 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
570 "' has already been registered");
571 }
572
573 LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
574#ifndef NDEBUG
575 if (impl.multiThreadedExecutionContext != 0)
576 llvm::report_fatal_error(
577 "Loading a dynamic dialect (" + dialectNamespace +
578 ") while in a multi-threaded execution context (maybe "
579 "the PassManager): this can indicate a "
580 "missing `dependentDialects` in a pass for example.");
581#endif
582
583 auto name = StringAttr::get(this, dialectNamespace);
584 auto *dialect = new DynamicDialect(name, this);
585 (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
586 ctor(dialect);
587 return std::unique_ptr<DynamicDialect>(dialect);
588 });
589 // This is the same result as `getOrLoadDialect` (if it didn't failed),
590 // since it has the same TypeID, and TypeIDs are unique.
591 return dialect;
592}
593
595 for (StringRef name : getAvailableDialects())
596 getOrLoadDialect(name);
597}
598
600 llvm::hash_code hash(0);
601 // Factor in number of loaded dialects, attributes, operations, types.
602 hash = llvm::hash_combine(hash, impl->loadedDialects.size());
603 hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
604 hash = llvm::hash_combine(hash, impl->registeredOperations.size());
605 hash = llvm::hash_combine(hash, impl->registeredTypes.size());
606 return hash;
607}
608
610 return impl->allowUnregisteredDialects;
611}
612
614 assert(impl->multiThreadedExecutionContext == 0 &&
615 "changing MLIRContext `allow-unregistered-dialects` configuration "
616 "while in a multi-threaded execution context");
617 impl->allowUnregisteredDialects = allowing;
618}
619
620/// Return true if multi-threading is enabled by the context.
622 return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
623}
624
625/// Set the flag specifying if multi-threading is disabled by the context.
627 // This API can be overridden by the global debugging flag
628 // --mlir-disable-threading
630 return;
631 assert(impl->multiThreadedExecutionContext == 0 &&
632 "changing MLIRContext `disable-threading` configuration while "
633 "in a multi-threaded execution context");
634
635 impl->threadingIsEnabled = !disable;
636
637 // Update the threading mode for each of the uniquers.
638 impl->affineUniquer.disableMultithreading(disable);
639 impl->attributeUniquer.disableMultithreading(disable);
640 impl->typeUniquer.disableMultithreading(disable);
641
642 // Destroy thread pool (stop all threads) if it is no longer needed, or create
643 // a new one if multithreading was re-enabled.
644 if (disable) {
645 // If the thread pool is owned, explicitly set it to nullptr to avoid
646 // keeping a dangling pointer around. If the thread pool is externally
647 // owned, we don't do anything.
648 if (impl->ownedThreadPool) {
649 assert(impl->threadPool);
650 impl->threadPool = nullptr;
651 impl->ownedThreadPool.reset();
652 }
653 } else if (!impl->threadPool) {
654 // The thread pool isn't externally provided.
655 assert(!impl->ownedThreadPool);
656 impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
657 impl->threadPool = impl->ownedThreadPool.get();
658 }
659}
660
661void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
662 assert(!isMultithreadingEnabled() &&
663 "expected multi-threading to be disabled when setting a ThreadPool");
664 impl->threadPool = &pool;
665 impl->ownedThreadPool.reset();
667}
668
671 assert(impl->threadPool &&
672 "multi-threading is enabled but threadpool not set");
673 return impl->threadPool->getMaxConcurrency();
674 }
675 // No multithreading or active thread pool. Return 1 thread.
676 return 1;
677}
678
679llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
680 assert(isMultithreadingEnabled() &&
681 "expected multi-threading to be enabled within the context");
682 assert(impl->threadPool &&
683 "multi-threading is enabled but threadpool not set");
684 return *impl->threadPool;
685}
686
688#ifndef NDEBUG
689 ++impl->multiThreadedExecutionContext;
690#endif
691}
693#ifndef NDEBUG
694 --impl->multiThreadedExecutionContext;
695#endif
696}
697
699 MLIRContextImpl &ctxImpl = getImpl();
700 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
701 "Beginning a transient scope while in a multi-threaded execution "
702 "context");
703 assert(!ctxImpl.transientState && "context is already in a transient scope");
704 ctxImpl.transientState =
705 std::make_unique<MLIRContextImpl::TransientScopeState>();
706
707 // Begin transient scope in the uniquers.
712
713 // Record base operations in operations map.
714 {
715 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
716 for (const auto &entry : ctxImpl.operations)
717 ctxImpl.transientState->baseOperations.insert(entry.first());
718 }
719
720 // Record dialect referencing string attribute counts.
721 {
722 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
723 for (const auto &entry : ctxImpl.dialectReferencingStrAttrs)
724 ctxImpl.transientState->baseDialectReferencingStrAttrCounts[entry.first] =
725 entry.second.size();
726 }
727}
728
730 MLIRContextImpl &ctxImpl = getImpl();
731 assert(ctxImpl.transientState && "context is not in a transient scope");
732 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
733 "Ending a transient scope while in a multi-threaded execution "
734 "context");
735 if (!ctxImpl.transientState)
736 return;
737
738 // Prune unregistered operations created during transient scope before
739 // destroying the attribute uniquer that holds their string attribute names.
740 {
741 llvm::sys::SmartScopedWriter<true> contextLock(ctxImpl.operationInfoMutex);
742 SmallVector<StringRef> opsToErase;
743 for (const auto &entry : ctxImpl.operations) {
744 if (!entry.second->isRegistered() &&
745 !ctxImpl.transientState->baseOperations.contains(entry.first()))
746 opsToErase.push_back(entry.first());
747 }
748 for (StringRef op : opsToErase)
749 ctxImpl.operations.erase(op);
750 }
751
752 // Restore dialect referencing string attributes before destroying the
753 // attribute uniquer that holds the underlying StringAttrStorage pointers.
754 // Note: Transient entries are always appended to the end of each dialect's
755 // vector, so truncating via resize() to the base count safely removes only
756 // transient entries while preserving base entries.
757 {
758 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
759 SmallVector<StringRef> dialectsToErase;
760 for (auto &entry : ctxImpl.dialectReferencingStrAttrs) {
761 auto countIt =
762 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.find(
763 entry.first);
764 if (countIt ==
765 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.end()) {
766 dialectsToErase.push_back(entry.first);
767 } else {
768 entry.second.resize(countIt->second);
769 }
770 }
771 for (StringRef dialect : dialectsToErase)
772 ctxImpl.dialectReferencingStrAttrs.erase(dialect);
773 }
774
775 // End transient scope in the uniquers now that all referencing structures
776 // are cleaned up.
781
782 ctxImpl.transientState.reset();
783}
784
786 return getImpl().transientState != nullptr;
787}
788
789/// Return true if we should attach the operation to diagnostics emitted via
790/// Operation::emit.
792 return impl->printOpOnDiagnostic;
793}
794
795/// Set the flag specifying if we should attach the operation to diagnostics
796/// emitted via Operation::emit.
798 assert(impl->multiThreadedExecutionContext == 0 &&
799 "changing MLIRContext `print-op-on-diagnostic` configuration while in "
800 "a multi-threaded execution context");
801 impl->printOpOnDiagnostic = enable;
802}
803
804/// Return true if we should attach the current stacktrace to diagnostics when
805/// emitted.
807 return impl->printStackTraceOnDiagnostic;
808}
809
810/// Set the flag specifying if we should attach the current stacktrace when
811/// emitting diagnostics.
813 assert(impl->multiThreadedExecutionContext == 0 &&
814 "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
815 "while in a multi-threaded execution context");
816 impl->printStackTraceOnDiagnostic = enable;
817}
818
819/// Return information about all registered operations.
821 return impl->sortedRegisteredOperations;
822}
823
824/// Return information for registered operations by dialect.
827 auto *lowerBound =
828 llvm::lower_bound(impl->sortedRegisteredOperations, dialectName,
829 [](const RegisteredOperationName &lhs, StringRef rhs) {
830 return lhs.getDialect().getNamespace() < rhs;
831 });
832
833 if (lowerBound == impl->sortedRegisteredOperations.end() ||
834 lowerBound->getDialect().getNamespace() != dialectName)
836
837 auto *upperBound = std::upper_bound(
838 lowerBound, impl->sortedRegisteredOperations.end(), dialectName,
839 [](StringRef lhs, const RegisteredOperationName &rhs) {
840 return lhs < rhs.getDialect().getNamespace();
841 });
842
843 size_t count = std::distance(lowerBound, upperBound);
844 return ArrayRef(&*lowerBound, count);
845}
846
848 return RegisteredOperationName::lookup(name, this).has_value();
849}
850
851void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
852 auto &impl = context->getImpl();
853 assert(impl.multiThreadedExecutionContext == 0 &&
854 "Registering a new type kind while in a multi-threaded execution "
855 "context");
856 auto *newInfo =
857 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
858 AbstractType(std::move(typeInfo));
859 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
860 llvm::report_fatal_error("Dialect Type already registered.");
861 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
862 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
863 " is already registered.");
864}
865
867 auto &impl = context->getImpl();
868 assert(impl.multiThreadedExecutionContext == 0 &&
869 "Registering a new attribute kind while in a multi-threaded execution "
870 "context");
871 auto *newInfo =
872 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
873 AbstractAttribute(std::move(attrInfo));
874 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
875 llvm::report_fatal_error("Dialect Attribute already registered.");
876 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
877 llvm::report_fatal_error("Dialect Attribute with name " +
878 newInfo->getName() + " is already registered.");
879}
880
881//===----------------------------------------------------------------------===//
882// AbstractAttribute
883//===----------------------------------------------------------------------===//
884
885/// Get the dialect that registered the attribute with the provided typeid.
886const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
887 MLIRContext *context) {
888 const AbstractAttribute *abstract = lookupMutable(typeID, context);
889 if (!abstract)
890 llvm::report_fatal_error("Trying to create an Attribute that was not "
891 "registered in this MLIRContext.");
892 return *abstract;
893}
894
895AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
896 MLIRContext *context) {
897 auto &impl = context->getImpl();
898 return impl.registeredAttributes.lookup(typeID);
899}
900
901std::optional<std::reference_wrapper<const AbstractAttribute>>
902AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
903 MLIRContextImpl &impl = context->getImpl();
904 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
905
906 if (!type)
907 return std::nullopt;
908 return {*type};
909}
910
911//===----------------------------------------------------------------------===//
912// OperationName
913//===----------------------------------------------------------------------===//
914
919
920OperationName::OperationName(StringRef name, MLIRContext *context) {
921 MLIRContextImpl &ctxImpl = context->getImpl();
922
923 // Check for an existing name in read-only mode.
924 bool isMultithreadingEnabled = context->isMultithreadingEnabled();
925 if (isMultithreadingEnabled) {
926 // Check the registered info map first. In the overwhelmingly common case,
927 // the entry will be in here and it also removes the need to acquire any
928 // locks.
929 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
930 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
931 impl = registeredIt->second.impl;
932 return;
933 }
934
935 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
936 auto it = ctxImpl.operations.find(name);
937 if (it != ctxImpl.operations.end()) {
938 impl = it->second.get();
939 return;
940 }
941 }
942
943 // Acquire a writer-lock so that we can safely create the new instance.
944 ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
945
946 auto it = ctxImpl.operations.try_emplace(name);
947 if (it.second) {
948 auto nameAttr = StringAttr::get(context, name);
949 it.first->second = std::make_unique<UnregisteredOpModel>(
950 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
952 }
953 impl = it.first->second.get();
954}
955
957 if (Dialect *dialect = getDialect())
958 return dialect->getNamespace();
959 return getStringRef().split('.').first;
960}
961
962LogicalResult
970
973 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
974}
978 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
979 p.printGenericOp(op);
980}
981LogicalResult
985LogicalResult
989
990std::optional<Attribute>
992 StringRef name) {
993 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
994 if (!dict)
995 return std::nullopt;
996 if (Attribute attr = dict.get(name))
997 return attr;
998 return std::nullopt;
999}
1001 StringAttr name,
1002 Attribute value) {
1003 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
1004 assert(dict);
1005 NamedAttrList attrs(dict);
1006 attrs.set(name, value);
1007 *op->getPropertiesStorage().as<Attribute *>() =
1008 attrs.getDictionary(op->getContext());
1009}
1021 PropertyRef storage,
1022 PropertyRef init) {
1023 new (storage.as<Attribute *>()) Attribute();
1024 if (init)
1025 *storage.as<Attribute *>() = *init.as<Attribute *>();
1026}
1033 OperationName opName, PropertyRef properties, Attribute attr,
1035 *properties.as<Attribute *>() = attr;
1036 return success();
1037}
1050llvm::hash_code
1052 return llvm::hash_combine(*prop.as<Attribute *>());
1053}
1054
1055//===----------------------------------------------------------------------===//
1056// RegisteredOperationName
1057//===----------------------------------------------------------------------===//
1058
1059std::optional<RegisteredOperationName>
1061 auto &impl = ctx->getImpl();
1062 auto it = impl.registeredOperations.find(typeID);
1063 if (it != impl.registeredOperations.end())
1064 return it->second;
1065 return std::nullopt;
1066}
1067
1068std::optional<RegisteredOperationName>
1070 auto &impl = ctx->getImpl();
1071 auto it = impl.registeredOperationsByName.find(name);
1072 if (it != impl.registeredOperationsByName.end())
1073 return it->getValue();
1074 return std::nullopt;
1075}
1076
1078 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
1079 ArrayRef<StringRef> attrNames) {
1080 RegisteredOperationName::Impl *impl = ownedImpl.get();
1081 MLIRContext *ctx = impl->getDialect()->getContext();
1082 auto &ctxImpl = ctx->getImpl();
1083 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
1084 "registering a new operation kind while in a multi-threaded execution "
1085 "context");
1086
1087 // Register the attribute names of this operation.
1088 MutableArrayRef<StringAttr> cachedAttrNames;
1089 if (!attrNames.empty()) {
1090 cachedAttrNames = MutableArrayRef<StringAttr>(
1091 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
1092 attrNames.size()),
1093 attrNames.size());
1094 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
1095 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
1096 impl->attributeNames = cachedAttrNames;
1097 }
1098 StringRef name = impl->getName().strref();
1099 // Insert the operation info if it doesn't exist yet.
1100 ctxImpl.operations[name] = std::move(ownedImpl);
1101
1102 // Update the registered info for this operation.
1103 auto emplaced = ctxImpl.registeredOperations.try_emplace(
1104 impl->getTypeID(), RegisteredOperationName(impl));
1105 assert(emplaced.second && "operation name registration must be successful");
1106 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
1108 (void)emplacedByName;
1109 assert(emplacedByName.second &&
1110 "operation name registration must be successful");
1111
1112 // Add emplaced operation name to the sorted operations container.
1113 RegisteredOperationName &value = emplaced.first->second;
1114 ctxImpl.sortedRegisteredOperations.insert(
1115 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1116 [](auto &lhs, auto &rhs) {
1117 return lhs.getIdentifier().strref() <
1118 rhs.getIdentifier().strref();
1119 }),
1120 value);
1121}
1122
1123//===----------------------------------------------------------------------===//
1124// AbstractType
1125//===----------------------------------------------------------------------===//
1126
1127const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1128 const AbstractType *type = lookupMutable(typeID, context);
1129 if (!type)
1130 llvm::report_fatal_error(
1131 "Trying to create a Type that was not registered in this MLIRContext.");
1132 return *type;
1133}
1134
1135AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1136 auto &impl = context->getImpl();
1137 return impl.registeredTypes.lookup(typeID);
1138}
1139
1140std::optional<std::reference_wrapper<const AbstractType>>
1141AbstractType::lookup(StringRef name, MLIRContext *context) {
1142 MLIRContextImpl &impl = context->getImpl();
1143 const AbstractType *type = impl.nameToType.lookup(name);
1144
1145 if (!type)
1146 return std::nullopt;
1147 return {*type};
1148}
1149
1150//===----------------------------------------------------------------------===//
1151// Type uniquing
1152//===----------------------------------------------------------------------===//
1153
1154/// Returns the storage uniquer used for constructing type storage instances.
1155/// This should not be used directly.
1157
1158BFloat16Type BFloat16Type::get(MLIRContext *context) {
1159 return context->getImpl().bf16Ty;
1160}
1161Float16Type Float16Type::get(MLIRContext *context) {
1162 return context->getImpl().f16Ty;
1163}
1164FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1165 return context->getImpl().tf32Ty;
1166}
1167Float32Type Float32Type::get(MLIRContext *context) {
1168 return context->getImpl().f32Ty;
1169}
1170Float64Type Float64Type::get(MLIRContext *context) {
1171 return context->getImpl().f64Ty;
1172}
1173Float80Type Float80Type::get(MLIRContext *context) {
1174 return context->getImpl().f80Ty;
1175}
1176Float128Type Float128Type::get(MLIRContext *context) {
1177 return context->getImpl().f128Ty;
1178}
1179
1180/// Get an instance of the IndexType.
1181IndexType IndexType::get(MLIRContext *context) {
1182 return context->getImpl().indexTy;
1183}
1184
1185/// Return an existing integer type instance if one is cached within the
1186/// context.
1187static IntegerType
1189 IntegerType::SignednessSemantics signedness,
1190 MLIRContext *context) {
1191 if (signedness != IntegerType::Signless)
1192 return IntegerType();
1193
1194 switch (width) {
1195 case 1:
1196 return context->getImpl().int1Ty;
1197 case 8:
1198 return context->getImpl().int8Ty;
1199 case 16:
1200 return context->getImpl().int16Ty;
1201 case 32:
1202 return context->getImpl().int32Ty;
1203 case 64:
1204 return context->getImpl().int64Ty;
1205 case 128:
1206 return context->getImpl().int128Ty;
1207 default:
1208 return IntegerType();
1209 }
1210}
1211
1212IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1213 IntegerType::SignednessSemantics signedness) {
1214 if (auto cached = getCachedIntegerType(width, signedness, context))
1215 return cached;
1216 return Base::get(context, width, signedness);
1217}
1218
1219IntegerType
1220IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1221 MLIRContext *context, unsigned width,
1222 SignednessSemantics signedness) {
1223 if (auto cached = getCachedIntegerType(width, signedness, context))
1224 return cached;
1225 return Base::getChecked(emitError, context, width, signedness);
1226}
1227
1228/// Get an instance of the NoneType.
1229NoneType NoneType::get(MLIRContext *context) {
1230 if (NoneType cachedInst = context->getImpl().noneType)
1231 return cachedInst;
1232 // Note: May happen when initializing the singleton attributes of the builtin
1233 // dialect.
1234 return Base::get(context);
1235}
1236
1237//===----------------------------------------------------------------------===//
1238// Attribute uniquing
1239//===----------------------------------------------------------------------===//
1240
1241/// Returns the storage uniquer used for constructing attribute storage
1242/// instances. This should not be used directly.
1244 return getImpl().attributeUniquer;
1245}
1246
1247/// Initialize the given attribute storage instance.
1248void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1249 MLIRContext *ctx,
1250 TypeID attrID) {
1252}
1253
1254BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1255 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1256}
1257
1258UnitAttr UnitAttr::get(MLIRContext *context) {
1259 return context->getImpl().unitAttr;
1260}
1261
1262UnknownLoc UnknownLoc::get(MLIRContext *context) {
1263 return context->getImpl().unknownLocAttr;
1264}
1265
1266DistinctAttrStorage *
1267detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1268 Attribute referencedAttr) {
1269 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1270}
1271
1272/// Return empty dictionary.
1273DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1274 return context->getImpl().emptyDictionaryAttr;
1275}
1276
1278 // Check for a dialect namespace prefix, if there isn't one we don't need to
1279 // do any additional initialization.
1280 auto dialectNamePair = value.split('.');
1281 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1282 return;
1283
1284 // If one exists, we check to see if this dialect is loaded. If it is, we set
1285 // the dialect now, if it isn't we record this storage for initialization
1286 // later if the dialect ever gets loaded.
1287 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1288 return;
1289
1290 MLIRContextImpl &impl = context->getImpl();
1291 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1292 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1293}
1294
1295/// Return an empty string.
1296StringAttr StringAttr::get(MLIRContext *context) {
1297 return context->getImpl().emptyStringAttr;
1298}
1299
1300//===----------------------------------------------------------------------===//
1301// AffineMap uniquing
1302//===----------------------------------------------------------------------===//
1303
1305 return getImpl().affineUniquer;
1306}
1307
1308AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1309 ArrayRef<AffineExpr> results,
1310 MLIRContext *context) {
1311 auto &impl = context->getImpl();
1312 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1313 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1314 symbolCount, results);
1315 return AffineMap(storage);
1316}
1317
1318/// Check whether the arguments passed to the AffineMap::get() are consistent.
1319/// This method checks whether the highest index of dimensional identifier
1320/// present in result expressions is less than `dimCount` and the highest index
1321/// of symbolic identifier present in result expressions is less than
1322/// `symbolCount`.
1323[[maybe_unused]] static bool
1324willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1325 ArrayRef<AffineExpr> results) {
1326 int64_t maxDimPosition = -1;
1327 int64_t maxSymbolPosition = -1;
1328 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1329 maxSymbolPosition);
1330 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1331 LDBG()
1332 << "maximum dimensional identifier position in result expression must "
1333 "be less than `dimCount` and maximum symbolic identifier position "
1334 "in result expression must be less than `symbolCount`";
1335 return false;
1336 }
1337 return true;
1338}
1339
1341 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1342}
1343
1344AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1345 MLIRContext *context) {
1346 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1347}
1348
1349AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1351 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1352 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1353}
1354
1355AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1356 ArrayRef<AffineExpr> results, MLIRContext *context) {
1357 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1358 return getImpl(dimCount, symbolCount, results, context);
1359}
1360
1361//===----------------------------------------------------------------------===//
1362// Integer Sets: these are allocated into the bump pointer, and are immutable.
1363// Unlike AffineMap's, these are uniqued only if they are small.
1364//===----------------------------------------------------------------------===//
1365
1366IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1367 ArrayRef<AffineExpr> constraints,
1368 ArrayRef<bool> eqFlags) {
1369 // The number of constraints can't be zero.
1370 assert(!constraints.empty());
1371 assert(constraints.size() == eqFlags.size());
1372
1373 auto &impl = constraints[0].getContext()->getImpl();
1374 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1375 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1376 return IntegerSet(storage);
1377}
1378
1379//===----------------------------------------------------------------------===//
1380// StorageUniquerSupport
1381//===----------------------------------------------------------------------===//
1382
1383/// Utility method to generate a callback that can be used to generate a
1384/// diagnostic when checking the construction invariants of a storage object.
1385/// This is defined out-of-line to avoid the need to include Location.h.
1386llvm::unique_function<InFlightDiagnostic()>
1388 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1389}
1390llvm::unique_function<InFlightDiagnostic()>
1392 return [=] { return emitError(loc); };
1393}
return success()
static llvm::ManagedStatic< DebugCounterOptions > clOptions
static size_t hash(const T &value)
Local helper to compute std::hash for a value.
Definition IRCore.cpp:56
lhs
static bool willBeValidAffineMap(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > results)
Check whether the arguments passed to the AffineMap::get() are consistent.
static bool isThreadingGloballyDisabled()
static ArrayRef< T > copyArrayRefInto(llvm::BumpPtrAllocator &allocator, ArrayRef< T > elements)
Copy the specified array of elements into memory managed by the provided bump pointer allocator.
static IntegerType getCachedIntegerType(unsigned width, IntegerType::SignednessSemantics signedness, MLIRContext *context)
Return an existing integer type instance if one is cached within the context.
This class contains all of the static information common to all instances of a registered Attribute.
static const AbstractAttribute & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract attribute in the MLIRContext and return a reference to it.
This class contains all of the static information common to all instances of a registered Type.
Definition TypeSupport.h:30
static const AbstractType & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract type in the MLIRContext and return a reference to it.
Base type for affine expression.
Definition AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
constexpr AffineMap()=default
Base storage class appearing in an attribute.
void initializeAbstractAttribute(const AbstractAttribute &abstractAttr)
Set the abstract attribute for this storage instance.
Attributes are known-constant values of operations.
Definition Attributes.h:25
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static BoolAttr get(MLIRContext *context, bool value)
This class is the main interface for diagnostics.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool isSubsetOf(const DialectRegistry &rhs) const
Returns true if the current registry is a subset of 'rhs', i.e.
Definition Dialect.cpp:343
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition Dialect.cpp:269
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
void addType(TypeID typeID, AbstractType &&typeInfo)
Register a type instance with this dialect.
void addAttribute(TypeID typeID, AbstractAttribute &&attrInfo)
Register an attribute instance with this dialect.
A dialect that can be defined at runtime.
This class represents a diagnostic that is inflight and set to be reported.
constexpr IntegerSet()=default
static IntegerSet get(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > constraints, ArrayRef< bool > eqFlags)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This is the implementation of the MLIRContext class, using the pImpl idiom.
llvm::ThreadPoolInterface * threadPool
This points to the ThreadPool used when processing MLIR tasks in parallel.
DictionaryAttr emptyDictionaryAttr
bool printStackTraceOnDiagnostic
If the current stack trace should be attached when emitting diagnostics.
llvm::DenseMap< StringRef, AbstractAttribute * > nameToAttribute
This is a mapping from attribute name to the abstract attribute describing it.
DenseMap< StringRef, std::unique_ptr< Dialect > > loadedDialects
This is a list of dialects that are created referring to this context.
llvm::DenseMap< TypeID, RegisteredOperationName > registeredOperations
A vector of operation info specifically for registered operations.
BoolAttr falseAttr
Cached Attribute Instances.
llvm::sys::SmartRWMutex< true > operationInfoMutex
A mutex used when accessing operation information.
BFloat16Type bf16Ty
Cached Type Instances.
DenseMap< StringRef, SmallVector< StringAttrStorage * > > dialectReferencingStrAttrs
std::unique_ptr< TransientScopeState > transientState
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 isInTransientScope() const
Returns true if the context is currently in a transient scope.
bool isOperationRegistered(StringRef name)
Return true if this operation name is registered in this context.
MLIRContext(Threading multithreading=Threading::ENABLED)
Create a new Context.
void disableMultithreading(bool disable=true)
Set the flag specifying if multi-threading is disabled by the context.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
void printStackTraceOnDiagnostic(bool enable)
Set the flag specifying if we should attach the current stacktrace when emitting diagnostics.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool hasActionHandler()
Return true if a valid ActionHandler is set.
void setRemarkEngine(std::unique_ptr< remark::detail::RemarkEngine > engine)
Set the remark engine for this context.
void setThreadPool(llvm::ThreadPoolInterface &pool)
Set a new thread pool to be used in this context.
const HandlerTy & getActionHandler() const
Return a reference to the currently registered action handler.
void enableMultithreading(bool enable=true)
remark::detail::RemarkEngine * getRemarkEngine()
Returns the remark engine for this context, or nullptr if none has been set.
std::vector< Dialect * > getLoadedDialects()
Return information about all IR dialects loaded in the context.
ArrayRef< RegisteredOperationName > getRegisteredOperationsByDialect(StringRef dialectName)
Return a sorted array containing the information for registered operations filtered by dialect name.
void printOpOnDiagnostic(bool enable)
Set the flag specifying if we should attach the operation to diagnostics emitted via Operation::emit.
void registerActionHandler(HandlerTy handler)
Register a handler for handling actions that are dispatched through this context.
ArrayRef< RegisteredOperationName > getRegisteredOperations()
Return a sorted array containing the information about all registered operations.
llvm::hash_code getRegistryHash()
Returns a hash of the registry of the context that may be used to give a rough indicator of if the st...
void enterMultiThreadedExecution()
These APIs are tracking whether the context will be used in a multithreading environment: this has no...
const DialectRegistry & getDialectRegistry()
Return the dialect registry associated with this context.
DynamicDialect * getOrLoadDynamicDialect(StringRef dialectNamespace, function_ref< void(DynamicDialect *)> ctor)
Get (or create) a dynamic dialect for the given name.
StorageUniquer & getAttributeUniquer()
Returns the storage uniquer used for constructing attribute storage instances.
StorageUniquer & getAffineUniquer()
Returns the storage uniquer used for creating affine constructs.
void endTransientScope()
Ends the transient scope and resets the context to the base state, pruning all types,...
std::function< void(function_ref< void()>, const tracing::Action &)> HandlerTy
Signatures for the action handler that can be registered with the context.
StorageUniquer & getTypeUniquer()
Returns the storage uniquer used for constructing type storage instances.
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
std::vector< StringRef > getAvailableDialects()
Return information about all available dialects in the registry in this context.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
MLIRContextImpl & getImpl()
void exitMultiThreadedExecution()
bool shouldPrintOpOnDiagnostic()
Return true if we should attach the operation to diagnostics emitted via Operation::emit.
void beginTransientScope()
Begins a transient scope on the context, freezing the current state (all loaded dialects,...
void loadAllAvailableDialects()
Load all dialects available in the registry in this context.
T * getLoadedDialect()
Get a registered IR dialect for the given derived dialect type.
Definition MLIRContext.h:93
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printGenericOp(Operation *op, bool printOpName=true)=0
Print the entire operation with the default generic assembly form.
StringAttr name
The name of the operation.
TypeID typeID
The unique identifier of the derived Op class.
Impl(StringRef, Dialect *dialect, TypeID typeID, detail::InterfaceMap interfaceMap)
Dialect * dialect
The following fields are only populated when the operation is registered.
detail::InterfaceMap interfaceMap
A map of interfaces that were registered to this operation.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
OperationName(StringRef name, MLIRContext *context)
StringRef getDialectNamespace() const
Return the name of the dialect this operation is registered to.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
MLIRContext * getContext()
Return the context this operation is associated with.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
Definition Operation.h:946
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
A utility class to get or create instances of "storage classes".
void beginTransientScope()
Begins a transient scope.
void endTransientScope()
Ends the transient scope and resets back to the base state, freeing all transiently allocated storage...
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.
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
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 ...
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
Bundled state dynamically allocated when in a transient scope.
llvm::DenseMap< StringRef, size_t > baseDialectReferencingStrAttrCounts
Number of entries in dialectReferencingStrAttrs per dialect at snapshot time.
llvm::DenseSet< StringRef > baseOperations
Set of operation names in operations at snapshot time.
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) final
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
llvm::hash_code hashProperties(PropertyRef) final
void initProperties(OperationName opName, PropertyRef storage, PropertyRef init) final
OperationName::ParseAssemblyFn getParseAssemblyFn() final
LogicalResult verifyRegionInvariants(Operation *) final
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) final
Implementation for properties.
void getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) final
LogicalResult setPropertiesFromAttr(OperationName, PropertyRef, Attribute, function_ref< InFlightDiagnostic()> emitError) final
void populateDefaultAttrs(const OperationName &, NamedAttrList &) final
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final
LogicalResult verifyInvariants(Operation *) final
void populateDefaultProperties(OperationName opName, PropertyRef properties) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(PropertyRef, PropertyRef) final
void copyProperties(PropertyRef, PropertyRef) final
A binary operation appearing in an affine expression.
An integer constant appearing in affine expression.
A dimensional or symbolic identifier appearing in an affine expression.
StringRef value
The raw string value.
Dialect * referencedDialect
If the string value contains a dialect namespace prefix (e.g.
void initialize(MLIRContext *context)
Initialize the storage given an MLIRContext.
static T get(MLIRContext *ctx, Args &&...args)
Get an uniqued instance of a type T.