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  // Debugging
125  //===--------------------------------------------------------------------===//
126 
127  /// An action handler for handling actions that are dispatched through this
128  /// context.
129  std::function<void(function_ref<void()>, const tracing::Action &)>
131 
132  //===--------------------------------------------------------------------===//
133  // Diagnostics
134  //===--------------------------------------------------------------------===//
136 
137  //===--------------------------------------------------------------------===//
138  // Remark
139  //===--------------------------------------------------------------------===//
140  std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;
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 
360 MLIRContext::~MLIRContext() = default;
361 
362 /// Copy the specified array of elements into memory managed by the provided
363 /// bump pointer allocator. This assumes the elements are all PODs.
364 template <typename T>
365 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
366  ArrayRef<T> elements) {
367  auto result = allocator.Allocate<T>(elements.size());
368  llvm::uninitialized_copy(elements, result);
369  return ArrayRef<T>(result, elements.size());
370 }
371 
372 //===----------------------------------------------------------------------===//
373 // Action Handling
374 //===----------------------------------------------------------------------===//
375 
377  getImpl().actionHandler = std::move(handler);
378 }
379 
380 /// Dispatch the provided action to the handler if any, or just execute it.
381 void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
382  const tracing::Action &action) {
383  assert(getImpl().actionHandler);
384  getImpl().actionHandler(actionFn, action);
385 }
386 
388 
389 //===----------------------------------------------------------------------===//
390 // Diagnostic Handlers
391 //===----------------------------------------------------------------------===//
392 
393 /// Returns the diagnostic engine for this context.
395 
396 //===----------------------------------------------------------------------===//
397 // Remark Handlers
398 //===----------------------------------------------------------------------===//
399 
401  std::unique_ptr<remark::detail::RemarkEngine> engine) {
402  getImpl().remarkEngine = std::move(engine);
403 }
404 
406  return getImpl().remarkEngine.get();
407 }
408 
409 //===----------------------------------------------------------------------===//
410 // Dialect and Operation Registration
411 //===----------------------------------------------------------------------===//
412 
414  if (registry.isSubsetOf(impl->dialectsRegistry))
415  return;
416 
417  assert(impl->multiThreadedExecutionContext == 0 &&
418  "appending to the MLIRContext dialect registry while in a "
419  "multi-threaded execution context");
420  registry.appendTo(impl->dialectsRegistry);
421 
422  // For the already loaded dialects, apply any possible extensions immediately.
423  registry.applyExtensions(this);
424 }
425 
427  return impl->dialectsRegistry;
428 }
429 
430 /// Return information about all registered IR dialects.
431 std::vector<Dialect *> MLIRContext::getLoadedDialects() {
432  std::vector<Dialect *> result;
433  result.reserve(impl->loadedDialects.size());
434  for (auto &dialect : impl->loadedDialects)
435  result.push_back(dialect.second.get());
436  llvm::array_pod_sort(result.begin(), result.end(),
437  [](Dialect *const *lhs, Dialect *const *rhs) -> int {
438  return (*lhs)->getNamespace() < (*rhs)->getNamespace();
439  });
440  return result;
441 }
442 std::vector<StringRef> MLIRContext::getAvailableDialects() {
443  std::vector<StringRef> result;
444  for (auto dialect : impl->dialectsRegistry.getDialectNames())
445  result.push_back(dialect);
446  return result;
447 }
448 
449 /// Get a registered IR dialect with the given namespace. If none is found,
450 /// then return nullptr.
452  // Dialects are sorted by name, so we can use binary search for lookup.
453  auto it = impl->loadedDialects.find(name);
454  return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
455 }
456 
458  Dialect *dialect = getLoadedDialect(name);
459  if (dialect)
460  return dialect;
461  DialectAllocatorFunctionRef allocator =
462  impl->dialectsRegistry.getDialectAllocator(name);
463  return allocator ? allocator(this) : nullptr;
464 }
465 
466 /// Get a dialect for the provided namespace and TypeID: abort the program if a
467 /// dialect exist for this namespace with different TypeID. Returns a pointer to
468 /// the dialect owned by the context.
469 Dialect *
470 MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
471  function_ref<std::unique_ptr<Dialect>()> ctor) {
472  auto &impl = getImpl();
473  // Get the correct insertion position sorted by namespace.
474  auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
475 
476  if (dialectIt.second) {
477  LDBG() << "Load new dialect in Context " << dialectNamespace;
478 #ifndef NDEBUG
479  if (impl.multiThreadedExecutionContext != 0)
480  llvm::report_fatal_error(
481  "Loading a dialect (" + dialectNamespace +
482  ") while in a multi-threaded execution context (maybe "
483  "the PassManager): this can indicate a "
484  "missing `dependentDialects` in a pass for example.");
485 #endif // NDEBUG
486  // loadedDialects entry is initialized to nullptr, indicating that the
487  // dialect is currently being loaded. Re-lookup the address in
488  // loadedDialects because the table might have been rehashed by recursive
489  // dialect loading in ctor().
490  std::unique_ptr<Dialect> &dialectOwned =
491  impl.loadedDialects[dialectNamespace] = ctor();
492  Dialect *dialect = dialectOwned.get();
493  assert(dialect && "dialect ctor failed");
494 
495  // Refresh all the identifiers dialect field, this catches cases where a
496  // dialect may be loaded after identifier prefixed with this dialect name
497  // were already created.
498  auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
499  if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
500  for (StringAttrStorage *storage : stringAttrsIt->second)
501  storage->referencedDialect = dialect;
502  impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
503  }
504 
505  // Apply any extensions to this newly loaded dialect.
506  impl.dialectsRegistry.applyExtensions(dialect);
507  return dialect;
508  }
509 
510 #ifndef NDEBUG
511  if (dialectIt.first->second == nullptr)
512  llvm::report_fatal_error(
513  "Loading (and getting) a dialect (" + dialectNamespace +
514  ") while the same dialect is still loading: use loadDialect instead "
515  "of getOrLoadDialect.");
516 #endif // NDEBUG
517 
518  // Abort if dialect with namespace has already been registered.
519  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
520  if (dialect->getTypeID() != dialectID)
521  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
522  "' has already been registered");
523 
524  return dialect.get();
525 }
526 
527 bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
528  auto it = getImpl().loadedDialects.find(dialectNamespace);
529  // nullptr indicates that the dialect is currently being loaded.
530  return it != getImpl().loadedDialects.end() && it->second == nullptr;
531 }
532 
534  StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
535  auto &impl = getImpl();
536  // Get the correct insertion position sorted by namespace.
537  auto dialectIt = impl.loadedDialects.find(dialectNamespace);
538 
539  if (dialectIt != impl.loadedDialects.end()) {
540  if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
541  return dynDialect;
542  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
543  "' has already been registered");
544  }
545 
546  LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;
547 #ifndef NDEBUG
548  if (impl.multiThreadedExecutionContext != 0)
549  llvm::report_fatal_error(
550  "Loading a dynamic dialect (" + dialectNamespace +
551  ") while in a multi-threaded execution context (maybe "
552  "the PassManager): this can indicate a "
553  "missing `dependentDialects` in a pass for example.");
554 #endif
555 
556  auto name = StringAttr::get(this, dialectNamespace);
557  auto *dialect = new DynamicDialect(name, this);
558  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
559  ctor(dialect);
560  return std::unique_ptr<DynamicDialect>(dialect);
561  });
562  // This is the same result as `getOrLoadDialect` (if it didn't failed),
563  // since it has the same TypeID, and TypeIDs are unique.
564  return dialect;
565 }
566 
568  for (StringRef name : getAvailableDialects())
569  getOrLoadDialect(name);
570 }
571 
572 llvm::hash_code MLIRContext::getRegistryHash() {
573  llvm::hash_code hash(0);
574  // Factor in number of loaded dialects, attributes, operations, types.
575  hash = llvm::hash_combine(hash, impl->loadedDialects.size());
576  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
577  hash = llvm::hash_combine(hash, impl->registeredOperations.size());
578  hash = llvm::hash_combine(hash, impl->registeredTypes.size());
579  return hash;
580 }
581 
583  return impl->allowUnregisteredDialects;
584 }
585 
587  assert(impl->multiThreadedExecutionContext == 0 &&
588  "changing MLIRContext `allow-unregistered-dialects` configuration "
589  "while in a multi-threaded execution context");
590  impl->allowUnregisteredDialects = allowing;
591 }
592 
593 /// Return true if multi-threading is enabled by the context.
595  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
596 }
597 
598 /// Set the flag specifying if multi-threading is disabled by the context.
600  // This API can be overridden by the global debugging flag
601  // --mlir-disable-threading
603  return;
604  assert(impl->multiThreadedExecutionContext == 0 &&
605  "changing MLIRContext `disable-threading` configuration while "
606  "in a multi-threaded execution context");
607 
608  impl->threadingIsEnabled = !disable;
609 
610  // Update the threading mode for each of the uniquers.
611  impl->affineUniquer.disableMultithreading(disable);
612  impl->attributeUniquer.disableMultithreading(disable);
613  impl->typeUniquer.disableMultithreading(disable);
614 
615  // Destroy thread pool (stop all threads) if it is no longer needed, or create
616  // a new one if multithreading was re-enabled.
617  if (disable) {
618  // If the thread pool is owned, explicitly set it to nullptr to avoid
619  // keeping a dangling pointer around. If the thread pool is externally
620  // owned, we don't do anything.
621  if (impl->ownedThreadPool) {
622  assert(impl->threadPool);
623  impl->threadPool = nullptr;
624  impl->ownedThreadPool.reset();
625  }
626  } else if (!impl->threadPool) {
627  // The thread pool isn't externally provided.
628  assert(!impl->ownedThreadPool);
629  impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
630  impl->threadPool = impl->ownedThreadPool.get();
631  }
632 }
633 
634 void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
635  assert(!isMultithreadingEnabled() &&
636  "expected multi-threading to be disabled when setting a ThreadPool");
637  impl->threadPool = &pool;
638  impl->ownedThreadPool.reset();
640 }
641 
643  if (isMultithreadingEnabled()) {
644  assert(impl->threadPool &&
645  "multi-threading is enabled but threadpool not set");
646  return impl->threadPool->getMaxConcurrency();
647  }
648  // No multithreading or active thread pool. Return 1 thread.
649  return 1;
650 }
651 
652 llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
653  assert(isMultithreadingEnabled() &&
654  "expected multi-threading to be enabled within the context");
655  assert(impl->threadPool &&
656  "multi-threading is enabled but threadpool not set");
657  return *impl->threadPool;
658 }
659 
661 #ifndef NDEBUG
662  ++impl->multiThreadedExecutionContext;
663 #endif
664 }
666 #ifndef NDEBUG
667  --impl->multiThreadedExecutionContext;
668 #endif
669 }
670 
671 /// Return true if we should attach the operation to diagnostics emitted via
672 /// Operation::emit.
674  return impl->printOpOnDiagnostic;
675 }
676 
677 /// Set the flag specifying if we should attach the operation to diagnostics
678 /// emitted via Operation::emit.
680  assert(impl->multiThreadedExecutionContext == 0 &&
681  "changing MLIRContext `print-op-on-diagnostic` configuration while in "
682  "a multi-threaded execution context");
683  impl->printOpOnDiagnostic = enable;
684 }
685 
686 /// Return true if we should attach the current stacktrace to diagnostics when
687 /// emitted.
689  return impl->printStackTraceOnDiagnostic;
690 }
691 
692 /// Set the flag specifying if we should attach the current stacktrace when
693 /// emitting diagnostics.
695  assert(impl->multiThreadedExecutionContext == 0 &&
696  "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
697  "while in a multi-threaded execution context");
698  impl->printStackTraceOnDiagnostic = enable;
699 }
700 
701 /// Return information about all registered operations.
703  return impl->sortedRegisteredOperations;
704 }
705 
706 /// Return information for registered operations by dialect.
709  auto lowerBound = llvm::lower_bound(
710  impl->sortedRegisteredOperations, dialectName, [](auto &lhs, auto &rhs) {
711  return lhs.getDialect().getNamespace().compare(rhs);
712  });
713 
714  if (lowerBound == impl->sortedRegisteredOperations.end() ||
715  lowerBound->getDialect().getNamespace() != dialectName)
717 
718  auto upperBound =
719  std::upper_bound(lowerBound, impl->sortedRegisteredOperations.end(),
720  dialectName, [](auto &lhs, auto &rhs) {
721  return lhs.compare(rhs.getDialect().getNamespace());
722  });
723 
724  size_t count = std::distance(lowerBound, upperBound);
725  return ArrayRef(&*lowerBound, count);
726 }
727 
729  return RegisteredOperationName::lookup(name, this).has_value();
730 }
731 
732 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
733  auto &impl = context->getImpl();
734  assert(impl.multiThreadedExecutionContext == 0 &&
735  "Registering a new type kind while in a multi-threaded execution "
736  "context");
737  auto *newInfo =
738  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
739  AbstractType(std::move(typeInfo));
740  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
741  llvm::report_fatal_error("Dialect Type already registered.");
742  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
743  llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
744  " is already registered.");
745 }
746 
747 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
748  auto &impl = context->getImpl();
749  assert(impl.multiThreadedExecutionContext == 0 &&
750  "Registering a new attribute kind while in a multi-threaded execution "
751  "context");
752  auto *newInfo =
753  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
754  AbstractAttribute(std::move(attrInfo));
755  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
756  llvm::report_fatal_error("Dialect Attribute already registered.");
757  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
758  llvm::report_fatal_error("Dialect Attribute with name " +
759  newInfo->getName() + " is already registered.");
760 }
761 
762 //===----------------------------------------------------------------------===//
763 // AbstractAttribute
764 //===----------------------------------------------------------------------===//
765 
766 /// Get the dialect that registered the attribute with the provided typeid.
768  MLIRContext *context) {
769  const AbstractAttribute *abstract = lookupMutable(typeID, context);
770  if (!abstract)
771  llvm::report_fatal_error("Trying to create an Attribute that was not "
772  "registered in this MLIRContext.");
773  return *abstract;
774 }
775 
776 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
777  MLIRContext *context) {
778  auto &impl = context->getImpl();
779  return impl.registeredAttributes.lookup(typeID);
780 }
781 
782 std::optional<std::reference_wrapper<const AbstractAttribute>>
783 AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
784  MLIRContextImpl &impl = context->getImpl();
785  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
786 
787  if (!type)
788  return std::nullopt;
789  return {*type};
790 }
791 
792 //===----------------------------------------------------------------------===//
793 // OperationName
794 //===----------------------------------------------------------------------===//
795 
796 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
797  detail::InterfaceMap interfaceMap)
798  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
799  std::move(interfaceMap)) {}
800 
801 OperationName::OperationName(StringRef name, MLIRContext *context) {
802  MLIRContextImpl &ctxImpl = context->getImpl();
803 
804  // Check for an existing name in read-only mode.
805  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
806  if (isMultithreadingEnabled) {
807  // Check the registered info map first. In the overwhelmingly common case,
808  // the entry will be in here and it also removes the need to acquire any
809  // locks.
810  auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
811  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
812  impl = registeredIt->second.impl;
813  return;
814  }
815 
816  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
817  auto it = ctxImpl.operations.find(name);
818  if (it != ctxImpl.operations.end()) {
819  impl = it->second.get();
820  return;
821  }
822  }
823 
824  // Acquire a writer-lock so that we can safely create the new instance.
825  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
826 
827  auto it = ctxImpl.operations.try_emplace(name);
828  if (it.second) {
829  auto nameAttr = StringAttr::get(context, name);
830  it.first->second = std::make_unique<UnregisteredOpModel>(
831  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
833  }
834  impl = it.first->second.get();
835 }
836 
838  if (Dialect *dialect = getDialect())
839  return dialect->getNamespace();
840  return getStringRef().split('.').first;
841 }
842 
843 LogicalResult
846  return failure();
847 }
851 
854  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
855 }
857  const OperationName &, NamedAttrList &) {}
859  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
860  p.printGenericOp(op);
861 }
862 LogicalResult
864  return success();
865 }
866 LogicalResult
868  return success();
869 }
870 
871 std::optional<Attribute>
873  StringRef name) {
874  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
875  if (!dict)
876  return std::nullopt;
877  if (Attribute attr = dict.get(name))
878  return attr;
879  return std::nullopt;
880 }
882  StringAttr name,
883  Attribute value) {
884  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
885  assert(dict);
886  NamedAttrList attrs(dict);
887  attrs.set(name, value);
888  *op->getPropertiesStorage().as<Attribute *>() =
889  attrs.getDictionary(op->getContext());
890 }
892  Operation *op, NamedAttrList &attrs) {}
894  OperationName opName, NamedAttrList &attributes,
896  return success();
897 }
899  return sizeof(Attribute);
900 }
902  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
903  new (storage.as<Attribute *>()) Attribute();
904  if (init)
905  *storage.as<Attribute *>() = *init.as<Attribute *>();
906 }
908  OpaqueProperties prop) {
909  prop.as<Attribute *>()->~Attribute();
910 }
912  OperationName opName, OpaqueProperties properties) {}
914  OperationName opName, OpaqueProperties properties, Attribute attr,
916  *properties.as<Attribute *>() = attr;
917  return success();
918 }
919 Attribute
921  return *op->getPropertiesStorage().as<Attribute *>();
922 }
924  OpaqueProperties rhs) {
925  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
926 }
929  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
930 }
931 llvm::hash_code
933  return llvm::hash_combine(*prop.as<Attribute *>());
934 }
935 
936 //===----------------------------------------------------------------------===//
937 // RegisteredOperationName
938 //===----------------------------------------------------------------------===//
939 
940 std::optional<RegisteredOperationName>
942  auto &impl = ctx->getImpl();
943  auto it = impl.registeredOperations.find(typeID);
944  if (it != impl.registeredOperations.end())
945  return it->second;
946  return std::nullopt;
947 }
948 
949 std::optional<RegisteredOperationName>
951  auto &impl = ctx->getImpl();
952  auto it = impl.registeredOperationsByName.find(name);
953  if (it != impl.registeredOperationsByName.end())
954  return it->getValue();
955  return std::nullopt;
956 }
957 
959  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
960  ArrayRef<StringRef> attrNames) {
961  RegisteredOperationName::Impl *impl = ownedImpl.get();
962  MLIRContext *ctx = impl->getDialect()->getContext();
963  auto &ctxImpl = ctx->getImpl();
964  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
965  "registering a new operation kind while in a multi-threaded execution "
966  "context");
967 
968  // Register the attribute names of this operation.
969  MutableArrayRef<StringAttr> cachedAttrNames;
970  if (!attrNames.empty()) {
971  cachedAttrNames = MutableArrayRef<StringAttr>(
972  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
973  attrNames.size()),
974  attrNames.size());
975  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
976  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
977  impl->attributeNames = cachedAttrNames;
978  }
979  StringRef name = impl->getName().strref();
980  // Insert the operation info if it doesn't exist yet.
981  ctxImpl.operations[name] = std::move(ownedImpl);
982 
983  // Update the registered info for this operation.
984  auto emplaced = ctxImpl.registeredOperations.try_emplace(
985  impl->getTypeID(), RegisteredOperationName(impl));
986  assert(emplaced.second && "operation name registration must be successful");
987  auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
989  (void)emplacedByName;
990  assert(emplacedByName.second &&
991  "operation name registration must be successful");
992 
993  // Add emplaced operation name to the sorted operations container.
994  RegisteredOperationName &value = emplaced.first->second;
995  ctxImpl.sortedRegisteredOperations.insert(
996  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
997  [](auto &lhs, auto &rhs) {
998  return lhs.getIdentifier().compare(
999  rhs.getIdentifier());
1000  }),
1001  value);
1002 }
1003 
1004 //===----------------------------------------------------------------------===//
1005 // AbstractType
1006 //===----------------------------------------------------------------------===//
1007 
1009  const AbstractType *type = lookupMutable(typeID, context);
1010  if (!type)
1011  llvm::report_fatal_error(
1012  "Trying to create a Type that was not registered in this MLIRContext.");
1013  return *type;
1014 }
1015 
1016 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1017  auto &impl = context->getImpl();
1018  return impl.registeredTypes.lookup(typeID);
1019 }
1020 
1021 std::optional<std::reference_wrapper<const AbstractType>>
1022 AbstractType::lookup(StringRef name, MLIRContext *context) {
1023  MLIRContextImpl &impl = context->getImpl();
1024  const AbstractType *type = impl.nameToType.lookup(name);
1025 
1026  if (!type)
1027  return std::nullopt;
1028  return {*type};
1029 }
1030 
1031 //===----------------------------------------------------------------------===//
1032 // Type uniquing
1033 //===----------------------------------------------------------------------===//
1034 
1035 /// Returns the storage uniquer used for constructing type storage instances.
1036 /// This should not be used directly.
1038 
1039 BFloat16Type BFloat16Type::get(MLIRContext *context) {
1040  return context->getImpl().bf16Ty;
1041 }
1042 Float16Type Float16Type::get(MLIRContext *context) {
1043  return context->getImpl().f16Ty;
1044 }
1045 FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1046  return context->getImpl().tf32Ty;
1047 }
1048 Float32Type Float32Type::get(MLIRContext *context) {
1049  return context->getImpl().f32Ty;
1050 }
1051 Float64Type Float64Type::get(MLIRContext *context) {
1052  return context->getImpl().f64Ty;
1053 }
1054 Float80Type Float80Type::get(MLIRContext *context) {
1055  return context->getImpl().f80Ty;
1056 }
1057 Float128Type Float128Type::get(MLIRContext *context) {
1058  return context->getImpl().f128Ty;
1059 }
1060 
1061 /// Get an instance of the IndexType.
1062 IndexType IndexType::get(MLIRContext *context) {
1063  return context->getImpl().indexTy;
1064 }
1065 
1066 /// Return an existing integer type instance if one is cached within the
1067 /// context.
1068 static IntegerType
1069 getCachedIntegerType(unsigned width,
1070  IntegerType::SignednessSemantics signedness,
1071  MLIRContext *context) {
1072  if (signedness != IntegerType::Signless)
1073  return IntegerType();
1074 
1075  switch (width) {
1076  case 1:
1077  return context->getImpl().int1Ty;
1078  case 8:
1079  return context->getImpl().int8Ty;
1080  case 16:
1081  return context->getImpl().int16Ty;
1082  case 32:
1083  return context->getImpl().int32Ty;
1084  case 64:
1085  return context->getImpl().int64Ty;
1086  case 128:
1087  return context->getImpl().int128Ty;
1088  default:
1089  return IntegerType();
1090  }
1091 }
1092 
1093 IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1094  IntegerType::SignednessSemantics signedness) {
1095  if (auto cached = getCachedIntegerType(width, signedness, context))
1096  return cached;
1097  return Base::get(context, width, signedness);
1098 }
1099 
1100 IntegerType
1101 IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1102  MLIRContext *context, unsigned width,
1103  SignednessSemantics signedness) {
1104  if (auto cached = getCachedIntegerType(width, signedness, context))
1105  return cached;
1106  return Base::getChecked(emitError, context, width, signedness);
1107 }
1108 
1109 /// Get an instance of the NoneType.
1110 NoneType NoneType::get(MLIRContext *context) {
1111  if (NoneType cachedInst = context->getImpl().noneType)
1112  return cachedInst;
1113  // Note: May happen when initializing the singleton attributes of the builtin
1114  // dialect.
1115  return Base::get(context);
1116 }
1117 
1118 //===----------------------------------------------------------------------===//
1119 // Attribute uniquing
1120 //===----------------------------------------------------------------------===//
1121 
1122 /// Returns the storage uniquer used for constructing attribute storage
1123 /// instances. This should not be used directly.
1125  return getImpl().attributeUniquer;
1126 }
1127 
1128 /// Initialize the given attribute storage instance.
1129 void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1130  MLIRContext *ctx,
1131  TypeID attrID) {
1133 }
1134 
1135 BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1136  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1137 }
1138 
1139 UnitAttr UnitAttr::get(MLIRContext *context) {
1140  return context->getImpl().unitAttr;
1141 }
1142 
1143 UnknownLoc UnknownLoc::get(MLIRContext *context) {
1144  return context->getImpl().unknownLocAttr;
1145 }
1146 
1148 detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1149  Attribute referencedAttr) {
1150  return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1151 }
1152 
1153 /// Return empty dictionary.
1154 DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1155  return context->getImpl().emptyDictionaryAttr;
1156 }
1157 
1158 void StringAttrStorage::initialize(MLIRContext *context) {
1159  // Check for a dialect namespace prefix, if there isn't one we don't need to
1160  // do any additional initialization.
1161  auto dialectNamePair = value.split('.');
1162  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1163  return;
1164 
1165  // If one exists, we check to see if this dialect is loaded. If it is, we set
1166  // the dialect now, if it isn't we record this storage for initialization
1167  // later if the dialect ever gets loaded.
1168  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1169  return;
1170 
1171  MLIRContextImpl &impl = context->getImpl();
1172  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1173  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1174 }
1175 
1176 /// Return an empty string.
1177 StringAttr StringAttr::get(MLIRContext *context) {
1178  return context->getImpl().emptyStringAttr;
1179 }
1180 
1181 //===----------------------------------------------------------------------===//
1182 // AffineMap uniquing
1183 //===----------------------------------------------------------------------===//
1184 
1186  return getImpl().affineUniquer;
1187 }
1188 
1189 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1190  ArrayRef<AffineExpr> results,
1191  MLIRContext *context) {
1192  auto &impl = context->getImpl();
1193  auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1194  [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1195  symbolCount, results);
1196  return AffineMap(storage);
1197 }
1198 
1199 /// Check whether the arguments passed to the AffineMap::get() are consistent.
1200 /// This method checks whether the highest index of dimensional identifier
1201 /// present in result expressions is less than `dimCount` and the highest index
1202 /// of symbolic identifier present in result expressions is less than
1203 /// `symbolCount`.
1204 LLVM_ATTRIBUTE_UNUSED static bool
1205 willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1206  ArrayRef<AffineExpr> results) {
1207  int64_t maxDimPosition = -1;
1208  int64_t maxSymbolPosition = -1;
1209  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1210  maxSymbolPosition);
1211  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1212  LDBG()
1213  << "maximum dimensional identifier position in result expression must "
1214  "be less than `dimCount` and maximum symbolic identifier position "
1215  "in result expression must be less than `symbolCount`";
1216  return false;
1217  }
1218  return true;
1219 }
1220 
1222  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1223 }
1224 
1225 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1226  MLIRContext *context) {
1227  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1228 }
1229 
1230 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1231  AffineExpr result) {
1232  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1233  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1234 }
1235 
1236 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1237  ArrayRef<AffineExpr> results, MLIRContext *context) {
1238  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1239  return getImpl(dimCount, symbolCount, results, context);
1240 }
1241 
1242 //===----------------------------------------------------------------------===//
1243 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1244 // Unlike AffineMap's, these are uniqued only if they are small.
1245 //===----------------------------------------------------------------------===//
1246 
1247 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1248  ArrayRef<AffineExpr> constraints,
1249  ArrayRef<bool> eqFlags) {
1250  // The number of constraints can't be zero.
1251  assert(!constraints.empty());
1252  assert(constraints.size() == eqFlags.size());
1253 
1254  auto &impl = constraints[0].getContext()->getImpl();
1255  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1256  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1257  return IntegerSet(storage);
1258 }
1259 
1260 //===----------------------------------------------------------------------===//
1261 // StorageUniquerSupport
1262 //===----------------------------------------------------------------------===//
1263 
1264 /// Utility method to generate a callback that can be used to generate a
1265 /// diagnostic when checking the construction invariants of a storage object.
1266 /// This is defined out-of-line to avoid the need to include Location.h.
1267 llvm::unique_function<InFlightDiagnostic()>
1269  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1270 }
1271 llvm::unique_function<InFlightDiagnostic()>
1273  return [=] { return emitError(loc); };
1274 }
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.