MLIR  19.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.
186  llvm::StringMap<RegisteredOperationName> registeredOperations;
187 
188  /// This is a sorted container of registered operations for a deterministic
189  /// and efficient `getRegisteredOperations` implementation.
191 
192  /// This is a list of dialects that are created referring to this context.
193  /// The MLIRContext owns the objects. These need to be declared after the
194  /// registered operations to ensure correct destruction order.
197 
198  /// A mutex used when accessing operation information.
199  llvm::sys::SmartRWMutex<true> operationInfoMutex;
200 
201  //===--------------------------------------------------------------------===//
202  // Affine uniquing
203  //===--------------------------------------------------------------------===//
204 
205  // Affine expression, map and integer set uniquing.
207 
208  //===--------------------------------------------------------------------===//
209  // Type uniquing
210  //===--------------------------------------------------------------------===//
211 
214 
215  /// This is a mapping from type name to the abstract type describing it.
216  /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.
217  /// As this map needs to be populated before `StringAttr` is loaded, we
218  /// cannot use `StringAttr` as the key. The context does not take ownership
219  /// of the key, so the `StringRef` must outlive the context.
221 
222  /// Cached Type Instances.
223  Float8E5M2Type f8E5M2Ty;
224  Float8E4M3FNType f8E4M3FNTy;
225  Float8E5M2FNUZType f8E5M2FNUZTy;
226  Float8E4M3FNUZType f8E4M3FNUZTy;
227  Float8E4M3B11FNUZType f8E4M3B11FNUZTy;
228  BFloat16Type bf16Ty;
229  Float16Type f16Ty;
230  FloatTF32Type tf32Ty;
231  Float32Type f32Ty;
232  Float64Type f64Ty;
233  Float80Type f80Ty;
234  Float128Type f128Ty;
235  IndexType indexTy;
236  IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
237  NoneType noneType;
238 
239  //===--------------------------------------------------------------------===//
240  // Attribute uniquing
241  //===--------------------------------------------------------------------===//
242 
245 
246  /// This is a mapping from attribute name to the abstract attribute describing
247  /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a
248  /// name.
249  /// As this map needs to be populated before `StringAttr` is loaded, we
250  /// cannot use `StringAttr` as the key. The context does not take ownership
251  /// of the key, so the `StringRef` must outlive the context.
253 
254  /// Cached Attribute Instances.
255  BoolAttr falseAttr, trueAttr;
256  UnitAttr unitAttr;
257  UnknownLoc unknownLocAttr;
258  DictionaryAttr emptyDictionaryAttr;
259  StringAttr emptyStringAttr;
260 
261  /// Map of string attributes that may reference a dialect, that are awaiting
262  /// that dialect to be loaded.
266 
267  /// A distinct attribute allocator that allocates every time since the
268  /// address of the distinct attribute storage serves as unique identifier. The
269  /// allocator is thread safe and frees the allocated storage after its
270  /// destruction.
272 
273 public:
274  MLIRContextImpl(bool threadingIsEnabled)
275  : threadingIsEnabled(threadingIsEnabled) {
276  if (threadingIsEnabled) {
277  ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
278  threadPool = ownedThreadPool.get();
279  }
280  }
282  for (auto typeMapping : registeredTypes)
283  typeMapping.second->~AbstractType();
284  for (auto attrMapping : registeredAttributes)
285  attrMapping.second->~AbstractAttribute();
286  }
287 };
288 } // namespace mlir
289 
291  : MLIRContext(DialectRegistry(), setting) {}
292 
294  : impl(new MLIRContextImpl(setting == Threading::ENABLED &&
296  // Initialize values based on the command line flags if they were provided.
297  if (clOptions.isConstructed()) {
298  printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
299  printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
300  }
301 
302  // Pre-populate the registry.
303  registry.appendTo(impl->dialectsRegistry);
304 
305  // Ensure the builtin dialect is always pre-loaded.
306  getOrLoadDialect<BuiltinDialect>();
307 
308  // Initialize several common attributes and types to avoid the need to lock
309  // the context when accessing them.
310 
311  //// Types.
312  /// Floating-point Types.
313  impl->f8E5M2Ty = TypeUniquer::get<Float8E5M2Type>(this);
314  impl->f8E4M3FNTy = TypeUniquer::get<Float8E4M3FNType>(this);
315  impl->f8E5M2FNUZTy = TypeUniquer::get<Float8E5M2FNUZType>(this);
316  impl->f8E4M3FNUZTy = TypeUniquer::get<Float8E4M3FNUZType>(this);
317  impl->f8E4M3B11FNUZTy = TypeUniquer::get<Float8E4M3B11FNUZType>(this);
318  impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
319  impl->f16Ty = TypeUniquer::get<Float16Type>(this);
320  impl->tf32Ty = TypeUniquer::get<FloatTF32Type>(this);
321  impl->f32Ty = TypeUniquer::get<Float32Type>(this);
322  impl->f64Ty = TypeUniquer::get<Float64Type>(this);
323  impl->f80Ty = TypeUniquer::get<Float80Type>(this);
324  impl->f128Ty = TypeUniquer::get<Float128Type>(this);
325  /// Index Type.
326  impl->indexTy = TypeUniquer::get<IndexType>(this);
327  /// Integer Types.
328  impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
329  impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
330  impl->int16Ty =
331  TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
332  impl->int32Ty =
333  TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
334  impl->int64Ty =
335  TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
336  impl->int128Ty =
337  TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
338  /// None Type.
339  impl->noneType = TypeUniquer::get<NoneType>(this);
340 
341  //// Attributes.
342  //// Note: These must be registered after the types as they may generate one
343  //// of the above types internally.
344  /// Unknown Location Attribute.
345  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
346  /// Bool Attributes.
347  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
348  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
349  /// Unit Attribute.
350  impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
351  /// The empty dictionary attribute.
352  impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
353  /// The empty string attribute.
354  impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
355 
356  // Register the affine storage objects with the uniquer.
357  impl->affineUniquer
358  .registerParametricStorageType<AffineBinaryOpExprStorage>();
359  impl->affineUniquer
360  .registerParametricStorageType<AffineConstantExprStorage>();
361  impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
362  impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
363  impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
364 }
365 
366 MLIRContext::~MLIRContext() = default;
367 
368 /// Copy the specified array of elements into memory managed by the provided
369 /// bump pointer allocator. This assumes the elements are all PODs.
370 template <typename T>
371 static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
372  ArrayRef<T> elements) {
373  auto result = allocator.Allocate<T>(elements.size());
374  std::uninitialized_copy(elements.begin(), elements.end(), result);
375  return ArrayRef<T>(result, elements.size());
376 }
377 
378 //===----------------------------------------------------------------------===//
379 // Action Handling
380 //===----------------------------------------------------------------------===//
381 
383  getImpl().actionHandler = std::move(handler);
384 }
385 
386 /// Dispatch the provided action to the handler if any, or just execute it.
387 void MLIRContext::executeActionInternal(function_ref<void()> actionFn,
388  const tracing::Action &action) {
389  assert(getImpl().actionHandler);
390  getImpl().actionHandler(actionFn, action);
391 }
392 
394 
395 //===----------------------------------------------------------------------===//
396 // Diagnostic Handlers
397 //===----------------------------------------------------------------------===//
398 
399 /// Returns the diagnostic engine for this context.
401 
402 //===----------------------------------------------------------------------===//
403 // Dialect and Operation Registration
404 //===----------------------------------------------------------------------===//
405 
407  if (registry.isSubsetOf(impl->dialectsRegistry))
408  return;
409 
410  assert(impl->multiThreadedExecutionContext == 0 &&
411  "appending to the MLIRContext dialect registry while in a "
412  "multi-threaded execution context");
413  registry.appendTo(impl->dialectsRegistry);
414 
415  // For the already loaded dialects, apply any possible extensions immediately.
416  registry.applyExtensions(this);
417 }
418 
420  return impl->dialectsRegistry;
421 }
422 
423 /// Return information about all registered IR dialects.
424 std::vector<Dialect *> MLIRContext::getLoadedDialects() {
425  std::vector<Dialect *> result;
426  result.reserve(impl->loadedDialects.size());
427  for (auto &dialect : impl->loadedDialects)
428  result.push_back(dialect.second.get());
429  llvm::array_pod_sort(result.begin(), result.end(),
430  [](Dialect *const *lhs, Dialect *const *rhs) -> int {
431  return (*lhs)->getNamespace() < (*rhs)->getNamespace();
432  });
433  return result;
434 }
435 std::vector<StringRef> MLIRContext::getAvailableDialects() {
436  std::vector<StringRef> result;
437  for (auto dialect : impl->dialectsRegistry.getDialectNames())
438  result.push_back(dialect);
439  return result;
440 }
441 
442 /// Get a registered IR dialect with the given namespace. If none is found,
443 /// then return nullptr.
445  // Dialects are sorted by name, so we can use binary search for lookup.
446  auto it = impl->loadedDialects.find(name);
447  return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
448 }
449 
451  Dialect *dialect = getLoadedDialect(name);
452  if (dialect)
453  return dialect;
454  DialectAllocatorFunctionRef allocator =
455  impl->dialectsRegistry.getDialectAllocator(name);
456  return allocator ? allocator(this) : nullptr;
457 }
458 
459 /// Get a dialect for the provided namespace and TypeID: abort the program if a
460 /// dialect exist for this namespace with different TypeID. Returns a pointer to
461 /// the dialect owned by the context.
462 Dialect *
463 MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
464  function_ref<std::unique_ptr<Dialect>()> ctor) {
465  auto &impl = getImpl();
466  // Get the correct insertion position sorted by namespace.
467  auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);
468 
469  if (dialectIt.second) {
470  LLVM_DEBUG(llvm::dbgs()
471  << "Load new dialect in Context " << dialectNamespace << "\n");
472 #ifndef NDEBUG
473  if (impl.multiThreadedExecutionContext != 0)
474  llvm::report_fatal_error(
475  "Loading a dialect (" + dialectNamespace +
476  ") while in a multi-threaded execution context (maybe "
477  "the PassManager): this can indicate a "
478  "missing `dependentDialects` in a pass for example.");
479 #endif // NDEBUG
480  // loadedDialects entry is initialized to nullptr, indicating that the
481  // dialect is currently being loaded. Re-lookup the address in
482  // loadedDialects because the table might have been rehashed by recursive
483  // dialect loading in ctor().
484  std::unique_ptr<Dialect> &dialectOwned =
485  impl.loadedDialects[dialectNamespace] = ctor();
486  Dialect *dialect = dialectOwned.get();
487  assert(dialect && "dialect ctor failed");
488 
489  // Refresh all the identifiers dialect field, this catches cases where a
490  // dialect may be loaded after identifier prefixed with this dialect name
491  // were already created.
492  auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
493  if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
494  for (StringAttrStorage *storage : stringAttrsIt->second)
495  storage->referencedDialect = dialect;
496  impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
497  }
498 
499  // Apply any extensions to this newly loaded dialect.
500  impl.dialectsRegistry.applyExtensions(dialect);
501  return dialect;
502  }
503 
504 #ifndef NDEBUG
505  if (dialectIt.first->second == nullptr)
506  llvm::report_fatal_error(
507  "Loading (and getting) a dialect (" + dialectNamespace +
508  ") while the same dialect is still loading: use loadDialect instead "
509  "of getOrLoadDialect.");
510 #endif // NDEBUG
511 
512  // Abort if dialect with namespace has already been registered.
513  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;
514  if (dialect->getTypeID() != dialectID)
515  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
516  "' has already been registered");
517 
518  return dialect.get();
519 }
520 
521 bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {
522  auto it = getImpl().loadedDialects.find(dialectNamespace);
523  // nullptr indicates that the dialect is currently being loaded.
524  return it != getImpl().loadedDialects.end() && it->second == nullptr;
525 }
526 
528  StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {
529  auto &impl = getImpl();
530  // Get the correct insertion position sorted by namespace.
531  auto dialectIt = impl.loadedDialects.find(dialectNamespace);
532 
533  if (dialectIt != impl.loadedDialects.end()) {
534  if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))
535  return dynDialect;
536  llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
537  "' has already been registered");
538  }
539 
540  LLVM_DEBUG(llvm::dbgs() << "Load new dynamic dialect in Context "
541  << dialectNamespace << "\n");
542 #ifndef NDEBUG
543  if (impl.multiThreadedExecutionContext != 0)
544  llvm::report_fatal_error(
545  "Loading a dynamic dialect (" + dialectNamespace +
546  ") while in a multi-threaded execution context (maybe "
547  "the PassManager): this can indicate a "
548  "missing `dependentDialects` in a pass for example.");
549 #endif
550 
551  auto name = StringAttr::get(this, dialectNamespace);
552  auto *dialect = new DynamicDialect(name, this);
553  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {
554  ctor(dialect);
555  return std::unique_ptr<DynamicDialect>(dialect);
556  });
557  // This is the same result as `getOrLoadDialect` (if it didn't failed),
558  // since it has the same TypeID, and TypeIDs are unique.
559  return dialect;
560 }
561 
563  for (StringRef name : getAvailableDialects())
564  getOrLoadDialect(name);
565 }
566 
567 llvm::hash_code MLIRContext::getRegistryHash() {
568  llvm::hash_code hash(0);
569  // Factor in number of loaded dialects, attributes, operations, types.
570  hash = llvm::hash_combine(hash, impl->loadedDialects.size());
571  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
572  hash = llvm::hash_combine(hash, impl->registeredOperations.size());
573  hash = llvm::hash_combine(hash, impl->registeredTypes.size());
574  return hash;
575 }
576 
578  return impl->allowUnregisteredDialects;
579 }
580 
582  assert(impl->multiThreadedExecutionContext == 0 &&
583  "changing MLIRContext `allow-unregistered-dialects` configuration "
584  "while in a multi-threaded execution context");
585  impl->allowUnregisteredDialects = allowing;
586 }
587 
588 /// Return true if multi-threading is enabled by the context.
590  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
591 }
592 
593 /// Set the flag specifying if multi-threading is disabled by the context.
595  // This API can be overridden by the global debugging flag
596  // --mlir-disable-threading
598  return;
599  assert(impl->multiThreadedExecutionContext == 0 &&
600  "changing MLIRContext `disable-threading` configuration while "
601  "in a multi-threaded execution context");
602 
603  impl->threadingIsEnabled = !disable;
604 
605  // Update the threading mode for each of the uniquers.
606  impl->affineUniquer.disableMultithreading(disable);
607  impl->attributeUniquer.disableMultithreading(disable);
608  impl->typeUniquer.disableMultithreading(disable);
609 
610  // Destroy thread pool (stop all threads) if it is no longer needed, or create
611  // a new one if multithreading was re-enabled.
612  if (disable) {
613  // If the thread pool is owned, explicitly set it to nullptr to avoid
614  // keeping a dangling pointer around. If the thread pool is externally
615  // owned, we don't do anything.
616  if (impl->ownedThreadPool) {
617  assert(impl->threadPool);
618  impl->threadPool = nullptr;
619  impl->ownedThreadPool.reset();
620  }
621  } else if (!impl->threadPool) {
622  // The thread pool isn't externally provided.
623  assert(!impl->ownedThreadPool);
624  impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
625  impl->threadPool = impl->ownedThreadPool.get();
626  }
627 }
628 
629 void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {
630  assert(!isMultithreadingEnabled() &&
631  "expected multi-threading to be disabled when setting a ThreadPool");
632  impl->threadPool = &pool;
633  impl->ownedThreadPool.reset();
635 }
636 
638  if (isMultithreadingEnabled()) {
639  assert(impl->threadPool &&
640  "multi-threading is enabled but threadpool not set");
641  return impl->threadPool->getMaxConcurrency();
642  }
643  // No multithreading or active thread pool. Return 1 thread.
644  return 1;
645 }
646 
647 llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {
648  assert(isMultithreadingEnabled() &&
649  "expected multi-threading to be enabled within the context");
650  assert(impl->threadPool &&
651  "multi-threading is enabled but threadpool not set");
652  return *impl->threadPool;
653 }
654 
656 #ifndef NDEBUG
657  ++impl->multiThreadedExecutionContext;
658 #endif
659 }
661 #ifndef NDEBUG
662  --impl->multiThreadedExecutionContext;
663 #endif
664 }
665 
666 /// Return true if we should attach the operation to diagnostics emitted via
667 /// Operation::emit.
669  return impl->printOpOnDiagnostic;
670 }
671 
672 /// Set the flag specifying if we should attach the operation to diagnostics
673 /// emitted via Operation::emit.
675  assert(impl->multiThreadedExecutionContext == 0 &&
676  "changing MLIRContext `print-op-on-diagnostic` configuration while in "
677  "a multi-threaded execution context");
678  impl->printOpOnDiagnostic = enable;
679 }
680 
681 /// Return true if we should attach the current stacktrace to diagnostics when
682 /// emitted.
684  return impl->printStackTraceOnDiagnostic;
685 }
686 
687 /// Set the flag specifying if we should attach the current stacktrace when
688 /// emitting diagnostics.
690  assert(impl->multiThreadedExecutionContext == 0 &&
691  "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
692  "while in a multi-threaded execution context");
693  impl->printStackTraceOnDiagnostic = enable;
694 }
695 
696 /// Return information about all registered operations.
698  return impl->sortedRegisteredOperations;
699 }
700 
702  return RegisteredOperationName::lookup(name, this).has_value();
703 }
704 
705 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
706  auto &impl = context->getImpl();
707  assert(impl.multiThreadedExecutionContext == 0 &&
708  "Registering a new type kind while in a multi-threaded execution "
709  "context");
710  auto *newInfo =
711  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
712  AbstractType(std::move(typeInfo));
713  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
714  llvm::report_fatal_error("Dialect Type already registered.");
715  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
716  llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
717  " is already registered.");
718 }
719 
720 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
721  auto &impl = context->getImpl();
722  assert(impl.multiThreadedExecutionContext == 0 &&
723  "Registering a new attribute kind while in a multi-threaded execution "
724  "context");
725  auto *newInfo =
726  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
727  AbstractAttribute(std::move(attrInfo));
728  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
729  llvm::report_fatal_error("Dialect Attribute already registered.");
730  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
731  llvm::report_fatal_error("Dialect Attribute with name " +
732  newInfo->getName() + " is already registered.");
733 }
734 
735 //===----------------------------------------------------------------------===//
736 // AbstractAttribute
737 //===----------------------------------------------------------------------===//
738 
739 /// Get the dialect that registered the attribute with the provided typeid.
741  MLIRContext *context) {
742  const AbstractAttribute *abstract = lookupMutable(typeID, context);
743  if (!abstract)
744  llvm::report_fatal_error("Trying to create an Attribute that was not "
745  "registered in this MLIRContext.");
746  return *abstract;
747 }
748 
749 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
750  MLIRContext *context) {
751  auto &impl = context->getImpl();
752  return impl.registeredAttributes.lookup(typeID);
753 }
754 
755 std::optional<std::reference_wrapper<const AbstractAttribute>>
756 AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
757  MLIRContextImpl &impl = context->getImpl();
758  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
759 
760  if (!type)
761  return std::nullopt;
762  return {*type};
763 }
764 
765 //===----------------------------------------------------------------------===//
766 // OperationName
767 //===----------------------------------------------------------------------===//
768 
769 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
770  detail::InterfaceMap interfaceMap)
771  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
772  std::move(interfaceMap)) {}
773 
774 OperationName::OperationName(StringRef name, MLIRContext *context) {
775  MLIRContextImpl &ctxImpl = context->getImpl();
776 
777  // Check for an existing name in read-only mode.
778  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
779  if (isMultithreadingEnabled) {
780  // Check the registered info map first. In the overwhelmingly common case,
781  // the entry will be in here and it also removes the need to acquire any
782  // locks.
783  auto registeredIt = ctxImpl.registeredOperations.find(name);
784  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperations.end())) {
785  impl = registeredIt->second.impl;
786  return;
787  }
788 
789  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
790  auto it = ctxImpl.operations.find(name);
791  if (it != ctxImpl.operations.end()) {
792  impl = it->second.get();
793  return;
794  }
795  }
796 
797  // Acquire a writer-lock so that we can safely create the new instance.
798  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
799 
800  auto it = ctxImpl.operations.insert({name, nullptr});
801  if (it.second) {
802  auto nameAttr = StringAttr::get(context, name);
803  it.first->second = std::make_unique<UnregisteredOpModel>(
804  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
806  }
807  impl = it.first->second.get();
808 }
809 
811  if (Dialect *dialect = getDialect())
812  return dialect->getNamespace();
813  return getStringRef().split('.').first;
814 }
815 
819  return failure();
820 }
824 
827  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
828 }
830  const OperationName &, NamedAttrList &) {}
832  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
833  p.printGenericOp(op);
834 }
837  return success();
838 }
841  return success();
842 }
843 
844 std::optional<Attribute>
846  StringRef name) {
847  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
848  if (!dict)
849  return std::nullopt;
850  if (Attribute attr = dict.get(name))
851  return attr;
852  return std::nullopt;
853 }
855  StringAttr name,
856  Attribute value) {
857  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
858  assert(dict);
859  NamedAttrList attrs(dict);
860  attrs.set(name, value);
861  *op->getPropertiesStorage().as<Attribute *>() =
862  attrs.getDictionary(op->getContext());
863 }
865  Operation *op, NamedAttrList &attrs) {}
867  OperationName opName, NamedAttrList &attributes,
869  return success();
870 }
872  return sizeof(Attribute);
873 }
875  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
876  new (storage.as<Attribute *>()) Attribute();
877 }
879  OpaqueProperties prop) {
880  prop.as<Attribute *>()->~Attribute();
881 }
883  OperationName opName, OpaqueProperties properties) {}
885  OperationName opName, OpaqueProperties properties, Attribute attr,
887  *properties.as<Attribute *>() = attr;
888  return success();
889 }
890 Attribute
892  return *op->getPropertiesStorage().as<Attribute *>();
893 }
895  OpaqueProperties rhs) {
896  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
897 }
900  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
901 }
902 llvm::hash_code
904  return llvm::hash_combine(*prop.as<Attribute *>());
905 }
906 
907 //===----------------------------------------------------------------------===//
908 // RegisteredOperationName
909 //===----------------------------------------------------------------------===//
910 
911 std::optional<RegisteredOperationName>
913  auto &impl = ctx->getImpl();
914  auto it = impl.registeredOperations.find(name);
915  if (it != impl.registeredOperations.end())
916  return it->getValue();
917  return std::nullopt;
918 }
919 
921  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
922  ArrayRef<StringRef> attrNames) {
923  RegisteredOperationName::Impl *impl = ownedImpl.get();
924  MLIRContext *ctx = impl->getDialect()->getContext();
925  auto &ctxImpl = ctx->getImpl();
926  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
927  "registering a new operation kind while in a multi-threaded execution "
928  "context");
929 
930  // Register the attribute names of this operation.
931  MutableArrayRef<StringAttr> cachedAttrNames;
932  if (!attrNames.empty()) {
933  cachedAttrNames = MutableArrayRef<StringAttr>(
934  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
935  attrNames.size()),
936  attrNames.size());
937  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
938  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
939  impl->attributeNames = cachedAttrNames;
940  }
941  StringRef name = impl->getName().strref();
942  // Insert the operation info if it doesn't exist yet.
943  auto it = ctxImpl.operations.insert({name, nullptr});
944  it.first->second = std::move(ownedImpl);
945 
946  // Update the registered info for this operation.
947  auto emplaced = ctxImpl.registeredOperations.try_emplace(
949  assert(emplaced.second && "operation name registration must be successful");
950 
951  // Add emplaced operation name to the sorted operations container.
952  RegisteredOperationName &value = emplaced.first->getValue();
953  ctxImpl.sortedRegisteredOperations.insert(
954  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
955  [](auto &lhs, auto &rhs) {
956  return lhs.getIdentifier().compare(
957  rhs.getIdentifier());
958  }),
959  value);
960 }
961 
962 //===----------------------------------------------------------------------===//
963 // AbstractType
964 //===----------------------------------------------------------------------===//
965 
967  const AbstractType *type = lookupMutable(typeID, context);
968  if (!type)
969  llvm::report_fatal_error(
970  "Trying to create a Type that was not registered in this MLIRContext.");
971  return *type;
972 }
973 
974 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
975  auto &impl = context->getImpl();
976  return impl.registeredTypes.lookup(typeID);
977 }
978 
979 std::optional<std::reference_wrapper<const AbstractType>>
980 AbstractType::lookup(StringRef name, MLIRContext *context) {
981  MLIRContextImpl &impl = context->getImpl();
982  const AbstractType *type = impl.nameToType.lookup(name);
983 
984  if (!type)
985  return std::nullopt;
986  return {*type};
987 }
988 
989 //===----------------------------------------------------------------------===//
990 // Type uniquing
991 //===----------------------------------------------------------------------===//
992 
993 /// Returns the storage uniquer used for constructing type storage instances.
994 /// This should not be used directly.
996 
997 Float8E5M2Type Float8E5M2Type::get(MLIRContext *context) {
998  return context->getImpl().f8E5M2Ty;
999 }
1000 Float8E4M3FNType Float8E4M3FNType::get(MLIRContext *context) {
1001  return context->getImpl().f8E4M3FNTy;
1002 }
1003 Float8E5M2FNUZType Float8E5M2FNUZType::get(MLIRContext *context) {
1004  return context->getImpl().f8E5M2FNUZTy;
1005 }
1006 Float8E4M3FNUZType Float8E4M3FNUZType::get(MLIRContext *context) {
1007  return context->getImpl().f8E4M3FNUZTy;
1008 }
1009 Float8E4M3B11FNUZType Float8E4M3B11FNUZType::get(MLIRContext *context) {
1010  return context->getImpl().f8E4M3B11FNUZTy;
1011 }
1012 BFloat16Type BFloat16Type::get(MLIRContext *context) {
1013  return context->getImpl().bf16Ty;
1014 }
1015 Float16Type Float16Type::get(MLIRContext *context) {
1016  return context->getImpl().f16Ty;
1017 }
1018 FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1019  return context->getImpl().tf32Ty;
1020 }
1021 Float32Type Float32Type::get(MLIRContext *context) {
1022  return context->getImpl().f32Ty;
1023 }
1024 Float64Type Float64Type::get(MLIRContext *context) {
1025  return context->getImpl().f64Ty;
1026 }
1027 Float80Type Float80Type::get(MLIRContext *context) {
1028  return context->getImpl().f80Ty;
1029 }
1030 Float128Type Float128Type::get(MLIRContext *context) {
1031  return context->getImpl().f128Ty;
1032 }
1033 
1034 /// Get an instance of the IndexType.
1035 IndexType IndexType::get(MLIRContext *context) {
1036  return context->getImpl().indexTy;
1037 }
1038 
1039 /// Return an existing integer type instance if one is cached within the
1040 /// context.
1041 static IntegerType
1042 getCachedIntegerType(unsigned width,
1043  IntegerType::SignednessSemantics signedness,
1044  MLIRContext *context) {
1045  if (signedness != IntegerType::Signless)
1046  return IntegerType();
1047 
1048  switch (width) {
1049  case 1:
1050  return context->getImpl().int1Ty;
1051  case 8:
1052  return context->getImpl().int8Ty;
1053  case 16:
1054  return context->getImpl().int16Ty;
1055  case 32:
1056  return context->getImpl().int32Ty;
1057  case 64:
1058  return context->getImpl().int64Ty;
1059  case 128:
1060  return context->getImpl().int128Ty;
1061  default:
1062  return IntegerType();
1063  }
1064 }
1065 
1066 IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1067  IntegerType::SignednessSemantics signedness) {
1068  if (auto cached = getCachedIntegerType(width, signedness, context))
1069  return cached;
1070  return Base::get(context, width, signedness);
1071 }
1072 
1073 IntegerType
1074 IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1075  MLIRContext *context, unsigned width,
1076  SignednessSemantics signedness) {
1077  if (auto cached = getCachedIntegerType(width, signedness, context))
1078  return cached;
1079  return Base::getChecked(emitError, context, width, signedness);
1080 }
1081 
1082 /// Get an instance of the NoneType.
1083 NoneType NoneType::get(MLIRContext *context) {
1084  if (NoneType cachedInst = context->getImpl().noneType)
1085  return cachedInst;
1086  // Note: May happen when initializing the singleton attributes of the builtin
1087  // dialect.
1088  return Base::get(context);
1089 }
1090 
1091 //===----------------------------------------------------------------------===//
1092 // Attribute uniquing
1093 //===----------------------------------------------------------------------===//
1094 
1095 /// Returns the storage uniquer used for constructing attribute storage
1096 /// instances. This should not be used directly.
1098  return getImpl().attributeUniquer;
1099 }
1100 
1101 /// Initialize the given attribute storage instance.
1102 void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1103  MLIRContext *ctx,
1104  TypeID attrID) {
1106 }
1107 
1108 BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1109  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1110 }
1111 
1112 UnitAttr UnitAttr::get(MLIRContext *context) {
1113  return context->getImpl().unitAttr;
1114 }
1115 
1116 UnknownLoc UnknownLoc::get(MLIRContext *context) {
1117  return context->getImpl().unknownLocAttr;
1118 }
1119 
1121 detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1122  Attribute referencedAttr) {
1123  return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1124 }
1125 
1126 /// Return empty dictionary.
1127 DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1128  return context->getImpl().emptyDictionaryAttr;
1129 }
1130 
1131 void StringAttrStorage::initialize(MLIRContext *context) {
1132  // Check for a dialect namespace prefix, if there isn't one we don't need to
1133  // do any additional initialization.
1134  auto dialectNamePair = value.split('.');
1135  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1136  return;
1137 
1138  // If one exists, we check to see if this dialect is loaded. If it is, we set
1139  // the dialect now, if it isn't we record this storage for initialization
1140  // later if the dialect ever gets loaded.
1141  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1142  return;
1143 
1144  MLIRContextImpl &impl = context->getImpl();
1145  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1146  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1147 }
1148 
1149 /// Return an empty string.
1150 StringAttr StringAttr::get(MLIRContext *context) {
1151  return context->getImpl().emptyStringAttr;
1152 }
1153 
1154 //===----------------------------------------------------------------------===//
1155 // AffineMap uniquing
1156 //===----------------------------------------------------------------------===//
1157 
1159  return getImpl().affineUniquer;
1160 }
1161 
1162 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1163  ArrayRef<AffineExpr> results,
1164  MLIRContext *context) {
1165  auto &impl = context->getImpl();
1166  auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1167  [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1168  symbolCount, results);
1169  return AffineMap(storage);
1170 }
1171 
1172 /// Check whether the arguments passed to the AffineMap::get() are consistent.
1173 /// This method checks whether the highest index of dimensional identifier
1174 /// present in result expressions is less than `dimCount` and the highest index
1175 /// of symbolic identifier present in result expressions is less than
1176 /// `symbolCount`.
1177 LLVM_ATTRIBUTE_UNUSED static bool
1178 willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1179  ArrayRef<AffineExpr> results) {
1180  int64_t maxDimPosition = -1;
1181  int64_t maxSymbolPosition = -1;
1182  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1183  maxSymbolPosition);
1184  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1185  LLVM_DEBUG(
1186  llvm::dbgs()
1187  << "maximum dimensional identifier position in result expression must "
1188  "be less than `dimCount` and maximum symbolic identifier position "
1189  "in result expression must be less than `symbolCount`\n");
1190  return false;
1191  }
1192  return true;
1193 }
1194 
1196  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1197 }
1198 
1199 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1200  MLIRContext *context) {
1201  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1202 }
1203 
1204 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1205  AffineExpr result) {
1206  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1207  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1208 }
1209 
1210 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1211  ArrayRef<AffineExpr> results, MLIRContext *context) {
1212  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1213  return getImpl(dimCount, symbolCount, results, context);
1214 }
1215 
1216 //===----------------------------------------------------------------------===//
1217 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1218 // Unlike AffineMap's, these are uniqued only if they are small.
1219 //===----------------------------------------------------------------------===//
1220 
1221 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1222  ArrayRef<AffineExpr> constraints,
1223  ArrayRef<bool> eqFlags) {
1224  // The number of constraints can't be zero.
1225  assert(!constraints.empty());
1226  assert(constraints.size() == eqFlags.size());
1227 
1228  auto &impl = constraints[0].getContext()->getImpl();
1229  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1230  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1231  return IntegerSet(storage);
1232 }
1233 
1234 //===----------------------------------------------------------------------===//
1235 // StorageUniquerSupport
1236 //===----------------------------------------------------------------------===//
1237 
1238 /// Utility method to generate a callback that can be used to generate a
1239 /// diagnostic when checking the construction invariants of a storage object.
1240 /// This is defined out-of-line to avoid the need to include Location.h.
1241 llvm::unique_function<InFlightDiagnostic()>
1243  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1244 }
1245 llvm::unique_function<InFlightDiagnostic()>
1247  return [=] { return emitError(loc); };
1248 }
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:69
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:47
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:293
void appendTo(DialectRegistry &destination) const
void applyExtensions(Dialect *dialect) const
Apply any held extensions that require the given dialect.
Definition: Dialect.cpp:215
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
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.
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.
llvm::DenseMap< StringRef, AbstractType * > nameToType
This is a mapping from type name to the abstract type describing it.
StorageUniquer typeUniquer
llvm::BumpPtrAllocator abstractDialectSymbolAllocator
An allocator used for AbstractAttribute and AbstractType objects.
DenseMap< TypeID, AbstractType * > registeredTypes
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
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
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: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...
Include the generated interface declarations.
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:90
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:672
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 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.