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 /// Enable locking for context access independently of parallel execution.
156
157 /// Track if we are currently executing in a threaded execution environment
158 /// (like the pass-manager): this is only a debugging feature to help reducing
159 /// the chances of data races one some context APIs.
160#ifndef NDEBUG
161 std::atomic<int> multiThreadedExecutionContext{0};
162#endif
163
164 /// If the operation should be attached to diagnostics printed via the
165 /// Operation::emit methods.
167
168 /// If the current stack trace should be attached when emitting diagnostics.
170
171 //===--------------------------------------------------------------------===//
172 // Other
173 //===--------------------------------------------------------------------===//
174
175 /// This points to the ThreadPool used when processing MLIR tasks in parallel.
176 /// It can't be nullptr when multi-threading is enabled. Otherwise if
177 /// multi-threading is disabled, and the threadpool wasn't externally provided
178 /// using `setThreadPool`, this will be nullptr.
179 llvm::ThreadPoolInterface *threadPool = nullptr;
180
181 /// In case where the thread pool is owned by the context, this ensures
182 /// destruction with the context.
183 std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
184
185 /// An allocator used for AbstractAttribute and AbstractType objects.
186 llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
187
188 /// This is a mapping from unregistered operation name to the operation info
189 /// describing it.
190 llvm::StringMap<std::unique_ptr<OperationName::Impl>>
192
193 /// A vector of operation info specifically for registered operations.
195 llvm::StringMap<std::unique_ptr<OperationName::Impl>, llvm::BumpPtrAllocator>
197
198 /// This is a sorted container of registered operations for a deterministic
199 /// and efficient `getRegisteredOperations` implementation.
201
202 /// This is a list of dialects that are created referring to this context.
203 /// The MLIRContext owns the objects. These need to be declared after the
204 /// registered operations to ensure correct destruction order.
207
208 /// A mutex used when accessing operation information.
209 llvm::sys::SmartRWMutex<true> operationInfoMutex;
210
211 //===--------------------------------------------------------------------===//
212 // Affine uniquing
213 //===--------------------------------------------------------------------===//
214
215 // Affine expression, map and integer set uniquing.
217
218 //===--------------------------------------------------------------------===//
219 // Type uniquing
220 //===--------------------------------------------------------------------===//
221
224
225 /// This is a mapping from type name to the abstract type describing it.
226 /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.
227 /// As this map needs to be populated before `StringAttr` is loaded, we
228 /// cannot use `StringAttr` as the key. The context does not take ownership
229 /// of the key, so the `StringRef` must outlive the context.
231
232 /// Cached Type Instances.
233 BFloat16Type bf16Ty;
234 Float16Type f16Ty;
235 FloatTF32Type tf32Ty;
236 Float32Type f32Ty;
237 Float64Type f64Ty;
238 Float80Type f80Ty;
239 Float128Type f128Ty;
240 IndexType indexTy;
242 NoneType noneType;
243
244 //===--------------------------------------------------------------------===//
245 // Attribute uniquing
246 //===--------------------------------------------------------------------===//
247
250
251 /// This is a mapping from attribute name to the abstract attribute describing
252 /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a
253 /// name.
254 /// As this map needs to be populated before `StringAttr` is loaded, we
255 /// cannot use `StringAttr` as the key. The context does not take ownership
256 /// of the key, so the `StringRef` must outlive the context.
258
259 /// Cached Attribute Instances.
261 UnitAttr unitAttr;
262 UnknownLoc unknownLocAttr;
263 DictionaryAttr emptyDictionaryAttr;
264 StringAttr emptyStringAttr;
265
266 /// Map of string attributes that may reference a dialect, that are awaiting
267 /// that dialect to be loaded.
271
272 /// A distinct attribute allocator that allocates every time since the
273 /// address of the distinct attribute storage serves as unique identifier. The
274 /// allocator is thread safe and frees the allocated storage after its
275 /// destruction.
277
278 /// Bundled state dynamically allocated when in a transient scope.
280 /// Set of operation names in `unregisteredOperationsByName` at snapshot
281 /// time.
283
284 /// Number of entries in `dialectReferencingStrAttrs` per dialect at
285 /// snapshot time.
287 };
288 std::unique_ptr<TransientScopeState> transientState;
289
290public:
293 if (threadingIsEnabled) {
294 ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
296 } else {
298 }
299 }
300 /// Update the locking mode for context access and each of the uniquers.
301 void setThreadSafeLocking(bool enable) {
303 affineUniquer.setThreadSafeLocking(enable);
304 attributeUniquer.setThreadSafeLocking(enable);
305 typeUniquer.setThreadSafeLocking(enable);
306 }
308 for (auto typeMapping : registeredTypes)
309 typeMapping.second->~AbstractType();
310 for (auto attrMapping : registeredAttributes)
311 attrMapping.second->~AbstractAttribute();
312 }
313};
314} // namespace mlir
315
318
320 : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
322 // Initialize values based on the command line flags if they were provided.
323 if (clOptions.isConstructed()) {
324 printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
325 printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
326 }
327
328 // Pre-populate the registry.
329 registry.appendTo(impl->dialectsRegistry);
330
331 // Ensure the builtin dialect is always pre-loaded.
333
334 // Initialize several common attributes and types to avoid the need to lock
335 // the context when accessing them.
336
337 //// Types.
338 /// Floating-point Types.
339 impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
340 impl->f16Ty = TypeUniquer::get<Float16Type>(this);
342 impl->f32Ty = TypeUniquer::get<Float32Type>(this);
343 impl->f64Ty = TypeUniquer::get<Float64Type>(this);
344 impl->f80Ty = TypeUniquer::get<Float80Type>(this);
345 impl->f128Ty = TypeUniquer::get<Float128Type>(this);
346 /// Index Type.
347 impl->indexTy = TypeUniquer::get<IndexType>(this);
348 /// Integer Types.
349 impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
350 impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
351 impl->int16Ty =
352 TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
353 impl->int32Ty =
354 TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
355 impl->int64Ty =
356 TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
357 impl->int128Ty =
358 TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
359 /// None Type.
360 impl->noneType = TypeUniquer::get<NoneType>(this);
361
362 //// Attributes.
363 //// Note: These must be registered after the types as they may generate one
364 //// of the above types internally.
365 /// Unknown Location Attribute.
366 impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
367 /// Bool Attributes.
368 impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
369 impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
370 /// Unit Attribute.
371 impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
372 /// The empty dictionary attribute.
373 impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
374 /// The empty string attribute.
375 impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
376
377 // Register the affine storage objects with the uniquer.
378 impl->affineUniquer
379 .registerParametricStorageType<AffineBinaryOpExprStorage>();
380 impl->affineUniquer
381 .registerParametricStorageType<AffineConstantExprStorage>();
382 impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
383 impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
384 impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
385}
386
388 // finalize remark engine before destroying anything else.
389 impl->remarkEngine.reset();
390}
391
392//===----------------------------------------------------------------------===//
393// Action Handling
394//===----------------------------------------------------------------------===//
395
397 getImpl().actionHandler = std::move(handler);
398}
399
403
407
408/// Dispatch the provided action to the handler if any, or just execute it.
409void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
410 const tracing::Action &action) {
411 assert(getImpl().actionHandler);
412 getImpl().actionHandler(actionFn, action);
413}
414
416
417//===----------------------------------------------------------------------===//
418// Diagnostic Handlers
419//===----------------------------------------------------------------------===//
420
421/// Returns the diagnostic engine for this context.
423
424//===----------------------------------------------------------------------===//
425// Remark Handlers
426//===----------------------------------------------------------------------===//
427
429 std::unique_ptr<remark::detail::RemarkEngine> engine) {
430 getImpl().remarkEngine = std::move(engine);
431}
432
436
437//===----------------------------------------------------------------------===//
438// Dialect and Operation Registration
439//===----------------------------------------------------------------------===//
440
442 if (registry.isSubsetOf(impl->dialectsRegistry))
443 return;
444
445 assert(impl->multiThreadedExecutionContext == 0 &&
446 "appending to the MLIRContext dialect registry while in a "
447 "multi-threaded execution context");
448 assert(!impl->transientState &&
449 "cannot append to dialect registry while in a transient scope");
450
451 registry.appendTo(impl->dialectsRegistry);
452
453 // For the already loaded dialects, apply any possible extensions immediately.
454 registry.applyExtensions(this);
455}
456
458 return impl->dialectsRegistry;
459}
460
461/// Return information about all registered IR dialects.
462std::vector<Dialect *> MLIRContext::getLoadedDialects() {
463 std::vector<Dialect *> result;
464 result.reserve(impl->loadedDialects.size());
465 for (auto &dialect : impl->loadedDialects)
466 result.push_back(dialect.second.get());
467 llvm::array_pod_sort(result.begin(), result.end(),
468 [](Dialect *const *lhs, Dialect *const *rhs) -> int {
469 return (*lhs)->getNamespace() < (*rhs)->getNamespace();
470 });
471 return result;
472}
473std::vector<StringRef> MLIRContext::getAvailableDialects() {
474 std::vector<StringRef> result;
475 for (auto dialect : impl->dialectsRegistry.getRegisteredDialectNames())
476 result.push_back(dialect);
477 return result;
478}
479
480/// Get a registered IR dialect with the given namespace. If none is found,
481/// then return nullptr.
483 // Dialects are sorted by name, so we can use binary search for lookup.
484 auto it = impl->loadedDialects.find(name);
485 return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
486}
487
489 Dialect *dialect = getLoadedDialect(name);
490 if (dialect)
491 return dialect;
493 impl->dialectsRegistry.getDialectAllocator(name);
494 return allocator ? allocator(this) : nullptr;
495}
496
497/// Get a dialect for the provided namespace and TypeID: abort the program if a
498/// dialect exist for this namespace with different TypeID. Returns a pointer to
499/// the dialect owned by the context.
500Dialect *
501MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
502 function_ref<std::unique_ptr<Dialect>()> ctor) {
503 auto &impl = getImpl();
504 // Get the correct insertion position sorted by namespace.
505 auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
506
507 if (dialectIt.second) {
508 LDBG() << "Load new dialect in Context " << dialectNamespace;
509 assert(!impl.transientState &&
510 "cannot load new dialects while in a transient scope");
511#ifndef NDEBUG
512 if (impl.multiThreadedExecutionContext != 0)
513 llvm::report_fatal_error(
514 "Loading a dialect (" + dialectNamespace +
515 ") while in a multi-threaded execution context (maybe "
516 "the PassManager): this can indicate a "
517 "missing `dependentDialects` in a pass for example.");
518#endif // NDEBUG
519 // loadedDialects entry is initialized to nullptr, indicating that the
520 // dialect is currently being loaded. Re-lookup the address in
521 // loadedDialects because the table might have been rehashed by recursive
522 // dialect loading in ctor().
523 std::unique_ptr<Dialect> &dialectOwned =
524 impl.loadedDialects[dialectNamespace] = ctor();
525 Dialect *dialect = dialectOwned.get();
526 assert(dialect && "dialect ctor failed");
527
528 // Refresh all the identifiers dialect field, this catches cases where a
529 // dialect may be loaded after identifier prefixed with this dialect name
530 // were already created.
531 auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
532 if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
533 for (StringAttrStorage *storage : stringAttrsIt->second)
534 storage->referencedDialect = dialect;
535 impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
536 }
537
538 // Apply any extensions to this newly loaded dialect.
539 impl.dialectsRegistry.applyExtensions(dialect);
540 return dialect;
541 }
542
543#ifndef NDEBUG
544 if (dialectIt.first->second == nullptr)
545 llvm::report_fatal_error(
546 "Loading (and getting) a dialect (" + dialectNamespace +
547 ") while the same dialect is still loading: use loadDialect instead "
548 "of getOrLoadDialect.");
549#endif // NDEBUG
550
551 // Abort if dialect with namespace has already been registered.
552 std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
553 if (dialect->getTypeID() != dialectID)
554 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
555 "' has already been registered");
556
557 return dialect.get();
558}
559
560bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
561 auto it = getImpl().loadedDialects.find(dialectNamespace);
562 // nullptr indicates that the dialect is currently being loaded.
563 return it != getImpl().loadedDialects.end() && it->second == nullptr;
564}
565
567 StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
568 auto &impl = getImpl();
569 // Get the correct insertion position sorted by namespace.
570 auto dialectIt = impl.loadedDialects.find(dialectNamespace);
571
572 if (dialectIt != impl.loadedDialects.end()) {
573 if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
574 return dynDialect;
575 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
576 "' has already been registered");
577 }
578
579 LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
580#ifndef NDEBUG
581 if (impl.multiThreadedExecutionContext != 0)
582 llvm::report_fatal_error(
583 "Loading a dynamic dialect (" + dialectNamespace +
584 ") while in a multi-threaded execution context (maybe "
585 "the PassManager): this can indicate a "
586 "missing `dependentDialects` in a pass for example.");
587#endif
588
589 auto name = StringAttr::get(this, dialectNamespace);
590 auto *dialect = new DynamicDialect(name, this);
591 (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
592 ctor(dialect);
593 return std::unique_ptr<DynamicDialect>(dialect);
594 });
595 // This is the same result as `getOrLoadDialect` (if it didn't failed),
596 // since it has the same TypeID, and TypeIDs are unique.
597 return dialect;
598}
599
601 for (StringRef name : getAvailableDialects())
602 getOrLoadDialect(name);
603}
604
606 llvm::hash_code hash(0);
607 // Factor in number of loaded dialects, attributes, operations, types.
608 hash = llvm::hash_combine(hash, impl->loadedDialects.size());
609 hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
610 hash = llvm::hash_combine(hash, impl->registeredOperations.size());
611 hash = llvm::hash_combine(hash, impl->registeredTypes.size());
612 return hash;
613}
614
616 return impl->allowUnregisteredDialects;
617}
618
620 assert(impl->multiThreadedExecutionContext == 0 &&
621 "changing MLIRContext `allow-unregistered-dialects` configuration "
622 "while in a multi-threaded execution context");
623 impl->allowUnregisteredDialects = allowing;
624}
625
626/// Return true if multi-threading is enabled by the context.
627#if LLVM_ENABLE_THREADS
628bool MLIRContext::isMultithreadingEnabled() { return impl->threadingIsEnabled; }
629#endif
630
631/// Set the flag specifying if multi-threading is disabled by the context.
633 // This API can be overridden by the global debugging flag
634 // --mlir-disable-threading
636 return;
637 assert(impl->multiThreadedExecutionContext == 0 &&
638 "changing MLIRContext `disable-threading` configuration while "
639 "in a multi-threaded execution context");
640
641 impl->threadingIsEnabled = !disable;
642
643 impl->setThreadSafeLocking(!disable);
644
645 // Destroy thread pool (stop all threads) if it is no longer needed, or create
646 // a new one if multithreading was re-enabled.
647 if (disable) {
648 // If the thread pool is owned, explicitly set it to nullptr to avoid
649 // keeping a dangling pointer around. If the thread pool is externally
650 // owned, we don't do anything.
651 if (impl->ownedThreadPool) {
652 assert(impl->threadPool);
653 impl->threadPool = nullptr;
654 impl->ownedThreadPool.reset();
655 }
656 } else if (!impl->threadPool) {
657 // The thread pool isn't externally provided.
658 assert(!impl->ownedThreadPool);
659 impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
660 impl->threadPool = impl->ownedThreadPool.get();
661 }
662}
663
664#if LLVM_ENABLE_THREADS
666 return impl->threadSafeLockingIsEnabled;
667}
668#endif
669
671 impl->setThreadSafeLocking(true);
672}
673
674void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
675 assert(!isMultithreadingEnabled() &&
676 "expected multi-threading to be disabled when setting a ThreadPool");
677 impl->threadPool = &pool;
678 impl->ownedThreadPool.reset();
680}
681
684 assert(impl->threadPool &&
685 "multi-threading is enabled but threadpool not set");
686 return impl->threadPool->getMaxConcurrency();
687 }
688 // No multithreading or active thread pool. Return 1 thread.
689 return 1;
690}
691
692llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
693 assert(isMultithreadingEnabled() &&
694 "expected multi-threading to be enabled within the context");
695 assert(impl->threadPool &&
696 "multi-threading is enabled but threadpool not set");
697 return *impl->threadPool;
698}
699
701#ifndef NDEBUG
702 ++impl->multiThreadedExecutionContext;
703#endif
704}
706#ifndef NDEBUG
707 --impl->multiThreadedExecutionContext;
708#endif
709}
710
712 MLIRContextImpl &ctxImpl = getImpl();
713 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
714 "Beginning a transient scope while in a multi-threaded execution "
715 "context");
716 assert(!ctxImpl.transientState && "context is already in a transient scope");
717 ctxImpl.transientState =
718 std::make_unique<MLIRContextImpl::TransientScopeState>();
719
720 // Begin transient scope in the uniquers.
725
726 // Record base unregistered operations.
727 {
728 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
729 for (const auto &entry : ctxImpl.unregisteredOperationsByName)
730 ctxImpl.transientState->baseOperations.insert(entry.first());
731 }
732
733 // Record dialect referencing string attribute counts.
734 {
735 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
736 for (const auto &entry : ctxImpl.dialectReferencingStrAttrs)
737 ctxImpl.transientState->baseDialectReferencingStrAttrCounts[entry.first] =
738 entry.second.size();
739 }
740}
741
743 MLIRContextImpl &ctxImpl = getImpl();
744 assert(ctxImpl.transientState && "context is not in a transient scope");
745 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
746 "Ending a transient scope while in a multi-threaded execution "
747 "context");
748 if (!ctxImpl.transientState)
749 return;
750
751 // Prune unregistered operations created during transient scope before
752 // destroying the attribute uniquer that holds their string attribute names.
753 {
754 llvm::sys::SmartScopedWriter<true> contextLock(ctxImpl.operationInfoMutex);
755 SmallVector<StringRef> opsToErase;
756 for (const auto &entry : ctxImpl.unregisteredOperationsByName)
757 if (!ctxImpl.transientState->baseOperations.contains(entry.first()))
758 opsToErase.push_back(entry.first());
759 for (StringRef op : opsToErase)
760 ctxImpl.unregisteredOperationsByName.erase(op);
761 }
762
763 // Restore dialect referencing string attributes before destroying the
764 // attribute uniquer that holds the underlying StringAttrStorage pointers.
765 // Note: Transient entries are always appended to the end of each dialect's
766 // vector, so truncating via resize() to the base count safely removes only
767 // transient entries while preserving base entries.
768 {
769 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
770 SmallVector<StringRef> dialectsToErase;
771 for (auto &entry : ctxImpl.dialectReferencingStrAttrs) {
772 auto countIt =
773 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.find(
774 entry.first);
775 if (countIt ==
776 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.end()) {
777 dialectsToErase.push_back(entry.first);
778 } else {
779 entry.second.resize(countIt->second);
780 }
781 }
782 for (StringRef dialect : dialectsToErase)
783 ctxImpl.dialectReferencingStrAttrs.erase(dialect);
784 }
785
786 // End transient scope in the uniquers now that all referencing structures
787 // are cleaned up.
792
793 ctxImpl.transientState.reset();
794}
795
797 return getImpl().transientState != nullptr;
798}
799
800/// Return true if we should attach the operation to diagnostics emitted via
801/// Operation::emit.
803 return impl->printOpOnDiagnostic;
804}
805
806/// Set the flag specifying if we should attach the operation to diagnostics
807/// emitted via Operation::emit.
809 assert(impl->multiThreadedExecutionContext == 0 &&
810 "changing MLIRContext `print-op-on-diagnostic` configuration while in "
811 "a multi-threaded execution context");
812 impl->printOpOnDiagnostic = enable;
813}
814
815/// Return true if we should attach the current stacktrace to diagnostics when
816/// emitted.
818 return impl->printStackTraceOnDiagnostic;
819}
820
821/// Set the flag specifying if we should attach the current stacktrace when
822/// emitting diagnostics.
824 assert(impl->multiThreadedExecutionContext == 0 &&
825 "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
826 "while in a multi-threaded execution context");
827 impl->printStackTraceOnDiagnostic = enable;
828}
829
830/// Return information about all registered operations.
832 return impl->sortedRegisteredOperations;
833}
834
835/// Return information for registered operations by dialect.
838 auto *lowerBound =
839 llvm::lower_bound(impl->sortedRegisteredOperations, dialectName,
840 [](const RegisteredOperationName &lhs, StringRef rhs) {
841 return lhs.getDialect().getNamespace() < rhs;
842 });
843
844 if (lowerBound == impl->sortedRegisteredOperations.end() ||
845 lowerBound->getDialect().getNamespace() != dialectName)
847
848 auto *upperBound = std::upper_bound(
849 lowerBound, impl->sortedRegisteredOperations.end(), dialectName,
850 [](StringRef lhs, const RegisteredOperationName &rhs) {
851 return lhs < rhs.getDialect().getNamespace();
852 });
853
854 size_t count = std::distance(lowerBound, upperBound);
855 return ArrayRef(&*lowerBound, count);
856}
857
859 return RegisteredOperationName::lookup(name, this).has_value();
860}
861
862void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
863 auto &impl = context->getImpl();
864 assert(impl.multiThreadedExecutionContext == 0 &&
865 "Registering a new type kind while in a multi-threaded execution "
866 "context");
867 auto *newInfo =
868 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
869 AbstractType(std::move(typeInfo));
870 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
871 llvm::report_fatal_error("Dialect Type already registered.");
872 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
873 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
874 " is already registered.");
875}
876
878 auto &impl = context->getImpl();
879 assert(impl.multiThreadedExecutionContext == 0 &&
880 "Registering a new attribute kind while in a multi-threaded execution "
881 "context");
882 auto *newInfo =
883 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
884 AbstractAttribute(std::move(attrInfo));
885 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
886 llvm::report_fatal_error("Dialect Attribute already registered.");
887 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
888 llvm::report_fatal_error("Dialect Attribute with name " +
889 newInfo->getName() + " is already registered.");
890}
891
892//===----------------------------------------------------------------------===//
893// AbstractAttribute
894//===----------------------------------------------------------------------===//
895
896/// Get the dialect that registered the attribute with the provided typeid.
897const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
898 MLIRContext *context) {
899 const AbstractAttribute *abstract = lookupMutable(typeID, context);
900 if (!abstract)
901 llvm::report_fatal_error("Trying to create an Attribute that was not "
902 "registered in this MLIRContext.");
903 return *abstract;
904}
905
906AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
907 MLIRContext *context) {
908 auto &impl = context->getImpl();
909 return impl.registeredAttributes.lookup(typeID);
910}
911
912std::optional<std::reference_wrapper<const AbstractAttribute>>
913AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
914 MLIRContextImpl &impl = context->getImpl();
915 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
916
917 if (!type)
918 return std::nullopt;
919 return {*type};
920}
921
922//===----------------------------------------------------------------------===//
923// OperationName
924//===----------------------------------------------------------------------===//
925
930
931OperationName::OperationName(StringRef name, MLIRContext *context) {
932 MLIRContextImpl &ctxImpl = context->getImpl();
933
934 // Check the registered info map first. In the overwhelmingly common case,
935 // the entry will be in here and it also removes the need to acquire any
936 // locks.
937 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
938 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
939 impl = registeredIt->second.get();
940 return;
941 }
942
943 // Check for an existing name in read-only mode.
944 bool shouldLock = context->isThreadSafeLockingEnabled();
945 if (shouldLock) {
946 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
947 auto it = ctxImpl.unregisteredOperationsByName.find(name);
948 if (it != ctxImpl.unregisteredOperationsByName.end()) {
949 impl = it->second.get();
950 return;
951 }
952 }
953
954 // Acquire a writer-lock so that we can safely create the new instance.
955 ScopedWriterLock lock(ctxImpl.operationInfoMutex, shouldLock);
956
957 auto it = ctxImpl.unregisteredOperationsByName.try_emplace(name);
958 if (it.second) {
959 auto nameAttr = StringAttr::get(context, name);
960 it.first->second = std::make_unique<UnregisteredOpModel>(
961 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
963 }
964 impl = it.first->second.get();
965}
966
968 if (Dialect *dialect = getDialect())
969 return dialect->getNamespace();
970 return getStringRef().split('.').first;
971}
972
973LogicalResult
981
984 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
985}
989 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
990 p.printGenericOp(op);
991}
992LogicalResult
996LogicalResult
1000
1001std::optional<Attribute>
1003 StringRef name) {
1004 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
1005 if (!dict)
1006 return std::nullopt;
1007 if (Attribute attr = dict.get(name))
1008 return attr;
1009 return std::nullopt;
1010}
1012 StringAttr name,
1013 Attribute value) {
1014 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
1015 assert(dict);
1016 NamedAttrList attrs(dict);
1017 attrs.set(name, value);
1018 *op->getPropertiesStorage().as<Attribute *>() =
1019 attrs.getDictionary(op->getContext());
1020}
1032 PropertyRef storage,
1033 PropertyRef init) {
1034 new (storage.as<Attribute *>()) Attribute();
1035 if (init)
1036 *storage.as<Attribute *>() = *init.as<Attribute *>();
1037}
1044 OperationName opName, PropertyRef properties, Attribute attr,
1046 *properties.as<Attribute *>() = attr;
1047 return success();
1048}
1054 PropertyRef rhs) {
1055 *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
1056}
1058 PropertyRef rhs) {
1059 return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
1060}
1061llvm::hash_code
1063 return llvm::hash_combine(*prop.as<Attribute *>());
1064}
1065
1066//===----------------------------------------------------------------------===//
1067// RegisteredOperationName
1068//===----------------------------------------------------------------------===//
1069
1070std::optional<RegisteredOperationName>
1072 auto &impl = ctx->getImpl();
1073 auto it = impl.registeredOperations.find(typeID);
1074 if (it != impl.registeredOperations.end())
1075 return it->second;
1076 return std::nullopt;
1077}
1078
1079std::optional<RegisteredOperationName>
1081 auto &impl = ctx->getImpl();
1082 auto it = impl.registeredOperationsByName.find(name);
1083 if (it != impl.registeredOperationsByName.end())
1084 return RegisteredOperationName(it->second.get());
1085 return std::nullopt;
1086}
1087
1089 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
1090 ArrayRef<StringRef> attrNames) {
1091 RegisteredOperationName::Impl *impl = ownedImpl.get();
1092 MLIRContext *ctx = impl->getDialect()->getContext();
1093 auto &ctxImpl = ctx->getImpl();
1094 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
1095 "registering a new operation kind while in a multi-threaded execution "
1096 "context");
1097
1098 // Register the attribute names of this operation.
1099 MutableArrayRef<StringAttr> cachedAttrNames;
1100 if (!attrNames.empty()) {
1101 cachedAttrNames = MutableArrayRef<StringAttr>(
1102 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
1103 attrNames.size()),
1104 attrNames.size());
1105 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
1106 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
1107 impl->attributeNames = cachedAttrNames;
1108 }
1109 StringRef name = impl->getName().strref();
1110
1111 // Update the registered info for this operation.
1112 auto emplaced = ctxImpl.registeredOperations.try_emplace(
1113 impl->getTypeID(), RegisteredOperationName(impl));
1114 assert(emplaced.second && "operation name registration must be successful");
1115 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
1116 name, std::move(ownedImpl));
1117 (void)emplacedByName;
1118 assert(emplacedByName.second &&
1119 "operation name registration must be successful");
1120
1121 // Add emplaced operation name to the sorted operations container.
1122 RegisteredOperationName &value = emplaced.first->second;
1123 ctxImpl.sortedRegisteredOperations.insert(
1124 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1125 [](auto &lhs, auto &rhs) {
1126 return lhs.getIdentifier().strref() <
1127 rhs.getIdentifier().strref();
1128 }),
1129 value);
1130}
1131
1132void *RegisteredOperationName::allocateModelStorage() {
1133 return ::operator new(sizeof(Impl));
1134}
1135
1136//===----------------------------------------------------------------------===//
1137// AbstractType
1138//===----------------------------------------------------------------------===//
1139
1140const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1141 const AbstractType *type = lookupMutable(typeID, context);
1142 if (!type)
1143 llvm::report_fatal_error(
1144 "Trying to create a Type that was not registered in this MLIRContext.");
1145 return *type;
1146}
1147
1148AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1149 auto &impl = context->getImpl();
1150 return impl.registeredTypes.lookup(typeID);
1151}
1152
1153std::optional<std::reference_wrapper<const AbstractType>>
1154AbstractType::lookup(StringRef name, MLIRContext *context) {
1155 MLIRContextImpl &impl = context->getImpl();
1156 const AbstractType *type = impl.nameToType.lookup(name);
1157
1158 if (!type)
1159 return std::nullopt;
1160 return {*type};
1161}
1162
1163//===----------------------------------------------------------------------===//
1164// Type uniquing
1165//===----------------------------------------------------------------------===//
1166
1167/// Returns the storage uniquer used for constructing type storage instances.
1168/// This should not be used directly.
1170
1171BFloat16Type BFloat16Type::get(MLIRContext *context) {
1172 return context->getImpl().bf16Ty;
1173}
1174Float16Type Float16Type::get(MLIRContext *context) {
1175 return context->getImpl().f16Ty;
1176}
1177FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1178 return context->getImpl().tf32Ty;
1179}
1180Float32Type Float32Type::get(MLIRContext *context) {
1181 return context->getImpl().f32Ty;
1182}
1183Float64Type Float64Type::get(MLIRContext *context) {
1184 return context->getImpl().f64Ty;
1185}
1186Float80Type Float80Type::get(MLIRContext *context) {
1187 return context->getImpl().f80Ty;
1188}
1189Float128Type Float128Type::get(MLIRContext *context) {
1190 return context->getImpl().f128Ty;
1191}
1192
1193/// Get an instance of the IndexType.
1194IndexType IndexType::get(MLIRContext *context) {
1195 return context->getImpl().indexTy;
1196}
1197
1198/// Return an existing integer type instance if one is cached within the
1199/// context.
1200static IntegerType
1202 IntegerType::SignednessSemantics signedness,
1203 MLIRContext *context) {
1204 if (signedness != IntegerType::Signless)
1205 return IntegerType();
1206
1207 switch (width) {
1208 case 1:
1209 return context->getImpl().int1Ty;
1210 case 8:
1211 return context->getImpl().int8Ty;
1212 case 16:
1213 return context->getImpl().int16Ty;
1214 case 32:
1215 return context->getImpl().int32Ty;
1216 case 64:
1217 return context->getImpl().int64Ty;
1218 case 128:
1219 return context->getImpl().int128Ty;
1220 default:
1221 return IntegerType();
1222 }
1223}
1224
1225IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1226 IntegerType::SignednessSemantics signedness) {
1227 if (auto cached = getCachedIntegerType(width, signedness, context))
1228 return cached;
1229 return Base::get(context, width, signedness);
1230}
1231
1232IntegerType
1233IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1234 MLIRContext *context, unsigned width,
1235 SignednessSemantics signedness) {
1236 if (auto cached = getCachedIntegerType(width, signedness, context))
1237 return cached;
1238 return Base::getChecked(emitError, context, width, signedness);
1239}
1240
1241/// Get an instance of the NoneType.
1242NoneType NoneType::get(MLIRContext *context) {
1243 if (NoneType cachedInst = context->getImpl().noneType)
1244 return cachedInst;
1245 // Note: May happen when initializing the singleton attributes of the builtin
1246 // dialect.
1247 return Base::get(context);
1248}
1249
1250//===----------------------------------------------------------------------===//
1251// Attribute uniquing
1252//===----------------------------------------------------------------------===//
1253
1254/// Returns the storage uniquer used for constructing attribute storage
1255/// instances. This should not be used directly.
1257 return getImpl().attributeUniquer;
1258}
1259
1260/// Initialize the given attribute storage instance.
1261void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1262 MLIRContext *ctx,
1263 TypeID attrID) {
1265}
1266
1267BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1268 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1269}
1270
1271UnitAttr UnitAttr::get(MLIRContext *context) {
1272 return context->getImpl().unitAttr;
1273}
1274
1275UnknownLoc UnknownLoc::get(MLIRContext *context) {
1276 return context->getImpl().unknownLocAttr;
1277}
1278
1279DistinctAttrStorage *
1280detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1281 Attribute referencedAttr) {
1282 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1283}
1284
1285/// Return empty dictionary.
1286DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1287 return context->getImpl().emptyDictionaryAttr;
1288}
1289
1291 // Check for a dialect namespace prefix, if there isn't one we don't need to
1292 // do any additional initialization.
1293 auto dialectNamePair = value.split('.');
1294 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1295 return;
1296
1297 // If one exists, we check to see if this dialect is loaded. If it is, we set
1298 // the dialect now, if it isn't we record this storage for initialization
1299 // later if the dialect ever gets loaded.
1300 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1301 return;
1302
1303 MLIRContextImpl &impl = context->getImpl();
1304 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1305 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1306}
1307
1308/// Return an empty string.
1309StringAttr StringAttr::get(MLIRContext *context) {
1310 return context->getImpl().emptyStringAttr;
1311}
1312
1313//===----------------------------------------------------------------------===//
1314// AffineMap uniquing
1315//===----------------------------------------------------------------------===//
1316
1318 return getImpl().affineUniquer;
1319}
1320
1321AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1322 ArrayRef<AffineExpr> results,
1323 MLIRContext *context) {
1324 auto &impl = context->getImpl();
1325 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1326 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1327 symbolCount, results);
1328 return AffineMap(storage);
1329}
1330
1331/// Check whether the arguments passed to the AffineMap::get() are consistent.
1332/// This method checks whether the highest index of dimensional identifier
1333/// present in result expressions is less than `dimCount` and the highest index
1334/// of symbolic identifier present in result expressions is less than
1335/// `symbolCount`.
1336[[maybe_unused]] static bool
1337willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1338 ArrayRef<AffineExpr> results) {
1339 int64_t maxDimPosition = -1;
1340 int64_t maxSymbolPosition = -1;
1341 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1342 maxSymbolPosition);
1343 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1344 LDBG()
1345 << "maximum dimensional identifier position in result expression must "
1346 "be less than `dimCount` and maximum symbolic identifier position "
1347 "in result expression must be less than `symbolCount`";
1348 return false;
1349 }
1350 return true;
1351}
1352
1354 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1355}
1356
1357AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1358 MLIRContext *context) {
1359 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1360}
1361
1362AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1364 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1365 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1366}
1367
1368AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1369 ArrayRef<AffineExpr> results, MLIRContext *context) {
1370 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1371 return getImpl(dimCount, symbolCount, results, context);
1372}
1373
1374//===----------------------------------------------------------------------===//
1375// Integer Sets: these are allocated into the bump pointer, and are immutable.
1376// Unlike AffineMap's, these are uniqued only if they are small.
1377//===----------------------------------------------------------------------===//
1378
1379IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1380 ArrayRef<AffineExpr> constraints,
1381 ArrayRef<bool> eqFlags) {
1382 // The number of constraints can't be zero.
1383 assert(!constraints.empty());
1384 assert(constraints.size() == eqFlags.size());
1385
1386 auto &impl = constraints[0].getContext()->getImpl();
1387 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1388 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1389 return IntegerSet(storage);
1390}
1391
1392//===----------------------------------------------------------------------===//
1393// StorageUniquerSupport
1394//===----------------------------------------------------------------------===//
1395
1396/// Utility method to generate a callback that can be used to generate a
1397/// diagnostic when checking the construction invariants of a storage object.
1398/// This is defined out-of-line to avoid the need to include Location.h.
1399llvm::unique_function<InFlightDiagnostic()>
1401 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1402}
1403llvm::unique_function<InFlightDiagnostic()>
1405 return [=] { return emitError(loc); };
1406}
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:57
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 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
std::atomic< int > multiThreadedExecutionContext
Track if we are currently executing in a threaded execution environment (like the pass-manager): this...
llvm::StringMap< std::unique_ptr< OperationName::Impl >, llvm::BumpPtrAllocator > registeredOperationsByName
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
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...
llvm::StringMap< std::unique_ptr< OperationName::Impl > > unregisteredOperationsByName
This is a mapping from unregistered operation name to the operation info describing it.
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 threadSafeLockingIsEnabled
Enable locking for context access independently of parallel execution.
bool threadingIsEnabled
Enable support for multi-threading within MLIR.
void setThreadSafeLocking(bool enable)
Update the locking mode for context access and each of the uniquers.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
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.
void enableThreadSafeLocking()
Enable thread-safe locking for context access, including uniquing types, attributes,...
StorageUniquer & getAttributeUniquer()
Returns the storage uniquer used for constructing attribute storage instances.
StorageUniquer & getAffineUniquer()
Returns the storage uniquer used for creating affine constructs.
void endTransientScope()
Ends the transient scope and resets the context to the base state, pruning all types,...
std::function< void(function_ref< void()>, const tracing::Action &)> HandlerTy
Signatures for the action handler that can be registered with the context.
StorageUniquer & getTypeUniquer()
Returns the storage uniquer used for constructing type storage instances.
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
std::vector< StringRef > getAvailableDialects()
Return information about all available dialects in the registry in this context.
bool isThreadSafeLockingEnabled()
Return true if thread-safe locking is enabled for context access.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
MLIRContextImpl & getImpl()
void exitMultiThreadedExecution()
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
bool shouldPrintOpOnDiagnostic()
Return true if we should attach the operation to diagnostics emitted via Operation::emit.
void beginTransientScope()
Begins a transient scope on the context, freezing the current state (all loaded dialects,...
void loadAllAvailableDialects()
Load all dialects available in the registry in this context.
T * getLoadedDialect()
Get a registered IR dialect for the given derived dialect type.
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
llvm::function_ref< void(StringRef, Attribute &)> InherentAttrVisitor
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:955
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:699
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:123
function_ref< Dialect *(MLIRContext *)> DialectAllocatorFunctionRef
llvm::function_ref< Fn > function_ref
Definition LLVM.h:155
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 unregisteredOperationsByName at snapshot time.
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) 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 walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) final
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.