MLIR  20.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/Types.h"
29 #include "llvm/ADT/DenseMap.h"
30 #include "llvm/ADT/DenseSet.h"
31 #include "llvm/ADT/SmallString.h"
32 #include "llvm/ADT/StringSet.h"
33 #include "llvm/ADT/Twine.h"
34 #include "llvm/Support/Allocator.h"
35 #include "llvm/Support/CommandLine.h"
36 #include "llvm/Support/Compiler.h"
37 #include "llvm/Support/Debug.h"
38 #include "llvm/Support/Mutex.h"
39 #include "llvm/Support/RWMutex.h"
40 #include "llvm/Support/ThreadPool.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include <memory>
43 #include <optional>
44 
45 #define DEBUG_TYPE "mlircontext"
46 
47 using namespace mlir;
48 using namespace mlir::detail;
49 
50 //===----------------------------------------------------------------------===//
51 // MLIRContext CommandLine Options
52 //===----------------------------------------------------------------------===//
53 
54 namespace {
55 /// This struct contains command line options that can be used to initialize
56 /// various bits of an MLIRContext. This uses a struct wrapper to avoid the need
57 /// for global command line options.
58 struct MLIRContextOptions {
59  llvm::cl::opt<bool> disableThreading{
60  "mlir-disable-threading",
61  llvm::cl::desc("Disable multi-threading within MLIR, overrides any "
62  "further call to MLIRContext::enableMultiThreading()")};
63 
64  llvm::cl::opt<bool> printOpOnDiagnostic{
65  "mlir-print-op-on-diagnostic",
66  llvm::cl::desc("When a diagnostic is emitted on an operation, also print "
67  "the operation as an attached note"),
68  llvm::cl::init(true)};
69 
70  llvm::cl::opt<bool> printStackTraceOnDiagnostic{
71  "mlir-print-stacktrace-on-diagnostic",
72  llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "
73  "as an attached note")};
74 };
75 } // namespace
76 
77 static llvm::ManagedStatic<MLIRContextOptions> clOptions;
78 
80 #if LLVM_ENABLE_THREADS != 0
81  return clOptions.isConstructed() && clOptions->disableThreading;
82 #else
83  return true;
84 #endif
85 }
86 
87 /// Register a set of useful command-line options that can be used to configure
88 /// various flags within the MLIRContext. These flags are used when constructing
89 /// an MLIR context for initialization.
91  // Make sure that the options struct has been initialized.
92  *clOptions;
93 }
94 
95 //===----------------------------------------------------------------------===//
96 // Locking Utilities
97 //===----------------------------------------------------------------------===//
98 
99 namespace {
100 /// Utility writer lock that takes a runtime flag that specifies if we really
101 /// need to lock.
102 struct ScopedWriterLock {
103  ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)
104  : mutex(shouldLock ? &mutexParam : nullptr) {
105  if (mutex)
106  mutex->lock();
107  }
108  ~ScopedWriterLock() {
109  if (mutex)
110  mutex->unlock();
111  }
112  llvm::sys::SmartRWMutex<true> *mutex;
113 };
114 } // namespace
115 
116 //===----------------------------------------------------------------------===//
117 // MLIRContextImpl
118 //===----------------------------------------------------------------------===//
119 
120 namespace mlir {
121 /// This is the implementation of the MLIRContext class, using the pImpl idiom.
122 /// This class is completely private to this file, so everything is public.
124 public:
125  //===--------------------------------------------------------------------===//
126  // Debugging
127  //===--------------------------------------------------------------------===//
128 
129  /// An action handler for handling actions that are dispatched through this
130  /// context.
131  std::function<void(function_ref<void()>, const tracing::Action &)>
133 
134  //===--------------------------------------------------------------------===//
135  // Diagnostics
136  //===--------------------------------------------------------------------===//
138 
139  //===--------------------------------------------------------------------===//
140  // Options
141  //===--------------------------------------------------------------------===//
142 
143  /// In most cases, creating operation in unregistered dialect is not desired
144  /// and indicate a misconfiguration of the compiler. This option enables to
145  /// detect such use cases
146  bool allowUnregisteredDialects = false;
147 
148  /// Enable support for multi-threading within MLIR.
149  bool threadingIsEnabled = true;
150 
151  /// Track if we are currently executing in a threaded execution environment
152  /// (like the pass-manager): this is only a debugging feature to help reducing
153  /// the chances of data races one some context APIs.
154 #ifndef NDEBUG
155  std::atomic<int> multiThreadedExecutionContext{0};
156 #endif
157 
158  /// If the operation should be attached to diagnostics printed via the
159  /// Operation::emit methods.
160  bool printOpOnDiagnostic = true;
161 
162  /// If the current stack trace should be attached when emitting diagnostics.
163  bool printStackTraceOnDiagnostic = false;
164 
165  //===--------------------------------------------------------------------===//
166  // Other
167  //===--------------------------------------------------------------------===//
168 
169  /// This points to the ThreadPool used when processing MLIR tasks in parallel.
170  /// It can't be nullptr when multi-threading is enabled. Otherwise if
171  /// multi-threading is disabled, and the threadpool wasn't externally provided
172  /// using `setThreadPool`, this will be nullptr.
173  llvm::ThreadPoolInterface *threadPool = nullptr;
174 
175  /// In case where the thread pool is owned by the context, this ensures
176  /// destruction with the context.
177  std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
178 
179  /// An allocator used for AbstractAttribute and AbstractType objects.
180  llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
181 
182  /// This is a mapping from operation name to the operation info describing it.
183  llvm::StringMap<std::unique_ptr<OperationName::Impl>> operations;
184 
185  /// A vector of operation info specifically for registered operations.
187  llvm::StringMap<RegisteredOperationName> registeredOperationsByName;
188 
189  /// This is a sorted container of registered operations for a deterministic
190  /// and efficient `getRegisteredOperations` implementation.
192 
193  /// This is a list of dialects that are created referring to this context.
194  /// The MLIRContext owns the objects. These need to be declared after the
195  /// registered operations to ensure correct destruction order.
198 
199  /// A mutex used when accessing operation information.
200  llvm::sys::SmartRWMutex<true> operationInfoMutex;
201 
202  //===--------------------------------------------------------------------===//
203  // Affine uniquing
204  //===--------------------------------------------------------------------===//
205 
206  // Affine expression, map and integer set uniquing.
208 
209  //===--------------------------------------------------------------------===//
210  // Type uniquing
211  //===--------------------------------------------------------------------===//
212 
215 
216  /// This is a mapping from type name to the abstract type describing it.
217  /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.
218  /// As this map needs to be populated before `StringAttr` is loaded, we
219  /// cannot use `StringAttr` as the key. The context does not take ownership
220  /// of the key, so the `StringRef` must outlive the context.
222 
223  /// Cached Type Instances.
224  Float6E3M2FNType f6E3M2FNTy;
225  Float8E5M2Type f8E5M2Ty;
226  Float8E4M3Type f8E4M3Ty;
227  Float8E4M3FNType f8E4M3FNTy;
228  Float8E5M2FNUZType f8E5M2FNUZTy;
229  Float8E4M3FNUZType f8E4M3FNUZTy;
230  Float8E4M3B11FNUZType f8E4M3B11FNUZTy;
231  Float8E3M4Type f8E3M4Ty;
232  BFloat16Type bf16Ty;
233  Float16Type f16Ty;
234  FloatTF32Type tf32Ty;
235  Float32Type f32Ty;
236  Float64Type f64Ty;
237  Float80Type f80Ty;
238  Float128Type f128Ty;
239  IndexType indexTy;
240  IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
241  NoneType noneType;
242 
243  //===--------------------------------------------------------------------===//
244  // Attribute uniquing
245  //===--------------------------------------------------------------------===//
246 
249 
250  /// This is a mapping from attribute name to the abstract attribute describing
251  /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a
252  /// name.
253  /// As this map needs to be populated before `StringAttr` is loaded, we
254  /// cannot use `StringAttr` as the key. The context does not take ownership
255  /// of the key, so the `StringRef` must outlive the context.
257 
258  /// Cached Attribute Instances.
259  BoolAttr falseAttr, trueAttr;
260  UnitAttr unitAttr;
261  UnknownLoc unknownLocAttr;
262  DictionaryAttr emptyDictionaryAttr;
263  StringAttr emptyStringAttr;
264 
265  /// Map of string attributes that may reference a dialect, that are awaiting
266  /// that dialect to be loaded.
270 
271  /// A distinct attribute allocator that allocates every time since the
272  /// address of the distinct attribute storage serves as unique identifier. The
273  /// allocator is thread safe and frees the allocated storage after its
274  /// destruction.
276 
277 public:
278  MLIRContextImpl(bool threadingIsEnabled)
279  : threadingIsEnabled(threadingIsEnabled) {
280  if (threadingIsEnabled) {
281  ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
282  threadPool = ownedThreadPool.get();
283  }
284  }
286  for (auto typeMapping : registeredTypes)
287  typeMapping.second->~AbstractType();
288  for (auto attrMapping : registeredAttributes)
289  attrMapping.second->~AbstractAttribute();
290  }
291 };
292 } // namespace mlir
293 
295  : MLIRContext(DialectRegistry(), setting) {}
296 
298  : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
300  // Initialize values based on the command line flags if they were provided.
301  if (clOptions.isConstructed()) {
302  printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
303  printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
304  }
305 
306  // Pre-populate the registry.
307  registry.appendTo(impl->dialectsRegistry);
308 
309  // Ensure the builtin dialect is always pre-loaded.
310  getOrLoadDialect<BuiltinDialect>();
311 
312  // Initialize several common attributes and types to avoid the need to lock
313  // the context when accessing them.
314 
315  //// Types.
316  /// Floating-point Types.
317  impl->f6E3M2FNTy = TypeUniquer::get<Float6E3M2FNType>(this);
318  impl->f8E5M2Ty = TypeUniquer::get<Float8E5M2Type>(this);
319  impl->f8E4M3Ty = TypeUniquer::get<Float8E4M3Type>(this);
320  impl->f8E4M3FNTy = TypeUniquer::get<Float8E4M3FNType>(this);
321  impl->f8E5M2FNUZTy = TypeUniquer::get<Float8E5M2FNUZType>(this);
322  impl->f8E4M3FNUZTy = TypeUniquer::get<Float8E4M3FNUZType>(this);
323  impl->f8E4M3B11FNUZTy = TypeUniquer::get<Float8E4M3B11FNUZType>(this);
324  impl->f8E3M4Ty = TypeUniquer::get<Float8E3M4Type>(this);
325  impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
326  impl->f16Ty = TypeUniquer::get<Float16Type>(this);
327  impl->tf32Ty = TypeUniquer::get<FloatTF32Type>(this);
328  impl->f32Ty = TypeUniquer::get<Float32Type>(this);
329  impl->f64Ty = TypeUniquer::get<Float64Type>(this);
330  impl->f80Ty = TypeUniquer::get<Float80Type>(this);
331  impl->f128Ty = TypeUniquer::get<Float128Type>(this);
332  /// Index Type.
333  impl->indexTy = TypeUniquer::get<IndexType>(this);
334  /// Integer Types.
335  impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
336  impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
337  impl->int16Ty =
338  TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
339  impl->int32Ty =
340  TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
341  impl->int64Ty =
342  TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
343  impl->int128Ty =
344  TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
345  /// None Type.
346  impl->noneType = TypeUniquer::get<NoneType>(this);
347 
348  //// Attributes.
349  //// Note: These must be registered after the types as they may generate one
350  //// of the above types internally.
351  /// Unknown Location Attribute.
352  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
353  /// Bool Attributes.
354  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
355  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
356  /// Unit Attribute.
357  impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
358  /// The empty dictionary attribute.
359  impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
360  /// The empty string attribute.
361  impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
362 
363  // Register the affine storage objects with the uniquer.
364  impl->affineUniquer
365  .registerParametricStorageType<AffineBinaryOpExprStorage>();
366  impl->affineUniquer
367  .registerParametricStorageType<AffineConstantExprStorage>();
368  impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
369  impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
370  impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
371 }
372 
373 MLIRContext::~MLIRContext() = default;
374 
375 /// Copy the specified array of elements into memory managed by the provided
376 /// bump pointer allocator. This assumes the elements are all PODs.
377 template <typename T>
378 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
379  ArrayRef<T> elements) {
380  auto result = allocator.Allocate<T>(elements.size());
381  std::uninitialized_copy(elements.begin(), elements.end(), result);
382  return ArrayRef<T>(result, elements.size());
383 }
384 
385 //===----------------------------------------------------------------------===//
386 // Action Handling
387 //===----------------------------------------------------------------------===//
388 
390  getImpl().actionHandler = std::move(handler);
391 }
392 
393 /// Dispatch the provided action to the handler if any, or just execute it.
394 void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
395  const tracing::Action &action) {
396  assert(getImpl().actionHandler);
397  getImpl().actionHandler(actionFn, action);
398 }
399 
401 
402 //===----------------------------------------------------------------------===//
403 // Diagnostic Handlers
404 //===----------------------------------------------------------------------===//
405 
406 /// Returns the diagnostic engine for this context.
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  LLVM_DEBUG(llvm::dbgs()
478  << "Load new dialect in Context " << dialectNamespace << "\n");
479 #ifndef NDEBUG
480  if (impl.multiThreadedExecutionContext != 0)
481  llvm::report_fatal_error(
482  "Loading a dialect (" + dialectNamespace +
483  ") while in a multi-threaded execution context (maybe "
484  "the PassManager): this can indicate a "
485  "missing `dependentDialects` in a pass for example.");
486 #endif // NDEBUG
487  // loadedDialects entry is initialized to nullptr, indicating that the
488  // dialect is currently being loaded. Re-lookup the address in
489  // loadedDialects because the table might have been rehashed by recursive
490  // dialect loading in ctor().
491  std::unique_ptr<Dialect> &dialectOwned =
492  impl.loadedDialects[dialectNamespace] = ctor();
493  Dialect *dialect = dialectOwned.get();
494  assert(dialect && "dialect ctor failed");
495 
496  // Refresh all the identifiers dialect field, this catches cases where a
497  // dialect may be loaded after identifier prefixed with this dialect name
498  // were already created.
499  auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
500  if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
501  for (StringAttrStorage *storage : stringAttrsIt->second)
502  storage->referencedDialect = dialect;
503  impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
504  }
505 
506  // Apply any extensions to this newly loaded dialect.
507  impl.dialectsRegistry.applyExtensions(dialect);
508  return dialect;
509  }
510 
511 #ifndef NDEBUG
512  if (dialectIt.first->second == nullptr)
513  llvm::report_fatal_error(
514  "Loading (and getting) a dialect (" + dialectNamespace +
515  ") while the same dialect is still loading: use loadDialect instead "
516  "of getOrLoadDialect.");
517 #endif // NDEBUG
518 
519  // Abort if dialect with namespace has already been registered.
520  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
521  if (dialect->getTypeID() != dialectID)
522  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
523  "' has already been registered");
524 
525  return dialect.get();
526 }
527 
528 bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
529  auto it = getImpl().loadedDialects.find(dialectNamespace);
530  // nullptr indicates that the dialect is currently being loaded.
531  return it != getImpl().loadedDialects.end() && it->second == nullptr;
532 }
533 
535  StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
536  auto &impl = getImpl();
537  // Get the correct insertion position sorted by namespace.
538  auto dialectIt = impl.loadedDialects.find(dialectNamespace);
539 
540  if (dialectIt != impl.loadedDialects.end()) {
541  if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
542  return dynDialect;
543  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
544  "' has already been registered");
545  }
546 
547  LLVM_DEBUG(llvm::dbgs() << "Load new dynamic dialect in Context "
548  << dialectNamespace << "\n");
549 #ifndef NDEBUG
550  if (impl.multiThreadedExecutionContext != 0)
551  llvm::report_fatal_error(
552  "Loading a dynamic dialect (" + dialectNamespace +
553  ") while in a multi-threaded execution context (maybe "
554  "the PassManager): this can indicate a "
555  "missing `dependentDialects` in a pass for example.");
556 #endif
557 
558  auto name = StringAttr::get(this, dialectNamespace);
559  auto *dialect = new DynamicDialect(name, this);
560  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
561  ctor(dialect);
562  return std::unique_ptr<DynamicDialect>(dialect);
563  });
564  // This is the same result as `getOrLoadDialect` (if it didn't failed),
565  // since it has the same TypeID, and TypeIDs are unique.
566  return dialect;
567 }
568 
570  for (StringRef name : getAvailableDialects())
571  getOrLoadDialect(name);
572 }
573 
574 llvm::hash_code MLIRContext::getRegistryHash() {
575  llvm::hash_code hash(0);
576  // Factor in number of loaded dialects, attributes, operations, types.
577  hash = llvm::hash_combine(hash, impl->loadedDialects.size());
578  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
579  hash = llvm::hash_combine(hash, impl->registeredOperations.size());
580  hash = llvm::hash_combine(hash, impl->registeredTypes.size());
581  return hash;
582 }
583 
585  return impl->allowUnregisteredDialects;
586 }
587 
589  assert(impl->multiThreadedExecutionContext == 0 &&
590  "changing MLIRContext `allow-unregistered-dialects` configuration "
591  "while in a multi-threaded execution context");
592  impl->allowUnregisteredDialects = allowing;
593 }
594 
595 /// Return true if multi-threading is enabled by the context.
597  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
598 }
599 
600 /// Set the flag specifying if multi-threading is disabled by the context.
602  // This API can be overridden by the global debugging flag
603  // --mlir-disable-threading
605  return;
606  assert(impl->multiThreadedExecutionContext == 0 &&
607  "changing MLIRContext `disable-threading` configuration while "
608  "in a multi-threaded execution context");
609 
610  impl->threadingIsEnabled = !disable;
611 
612  // Update the threading mode for each of the uniquers.
613  impl->affineUniquer.disableMultithreading(disable);
614  impl->attributeUniquer.disableMultithreading(disable);
615  impl->typeUniquer.disableMultithreading(disable);
616 
617  // Destroy thread pool (stop all threads) if it is no longer needed, or create
618  // a new one if multithreading was re-enabled.
619  if (disable) {
620  // If the thread pool is owned, explicitly set it to nullptr to avoid
621  // keeping a dangling pointer around. If the thread pool is externally
622  // owned, we don't do anything.
623  if (impl->ownedThreadPool) {
624  assert(impl->threadPool);
625  impl->threadPool = nullptr;
626  impl->ownedThreadPool.reset();
627  }
628  } else if (!impl->threadPool) {
629  // The thread pool isn't externally provided.
630  assert(!impl->ownedThreadPool);
631  impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
632  impl->threadPool = impl->ownedThreadPool.get();
633  }
634 }
635 
636 void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
637  assert(!isMultithreadingEnabled() &&
638  "expected multi-threading to be disabled when setting a ThreadPool");
639  impl->threadPool = &pool;
640  impl->ownedThreadPool.reset();
642 }
643 
645  if (isMultithreadingEnabled()) {
646  assert(impl->threadPool &&
647  "multi-threading is enabled but threadpool not set");
648  return impl->threadPool->getMaxConcurrency();
649  }
650  // No multithreading or active thread pool. Return 1 thread.
651  return 1;
652 }
653 
654 llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
655  assert(isMultithreadingEnabled() &&
656  "expected multi-threading to be enabled within the context");
657  assert(impl->threadPool &&
658  "multi-threading is enabled but threadpool not set");
659  return *impl->threadPool;
660 }
661 
663 #ifndef NDEBUG
664  ++impl->multiThreadedExecutionContext;
665 #endif
666 }
668 #ifndef NDEBUG
669  --impl->multiThreadedExecutionContext;
670 #endif
671 }
672 
673 /// Return true if we should attach the operation to diagnostics emitted via
674 /// Operation::emit.
676  return impl->printOpOnDiagnostic;
677 }
678 
679 /// Set the flag specifying if we should attach the operation to diagnostics
680 /// emitted via Operation::emit.
682  assert(impl->multiThreadedExecutionContext == 0 &&
683  "changing MLIRContext `print-op-on-diagnostic` configuration while in "
684  "a multi-threaded execution context");
685  impl->printOpOnDiagnostic = enable;
686 }
687 
688 /// Return true if we should attach the current stacktrace to diagnostics when
689 /// emitted.
691  return impl->printStackTraceOnDiagnostic;
692 }
693 
694 /// Set the flag specifying if we should attach the current stacktrace when
695 /// emitting diagnostics.
697  assert(impl->multiThreadedExecutionContext == 0 &&
698  "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
699  "while in a multi-threaded execution context");
700  impl->printStackTraceOnDiagnostic = enable;
701 }
702 
703 /// Return information about all registered operations.
705  return impl->sortedRegisteredOperations;
706 }
707 
709  return RegisteredOperationName::lookup(name, this).has_value();
710 }
711 
712 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
713  auto &impl = context->getImpl();
714  assert(impl.multiThreadedExecutionContext == 0 &&
715  "Registering a new type kind while in a multi-threaded execution "
716  "context");
717  auto *newInfo =
718  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
719  AbstractType(std::move(typeInfo));
720  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
721  llvm::report_fatal_error("Dialect Type already registered.");
722  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
723  llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
724  " is already registered.");
725 }
726 
727 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
728  auto &impl = context->getImpl();
729  assert(impl.multiThreadedExecutionContext == 0 &&
730  "Registering a new attribute kind while in a multi-threaded execution "
731  "context");
732  auto *newInfo =
733  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
734  AbstractAttribute(std::move(attrInfo));
735  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
736  llvm::report_fatal_error("Dialect Attribute already registered.");
737  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
738  llvm::report_fatal_error("Dialect Attribute with name " +
739  newInfo->getName() + " is already registered.");
740 }
741 
742 //===----------------------------------------------------------------------===//
743 // AbstractAttribute
744 //===----------------------------------------------------------------------===//
745 
746 /// Get the dialect that registered the attribute with the provided typeid.
748  MLIRContext *context) {
749  const AbstractAttribute *abstract = lookupMutable(typeID, context);
750  if (!abstract)
751  llvm::report_fatal_error("Trying to create an Attribute that was not "
752  "registered in this MLIRContext.");
753  return *abstract;
754 }
755 
756 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
757  MLIRContext *context) {
758  auto &impl = context->getImpl();
759  return impl.registeredAttributes.lookup(typeID);
760 }
761 
762 std::optional<std::reference_wrapper<const AbstractAttribute>>
763 AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
764  MLIRContextImpl &impl = context->getImpl();
765  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
766 
767  if (!type)
768  return std::nullopt;
769  return {*type};
770 }
771 
772 //===----------------------------------------------------------------------===//
773 // OperationName
774 //===----------------------------------------------------------------------===//
775 
776 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
777  detail::InterfaceMap interfaceMap)
778  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
779  std::move(interfaceMap)) {}
780 
781 OperationName::OperationName(StringRef name, MLIRContext *context) {
782  MLIRContextImpl &ctxImpl = context->getImpl();
783 
784  // Check for an existing name in read-only mode.
785  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
786  if (isMultithreadingEnabled) {
787  // Check the registered info map first. In the overwhelmingly common case,
788  // the entry will be in here and it also removes the need to acquire any
789  // locks.
790  auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
791  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
792  impl = registeredIt->second.impl;
793  return;
794  }
795 
796  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
797  auto it = ctxImpl.operations.find(name);
798  if (it != ctxImpl.operations.end()) {
799  impl = it->second.get();
800  return;
801  }
802  }
803 
804  // Acquire a writer-lock so that we can safely create the new instance.
805  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
806 
807  auto it = ctxImpl.operations.insert({name, nullptr});
808  if (it.second) {
809  auto nameAttr = StringAttr::get(context, name);
810  it.first->second = std::make_unique<UnregisteredOpModel>(
811  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
813  }
814  impl = it.first->second.get();
815 }
816 
818  if (Dialect *dialect = getDialect())
819  return dialect->getNamespace();
820  return getStringRef().split('.').first;
821 }
822 
823 LogicalResult
826  return failure();
827 }
831 
834  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
835 }
837  const OperationName &, NamedAttrList &) {}
839  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
840  p.printGenericOp(op);
841 }
842 LogicalResult
844  return success();
845 }
846 LogicalResult
848  return success();
849 }
850 
851 std::optional<Attribute>
853  StringRef name) {
854  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
855  if (!dict)
856  return std::nullopt;
857  if (Attribute attr = dict.get(name))
858  return attr;
859  return std::nullopt;
860 }
862  StringAttr name,
863  Attribute value) {
864  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
865  assert(dict);
866  NamedAttrList attrs(dict);
867  attrs.set(name, value);
868  *op->getPropertiesStorage().as<Attribute *>() =
869  attrs.getDictionary(op->getContext());
870 }
872  Operation *op, NamedAttrList &attrs) {}
874  OperationName opName, NamedAttrList &attributes,
876  return success();
877 }
879  return sizeof(Attribute);
880 }
882  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
883  new (storage.as<Attribute *>()) Attribute();
884 }
886  OpaqueProperties prop) {
887  prop.as<Attribute *>()->~Attribute();
888 }
890  OperationName opName, OpaqueProperties properties) {}
892  OperationName opName, OpaqueProperties properties, Attribute attr,
894  *properties.as<Attribute *>() = attr;
895  return success();
896 }
897 Attribute
899  return *op->getPropertiesStorage().as<Attribute *>();
900 }
902  OpaqueProperties rhs) {
903  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
904 }
907  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
908 }
909 llvm::hash_code
911  return llvm::hash_combine(*prop.as<Attribute *>());
912 }
913 
914 //===----------------------------------------------------------------------===//
915 // RegisteredOperationName
916 //===----------------------------------------------------------------------===//
917 
918 std::optional<RegisteredOperationName>
920  auto &impl = ctx->getImpl();
921  auto it = impl.registeredOperations.find(typeID);
922  if (it != impl.registeredOperations.end())
923  return it->second;
924  return std::nullopt;
925 }
926 
927 std::optional<RegisteredOperationName>
929  auto &impl = ctx->getImpl();
930  auto it = impl.registeredOperationsByName.find(name);
931  if (it != impl.registeredOperationsByName.end())
932  return it->getValue();
933  return std::nullopt;
934 }
935 
937  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
938  ArrayRef<StringRef> attrNames) {
939  RegisteredOperationName::Impl *impl = ownedImpl.get();
940  MLIRContext *ctx = impl->getDialect()->getContext();
941  auto &ctxImpl = ctx->getImpl();
942  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
943  "registering a new operation kind while in a multi-threaded execution "
944  "context");
945 
946  // Register the attribute names of this operation.
947  MutableArrayRef<StringAttr> cachedAttrNames;
948  if (!attrNames.empty()) {
949  cachedAttrNames = MutableArrayRef<StringAttr>(
950  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
951  attrNames.size()),
952  attrNames.size());
953  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
954  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
955  impl->attributeNames = cachedAttrNames;
956  }
957  StringRef name = impl->getName().strref();
958  // Insert the operation info if it doesn't exist yet.
959  auto it = ctxImpl.operations.insert({name, nullptr});
960  it.first->second = std::move(ownedImpl);
961 
962  // Update the registered info for this operation.
963  auto emplaced = ctxImpl.registeredOperations.try_emplace(
964  impl->getTypeID(), RegisteredOperationName(impl));
965  assert(emplaced.second && "operation name registration must be successful");
966  auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
968  (void)emplacedByName;
969  assert(emplacedByName.second &&
970  "operation name registration must be successful");
971 
972  // Add emplaced operation name to the sorted operations container.
973  RegisteredOperationName &value = emplaced.first->second;
974  ctxImpl.sortedRegisteredOperations.insert(
975  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
976  [](auto &lhs, auto &rhs) {
977  return lhs.getIdentifier().compare(
978  rhs.getIdentifier());
979  }),
980  value);
981 }
982 
983 //===----------------------------------------------------------------------===//
984 // AbstractType
985 //===----------------------------------------------------------------------===//
986 
988  const AbstractType *type = lookupMutable(typeID, context);
989  if (!type)
990  llvm::report_fatal_error(
991  "Trying to create a Type that was not registered in this MLIRContext.");
992  return *type;
993 }
994 
995 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
996  auto &impl = context->getImpl();
997  return impl.registeredTypes.lookup(typeID);
998 }
999 
1000 std::optional<std::reference_wrapper<const AbstractType>>
1001 AbstractType::lookup(StringRef name, MLIRContext *context) {
1002  MLIRContextImpl &impl = context->getImpl();
1003  const AbstractType *type = impl.nameToType.lookup(name);
1004 
1005  if (!type)
1006  return std::nullopt;
1007  return {*type};
1008 }
1009 
1010 //===----------------------------------------------------------------------===//
1011 // Type uniquing
1012 //===----------------------------------------------------------------------===//
1013 
1014 /// Returns the storage uniquer used for constructing type storage instances.
1015 /// This should not be used directly.
1017 
1018 Float6E3M2FNType Float6E3M2FNType::get(MLIRContext *context) {
1019  return context->getImpl().f6E3M2FNTy;
1020 }
1021 Float8E5M2Type Float8E5M2Type::get(MLIRContext *context) {
1022  return context->getImpl().f8E5M2Ty;
1023 }
1024 Float8E4M3Type Float8E4M3Type::get(MLIRContext *context) {
1025  return context->getImpl().f8E4M3Ty;
1026 }
1027 Float8E4M3FNType Float8E4M3FNType::get(MLIRContext *context) {
1028  return context->getImpl().f8E4M3FNTy;
1029 }
1030 Float8E5M2FNUZType Float8E5M2FNUZType::get(MLIRContext *context) {
1031  return context->getImpl().f8E5M2FNUZTy;
1032 }
1033 Float8E4M3FNUZType Float8E4M3FNUZType::get(MLIRContext *context) {
1034  return context->getImpl().f8E4M3FNUZTy;
1035 }
1036 Float8E4M3B11FNUZType Float8E4M3B11FNUZType::get(MLIRContext *context) {
1037  return context->getImpl().f8E4M3B11FNUZTy;
1038 }
1039 Float8E3M4Type Float8E3M4Type::get(MLIRContext *context) {
1040  return context->getImpl().f8E3M4Ty;
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  LLVM_DEBUG(
1216  llvm::dbgs()
1217  << "maximum dimensional identifier position in result expression must "
1218  "be less than `dimCount` and maximum symbolic identifier position "
1219  "in result expression must be less than `symbolCount`\n");
1220  return false;
1221  }
1222  return true;
1223 }
1224 
1226  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1227 }
1228 
1229 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1230  MLIRContext *context) {
1231  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1232 }
1233 
1234 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1235  AffineExpr result) {
1236  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1237  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1238 }
1239 
1240 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1241  ArrayRef<AffineExpr> results, MLIRContext *context) {
1242  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1243  return getImpl(dimCount, symbolCount, results, context);
1244 }
1245 
1246 //===----------------------------------------------------------------------===//
1247 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1248 // Unlike AffineMap's, these are uniqued only if they are small.
1249 //===----------------------------------------------------------------------===//
1250 
1251 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1252  ArrayRef<AffineExpr> constraints,
1253  ArrayRef<bool> eqFlags) {
1254  // The number of constraints can't be zero.
1255  assert(!constraints.empty());
1256  assert(constraints.size() == eqFlags.size());
1257 
1258  auto &impl = constraints[0].getContext()->getImpl();
1259  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1260  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1261  return IntegerSet(storage);
1262 }
1263 
1264 //===----------------------------------------------------------------------===//
1265 // StorageUniquerSupport
1266 //===----------------------------------------------------------------------===//
1267 
1268 /// Utility method to generate a callback that can be used to generate a
1269 /// diagnostic when checking the construction invariants of a storage object.
1270 /// This is defined out-of-line to avoid the need to include Location.h.
1271 llvm::unique_function<InFlightDiagnostic()>
1273  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1274 }
1275 llvm::unique_function<InFlightDiagnostic()>
1277  return [=] { return emitError(loc); };
1278 }
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:79
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:77
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:33
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:413
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:329
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition: Dialect.cpp:255
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:313
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:63
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.
Float8E5M2FNUZType f8E5M2FNUZTy
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
Float8E3M4Type f8E3M4Ty
llvm::BumpPtrAllocator abstractDialectSymbolAllocator
An allocator used for AbstractAttribute and AbstractType objects.
Float6E3M2FNType f6E3M2FNTy
Cached Type Instances.
DenseMap< TypeID, AbstractType * > registeredTypes
Float8E5M2Type f8E5M2Ty
StorageUniquer affineUniquer
DiagnosticEngine diagEngine
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.
Float8E4M3FNUZType f8E4M3FNUZTy
Float8E4M3B11FNUZType f8E4M3B11FNUZTy
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...
Float8E4M3FNType f8E4M3FNTy
DistinctAttributeAllocator distinctAttributeAllocator
A distinct attribute allocator that allocates every time since the address of the distinct attribute ...
MLIRContextImpl(bool threadingIsEnabled)
StorageUniquer attributeUniquer
Float8E4M3Type f8E4M3Ty
DialectRegistry dialectsRegistry
FloatTF32Type tf32Ty
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
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 setThreadPool(llvm::ThreadPoolInterface &pool)
Set a new thread pool to be used in this context.
void enableMultithreading(bool enable=true)
Definition: MLIRContext.h:152
std::vector< Dialect * > getLoadedDialects()
Return information about all IR dialects loaded in the context.
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:90
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:249
MLIRContextImpl & getImpl()
Definition: MLIRContext.h:205
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:97
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:896
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:104
An allocator for distinct attribute storage instances.
DistinctAttrStorage * allocate(Attribute referencedAttr)
Allocates a distinct attribute storage using a thread local bump pointer allocator to enable synchron...
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:90
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:679
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.