MLIR  17.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"
27 #include "mlir/IR/Types.h"
28 #include "llvm/ADT/DenseMap.h"
29 #include "llvm/ADT/DenseSet.h"
30 #include "llvm/ADT/SmallString.h"
31 #include "llvm/ADT/StringSet.h"
32 #include "llvm/ADT/Twine.h"
33 #include "llvm/Support/Allocator.h"
34 #include "llvm/Support/CommandLine.h"
35 #include "llvm/Support/Compiler.h"
36 #include "llvm/Support/Debug.h"
37 #include "llvm/Support/Mutex.h"
38 #include "llvm/Support/RWMutex.h"
39 #include "llvm/Support/ThreadPool.h"
40 #include "llvm/Support/raw_ostream.h"
41 #include <memory>
42 #include <optional>
43 
44 #define DEBUG_TYPE "mlircontext"
45 
46 using namespace mlir;
47 using namespace mlir::detail;
48 
49 //===----------------------------------------------------------------------===//
50 // MLIRContext CommandLine Options
51 //===----------------------------------------------------------------------===//
52 
53 namespace {
54 /// This struct contains command line options that can be used to initialize
55 /// various bits of an MLIRContext. This uses a struct wrapper to avoid the need
56 /// for global command line options.
57 struct MLIRContextOptions {
58  llvm::cl::opt<bool> disableThreading{
59  "mlir-disable-threading",
60  llvm::cl::desc("Disable multi-threading within MLIR, overrides any "
61  "further call to MLIRContext::enableMultiThreading()")};
62 
63  llvm::cl::opt<bool> printOpOnDiagnostic{
64  "mlir-print-op-on-diagnostic",
65  llvm::cl::desc("When a diagnostic is emitted on an operation, also print "
66  "the operation as an attached note"),
67  llvm::cl::init(true)};
68 
69  llvm::cl::opt<bool> printStackTraceOnDiagnostic{
70  "mlir-print-stacktrace-on-diagnostic",
71  llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "
72  "as an attached note")};
73 };
74 } // namespace
75 
76 static llvm::ManagedStatic<MLIRContextOptions> clOptions;
77 
79 #if LLVM_ENABLE_THREADS != 0
80  return clOptions.isConstructed() && clOptions->disableThreading;
81 #else
82  return true;
83 #endif
84 }
85 
86 /// Register a set of useful command-line options that can be used to configure
87 /// various flags within the MLIRContext. These flags are used when constructing
88 /// an MLIR context for initialization.
90  // Make sure that the options struct has been initialized.
91  *clOptions;
92 }
93 
94 //===----------------------------------------------------------------------===//
95 // Locking Utilities
96 //===----------------------------------------------------------------------===//
97 
98 namespace {
99 /// Utility writer lock that takes a runtime flag that specifies if we really
100 /// need to lock.
101 struct ScopedWriterLock {
102  ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)
103  : mutex(shouldLock ? &mutexParam : nullptr) {
104  if (mutex)
105  mutex->lock();
106  }
107  ~ScopedWriterLock() {
108  if (mutex)
109  mutex->unlock();
110  }
111  llvm::sys::SmartRWMutex<true> *mutex;
112 };
113 } // namespace
114 
115 //===----------------------------------------------------------------------===//
116 // MLIRContextImpl
117 //===----------------------------------------------------------------------===//
118 
119 namespace mlir {
120 /// This is the implementation of the MLIRContext class, using the pImpl idiom.
121 /// This class is completely private to this file, so everything is public.
123 public:
124  //===--------------------------------------------------------------------===//
125  // Debugging
126  //===--------------------------------------------------------------------===//
127 
128  /// An action handler for handling actions that are dispatched through this
129  /// context.
130  std::function<void(function_ref<void()>, const tracing::Action &)>
132 
133  //===--------------------------------------------------------------------===//
134  // Diagnostics
135  //===--------------------------------------------------------------------===//
137 
138  //===--------------------------------------------------------------------===//
139  // Options
140  //===--------------------------------------------------------------------===//
141 
142  /// In most cases, creating operation in unregistered dialect is not desired
143  /// and indicate a misconfiguration of the compiler. This option enables to
144  /// detect such use cases
145  bool allowUnregisteredDialects = false;
146 
147  /// Enable support for multi-threading within MLIR.
148  bool threadingIsEnabled = true;
149 
150  /// Track if we are currently executing in a threaded execution environment
151  /// (like the pass-manager): this is only a debugging feature to help reducing
152  /// the chances of data races one some context APIs.
153 #ifndef NDEBUG
154  std::atomic<int> multiThreadedExecutionContext{0};
155 #endif
156 
157  /// If the operation should be attached to diagnostics printed via the
158  /// Operation::emit methods.
159  bool printOpOnDiagnostic = true;
160 
161  /// If the current stack trace should be attached when emitting diagnostics.
162  bool printStackTraceOnDiagnostic = false;
163 
164  //===--------------------------------------------------------------------===//
165  // Other
166  //===--------------------------------------------------------------------===//
167 
168  /// This points to the ThreadPool used when processing MLIR tasks in parallel.
169  /// It can't be nullptr when multi-threading is enabled. Otherwise if
170  /// multi-threading is disabled, and the threadpool wasn't externally provided
171  /// using `setThreadPool`, this will be nullptr.
172  llvm::ThreadPool *threadPool = nullptr;
173 
174  /// In case where the thread pool is owned by the context, this ensures
175  /// destruction with the context.
176  std::unique_ptr<llvm::ThreadPool> ownedThreadPool;
177 
178  /// An allocator used for AbstractAttribute and AbstractType objects.
179  llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
180 
181  /// This is a mapping from operation name to the operation info describing it.
182  llvm::StringMap<std::unique_ptr<OperationName::Impl>> operations;
183 
184  /// A vector of operation info specifically for registered operations.
185  llvm::StringMap<RegisteredOperationName> registeredOperations;
186 
187  /// This is a sorted container of registered operations for a deterministic
188  /// and efficient `getRegisteredOperations` implementation.
190 
191  /// This is a list of dialects that are created referring to this context.
192  /// The MLIRContext owns the objects. These need to be declared after the
193  /// registered operations to ensure correct destruction order.
196 
197  /// A mutex used when accessing operation information.
198  llvm::sys::SmartRWMutex<true> operationInfoMutex;
199 
200  //===--------------------------------------------------------------------===//
201  // Affine uniquing
202  //===--------------------------------------------------------------------===//
203 
204  // Affine expression, map and integer set uniquing.
206 
207  //===--------------------------------------------------------------------===//
208  // Type uniquing
209  //===--------------------------------------------------------------------===//
210 
213 
214  /// Cached Type Instances.
215  Float8E5M2Type f8E5M2Ty;
216  Float8E4M3FNType f8E4M3FNTy;
217  Float8E5M2FNUZType f8E5M2FNUZTy;
218  Float8E4M3FNUZType f8E4M3FNUZTy;
219  Float8E4M3B11FNUZType f8E4M3B11FNUZTy;
220  BFloat16Type bf16Ty;
221  Float16Type f16Ty;
222  Float32Type f32Ty;
223  Float64Type f64Ty;
224  Float80Type f80Ty;
225  Float128Type f128Ty;
226  IndexType indexTy;
227  IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
228  NoneType noneType;
229 
230  //===--------------------------------------------------------------------===//
231  // Attribute uniquing
232  //===--------------------------------------------------------------------===//
233 
236 
237  /// Cached Attribute Instances.
238  BoolAttr falseAttr, trueAttr;
239  UnitAttr unitAttr;
240  UnknownLoc unknownLocAttr;
241  DictionaryAttr emptyDictionaryAttr;
242  StringAttr emptyStringAttr;
243 
244  /// Map of string attributes that may reference a dialect, that are awaiting
245  /// that dialect to be loaded.
249 
250 public:
251  MLIRContextImpl(bool threadingIsEnabled)
252  : threadingIsEnabled(threadingIsEnabled) {
253  if (threadingIsEnabled) {
254  ownedThreadPool = std::make_unique<llvm::ThreadPool>();
255  threadPool = ownedThreadPool.get();
256  }
257  }
259  for (auto typeMapping : registeredTypes)
260  typeMapping.second->~AbstractType();
261  for (auto attrMapping : registeredAttributes)
262  attrMapping.second->~AbstractAttribute();
263  }
264 };
265 } // namespace mlir
266 
268  : MLIRContext(DialectRegistry(), setting) {}
269 
271  : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
273  // Initialize values based on the command line flags if they were provided.
274  if (clOptions.isConstructed()) {
275  printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
276  printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
277  }
278 
279  // Pre-populate the registry.
280  registry.appendTo(impl->dialectsRegistry);
281 
282  // Ensure the builtin dialect is always pre-loaded.
283  getOrLoadDialect<BuiltinDialect>();
284 
285  // Initialize several common attributes and types to avoid the need to lock
286  // the context when accessing them.
287 
288  //// Types.
289  /// Floating-point Types.
290  impl->f8E5M2Ty = TypeUniquer::get<Float8E5M2Type>(this);
291  impl->f8E4M3FNTy = TypeUniquer::get<Float8E4M3FNType>(this);
292  impl->f8E5M2FNUZTy = TypeUniquer::get<Float8E5M2FNUZType>(this);
293  impl->f8E4M3FNUZTy = TypeUniquer::get<Float8E4M3FNUZType>(this);
294  impl->f8E4M3B11FNUZTy = TypeUniquer::get<Float8E4M3B11FNUZType>(this);
295  impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
296  impl->f16Ty = TypeUniquer::get<Float16Type>(this);
297  impl->f32Ty = TypeUniquer::get<Float32Type>(this);
298  impl->f64Ty = TypeUniquer::get<Float64Type>(this);
299  impl->f80Ty = TypeUniquer::get<Float80Type>(this);
300  impl->f128Ty = TypeUniquer::get<Float128Type>(this);
301  /// Index Type.
302  impl->indexTy = TypeUniquer::get<IndexType>(this);
303  /// Integer Types.
304  impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
305  impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
306  impl->int16Ty =
307  TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
308  impl->int32Ty =
309  TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
310  impl->int64Ty =
311  TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
312  impl->int128Ty =
313  TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
314  /// None Type.
315  impl->noneType = TypeUniquer::get<NoneType>(this);
316 
317  //// Attributes.
318  //// Note: These must be registered after the types as they may generate one
319  //// of the above types internally.
320  /// Unknown Location Attribute.
321  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
322  /// Bool Attributes.
323  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
324  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
325  /// Unit Attribute.
326  impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
327  /// The empty dictionary attribute.
328  impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
329  /// The empty string attribute.
330  impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
331 
332  // Register the affine storage objects with the uniquer.
333  impl->affineUniquer
334  .registerParametricStorageType<AffineBinaryOpExprStorage>();
335  impl->affineUniquer
336  .registerParametricStorageType<AffineConstantExprStorage>();
337  impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
338  impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
339  impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
340 }
341 
342 MLIRContext::~MLIRContext() = default;
343 
344 /// Copy the specified array of elements into memory managed by the provided
345 /// bump pointer allocator. This assumes the elements are all PODs.
346 template <typename T>
347 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
348  ArrayRef<T> elements) {
349  auto result = allocator.Allocate<T>(elements.size());
350  std::uninitialized_copy(elements.begin(), elements.end(), result);
351  return ArrayRef<T>(result, elements.size());
352 }
353 
354 //===----------------------------------------------------------------------===//
355 // Action Handling
356 //===----------------------------------------------------------------------===//
357 
359  getImpl().actionHandler = std::move(handler);
360 }
361 
362 /// Dispatch the provided action to the handler if any, or just execute it.
363 void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
364  const tracing::Action &action) {
365  assert(getImpl().actionHandler);
366  getImpl().actionHandler(actionFn, action);
367 }
368 
370 
371 //===----------------------------------------------------------------------===//
372 // Diagnostic Handlers
373 //===----------------------------------------------------------------------===//
374 
375 /// Returns the diagnostic engine for this context.
377 
378 //===----------------------------------------------------------------------===//
379 // Dialect and Operation Registration
380 //===----------------------------------------------------------------------===//
381 
383  if (registry.isSubsetOf(impl->dialectsRegistry))
384  return;
385 
386  assert(impl->multiThreadedExecutionContext == 0 &&
387  "appending to the MLIRContext dialect registry while in a "
388  "multi-threaded execution context");
389  registry.appendTo(impl->dialectsRegistry);
390 
391  // For the already loaded dialects, apply any possible extensions immediately.
392  registry.applyExtensions(this);
393 }
394 
396  return impl->dialectsRegistry;
397 }
398 
399 /// Return information about all registered IR dialects.
400 std::vector<Dialect *> MLIRContext::getLoadedDialects() {
401  std::vector<Dialect *> result;
402  result.reserve(impl->loadedDialects.size());
403  for (auto &dialect : impl->loadedDialects)
404  result.push_back(dialect.second.get());
405  llvm::array_pod_sort(result.begin(), result.end(),
406  [](Dialect *const *lhs, Dialect *const *rhs) -> int {
407  return (*lhs)->getNamespace() < (*rhs)->getNamespace();
408  });
409  return result;
410 }
411 std::vector<StringRef> MLIRContext::getAvailableDialects() {
412  std::vector<StringRef> result;
413  for (auto dialect : impl->dialectsRegistry.getDialectNames())
414  result.push_back(dialect);
415  return result;
416 }
417 
418 /// Get a registered IR dialect with the given namespace. If none is found,
419 /// then return nullptr.
421  // Dialects are sorted by name, so we can use binary search for lookup.
422  auto it = impl->loadedDialects.find(name);
423  return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
424 }
425 
427  Dialect *dialect = getLoadedDialect(name);
428  if (dialect)
429  return dialect;
430  DialectAllocatorFunctionRef allocator =
431  impl->dialectsRegistry.getDialectAllocator(name);
432  return allocator ? allocator(this) : nullptr;
433 }
434 
435 /// Get a dialect for the provided namespace and TypeID: abort the program if a
436 /// dialect exist for this namespace with different TypeID. Returns a pointer to
437 /// the dialect owned by the context.
438 Dialect *
439 MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
440  function_ref<std::unique_ptr<Dialect>()> ctor) {
441  auto &impl = getImpl();
442  // Get the correct insertion position sorted by namespace.
443  auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
444 
445  if (dialectIt.second) {
446  LLVM_DEBUG(llvm::dbgs()
447  << "Load new dialect in Context " << dialectNamespace << "\n");
448 #ifndef NDEBUG
449  if (impl.multiThreadedExecutionContext != 0)
450  llvm::report_fatal_error(
451  "Loading a dialect (" + dialectNamespace +
452  ") while in a multi-threaded execution context (maybe "
453  "the PassManager): this can indicate a "
454  "missing `dependentDialects` in a pass for example.");
455 #endif // NDEBUG
456  // loadedDialects entry is initialized to nullptr, indicating that the
457  // dialect is currently being loaded. Re-lookup the address in
458  // loadedDialects because the table might have been rehashed by recursive
459  // dialect loading in ctor().
460  std::unique_ptr<Dialect> &dialect = impl.loadedDialects[dialectNamespace] =
461  ctor();
462  assert(dialect && "dialect ctor failed");
463 
464  // Refresh all the identifiers dialect field, this catches cases where a
465  // dialect may be loaded after identifier prefixed with this dialect name
466  // were already created.
467  auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
468  if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
469  for (StringAttrStorage *storage : stringAttrsIt->second)
470  storage->referencedDialect = dialect.get();
471  impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
472  }
473 
474  // Apply any extensions to this newly loaded dialect.
475  impl.dialectsRegistry.applyExtensions(dialect.get());
476  return dialect.get();
477  }
478 
479 #ifndef NDEBUG
480  if (dialectIt.first->second == nullptr)
481  llvm::report_fatal_error(
482  "Loading (and getting) a dialect (" + dialectNamespace +
483  ") while the same dialect is still loading: use loadDialect instead "
484  "of getOrLoadDialect.");
485 #endif // NDEBUG
486 
487  // Abort if dialect with namespace has already been registered.
488  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
489  if (dialect->getTypeID() != dialectID)
490  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
491  "' has already been registered");
492 
493  return dialect.get();
494 }
495 
496 bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
497  auto it = getImpl().loadedDialects.find(dialectNamespace);
498  // nullptr indicates that the dialect is currently being loaded.
499  return it != getImpl().loadedDialects.end() && it->second == nullptr;
500 }
501 
503  StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
504  auto &impl = getImpl();
505  // Get the correct insertion position sorted by namespace.
506  auto dialectIt = impl.loadedDialects.find(dialectNamespace);
507 
508  if (dialectIt != impl.loadedDialects.end()) {
509  if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
510  return dynDialect;
511  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
512  "' has already been registered");
513  }
514 
515  LLVM_DEBUG(llvm::dbgs() << "Load new dynamic dialect in Context "
516  << dialectNamespace << "\n");
517 #ifndef NDEBUG
518  if (impl.multiThreadedExecutionContext != 0)
519  llvm::report_fatal_error(
520  "Loading a dynamic dialect (" + dialectNamespace +
521  ") while in a multi-threaded execution context (maybe "
522  "the PassManager): this can indicate a "
523  "missing `dependentDialects` in a pass for example.");
524 #endif
525 
526  auto name = StringAttr::get(this, dialectNamespace);
527  auto *dialect = new DynamicDialect(name, this);
528  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
529  ctor(dialect);
530  return std::unique_ptr<DynamicDialect>(dialect);
531  });
532  // This is the same result as `getOrLoadDialect` (if it didn't failed),
533  // since it has the same TypeID, and TypeIDs are unique.
534  return dialect;
535 }
536 
538  for (StringRef name : getAvailableDialects())
539  getOrLoadDialect(name);
540 }
541 
542 llvm::hash_code MLIRContext::getRegistryHash() {
543  llvm::hash_code hash(0);
544  // Factor in number of loaded dialects, attributes, operations, types.
545  hash = llvm::hash_combine(hash, impl->loadedDialects.size());
546  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
547  hash = llvm::hash_combine(hash, impl->registeredOperations.size());
548  hash = llvm::hash_combine(hash, impl->registeredTypes.size());
549  return hash;
550 }
551 
553  return impl->allowUnregisteredDialects;
554 }
555 
557  assert(impl->multiThreadedExecutionContext == 0 &&
558  "changing MLIRContext `allow-unregistered-dialects` configuration "
559  "while in a multi-threaded execution context");
560  impl->allowUnregisteredDialects = allowing;
561 }
562 
563 /// Return true if multi-threading is enabled by the context.
565  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
566 }
567 
568 /// Set the flag specifying if multi-threading is disabled by the context.
570  // This API can be overridden by the global debugging flag
571  // --mlir-disable-threading
573  return;
574  assert(impl->multiThreadedExecutionContext == 0 &&
575  "changing MLIRContext `disable-threading` configuration while "
576  "in a multi-threaded execution context");
577 
578  impl->threadingIsEnabled = !disable;
579 
580  // Update the threading mode for each of the uniquers.
581  impl->affineUniquer.disableMultithreading(disable);
582  impl->attributeUniquer.disableMultithreading(disable);
583  impl->typeUniquer.disableMultithreading(disable);
584 
585  // Destroy thread pool (stop all threads) if it is no longer needed, or create
586  // a new one if multithreading was re-enabled.
587  if (disable) {
588  // If the thread pool is owned, explicitly set it to nullptr to avoid
589  // keeping a dangling pointer around. If the thread pool is externally
590  // owned, we don't do anything.
591  if (impl->ownedThreadPool) {
592  assert(impl->threadPool);
593  impl->threadPool = nullptr;
594  impl->ownedThreadPool.reset();
595  }
596  } else if (!impl->threadPool) {
597  // The thread pool isn't externally provided.
598  assert(!impl->ownedThreadPool);
599  impl->ownedThreadPool = std::make_unique<llvm::ThreadPool>();
600  impl->threadPool = impl->ownedThreadPool.get();
601  }
602 }
603 
604 void MLIRContext::setThreadPool(llvm::ThreadPool &pool) {
605  assert(!isMultithreadingEnabled() &&
606  "expected multi-threading to be disabled when setting a ThreadPool");
607  impl->threadPool = &pool;
608  impl->ownedThreadPool.reset();
610 }
611 
613  if (isMultithreadingEnabled()) {
614  assert(impl->threadPool &&
615  "multi-threading is enabled but threadpool not set");
616  return impl->threadPool->getThreadCount();
617  }
618  // No multithreading or active thread pool. Return 1 thread.
619  return 1;
620 }
621 
622 llvm::ThreadPool &MLIRContext::getThreadPool() {
623  assert(isMultithreadingEnabled() &&
624  "expected multi-threading to be enabled within the context");
625  assert(impl->threadPool &&
626  "multi-threading is enabled but threadpool not set");
627  return *impl->threadPool;
628 }
629 
631 #ifndef NDEBUG
632  ++impl->multiThreadedExecutionContext;
633 #endif
634 }
636 #ifndef NDEBUG
637  --impl->multiThreadedExecutionContext;
638 #endif
639 }
640 
641 /// Return true if we should attach the operation to diagnostics emitted via
642 /// Operation::emit.
644  return impl->printOpOnDiagnostic;
645 }
646 
647 /// Set the flag specifying if we should attach the operation to diagnostics
648 /// emitted via Operation::emit.
650  assert(impl->multiThreadedExecutionContext == 0 &&
651  "changing MLIRContext `print-op-on-diagnostic` configuration while in "
652  "a multi-threaded execution context");
653  impl->printOpOnDiagnostic = enable;
654 }
655 
656 /// Return true if we should attach the current stacktrace to diagnostics when
657 /// emitted.
659  return impl->printStackTraceOnDiagnostic;
660 }
661 
662 /// Set the flag specifying if we should attach the current stacktrace when
663 /// emitting diagnostics.
665  assert(impl->multiThreadedExecutionContext == 0 &&
666  "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
667  "while in a multi-threaded execution context");
668  impl->printStackTraceOnDiagnostic = enable;
669 }
670 
671 /// Return information about all registered operations.
673  return impl->sortedRegisteredOperations;
674 }
675 
677  return RegisteredOperationName::lookup(name, this).has_value();
678 }
679 
680 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
681  auto &impl = context->getImpl();
682  assert(impl.multiThreadedExecutionContext == 0 &&
683  "Registering a new type kind while in a multi-threaded execution "
684  "context");
685  auto *newInfo =
686  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
687  AbstractType(std::move(typeInfo));
688  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
689  llvm::report_fatal_error("Dialect Type already registered.");
690 }
691 
692 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
693  auto &impl = context->getImpl();
694  assert(impl.multiThreadedExecutionContext == 0 &&
695  "Registering a new attribute kind while in a multi-threaded execution "
696  "context");
697  auto *newInfo =
698  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
699  AbstractAttribute(std::move(attrInfo));
700  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
701  llvm::report_fatal_error("Dialect Attribute already registered.");
702 }
703 
704 //===----------------------------------------------------------------------===//
705 // AbstractAttribute
706 //===----------------------------------------------------------------------===//
707 
708 /// Get the dialect that registered the attribute with the provided typeid.
710  MLIRContext *context) {
711  const AbstractAttribute *abstract = lookupMutable(typeID, context);
712  if (!abstract)
713  llvm::report_fatal_error("Trying to create an Attribute that was not "
714  "registered in this MLIRContext.");
715  return *abstract;
716 }
717 
718 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
719  MLIRContext *context) {
720  auto &impl = context->getImpl();
721  auto it = impl.registeredAttributes.find(typeID);
722  if (it == impl.registeredAttributes.end())
723  return nullptr;
724  return it->second;
725 }
726 
727 //===----------------------------------------------------------------------===//
728 // OperationName
729 //===----------------------------------------------------------------------===//
730 
731 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
732  detail::InterfaceMap interfaceMap)
733  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
734  std::move(interfaceMap)) {}
735 
736 OperationName::OperationName(StringRef name, MLIRContext *context) {
737  MLIRContextImpl &ctxImpl = context->getImpl();
738 
739  // Check for an existing name in read-only mode.
740  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
741  if (isMultithreadingEnabled) {
742  // Check the registered info map first. In the overwhelmingly common case,
743  // the entry will be in here and it also removes the need to acquire any
744  // locks.
745  auto registeredIt = ctxImpl.registeredOperations.find(name);
746  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperations.end())) {
747  impl = registeredIt->second.impl;
748  return;
749  }
750 
751  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
752  auto it = ctxImpl.operations.find(name);
753  if (it != ctxImpl.operations.end()) {
754  impl = it->second.get();
755  return;
756  }
757  }
758 
759  // Acquire a writer-lock so that we can safely create the new instance.
760  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
761 
762  auto it = ctxImpl.operations.insert({name, nullptr});
763  if (it.second) {
764  auto nameAttr = StringAttr::get(context, name);
765  it.first->second = std::make_unique<UnregisteredOpModel>(
766  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
768  }
769  impl = it.first->second.get();
770 }
771 
773  if (Dialect *dialect = getDialect())
774  return dialect->getNamespace();
775  return getStringRef().split('.').first;
776 }
777 
781  return failure();
782 }
786 
789  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
790 }
792  const OperationName &, NamedAttrList &) {}
794  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
795  p.printGenericOp(op);
796 }
799  return success();
800 }
803  return success();
804 }
805 
806 std::optional<Attribute>
808  StringRef name) {
809  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
810  if (!dict)
811  return std::nullopt;
812  if (Attribute attr = dict.get(name))
813  return attr;
814  return std::nullopt;
815 }
817  StringAttr name,
818  Attribute value) {
819  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
820  assert(dict);
821  NamedAttrList attrs(dict);
822  attrs.set(name, value);
823  *op->getPropertiesStorage().as<Attribute *>() =
824  attrs.getDictionary(op->getContext());
825 }
827  Operation *op, NamedAttrList &attrs) {}
829  OperationName opName, NamedAttrList &attributes,
830  function_ref<InFlightDiagnostic()> getDiag) {
831  return success();
832 }
834  return sizeof(Attribute);
835 }
837  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
838  new (storage.as<Attribute *>()) Attribute();
839 }
841  OpaqueProperties prop) {
842  prop.as<Attribute *>()->~Attribute();
843 }
845  OperationName opName, OpaqueProperties properties) {}
848  *op->getPropertiesStorage().as<Attribute *>() = attr;
849  return success();
850 }
851 Attribute
853  return *op->getPropertiesStorage().as<Attribute *>();
854 }
856  OpaqueProperties rhs) {
857  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
858 }
859 llvm::hash_code
861  return llvm::hash_combine(*prop.as<Attribute *>());
862 }
863 
864 //===----------------------------------------------------------------------===//
865 // RegisteredOperationName
866 //===----------------------------------------------------------------------===//
867 
868 std::optional<RegisteredOperationName>
870  auto &impl = ctx->getImpl();
871  auto it = impl.registeredOperations.find(name);
872  if (it != impl.registeredOperations.end())
873  return it->getValue();
874  return std::nullopt;
875 }
876 
878  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
879  ArrayRef<StringRef> attrNames) {
880  RegisteredOperationName::Impl *impl = ownedImpl.get();
881  MLIRContext *ctx = impl->getDialect()->getContext();
882  auto &ctxImpl = ctx->getImpl();
883  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
884  "registering a new operation kind while in a multi-threaded execution "
885  "context");
886 
887  // Register the attribute names of this operation.
888  MutableArrayRef<StringAttr> cachedAttrNames;
889  if (!attrNames.empty()) {
890  cachedAttrNames = MutableArrayRef<StringAttr>(
891  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
892  attrNames.size()),
893  attrNames.size());
894  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
895  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
896  impl->attributeNames = cachedAttrNames;
897  }
898  StringRef name = impl->getName().strref();
899  // Insert the operation info if it doesn't exist yet.
900  auto it = ctxImpl.operations.insert({name, nullptr});
901  it.first->second = std::move(ownedImpl);
902 
903  // Update the registered info for this operation.
904  auto emplaced = ctxImpl.registeredOperations.try_emplace(
906  assert(emplaced.second && "operation name registration must be successful");
907 
908  // Add emplaced operation name to the sorted operations container.
909  RegisteredOperationName &value = emplaced.first->getValue();
910  ctxImpl.sortedRegisteredOperations.insert(
911  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
912  [](auto &lhs, auto &rhs) {
913  return lhs.getIdentifier().compare(
914  rhs.getIdentifier());
915  }),
916  value);
917 }
918 
919 //===----------------------------------------------------------------------===//
920 // AbstractType
921 //===----------------------------------------------------------------------===//
922 
924  const AbstractType *type = lookupMutable(typeID, context);
925  if (!type)
926  llvm::report_fatal_error(
927  "Trying to create a Type that was not registered in this MLIRContext.");
928  return *type;
929 }
930 
931 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
932  auto &impl = context->getImpl();
933  auto it = impl.registeredTypes.find(typeID);
934  if (it == impl.registeredTypes.end())
935  return nullptr;
936  return it->second;
937 }
938 
939 //===----------------------------------------------------------------------===//
940 // Type uniquing
941 //===----------------------------------------------------------------------===//
942 
943 /// Returns the storage uniquer used for constructing type storage instances.
944 /// This should not be used directly.
946 
947 Float8E5M2Type Float8E5M2Type::get(MLIRContext *context) {
948  return context->getImpl().f8E5M2Ty;
949 }
950 Float8E4M3FNType Float8E4M3FNType::get(MLIRContext *context) {
951  return context->getImpl().f8E4M3FNTy;
952 }
953 Float8E5M2FNUZType Float8E5M2FNUZType::get(MLIRContext *context) {
954  return context->getImpl().f8E5M2FNUZTy;
955 }
956 Float8E4M3FNUZType Float8E4M3FNUZType::get(MLIRContext *context) {
957  return context->getImpl().f8E4M3FNUZTy;
958 }
959 Float8E4M3B11FNUZType Float8E4M3B11FNUZType::get(MLIRContext *context) {
960  return context->getImpl().f8E4M3B11FNUZTy;
961 }
962 BFloat16Type BFloat16Type::get(MLIRContext *context) {
963  return context->getImpl().bf16Ty;
964 }
965 Float16Type Float16Type::get(MLIRContext *context) {
966  return context->getImpl().f16Ty;
967 }
968 Float32Type Float32Type::get(MLIRContext *context) {
969  return context->getImpl().f32Ty;
970 }
971 Float64Type Float64Type::get(MLIRContext *context) {
972  return context->getImpl().f64Ty;
973 }
974 Float80Type Float80Type::get(MLIRContext *context) {
975  return context->getImpl().f80Ty;
976 }
977 Float128Type Float128Type::get(MLIRContext *context) {
978  return context->getImpl().f128Ty;
979 }
980 
981 /// Get an instance of the IndexType.
982 IndexType IndexType::get(MLIRContext *context) {
983  return context->getImpl().indexTy;
984 }
985 
986 /// Return an existing integer type instance if one is cached within the
987 /// context.
988 static IntegerType
989 getCachedIntegerType(unsigned width,
990  IntegerType::SignednessSemantics signedness,
991  MLIRContext *context) {
992  if (signedness != IntegerType::Signless)
993  return IntegerType();
994 
995  switch (width) {
996  case 1:
997  return context->getImpl().int1Ty;
998  case 8:
999  return context->getImpl().int8Ty;
1000  case 16:
1001  return context->getImpl().int16Ty;
1002  case 32:
1003  return context->getImpl().int32Ty;
1004  case 64:
1005  return context->getImpl().int64Ty;
1006  case 128:
1007  return context->getImpl().int128Ty;
1008  default:
1009  return IntegerType();
1010  }
1011 }
1012 
1013 IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1014  IntegerType::SignednessSemantics signedness) {
1015  if (auto cached = getCachedIntegerType(width, signedness, context))
1016  return cached;
1017  return Base::get(context, width, signedness);
1018 }
1019 
1020 IntegerType
1021 IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1022  MLIRContext *context, unsigned width,
1023  SignednessSemantics signedness) {
1024  if (auto cached = getCachedIntegerType(width, signedness, context))
1025  return cached;
1026  return Base::getChecked(emitError, context, width, signedness);
1027 }
1028 
1029 /// Get an instance of the NoneType.
1030 NoneType NoneType::get(MLIRContext *context) {
1031  if (NoneType cachedInst = context->getImpl().noneType)
1032  return cachedInst;
1033  // Note: May happen when initializing the singleton attributes of the builtin
1034  // dialect.
1035  return Base::get(context);
1036 }
1037 
1038 //===----------------------------------------------------------------------===//
1039 // Attribute uniquing
1040 //===----------------------------------------------------------------------===//
1041 
1042 /// Returns the storage uniquer used for constructing attribute storage
1043 /// instances. This should not be used directly.
1045  return getImpl().attributeUniquer;
1046 }
1047 
1048 /// Initialize the given attribute storage instance.
1049 void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1050  MLIRContext *ctx,
1051  TypeID attrID) {
1053 }
1054 
1055 BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1056  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1057 }
1058 
1059 UnitAttr UnitAttr::get(MLIRContext *context) {
1060  return context->getImpl().unitAttr;
1061 }
1062 
1063 UnknownLoc UnknownLoc::get(MLIRContext *context) {
1064  return context->getImpl().unknownLocAttr;
1065 }
1066 
1067 /// Return empty dictionary.
1068 DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1069  return context->getImpl().emptyDictionaryAttr;
1070 }
1071 
1072 void StringAttrStorage::initialize(MLIRContext *context) {
1073  // Check for a dialect namespace prefix, if there isn't one we don't need to
1074  // do any additional initialization.
1075  auto dialectNamePair = value.split('.');
1076  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1077  return;
1078 
1079  // If one exists, we check to see if this dialect is loaded. If it is, we set
1080  // the dialect now, if it isn't we record this storage for initialization
1081  // later if the dialect ever gets loaded.
1082  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1083  return;
1084 
1085  MLIRContextImpl &impl = context->getImpl();
1086  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1087  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1088 }
1089 
1090 /// Return an empty string.
1091 StringAttr StringAttr::get(MLIRContext *context) {
1092  return context->getImpl().emptyStringAttr;
1093 }
1094 
1095 //===----------------------------------------------------------------------===//
1096 // AffineMap uniquing
1097 //===----------------------------------------------------------------------===//
1098 
1100  return getImpl().affineUniquer;
1101 }
1102 
1103 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1104  ArrayRef<AffineExpr> results,
1105  MLIRContext *context) {
1106  auto &impl = context->getImpl();
1107  auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1108  [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1109  symbolCount, results);
1110  return AffineMap(storage);
1111 }
1112 
1113 /// Check whether the arguments passed to the AffineMap::get() are consistent.
1114 /// This method checks whether the highest index of dimensional identifier
1115 /// present in result expressions is less than `dimCount` and the highest index
1116 /// of symbolic identifier present in result expressions is less than
1117 /// `symbolCount`.
1118 LLVM_ATTRIBUTE_UNUSED static bool
1119 willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1120  ArrayRef<AffineExpr> results) {
1121  int64_t maxDimPosition = -1;
1122  int64_t maxSymbolPosition = -1;
1123  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1124  maxSymbolPosition);
1125  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1126  LLVM_DEBUG(
1127  llvm::dbgs()
1128  << "maximum dimensional identifier position in result expression must "
1129  "be less than `dimCount` and maximum symbolic identifier position "
1130  "in result expression must be less than `symbolCount`\n");
1131  return false;
1132  }
1133  return true;
1134 }
1135 
1137  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1138 }
1139 
1140 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1141  MLIRContext *context) {
1142  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1143 }
1144 
1145 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1146  AffineExpr result) {
1147  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1148  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1149 }
1150 
1151 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1152  ArrayRef<AffineExpr> results, MLIRContext *context) {
1153  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1154  return getImpl(dimCount, symbolCount, results, context);
1155 }
1156 
1157 //===----------------------------------------------------------------------===//
1158 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1159 // Unlike AffineMap's, these are uniqued only if they are small.
1160 //===----------------------------------------------------------------------===//
1161 
1162 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1163  ArrayRef<AffineExpr> constraints,
1164  ArrayRef<bool> eqFlags) {
1165  // The number of constraints can't be zero.
1166  assert(!constraints.empty());
1167  assert(constraints.size() == eqFlags.size());
1168 
1169  auto &impl = constraints[0].getContext()->getImpl();
1170  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1171  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1172  return IntegerSet(storage);
1173 }
1174 
1175 //===----------------------------------------------------------------------===//
1176 // StorageUniquerSupport
1177 //===----------------------------------------------------------------------===//
1178 
1179 /// Utility method to generate a callback that can be used to generate a
1180 /// diagnostic when checking the construction invariants of a storage object.
1181 /// This is defined out-of-line to avoid the need to include Location.h.
1182 llvm::unique_function<InFlightDiagnostic()>
1184  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1185 }
1186 llvm::unique_function<InFlightDiagnostic()>
1188  return [=] { return emitError(loc); };
1189 }
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:78
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:76
static IntegerType getCachedIntegerType(unsigned width, IntegerType::SignednessSemantics signedness, MLIRContext *context)
Return an existing integer type instance if one is cached within the context.
static std::string diag(const llvm::Value &value)
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:25
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:44
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:408
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:255
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition: Dialect.cpp:189
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
A dialect that can be defined at runtime.
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
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
DenseMap< StringRef, std::unique_ptr< Dialect > > loadedDialects
This is a list of dialects that are created referring to this context.
BoolAttr falseAttr
Cached Attribute Instances.
llvm::sys::SmartRWMutex< true > operationInfoMutex
A mutex used when accessing operation information.
Float8E5M2FNUZType f8E5M2FNUZTy
DenseMap< StringRef, SmallVector< StringAttrStorage * > > dialectReferencingStrAttrs
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.
StorageUniquer typeUniquer
llvm::BumpPtrAllocator abstractDialectSymbolAllocator
An allocator used for AbstractAttribute and AbstractType objects.
DenseMap< TypeID, AbstractType * > registeredTypes
Float8E5M2Type f8E5M2Ty
Cached Type Instances.
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
llvm::StringMap< RegisteredOperationName > registeredOperations
A vector of operation info specifically for registered operations.
Float8E4M3B11FNUZType f8E4M3B11FNUZTy
SmallVector< RegisteredOperationName, 0 > sortedRegisteredOperations
This is a sorted container of registered operations for a deterministic and efficient getRegisteredOp...
Float8E4M3FNType f8E4M3FNTy
MLIRContextImpl(bool threadingIsEnabled)
std::unique_ptr< llvm::ThreadPool > ownedThreadPool
In case where the thread pool is owned by the context, this ensures destruction with the context.
StorageUniquer attributeUniquer
DialectRegistry dialectsRegistry
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::ThreadPool &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.
llvm::ThreadPool & getThreadPool()
Return the thread pool used by this context.
StorageUniquer & getTypeUniquer()
Returns the storage uniquer used for constructing type storage instances.
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:841
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
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:39
Detect if any of the given parameter types has a sub-element handler.
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...
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
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:89
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
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:632
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
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 verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> getDiag) 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 setPropertiesFromAttr(Operation *, Attribute, InFlightDiagnostic *) final
Attribute getPropertiesAsAttr(Operation *) 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.
Dialect * referencedDialect
If the string value contains a dialect namespace prefix (e.g.