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//===----------------------------------------------------------------------===//
377// Action Handling
378//===----------------------------------------------------------------------===//
379
381 getImpl().actionHandler = std::move(handler);
382}
383
387
391
392/// Dispatch the provided action to the handler if any, or just execute it.
393void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
394 const tracing::Action &action) {
395 assert(getImpl().actionHandler);
396 getImpl().actionHandler(actionFn, action);
397}
398
400
401//===----------------------------------------------------------------------===//
402// Diagnostic Handlers
403//===----------------------------------------------------------------------===//
404
405/// Returns the diagnostic engine for this context.
407
408//===----------------------------------------------------------------------===//
409// Remark Handlers
410//===----------------------------------------------------------------------===//
411
413 std::unique_ptr<remark::detail::RemarkEngine> engine) {
414 getImpl().remarkEngine = std::move(engine);
415}
416
420
421//===----------------------------------------------------------------------===//
422// Dialect and Operation Registration
423//===----------------------------------------------------------------------===//
424
426 if (registry.isSubsetOf(impl->dialectsRegistry))
427 return;
428
429 assert(impl->multiThreadedExecutionContext == 0 &&
430 "appending to the MLIRContext dialect registry while in a "
431 "multi-threaded execution context");
432 assert(!impl->transientState &&
433 "cannot append to dialect registry while in a transient scope");
434
435 registry.appendTo(impl->dialectsRegistry);
436
437 // For the already loaded dialects, apply any possible extensions immediately.
438 registry.applyExtensions(this);
439}
440
442 return impl->dialectsRegistry;
443}
444
445/// Return information about all registered IR dialects.
446std::vector<Dialect *> MLIRContext::getLoadedDialects() {
447 std::vector<Dialect *> result;
448 result.reserve(impl->loadedDialects.size());
449 for (auto &dialect : impl->loadedDialects)
450 result.push_back(dialect.second.get());
451 llvm::array_pod_sort(result.begin(), result.end(),
452 [](Dialect *const *lhs, Dialect *const *rhs) -> int {
453 return (*lhs)->getNamespace() < (*rhs)->getNamespace();
454 });
455 return result;
456}
457std::vector<StringRef> MLIRContext::getAvailableDialects() {
458 std::vector<StringRef> result;
459 for (auto dialect : impl->dialectsRegistry.getRegisteredDialectNames())
460 result.push_back(dialect);
461 return result;
462}
463
464/// Get a registered IR dialect with the given namespace. If none is found,
465/// then return nullptr.
467 // Dialects are sorted by name, so we can use binary search for lookup.
468 auto it = impl->loadedDialects.find(name);
469 return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
470}
471
473 Dialect *dialect = getLoadedDialect(name);
474 if (dialect)
475 return dialect;
477 impl->dialectsRegistry.getDialectAllocator(name);
478 return allocator ? allocator(this) : nullptr;
479}
480
481/// Get a dialect for the provided namespace and TypeID: abort the program if a
482/// dialect exist for this namespace with different TypeID. Returns a pointer to
483/// the dialect owned by the context.
484Dialect *
485MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
486 function_ref<std::unique_ptr<Dialect>()> ctor) {
487 auto &impl = getImpl();
488 // Get the correct insertion position sorted by namespace.
489 auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
490
491 if (dialectIt.second) {
492 LDBG() << "Load new dialect in Context " << dialectNamespace;
493 assert(!impl.transientState &&
494 "cannot load new dialects while in a transient scope");
495#ifndef NDEBUG
496 if (impl.multiThreadedExecutionContext != 0)
497 llvm::report_fatal_error(
498 "Loading a dialect (" + dialectNamespace +
499 ") while in a multi-threaded execution context (maybe "
500 "the PassManager): this can indicate a "
501 "missing `dependentDialects` in a pass for example.");
502#endif // NDEBUG
503 // loadedDialects entry is initialized to nullptr, indicating that the
504 // dialect is currently being loaded. Re-lookup the address in
505 // loadedDialects because the table might have been rehashed by recursive
506 // dialect loading in ctor().
507 std::unique_ptr<Dialect> &dialectOwned =
508 impl.loadedDialects[dialectNamespace] = ctor();
509 Dialect *dialect = dialectOwned.get();
510 assert(dialect && "dialect ctor failed");
511
512 // Refresh all the identifiers dialect field, this catches cases where a
513 // dialect may be loaded after identifier prefixed with this dialect name
514 // were already created.
515 auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
516 if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
517 for (StringAttrStorage *storage : stringAttrsIt->second)
518 storage->referencedDialect = dialect;
519 impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
520 }
521
522 // Apply any extensions to this newly loaded dialect.
523 impl.dialectsRegistry.applyExtensions(dialect);
524 return dialect;
525 }
526
527#ifndef NDEBUG
528 if (dialectIt.first->second == nullptr)
529 llvm::report_fatal_error(
530 "Loading (and getting) a dialect (" + dialectNamespace +
531 ") while the same dialect is still loading: use loadDialect instead "
532 "of getOrLoadDialect.");
533#endif // NDEBUG
534
535 // Abort if dialect with namespace has already been registered.
536 std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
537 if (dialect->getTypeID() != dialectID)
538 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
539 "' has already been registered");
540
541 return dialect.get();
542}
543
544bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
545 auto it = getImpl().loadedDialects.find(dialectNamespace);
546 // nullptr indicates that the dialect is currently being loaded.
547 return it != getImpl().loadedDialects.end() && it->second == nullptr;
548}
549
551 StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
552 auto &impl = getImpl();
553 // Get the correct insertion position sorted by namespace.
554 auto dialectIt = impl.loadedDialects.find(dialectNamespace);
555
556 if (dialectIt != impl.loadedDialects.end()) {
557 if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
558 return dynDialect;
559 llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
560 "' has already been registered");
561 }
562
563 LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
564#ifndef NDEBUG
565 if (impl.multiThreadedExecutionContext != 0)
566 llvm::report_fatal_error(
567 "Loading a dynamic dialect (" + dialectNamespace +
568 ") while in a multi-threaded execution context (maybe "
569 "the PassManager): this can indicate a "
570 "missing `dependentDialects` in a pass for example.");
571#endif
572
573 auto name = StringAttr::get(this, dialectNamespace);
574 auto *dialect = new DynamicDialect(name, this);
575 (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
576 ctor(dialect);
577 return std::unique_ptr<DynamicDialect>(dialect);
578 });
579 // This is the same result as `getOrLoadDialect` (if it didn't failed),
580 // since it has the same TypeID, and TypeIDs are unique.
581 return dialect;
582}
583
585 for (StringRef name : getAvailableDialects())
586 getOrLoadDialect(name);
587}
588
590 llvm::hash_code hash(0);
591 // Factor in number of loaded dialects, attributes, operations, types.
592 hash = llvm::hash_combine(hash, impl->loadedDialects.size());
593 hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
594 hash = llvm::hash_combine(hash, impl->registeredOperations.size());
595 hash = llvm::hash_combine(hash, impl->registeredTypes.size());
596 return hash;
597}
598
600 return impl->allowUnregisteredDialects;
601}
602
604 assert(impl->multiThreadedExecutionContext == 0 &&
605 "changing MLIRContext `allow-unregistered-dialects` configuration "
606 "while in a multi-threaded execution context");
607 impl->allowUnregisteredDialects = allowing;
608}
609
610/// Return true if multi-threading is enabled by the context.
612 return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
613}
614
615/// Set the flag specifying if multi-threading is disabled by the context.
617 // This API can be overridden by the global debugging flag
618 // --mlir-disable-threading
620 return;
621 assert(impl->multiThreadedExecutionContext == 0 &&
622 "changing MLIRContext `disable-threading` configuration while "
623 "in a multi-threaded execution context");
624
625 impl->threadingIsEnabled = !disable;
626
627 // Update the threading mode for each of the uniquers.
628 impl->affineUniquer.disableMultithreading(disable);
629 impl->attributeUniquer.disableMultithreading(disable);
630 impl->typeUniquer.disableMultithreading(disable);
631
632 // Destroy thread pool (stop all threads) if it is no longer needed, or create
633 // a new one if multithreading was re-enabled.
634 if (disable) {
635 // If the thread pool is owned, explicitly set it to nullptr to avoid
636 // keeping a dangling pointer around. If the thread pool is externally
637 // owned, we don't do anything.
638 if (impl->ownedThreadPool) {
639 assert(impl->threadPool);
640 impl->threadPool = nullptr;
641 impl->ownedThreadPool.reset();
642 }
643 } else if (!impl->threadPool) {
644 // The thread pool isn't externally provided.
645 assert(!impl->ownedThreadPool);
646 impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
647 impl->threadPool = impl->ownedThreadPool.get();
648 }
649}
650
651void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
652 assert(!isMultithreadingEnabled() &&
653 "expected multi-threading to be disabled when setting a ThreadPool");
654 impl->threadPool = &pool;
655 impl->ownedThreadPool.reset();
657}
658
661 assert(impl->threadPool &&
662 "multi-threading is enabled but threadpool not set");
663 return impl->threadPool->getMaxConcurrency();
664 }
665 // No multithreading or active thread pool. Return 1 thread.
666 return 1;
667}
668
669llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
670 assert(isMultithreadingEnabled() &&
671 "expected multi-threading to be enabled within the context");
672 assert(impl->threadPool &&
673 "multi-threading is enabled but threadpool not set");
674 return *impl->threadPool;
675}
676
678#ifndef NDEBUG
679 ++impl->multiThreadedExecutionContext;
680#endif
681}
683#ifndef NDEBUG
684 --impl->multiThreadedExecutionContext;
685#endif
686}
687
689 MLIRContextImpl &ctxImpl = getImpl();
690 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
691 "Beginning a transient scope while in a multi-threaded execution "
692 "context");
693 assert(!ctxImpl.transientState && "context is already in a transient scope");
694 ctxImpl.transientState =
695 std::make_unique<MLIRContextImpl::TransientScopeState>();
696
697 // Begin transient scope in the uniquers.
702
703 // Record base operations in operations map.
704 {
705 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
706 for (const auto &entry : ctxImpl.operations)
707 ctxImpl.transientState->baseOperations.insert(entry.first());
708 }
709
710 // Record dialect referencing string attribute counts.
711 {
712 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
713 for (const auto &entry : ctxImpl.dialectReferencingStrAttrs)
714 ctxImpl.transientState->baseDialectReferencingStrAttrCounts[entry.first] =
715 entry.second.size();
716 }
717}
718
720 MLIRContextImpl &ctxImpl = getImpl();
721 assert(ctxImpl.transientState && "context is not in a transient scope");
722 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
723 "Ending a transient scope while in a multi-threaded execution "
724 "context");
725 if (!ctxImpl.transientState)
726 return;
727
728 // Prune unregistered operations created during transient scope before
729 // destroying the attribute uniquer that holds their string attribute names.
730 {
731 llvm::sys::SmartScopedWriter<true> contextLock(ctxImpl.operationInfoMutex);
732 SmallVector<StringRef> opsToErase;
733 for (const auto &entry : ctxImpl.operations) {
734 if (!entry.second->isRegistered() &&
735 !ctxImpl.transientState->baseOperations.contains(entry.first()))
736 opsToErase.push_back(entry.first());
737 }
738 for (StringRef op : opsToErase)
739 ctxImpl.operations.erase(op);
740 }
741
742 // Restore dialect referencing string attributes before destroying the
743 // attribute uniquer that holds the underlying StringAttrStorage pointers.
744 // Note: Transient entries are always appended to the end of each dialect's
745 // vector, so truncating via resize() to the base count safely removes only
746 // transient entries while preserving base entries.
747 {
748 llvm::sys::SmartScopedLock<true> lock(ctxImpl.dialectRefStrAttrMutex);
749 SmallVector<StringRef> dialectsToErase;
750 for (auto &entry : ctxImpl.dialectReferencingStrAttrs) {
751 auto countIt =
752 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.find(
753 entry.first);
754 if (countIt ==
755 ctxImpl.transientState->baseDialectReferencingStrAttrCounts.end()) {
756 dialectsToErase.push_back(entry.first);
757 } else {
758 entry.second.resize(countIt->second);
759 }
760 }
761 for (StringRef dialect : dialectsToErase)
762 ctxImpl.dialectReferencingStrAttrs.erase(dialect);
763 }
764
765 // End transient scope in the uniquers now that all referencing structures
766 // are cleaned up.
771
772 ctxImpl.transientState.reset();
773}
774
776 return getImpl().transientState != nullptr;
777}
778
779/// Return true if we should attach the operation to diagnostics emitted via
780/// Operation::emit.
782 return impl->printOpOnDiagnostic;
783}
784
785/// Set the flag specifying if we should attach the operation to diagnostics
786/// emitted via Operation::emit.
788 assert(impl->multiThreadedExecutionContext == 0 &&
789 "changing MLIRContext `print-op-on-diagnostic` configuration while in "
790 "a multi-threaded execution context");
791 impl->printOpOnDiagnostic = enable;
792}
793
794/// Return true if we should attach the current stacktrace to diagnostics when
795/// emitted.
797 return impl->printStackTraceOnDiagnostic;
798}
799
800/// Set the flag specifying if we should attach the current stacktrace when
801/// emitting diagnostics.
803 assert(impl->multiThreadedExecutionContext == 0 &&
804 "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
805 "while in a multi-threaded execution context");
806 impl->printStackTraceOnDiagnostic = enable;
807}
808
809/// Return information about all registered operations.
811 return impl->sortedRegisteredOperations;
812}
813
814/// Return information for registered operations by dialect.
817 auto *lowerBound =
818 llvm::lower_bound(impl->sortedRegisteredOperations, dialectName,
819 [](const RegisteredOperationName &lhs, StringRef rhs) {
820 return lhs.getDialect().getNamespace() < rhs;
821 });
822
823 if (lowerBound == impl->sortedRegisteredOperations.end() ||
824 lowerBound->getDialect().getNamespace() != dialectName)
826
827 auto *upperBound = std::upper_bound(
828 lowerBound, impl->sortedRegisteredOperations.end(), dialectName,
829 [](StringRef lhs, const RegisteredOperationName &rhs) {
830 return lhs < rhs.getDialect().getNamespace();
831 });
832
833 size_t count = std::distance(lowerBound, upperBound);
834 return ArrayRef(&*lowerBound, count);
835}
836
838 return RegisteredOperationName::lookup(name, this).has_value();
839}
840
841void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
842 auto &impl = context->getImpl();
843 assert(impl.multiThreadedExecutionContext == 0 &&
844 "Registering a new type kind while in a multi-threaded execution "
845 "context");
846 auto *newInfo =
847 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
848 AbstractType(std::move(typeInfo));
849 if (!impl.registeredTypes.insert({typeID, newInfo}).second)
850 llvm::report_fatal_error("Dialect Type already registered.");
851 if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
852 llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
853 " is already registered.");
854}
855
857 auto &impl = context->getImpl();
858 assert(impl.multiThreadedExecutionContext == 0 &&
859 "Registering a new attribute kind while in a multi-threaded execution "
860 "context");
861 auto *newInfo =
862 new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
863 AbstractAttribute(std::move(attrInfo));
864 if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
865 llvm::report_fatal_error("Dialect Attribute already registered.");
866 if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
867 llvm::report_fatal_error("Dialect Attribute with name " +
868 newInfo->getName() + " is already registered.");
869}
870
871//===----------------------------------------------------------------------===//
872// AbstractAttribute
873//===----------------------------------------------------------------------===//
874
875/// Get the dialect that registered the attribute with the provided typeid.
876const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
877 MLIRContext *context) {
878 const AbstractAttribute *abstract = lookupMutable(typeID, context);
879 if (!abstract)
880 llvm::report_fatal_error("Trying to create an Attribute that was not "
881 "registered in this MLIRContext.");
882 return *abstract;
883}
884
885AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
886 MLIRContext *context) {
887 auto &impl = context->getImpl();
888 return impl.registeredAttributes.lookup(typeID);
889}
890
891std::optional<std::reference_wrapper<const AbstractAttribute>>
892AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
893 MLIRContextImpl &impl = context->getImpl();
894 const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
895
896 if (!type)
897 return std::nullopt;
898 return {*type};
899}
900
901//===----------------------------------------------------------------------===//
902// OperationName
903//===----------------------------------------------------------------------===//
904
909
910OperationName::OperationName(StringRef name, MLIRContext *context) {
911 MLIRContextImpl &ctxImpl = context->getImpl();
912
913 // Check for an existing name in read-only mode.
914 bool isMultithreadingEnabled = context->isMultithreadingEnabled();
915 if (isMultithreadingEnabled) {
916 // Check the registered info map first. In the overwhelmingly common case,
917 // the entry will be in here and it also removes the need to acquire any
918 // locks.
919 auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
920 if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
921 impl = registeredIt->second.impl;
922 return;
923 }
924
925 llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
926 auto it = ctxImpl.operations.find(name);
927 if (it != ctxImpl.operations.end()) {
928 impl = it->second.get();
929 return;
930 }
931 }
932
933 // Acquire a writer-lock so that we can safely create the new instance.
934 ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
935
936 auto it = ctxImpl.operations.try_emplace(name);
937 if (it.second) {
938 auto nameAttr = StringAttr::get(context, name);
939 it.first->second = std::make_unique<UnregisteredOpModel>(
940 nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
942 }
943 impl = it.first->second.get();
944}
945
947 if (Dialect *dialect = getDialect())
948 return dialect->getNamespace();
949 return getStringRef().split('.').first;
950}
951
952LogicalResult
960
963 llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
964}
968 Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
969 p.printGenericOp(op);
970}
971LogicalResult
975LogicalResult
979
980std::optional<Attribute>
982 StringRef name) {
983 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
984 if (!dict)
985 return std::nullopt;
986 if (Attribute attr = dict.get(name))
987 return attr;
988 return std::nullopt;
989}
991 StringAttr name,
992 Attribute value) {
993 auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
994 assert(dict);
995 NamedAttrList attrs(dict);
996 attrs.set(name, value);
997 *op->getPropertiesStorage().as<Attribute *>() =
998 attrs.getDictionary(op->getContext());
999}
1011 PropertyRef storage,
1012 PropertyRef init) {
1013 new (storage.as<Attribute *>()) Attribute();
1014 if (init)
1015 *storage.as<Attribute *>() = *init.as<Attribute *>();
1016}
1023 OperationName opName, PropertyRef properties, Attribute attr,
1025 *properties.as<Attribute *>() = attr;
1026 return success();
1027}
1033 PropertyRef rhs) {
1034 *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
1035}
1037 PropertyRef rhs) {
1038 return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
1039}
1040llvm::hash_code
1042 return llvm::hash_combine(*prop.as<Attribute *>());
1043}
1044
1045//===----------------------------------------------------------------------===//
1046// RegisteredOperationName
1047//===----------------------------------------------------------------------===//
1048
1049std::optional<RegisteredOperationName>
1051 auto &impl = ctx->getImpl();
1052 auto it = impl.registeredOperations.find(typeID);
1053 if (it != impl.registeredOperations.end())
1054 return it->second;
1055 return std::nullopt;
1056}
1057
1058std::optional<RegisteredOperationName>
1060 auto &impl = ctx->getImpl();
1061 auto it = impl.registeredOperationsByName.find(name);
1062 if (it != impl.registeredOperationsByName.end())
1063 return it->getValue();
1064 return std::nullopt;
1065}
1066
1068 std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
1069 ArrayRef<StringRef> attrNames) {
1070 RegisteredOperationName::Impl *impl = ownedImpl.get();
1071 MLIRContext *ctx = impl->getDialect()->getContext();
1072 auto &ctxImpl = ctx->getImpl();
1073 assert(ctxImpl.multiThreadedExecutionContext == 0 &&
1074 "registering a new operation kind while in a multi-threaded execution "
1075 "context");
1076
1077 // Register the attribute names of this operation.
1078 MutableArrayRef<StringAttr> cachedAttrNames;
1079 if (!attrNames.empty()) {
1080 cachedAttrNames = MutableArrayRef<StringAttr>(
1081 ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
1082 attrNames.size()),
1083 attrNames.size());
1084 for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
1085 new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
1086 impl->attributeNames = cachedAttrNames;
1087 }
1088 StringRef name = impl->getName().strref();
1089 // Insert the operation info if it doesn't exist yet.
1090 ctxImpl.operations[name] = std::move(ownedImpl);
1091
1092 // Update the registered info for this operation.
1093 auto emplaced = ctxImpl.registeredOperations.try_emplace(
1094 impl->getTypeID(), RegisteredOperationName(impl));
1095 assert(emplaced.second && "operation name registration must be successful");
1096 auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
1098 (void)emplacedByName;
1099 assert(emplacedByName.second &&
1100 "operation name registration must be successful");
1101
1102 // Add emplaced operation name to the sorted operations container.
1103 RegisteredOperationName &value = emplaced.first->second;
1104 ctxImpl.sortedRegisteredOperations.insert(
1105 llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1106 [](auto &lhs, auto &rhs) {
1107 return lhs.getIdentifier().strref() <
1108 rhs.getIdentifier().strref();
1109 }),
1110 value);
1111}
1112
1113void *RegisteredOperationName::allocateModelStorage() {
1114 return ::operator new(sizeof(Impl));
1115}
1116
1117//===----------------------------------------------------------------------===//
1118// AbstractType
1119//===----------------------------------------------------------------------===//
1120
1121const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
1122 const AbstractType *type = lookupMutable(typeID, context);
1123 if (!type)
1124 llvm::report_fatal_error(
1125 "Trying to create a Type that was not registered in this MLIRContext.");
1126 return *type;
1127}
1128
1129AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1130 auto &impl = context->getImpl();
1131 return impl.registeredTypes.lookup(typeID);
1132}
1133
1134std::optional<std::reference_wrapper<const AbstractType>>
1135AbstractType::lookup(StringRef name, MLIRContext *context) {
1136 MLIRContextImpl &impl = context->getImpl();
1137 const AbstractType *type = impl.nameToType.lookup(name);
1138
1139 if (!type)
1140 return std::nullopt;
1141 return {*type};
1142}
1143
1144//===----------------------------------------------------------------------===//
1145// Type uniquing
1146//===----------------------------------------------------------------------===//
1147
1148/// Returns the storage uniquer used for constructing type storage instances.
1149/// This should not be used directly.
1151
1152BFloat16Type BFloat16Type::get(MLIRContext *context) {
1153 return context->getImpl().bf16Ty;
1154}
1155Float16Type Float16Type::get(MLIRContext *context) {
1156 return context->getImpl().f16Ty;
1157}
1158FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1159 return context->getImpl().tf32Ty;
1160}
1161Float32Type Float32Type::get(MLIRContext *context) {
1162 return context->getImpl().f32Ty;
1163}
1164Float64Type Float64Type::get(MLIRContext *context) {
1165 return context->getImpl().f64Ty;
1166}
1167Float80Type Float80Type::get(MLIRContext *context) {
1168 return context->getImpl().f80Ty;
1169}
1170Float128Type Float128Type::get(MLIRContext *context) {
1171 return context->getImpl().f128Ty;
1172}
1173
1174/// Get an instance of the IndexType.
1175IndexType IndexType::get(MLIRContext *context) {
1176 return context->getImpl().indexTy;
1177}
1178
1179/// Return an existing integer type instance if one is cached within the
1180/// context.
1181static IntegerType
1183 IntegerType::SignednessSemantics signedness,
1184 MLIRContext *context) {
1185 if (signedness != IntegerType::Signless)
1186 return IntegerType();
1187
1188 switch (width) {
1189 case 1:
1190 return context->getImpl().int1Ty;
1191 case 8:
1192 return context->getImpl().int8Ty;
1193 case 16:
1194 return context->getImpl().int16Ty;
1195 case 32:
1196 return context->getImpl().int32Ty;
1197 case 64:
1198 return context->getImpl().int64Ty;
1199 case 128:
1200 return context->getImpl().int128Ty;
1201 default:
1202 return IntegerType();
1203 }
1204}
1205
1206IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1207 IntegerType::SignednessSemantics signedness) {
1208 if (auto cached = getCachedIntegerType(width, signedness, context))
1209 return cached;
1210 return Base::get(context, width, signedness);
1211}
1212
1213IntegerType
1214IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1215 MLIRContext *context, unsigned width,
1216 SignednessSemantics signedness) {
1217 if (auto cached = getCachedIntegerType(width, signedness, context))
1218 return cached;
1219 return Base::getChecked(emitError, context, width, signedness);
1220}
1221
1222/// Get an instance of the NoneType.
1223NoneType NoneType::get(MLIRContext *context) {
1224 if (NoneType cachedInst = context->getImpl().noneType)
1225 return cachedInst;
1226 // Note: May happen when initializing the singleton attributes of the builtin
1227 // dialect.
1228 return Base::get(context);
1229}
1230
1231//===----------------------------------------------------------------------===//
1232// Attribute uniquing
1233//===----------------------------------------------------------------------===//
1234
1235/// Returns the storage uniquer used for constructing attribute storage
1236/// instances. This should not be used directly.
1238 return getImpl().attributeUniquer;
1239}
1240
1241/// Initialize the given attribute storage instance.
1242void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1243 MLIRContext *ctx,
1244 TypeID attrID) {
1246}
1247
1248BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1249 return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1250}
1251
1252UnitAttr UnitAttr::get(MLIRContext *context) {
1253 return context->getImpl().unitAttr;
1254}
1255
1256UnknownLoc UnknownLoc::get(MLIRContext *context) {
1257 return context->getImpl().unknownLocAttr;
1258}
1259
1260DistinctAttrStorage *
1261detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1262 Attribute referencedAttr) {
1263 return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1264}
1265
1266/// Return empty dictionary.
1267DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1268 return context->getImpl().emptyDictionaryAttr;
1269}
1270
1272 // Check for a dialect namespace prefix, if there isn't one we don't need to
1273 // do any additional initialization.
1274 auto dialectNamePair = value.split('.');
1275 if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1276 return;
1277
1278 // If one exists, we check to see if this dialect is loaded. If it is, we set
1279 // the dialect now, if it isn't we record this storage for initialization
1280 // later if the dialect ever gets loaded.
1281 if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1282 return;
1283
1284 MLIRContextImpl &impl = context->getImpl();
1285 llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1286 impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1287}
1288
1289/// Return an empty string.
1290StringAttr StringAttr::get(MLIRContext *context) {
1291 return context->getImpl().emptyStringAttr;
1292}
1293
1294//===----------------------------------------------------------------------===//
1295// AffineMap uniquing
1296//===----------------------------------------------------------------------===//
1297
1299 return getImpl().affineUniquer;
1300}
1301
1302AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1303 ArrayRef<AffineExpr> results,
1304 MLIRContext *context) {
1305 auto &impl = context->getImpl();
1306 auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1307 [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1308 symbolCount, results);
1309 return AffineMap(storage);
1310}
1311
1312/// Check whether the arguments passed to the AffineMap::get() are consistent.
1313/// This method checks whether the highest index of dimensional identifier
1314/// present in result expressions is less than `dimCount` and the highest index
1315/// of symbolic identifier present in result expressions is less than
1316/// `symbolCount`.
1317[[maybe_unused]] static bool
1318willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1319 ArrayRef<AffineExpr> results) {
1320 int64_t maxDimPosition = -1;
1321 int64_t maxSymbolPosition = -1;
1322 getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1323 maxSymbolPosition);
1324 if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1325 LDBG()
1326 << "maximum dimensional identifier position in result expression must "
1327 "be less than `dimCount` and maximum symbolic identifier position "
1328 "in result expression must be less than `symbolCount`";
1329 return false;
1330 }
1331 return true;
1332}
1333
1335 return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1336}
1337
1338AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1339 MLIRContext *context) {
1340 return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1341}
1342
1343AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1345 assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1346 return getImpl(dimCount, symbolCount, {result}, result.getContext());
1347}
1348
1349AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1350 ArrayRef<AffineExpr> results, MLIRContext *context) {
1351 assert(willBeValidAffineMap(dimCount, symbolCount, results));
1352 return getImpl(dimCount, symbolCount, results, context);
1353}
1354
1355//===----------------------------------------------------------------------===//
1356// Integer Sets: these are allocated into the bump pointer, and are immutable.
1357// Unlike AffineMap's, these are uniqued only if they are small.
1358//===----------------------------------------------------------------------===//
1359
1360IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1361 ArrayRef<AffineExpr> constraints,
1362 ArrayRef<bool> eqFlags) {
1363 // The number of constraints can't be zero.
1364 assert(!constraints.empty());
1365 assert(constraints.size() == eqFlags.size());
1366
1367 auto &impl = constraints[0].getContext()->getImpl();
1368 auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1369 [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1370 return IntegerSet(storage);
1371}
1372
1373//===----------------------------------------------------------------------===//
1374// StorageUniquerSupport
1375//===----------------------------------------------------------------------===//
1376
1377/// Utility method to generate a callback that can be used to generate a
1378/// diagnostic when checking the construction invariants of a storage object.
1379/// This is defined out-of-line to avoid the need to include Location.h.
1380llvm::unique_function<InFlightDiagnostic()>
1382 return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1383}
1384llvm::unique_function<InFlightDiagnostic()>
1386 return [=] { return emitError(loc); };
1387}
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
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
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
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:953
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 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.