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