MLIR  22.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 
9 #include "mlir/IR/MLIRContext.h"
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"
20 #include "mlir/IR/BuiltinDialect.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 
45 using namespace mlir;
46 using namespace mlir::detail;
47 
48 //===----------------------------------------------------------------------===//
49 // MLIRContext CommandLine Options
50 //===----------------------------------------------------------------------===//
51 
52 namespace {
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.
56 struct 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 
75 static 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 
97 namespace {
98 /// Utility writer lock that takes a runtime flag that specifies if we really
99 /// need to lock.
100 struct 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 
118 namespace 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.
122 public:
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
149  bool allowUnregisteredDialects = false;
150 
151  /// Enable support for multi-threading within MLIR.
152  bool threadingIsEnabled = true;
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.
163  bool printOpOnDiagnostic = true;
164 
165  /// If the current stack trace should be attached when emitting diagnostics.
166  bool printStackTraceOnDiagnostic = false;
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;
235  IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
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.
254  BoolAttr falseAttr, trueAttr;
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 public:
273  MLIRContextImpl(bool threadingIsEnabled)
274  : threadingIsEnabled(threadingIsEnabled) {
275  if (threadingIsEnabled) {
276  ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
277  threadPool = ownedThreadPool.get();
278  }
279  }
281  for (auto typeMapping : registeredTypes)
282  typeMapping.second->~AbstractType();
283  for (auto attrMapping : registeredAttributes)
284  attrMapping.second->~AbstractAttribute();
285  }
286 };
287 } // namespace mlir
288 
290  : MLIRContext(DialectRegistry(), setting) {}
291 
293  : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
295  // Initialize values based on the command line flags if they were provided.
296  if (clOptions.isConstructed()) {
297  printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
298  printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
299  }
300 
301  // Pre-populate the registry.
302  registry.appendTo(impl->dialectsRegistry);
303 
304  // Ensure the builtin dialect is always pre-loaded.
305  getOrLoadDialect<BuiltinDialect>();
306 
307  // Initialize several common attributes and types to avoid the need to lock
308  // the context when accessing them.
309 
310  //// Types.
311  /// Floating-point Types.
312  impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
313  impl->f16Ty = TypeUniquer::get<Float16Type>(this);
314  impl->tf32Ty = TypeUniquer::get<FloatTF32Type>(this);
315  impl->f32Ty = TypeUniquer::get<Float32Type>(this);
316  impl->f64Ty = TypeUniquer::get<Float64Type>(this);
317  impl->f80Ty = TypeUniquer::get<Float80Type>(this);
318  impl->f128Ty = TypeUniquer::get<Float128Type>(this);
319  /// Index Type.
320  impl->indexTy = TypeUniquer::get<IndexType>(this);
321  /// Integer Types.
322  impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
323  impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
324  impl->int16Ty =
325  TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
326  impl->int32Ty =
327  TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
328  impl->int64Ty =
329  TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
330  impl->int128Ty =
331  TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
332  /// None Type.
333  impl->noneType = TypeUniquer::get<NoneType>(this);
334 
335  //// Attributes.
336  //// Note: These must be registered after the types as they may generate one
337  //// of the above types internally.
338  /// Unknown Location Attribute.
339  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
340  /// Bool Attributes.
341  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
342  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
343  /// Unit Attribute.
344  impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
345  /// The empty dictionary attribute.
346  impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
347  /// The empty string attribute.
348  impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
349 
350  // Register the affine storage objects with the uniquer.
351  impl->affineUniquer
352  .registerParametricStorageType<AffineBinaryOpExprStorage>();
353  impl->affineUniquer
354  .registerParametricStorageType<AffineConstantExprStorage>();
355  impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
356  impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
357  impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
358 }
359 
361  // finalize remark engine before destroying anything else.
362  impl->remarkEngine.reset();
363 }
364 
365 /// Copy the specified array of elements into memory managed by the provided
366 /// bump pointer allocator. This assumes the elements are all PODs.
367 template <typename T>
368 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
369  ArrayRef<T> elements) {
370  auto result = allocator.Allocate<T>(elements.size());
371  llvm::uninitialized_copy(elements, result);
372  return ArrayRef<T>(result, elements.size());
373 }
374 
375 //===----------------------------------------------------------------------===//
376 // Action Handling
377 //===----------------------------------------------------------------------===//
378 
380  getImpl().actionHandler = std::move(handler);
381 }
382 
383 /// Dispatch the provided action to the handler if any, or just execute it.
384 void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
385  const tracing::Action &action) {
386  assert(getImpl().actionHandler);
387  getImpl().actionHandler(actionFn, action);
388 }
389 
391 
392 //===----------------------------------------------------------------------===//
393 // Diagnostic Handlers
394 //===----------------------------------------------------------------------===//
395 
396 /// Returns the diagnostic engine for this context.
398 
399 //===----------------------------------------------------------------------===//
400 // Remark Handlers
401 //===----------------------------------------------------------------------===//
402 
404  std::unique_ptr<remark::detail::RemarkEngine> engine) {
405  getImpl().remarkEngine = std::move(engine);
406 }
407 
409  return getImpl().remarkEngine.get();
410 }
411 
412 //===----------------------------------------------------------------------===//
413 // Dialect and Operation Registration
414 //===----------------------------------------------------------------------===//
415 
417  if (registry.isSubsetOf(impl->dialectsRegistry))
418  return;
419 
420  assert(impl->multiThreadedExecutionContext == 0 &&
421  "appending to the MLIRContext dialect registry while in a "
422  "multi-threaded execution context");
423  registry.appendTo(impl->dialectsRegistry);
424 
425  // For the already loaded dialects, apply any possible extensions immediately.
426  registry.applyExtensions(this);
427 }
428 
430  return impl->dialectsRegistry;
431 }
432 
433 /// Return information about all registered IR dialects.
434 std::vector<Dialect *> MLIRContext::getLoadedDialects() {
435  std::vector<Dialect *> result;
436  result.reserve(impl->loadedDialects.size());
437  for (auto &dialect : impl->loadedDialects)
438  result.push_back(dialect.second.get());
439  llvm::array_pod_sort(result.begin(), result.end(),
440  [](Dialect *const *lhs, Dialect *const *rhs) -> int {
441  return (*lhs)->getNamespace() < (*rhs)->getNamespace();
442  });
443  return result;
444 }
445 std::vector<StringRef> MLIRContext::getAvailableDialects() {
446  std::vector<StringRef> result;
447  for (auto dialect : impl->dialectsRegistry.getDialectNames())
448  result.push_back(dialect);
449  return result;
450 }
451 
452 /// Get a registered IR dialect with the given namespace. If none is found,
453 /// then return nullptr.
455  // Dialects are sorted by name, so we can use binary search for lookup.
456  auto it = impl->loadedDialects.find(name);
457  return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
458 }
459 
461  Dialect *dialect = getLoadedDialect(name);
462  if (dialect)
463  return dialect;
464  DialectAllocatorFunctionRef allocator =
465  impl->dialectsRegistry.getDialectAllocator(name);
466  return allocator ? allocator(this) : nullptr;
467 }
468 
469 /// Get a dialect for the provided namespace and TypeID: abort the program if a
470 /// dialect exist for this namespace with different TypeID. Returns a pointer to
471 /// the dialect owned by the context.
472 Dialect *
473 MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
474  function_ref<std::unique_ptr<Dialect>()> ctor) {
475  auto &impl = getImpl();
476  // Get the correct insertion position sorted by namespace.
477  auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
478 
479  if (dialectIt.second) {
480  LDBG() << "Load new dialect in Context " << dialectNamespace;
481 #ifndef NDEBUG
482  if (impl.multiThreadedExecutionContext != 0)
483  llvm::report_fatal_error(
484  "Loading a dialect (" + dialectNamespace +
485  ") while in a multi-threaded execution context (maybe "
486  "the PassManager): this can indicate a "
487  "missing `dependentDialects` in a pass for example.");
488 #endif // NDEBUG
489  // loadedDialects entry is initialized to nullptr, indicating that the
490  // dialect is currently being loaded. Re-lookup the address in
491  // loadedDialects because the table might have been rehashed by recursive
492  // dialect loading in ctor().
493  std::unique_ptr<Dialect> &dialectOwned =
494  impl.loadedDialects[dialectNamespace] = ctor();
495  Dialect *dialect = dialectOwned.get();
496  assert(dialect && "dialect ctor failed");
497 
498  // Refresh all the identifiers dialect field, this catches cases where a
499  // dialect may be loaded after identifier prefixed with this dialect name
500  // were already created.
501  auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
502  if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
503  for (StringAttrStorage *storage : stringAttrsIt->second)
504  storage->referencedDialect = dialect;
505  impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
506  }
507 
508  // Apply any extensions to this newly loaded dialect.
509  impl.dialectsRegistry.applyExtensions(dialect);
510  return dialect;
511  }
512 
513 #ifndef NDEBUG
514  if (dialectIt.first->second == nullptr)
515  llvm::report_fatal_error(
516  "Loading (and getting) a dialect (" + dialectNamespace +
517  ") while the same dialect is still loading: use loadDialect instead "
518  "of getOrLoadDialect.");
519 #endif // NDEBUG
520 
521  // Abort if dialect with namespace has already been registered.
522  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
523  if (dialect->getTypeID() != dialectID)
524  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
525  "' has already been registered");
526 
527  return dialect.get();
528 }
529 
530 bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
531  auto it = getImpl().loadedDialects.find(dialectNamespace);
532  // nullptr indicates that the dialect is currently being loaded.
533  return it != getImpl().loadedDialects.end() && it->second == nullptr;
534 }
535 
537  StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
538  auto &impl = getImpl();
539  // Get the correct insertion position sorted by namespace.
540  auto dialectIt = impl.loadedDialects.find(dialectNamespace);
541 
542  if (dialectIt != impl.loadedDialects.end()) {
543  if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
544  return dynDialect;
545  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
546  "' has already been registered");
547  }
548 
549  LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
550 #ifndef NDEBUG
551  if (impl.multiThreadedExecutionContext != 0)
552  llvm::report_fatal_error(
553  "Loading a dynamic dialect (" + dialectNamespace +
554  ") while in a multi-threaded execution context (maybe "
555  "the PassManager): this can indicate a "
556  "missing `dependentDialects` in a pass for example.");
557 #endif
558 
559  auto name = StringAttr::get(this, dialectNamespace);
560  auto *dialect = new DynamicDialect(name, this);
561  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
562  ctor(dialect);
563  return std::unique_ptr<DynamicDialect>(dialect);
564  });
565  // This is the same result as `getOrLoadDialect` (if it didn't failed),
566  // since it has the same TypeID, and TypeIDs are unique.
567  return dialect;
568 }
569 
571  for (StringRef name : getAvailableDialects())
572  getOrLoadDialect(name);
573 }
574 
575 llvm::hash_code MLIRContext::getRegistryHash() {
576  llvm::hash_code hash(0);
577  // Factor in number of loaded dialects, attributes, operations, types.
578  hash = llvm::hash_combine(hash, impl->loadedDialects.size());
579  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
580  hash = llvm::hash_combine(hash, impl->registeredOperations.size());
581  hash = llvm::hash_combine(hash, impl->registeredTypes.size());
582  return hash;
583 }
584 
586  return impl->allowUnregisteredDialects;
587 }
588 
590  assert(impl->multiThreadedExecutionContext == 0 &&
591  "changing MLIRContext `allow-unregistered-dialects` configuration "
592  "while in a multi-threaded execution context");
593  impl->allowUnregisteredDialects = allowing;
594 }
595 
596 /// Return true if multi-threading is enabled by the context.
598  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
599 }
600 
601 /// Set the flag specifying if multi-threading is disabled by the context.
603  // This API can be overridden by the global debugging flag
604  // --mlir-disable-threading
606  return;
607  assert(impl->multiThreadedExecutionContext == 0 &&
608  "changing MLIRContext `disable-threading` configuration while "
609  "in a multi-threaded execution context");
610 
611  impl->threadingIsEnabled = !disable;
612 
613  // Update the threading mode for each of the uniquers.
614  impl->affineUniquer.disableMultithreading(disable);
615  impl->attributeUniquer.disableMultithreading(disable);
616  impl->typeUniquer.disableMultithreading(disable);
617 
618  // Destroy thread pool (stop all threads) if it is no longer needed, or create
619  // a new one if multithreading was re-enabled.
620  if (disable) {
621  // If the thread pool is owned, explicitly set it to nullptr to avoid
622  // keeping a dangling pointer around. If the thread pool is externally
623  // owned, we don't do anything.
624  if (impl->ownedThreadPool) {
625  assert(impl->threadPool);
626  impl->threadPool = nullptr;
627  impl->ownedThreadPool.reset();
628  }
629  } else if (!impl->threadPool) {
630  // The thread pool isn't externally provided.
631  assert(!impl->ownedThreadPool);
632  impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
633  impl->threadPool = impl->ownedThreadPool.get();
634  }
635 }
636 
637 void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
638  assert(!isMultithreadingEnabled() &&
639  "expected multi-threading to be disabled when setting a ThreadPool");
640  impl->threadPool = &pool;
641  impl->ownedThreadPool.reset();
643 }
644 
646  if (isMultithreadingEnabled()) {
647  assert(impl->threadPool &&
648  "multi-threading is enabled but threadpool not set");
649  return impl->threadPool->getMaxConcurrency();
650  }
651  // No multithreading or active thread pool. Return 1 thread.
652  return 1;
653 }
654 
655 llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
656  assert(isMultithreadingEnabled() &&
657  "expected multi-threading to be enabled within the context");
658  assert(impl->threadPool &&
659  "multi-threading is enabled but threadpool not set");
660  return *impl->threadPool;
661 }
662 
664 #ifndef NDEBUG
665  ++impl->multiThreadedExecutionContext;
666 #endif
667 }
669 #ifndef NDEBUG
670  --impl->multiThreadedExecutionContext;
671 #endif
672 }
673 
674 /// Return true if we should attach the operation to diagnostics emitted via
675 /// Operation::emit.
677  return impl->printOpOnDiagnostic;
678 }
679 
680 /// Set the flag specifying if we should attach the operation to diagnostics
681 /// emitted via Operation::emit.
683  assert(impl->multiThreadedExecutionContext == 0 &&
684  "changing MLIRContext `print-op-on-diagnostic` configuration while in "
685  "a multi-threaded execution context");
686  impl->printOpOnDiagnostic = enable;
687 }
688 
689 /// Return true if we should attach the current stacktrace to diagnostics when
690 /// emitted.
692  return impl->printStackTraceOnDiagnostic;
693 }
694 
695 /// Set the flag specifying if we should attach the current stacktrace when
696 /// emitting diagnostics.
698  assert(impl->multiThreadedExecutionContext == 0 &&
699  "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
700  "while in a multi-threaded execution context");
701  impl->printStackTraceOnDiagnostic = enable;
702 }
703 
704 /// Return information about all registered operations.
706  return impl->sortedRegisteredOperations;
707 }
708 
709 /// Return information for registered operations by dialect.
712  auto lowerBound = llvm::lower_bound(
713  impl->sortedRegisteredOperations, dialectName, [](auto &lhs, auto &rhs) {
714  return lhs.getDialect().getNamespace().compare(rhs);
715  });
716 
717  if (lowerBound == impl->sortedRegisteredOperations.end() ||
718  lowerBound->getDialect().getNamespace() != dialectName)
720 
721  auto upperBound =
722  std::upper_bound(lowerBound, impl->sortedRegisteredOperations.end(),
723  dialectName, [](auto &lhs, auto &rhs) {
724  return lhs.compare(rhs.getDialect().getNamespace());
725  });
726 
727  size_t count = std::distance(lowerBound, upperBound);
728  return ArrayRef(&*lowerBound, count);
729 }
730 
732  return RegisteredOperationName::lookup(name, this).has_value();
733 }
734 
735 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
736  auto &impl = context->getImpl();
737  assert(impl.multiThreadedExecutionContext == 0 &&
738  "Registering a new type kind while in a multi-threaded execution "
739  "context");
740  auto *newInfo =
741  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
742  AbstractType(std::move(typeInfo));
743  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
744  llvm::report_fatal_error("Dialect Type already registered.");
745  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
746  llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
747  " is already registered.");
748 }
749 
750 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
751  auto &impl = context->getImpl();
752  assert(impl.multiThreadedExecutionContext == 0 &&
753  "Registering a new attribute kind while in a multi-threaded execution "
754  "context");
755  auto *newInfo =
756  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
757  AbstractAttribute(std::move(attrInfo));
758  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
759  llvm::report_fatal_error("Dialect Attribute already registered.");
760  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
761  llvm::report_fatal_error("Dialect Attribute with name " +
762  newInfo->getName() + " is already registered.");
763 }
764 
765 //===----------------------------------------------------------------------===//
766 // AbstractAttribute
767 //===----------------------------------------------------------------------===//
768 
769 /// Get the dialect that registered the attribute with the provided typeid.
771  MLIRContext *context) {
772  const AbstractAttribute *abstract = lookupMutable(typeID, context);
773  if (!abstract)
774  llvm::report_fatal_error("Trying to create an Attribute that was not "
775  "registered in this MLIRContext.");
776  return *abstract;
777 }
778 
779 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
780  MLIRContext *context) {
781  auto &impl = context->getImpl();
782  return impl.registeredAttributes.lookup(typeID);
783 }
784 
785 std::optional<std::reference_wrapper<const AbstractAttribute>>
786 AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
787  MLIRContextImpl &impl = context->getImpl();
788  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
789 
790  if (!type)
791  return std::nullopt;
792  return {*type};
793 }
794 
795 //===----------------------------------------------------------------------===//
796 // OperationName
797 //===----------------------------------------------------------------------===//
798 
799 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
800  detail::InterfaceMap interfaceMap)
801  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
802  std::move(interfaceMap)) {}
803 
804 OperationName::OperationName(StringRef name, MLIRContext *context) {
805  MLIRContextImpl &ctxImpl = context->getImpl();
806 
807  // Check for an existing name in read-only mode.
808  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
809  if (isMultithreadingEnabled) {
810  // Check the registered info map first. In the overwhelmingly common case,
811  // the entry will be in here and it also removes the need to acquire any
812  // locks.
813  auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
814  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
815  impl = registeredIt->second.impl;
816  return;
817  }
818 
819  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
820  auto it = ctxImpl.operations.find(name);
821  if (it != ctxImpl.operations.end()) {
822  impl = it->second.get();
823  return;
824  }
825  }
826 
827  // Acquire a writer-lock so that we can safely create the new instance.
828  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
829 
830  auto it = ctxImpl.operations.try_emplace(name);
831  if (it.second) {
832  auto nameAttr = StringAttr::get(context, name);
833  it.first->second = std::make_unique<UnregisteredOpModel>(
834  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
836  }
837  impl = it.first->second.get();
838 }
839 
841  if (Dialect *dialect = getDialect())
842  return dialect->getNamespace();
843  return getStringRef().split('.').first;
844 }
845 
846 LogicalResult
849  return failure();
850 }
854 
857  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
858 }
860  const OperationName &, NamedAttrList &) {}
862  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
863  p.printGenericOp(op);
864 }
865 LogicalResult
867  return success();
868 }
869 LogicalResult
871  return success();
872 }
873 
874 std::optional<Attribute>
876  StringRef name) {
877  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
878  if (!dict)
879  return std::nullopt;
880  if (Attribute attr = dict.get(name))
881  return attr;
882  return std::nullopt;
883 }
885  StringAttr name,
886  Attribute value) {
887  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
888  assert(dict);
889  NamedAttrList attrs(dict);
890  attrs.set(name, value);
891  *op->getPropertiesStorage().as<Attribute *>() =
892  attrs.getDictionary(op->getContext());
893 }
895  Operation *op, NamedAttrList &attrs) {}
897  OperationName opName, NamedAttrList &attributes,
899  return success();
900 }
902  return sizeof(Attribute);
903 }
905  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
906  new (storage.as<Attribute *>()) Attribute();
907  if (init)
908  *storage.as<Attribute *>() = *init.as<Attribute *>();
909 }
911  OpaqueProperties prop) {
912  prop.as<Attribute *>()->~Attribute();
913 }
915  OperationName opName, OpaqueProperties properties) {}
917  OperationName opName, OpaqueProperties properties, Attribute attr,
919  *properties.as<Attribute *>() = attr;
920  return success();
921 }
922 Attribute
924  return *op->getPropertiesStorage().as<Attribute *>();
925 }
927  OpaqueProperties rhs) {
928  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
929 }
932  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
933 }
934 llvm::hash_code
936  return llvm::hash_combine(*prop.as<Attribute *>());
937 }
938 
939 //===----------------------------------------------------------------------===//
940 // RegisteredOperationName
941 //===----------------------------------------------------------------------===//
942 
943 std::optional<RegisteredOperationName>
945  auto &impl = ctx->getImpl();
946  auto it = impl.registeredOperations.find(typeID);
947  if (it != impl.registeredOperations.end())
948  return it->second;
949  return std::nullopt;
950 }
951 
952 std::optional<RegisteredOperationName>
954  auto &impl = ctx->getImpl();
955  auto it = impl.registeredOperationsByName.find(name);
956  if (it != impl.registeredOperationsByName.end())
957  return it->getValue();
958  return std::nullopt;
959 }
960 
962  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
963  ArrayRef<StringRef> attrNames) {
964  RegisteredOperationName::Impl *impl = ownedImpl.get();
965  MLIRContext *ctx = impl->getDialect()->getContext();
966  auto &ctxImpl = ctx->getImpl();
967  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
968  "registering a new operation kind while in a multi-threaded execution "
969  "context");
970 
971  // Register the attribute names of this operation.
972  MutableArrayRef<StringAttr> cachedAttrNames;
973  if (!attrNames.empty()) {
974  cachedAttrNames = MutableArrayRef<StringAttr>(
975  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
976  attrNames.size()),
977  attrNames.size());
978  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
979  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
980  impl->attributeNames = cachedAttrNames;
981  }
982  StringRef name = impl->getName().strref();
983  // Insert the operation info if it doesn't exist yet.
984  ctxImpl.operations[name] = std::move(ownedImpl);
985 
986  // Update the registered info for this operation.
987  auto emplaced = ctxImpl.registeredOperations.try_emplace(
988  impl->getTypeID(), RegisteredOperationName(impl));
989  assert(emplaced.second && "operation name registration must be successful");
990  auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
992  (void)emplacedByName;
993  assert(emplacedByName.second &&
994  "operation name registration must be successful");
995 
996  // Add emplaced operation name to the sorted operations container.
997  RegisteredOperationName &value = emplaced.first->second;
998  ctxImpl.sortedRegisteredOperations.insert(
999  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
1000  [](auto &lhs, auto &rhs) {
1001  return lhs.getIdentifier().compare(
1002  rhs.getIdentifier());
1003  }),
1004  value);
1005 }
1006 
1007 //===----------------------------------------------------------------------===//
1008 // AbstractType
1009 //===----------------------------------------------------------------------===//
1010 
1012  const AbstractType *type = lookupMutable(typeID, context);
1013  if (!type)
1014  llvm::report_fatal_error(
1015  "Trying to create a Type that was not registered in this MLIRContext.");
1016  return *type;
1017 }
1018 
1019 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1020  auto &impl = context->getImpl();
1021  return impl.registeredTypes.lookup(typeID);
1022 }
1023 
1024 std::optional<std::reference_wrapper<const AbstractType>>
1025 AbstractType::lookup(StringRef name, MLIRContext *context) {
1026  MLIRContextImpl &impl = context->getImpl();
1027  const AbstractType *type = impl.nameToType.lookup(name);
1028 
1029  if (!type)
1030  return std::nullopt;
1031  return {*type};
1032 }
1033 
1034 //===----------------------------------------------------------------------===//
1035 // Type uniquing
1036 //===----------------------------------------------------------------------===//
1037 
1038 /// Returns the storage uniquer used for constructing type storage instances.
1039 /// This should not be used directly.
1041 
1042 BFloat16Type BFloat16Type::get(MLIRContext *context) {
1043  return context->getImpl().bf16Ty;
1044 }
1045 Float16Type Float16Type::get(MLIRContext *context) {
1046  return context->getImpl().f16Ty;
1047 }
1048 FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1049  return context->getImpl().tf32Ty;
1050 }
1051 Float32Type Float32Type::get(MLIRContext *context) {
1052  return context->getImpl().f32Ty;
1053 }
1054 Float64Type Float64Type::get(MLIRContext *context) {
1055  return context->getImpl().f64Ty;
1056 }
1057 Float80Type Float80Type::get(MLIRContext *context) {
1058  return context->getImpl().f80Ty;
1059 }
1060 Float128Type Float128Type::get(MLIRContext *context) {
1061  return context->getImpl().f128Ty;
1062 }
1063 
1064 /// Get an instance of the IndexType.
1065 IndexType IndexType::get(MLIRContext *context) {
1066  return context->getImpl().indexTy;
1067 }
1068 
1069 /// Return an existing integer type instance if one is cached within the
1070 /// context.
1071 static IntegerType
1072 getCachedIntegerType(unsigned width,
1073  IntegerType::SignednessSemantics signedness,
1074  MLIRContext *context) {
1075  if (signedness != IntegerType::Signless)
1076  return IntegerType();
1077 
1078  switch (width) {
1079  case 1:
1080  return context->getImpl().int1Ty;
1081  case 8:
1082  return context->getImpl().int8Ty;
1083  case 16:
1084  return context->getImpl().int16Ty;
1085  case 32:
1086  return context->getImpl().int32Ty;
1087  case 64:
1088  return context->getImpl().int64Ty;
1089  case 128:
1090  return context->getImpl().int128Ty;
1091  default:
1092  return IntegerType();
1093  }
1094 }
1095 
1096 IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1097  IntegerType::SignednessSemantics signedness) {
1098  if (auto cached = getCachedIntegerType(width, signedness, context))
1099  return cached;
1100  return Base::get(context, width, signedness);
1101 }
1102 
1103 IntegerType
1104 IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1105  MLIRContext *context, unsigned width,
1106  SignednessSemantics signedness) {
1107  if (auto cached = getCachedIntegerType(width, signedness, context))
1108  return cached;
1109  return Base::getChecked(emitError, context, width, signedness);
1110 }
1111 
1112 /// Get an instance of the NoneType.
1113 NoneType NoneType::get(MLIRContext *context) {
1114  if (NoneType cachedInst = context->getImpl().noneType)
1115  return cachedInst;
1116  // Note: May happen when initializing the singleton attributes of the builtin
1117  // dialect.
1118  return Base::get(context);
1119 }
1120 
1121 //===----------------------------------------------------------------------===//
1122 // Attribute uniquing
1123 //===----------------------------------------------------------------------===//
1124 
1125 /// Returns the storage uniquer used for constructing attribute storage
1126 /// instances. This should not be used directly.
1128  return getImpl().attributeUniquer;
1129 }
1130 
1131 /// Initialize the given attribute storage instance.
1132 void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1133  MLIRContext *ctx,
1134  TypeID attrID) {
1136 }
1137 
1138 BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1139  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1140 }
1141 
1142 UnitAttr UnitAttr::get(MLIRContext *context) {
1143  return context->getImpl().unitAttr;
1144 }
1145 
1146 UnknownLoc UnknownLoc::get(MLIRContext *context) {
1147  return context->getImpl().unknownLocAttr;
1148 }
1149 
1151 detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1152  Attribute referencedAttr) {
1153  return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1154 }
1155 
1156 /// Return empty dictionary.
1157 DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1158  return context->getImpl().emptyDictionaryAttr;
1159 }
1160 
1161 void StringAttrStorage::initialize(MLIRContext *context) {
1162  // Check for a dialect namespace prefix, if there isn't one we don't need to
1163  // do any additional initialization.
1164  auto dialectNamePair = value.split('.');
1165  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1166  return;
1167 
1168  // If one exists, we check to see if this dialect is loaded. If it is, we set
1169  // the dialect now, if it isn't we record this storage for initialization
1170  // later if the dialect ever gets loaded.
1171  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1172  return;
1173 
1174  MLIRContextImpl &impl = context->getImpl();
1175  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1176  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1177 }
1178 
1179 /// Return an empty string.
1180 StringAttr StringAttr::get(MLIRContext *context) {
1181  return context->getImpl().emptyStringAttr;
1182 }
1183 
1184 //===----------------------------------------------------------------------===//
1185 // AffineMap uniquing
1186 //===----------------------------------------------------------------------===//
1187 
1189  return getImpl().affineUniquer;
1190 }
1191 
1192 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1193  ArrayRef<AffineExpr> results,
1194  MLIRContext *context) {
1195  auto &impl = context->getImpl();
1196  auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1197  [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1198  symbolCount, results);
1199  return AffineMap(storage);
1200 }
1201 
1202 /// Check whether the arguments passed to the AffineMap::get() are consistent.
1203 /// This method checks whether the highest index of dimensional identifier
1204 /// present in result expressions is less than `dimCount` and the highest index
1205 /// of symbolic identifier present in result expressions is less than
1206 /// `symbolCount`.
1207 LLVM_ATTRIBUTE_UNUSED static bool
1208 willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1209  ArrayRef<AffineExpr> results) {
1210  int64_t maxDimPosition = -1;
1211  int64_t maxSymbolPosition = -1;
1212  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1213  maxSymbolPosition);
1214  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1215  LDBG()
1216  << "maximum dimensional identifier position in result expression must "
1217  "be less than `dimCount` and maximum symbolic identifier position "
1218  "in result expression must be less than `symbolCount`";
1219  return false;
1220  }
1221  return true;
1222 }
1223 
1225  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1226 }
1227 
1228 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1229  MLIRContext *context) {
1230  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1231 }
1232 
1233 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1234  AffineExpr result) {
1235  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1236  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1237 }
1238 
1239 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1240  ArrayRef<AffineExpr> results, MLIRContext *context) {
1241  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1242  return getImpl(dimCount, symbolCount, results, context);
1243 }
1244 
1245 //===----------------------------------------------------------------------===//
1246 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1247 // Unlike AffineMap's, these are uniqued only if they are small.
1248 //===----------------------------------------------------------------------===//
1249 
1250 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1251  ArrayRef<AffineExpr> constraints,
1252  ArrayRef<bool> eqFlags) {
1253  // The number of constraints can't be zero.
1254  assert(!constraints.empty());
1255  assert(constraints.size() == eqFlags.size());
1256 
1257  auto &impl = constraints[0].getContext()->getImpl();
1258  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1259  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1260  return IntegerSet(storage);
1261 }
1262 
1263 //===----------------------------------------------------------------------===//
1264 // StorageUniquerSupport
1265 //===----------------------------------------------------------------------===//
1266 
1267 /// Utility method to generate a callback that can be used to generate a
1268 /// diagnostic when checking the construction invariants of a storage object.
1269 /// This is defined out-of-line to avoid the need to include Location.h.
1270 llvm::unique_function<InFlightDiagnostic()>
1272  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1273 }
1274 llvm::unique_function<InFlightDiagnostic()>
1276  return [=] { return emitError(loc); };
1277 }
static MLIRContext * getContext(OpFoldResult val)
static LLVM_ATTRIBUTE_UNUSED bool willBeValidAffineMap(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > results)
Check whether the arguments passed to the AffineMap::get() are consistent.
static bool isThreadingGloballyDisabled()
Definition: MLIRContext.cpp:77
static ArrayRef< T > copyArrayRefInto(llvm::BumpPtrAllocator &allocator, ArrayRef< T > elements)
Copy the specified array of elements into memory managed by the provided bump pointer allocator.
static llvm::ManagedStatic< MLIRContextOptions > clOptions
Definition: MLIRContext.cpp:75
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
MLIRContext * getContext() const
Definition: AffineExpr.cpp:31
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: () -> ().
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.
Definition: Diagnostics.h:414
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool isSubsetOf(const DialectRegistry &rhs) const
Returns true if the current registry is a subset of 'rhs', i.e.
Definition: Dialect.cpp:320
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition: Dialect.cpp:246
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:38
A dialect that can be defined at runtime.
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
An integer set representing a conjunction of one or more affine equalities and inequalities.
Definition: IntegerSet.h:44
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.
DictionaryAttr emptyDictionaryAttr
llvm::DenseMap< StringRef, AbstractAttribute * > nameToAttribute
This is a mapping from attribute name to the abstract attribute describing it.
DenseMap< StringRef, std::unique_ptr< Dialect > > loadedDialects
This is a list of dialects that are created referring to this context.
llvm::DenseMap< TypeID, RegisteredOperationName > registeredOperations
A vector of operation info specifically for registered operations.
BoolAttr falseAttr
Cached Attribute Instances.
llvm::sys::SmartRWMutex< true > operationInfoMutex
A mutex used when accessing operation information.
BFloat16Type bf16Ty
Cached Type Instances.
DenseMap< StringRef, SmallVector< StringAttrStorage * > > dialectReferencingStrAttrs
llvm::StringMap< RegisteredOperationName > registeredOperationsByName
StringAttr emptyStringAttr
std::function< void(function_ref< void()>, const tracing::Action &)> actionHandler
An action handler for handling actions that are dispatched through this context.
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
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
FloatTF32Type tf32Ty
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
bool shouldPrintStackTraceOnDiagnostic()
Return true if we should attach the current stacktrace to diagnostics when emitted.
unsigned getNumThreads()
Return the number of threads used by the thread pool in this context.
bool isOperationRegistered(StringRef name)
Return true if this operation name is registered in this context.
MLIRContext(Threading multithreading=Threading::ENABLED)
Create a new Context.
void disableMultithreading(bool disable=true)
Set the flag specifying if multi-threading is disabled by the context.
void printStackTraceOnDiagnostic(bool enable)
Set the flag specifying if we should attach the current stacktrace when emitting diagnostics.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool hasActionHandler()
Return true if a valid ActionHandler is set.
void setRemarkEngine(std::unique_ptr< remark::detail::RemarkEngine > engine)
Set the remark engine for this context.
void setThreadPool(llvm::ThreadPoolInterface &pool)
Set a new thread pool to be used in this context.
void enableMultithreading(bool enable=true)
Definition: MLIRContext.h:155
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.
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.
T * getLoadedDialect()
Get a registered IR dialect for the given derived dialect type.
Definition: MLIRContext.h:93
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
std::function< void(function_ref< void()>, const tracing::Action &)> HandlerTy
Signatures for the action handler that can be registered with the context.
Definition: MLIRContext.h:264
MLIRContextImpl & getImpl()
Definition: MLIRContext.h:213
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:100
void exitMultiThreadedExecution()
bool shouldPrintOpOnDiagnostic()
Return true if we should attach the operation to diagnostics emitted via Operation::emit.
void loadAllAvailableDialects()
Load all dialects available in the registry in this context.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printGenericOp(Operation *op, bool printOpName=true)=0
Print the entire operation with the default generic assembly form.
Simple wrapper around a void* in order to express generically how to pass in op properties through AP...
Impl(StringRef, Dialect *dialect, TypeID typeID, detail::InterfaceMap interfaceMap)
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
Impl * getImpl() const
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.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
Definition: Operation.h:900
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
A utility class to get or create instances of "storage classes".
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:107
An allocator for distinct attribute storage instances.
DistinctAttrStorage * allocate(Attribute referencedAttr)
This class provides an efficient mapping between a given Interface type, and a particular implementat...
An action is a specific action that is to be taken by the compiler, that can be toggled and controlle...
Definition: Action.h:38
AttrTypeReplacer.
llvm::unique_function< InFlightDiagnostic()> getDefaultDiagnosticEmitFn(MLIRContext *ctx)
Utility method to generate a callback that can be used to generate a diagnostic when checking the con...
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Definition: MLIRContext.cpp:88
static void getMaxDimAndSymbol(ArrayRef< AffineExprContainer > exprsList, int64_t &maxDim, int64_t &maxSym)
Calculates maximum dimension and symbol positions from the expressions in exprsLists and stores them ...
Definition: AffineMap.h:697
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) final
llvm::hash_code hashProperties(OpaqueProperties) final
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
void deleteProperties(OpaqueProperties) final
LogicalResult setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic()> emitError) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
void populateDefaultProperties(OperationName opName, OpaqueProperties properties) final
OperationName::ParseAssemblyFn getParseAssemblyFn() final
LogicalResult verifyRegionInvariants(Operation *) final
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) final
Implementation for properties.
void getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) final
void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init) final
void populateDefaultAttrs(const OperationName &, NamedAttrList &) final
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final
LogicalResult verifyInvariants(Operation *) final
void copyProperties(OpaqueProperties, OpaqueProperties) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(OpaqueProperties, OpaqueProperties) final
A binary operation appearing in an affine expression.
An integer constant appearing in affine expression.
A dimensional or symbolic identifier appearing in an affine expression.
An attribute to store a distinct reference to another attribute.
Dialect * referencedDialect
If the string value contains a dialect namespace prefix (e.g.