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