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  llvm::uninitialized_copy(elements, 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 = llvm::lower_bound(
696  impl->sortedRegisteredOperations, dialectName, [](auto &lhs, auto &rhs) {
697  return lhs.getDialect().getNamespace().compare(rhs);
698  });
699 
700  if (lowerBound == impl->sortedRegisteredOperations.end() ||
701  lowerBound->getDialect().getNamespace() != dialectName)
703 
704  auto upperBound =
705  std::upper_bound(lowerBound, impl->sortedRegisteredOperations.end(),
706  dialectName, [](auto &lhs, auto &rhs) {
707  return lhs.compare(rhs.getDialect().getNamespace());
708  });
709 
710  size_t count = std::distance(lowerBound, upperBound);
711  return ArrayRef(&*lowerBound, count);
712 }
713 
715  return RegisteredOperationName::lookup(name, this).has_value();
716 }
717 
718 void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
719  auto &impl = context->getImpl();
720  assert(impl.multiThreadedExecutionContext == 0 &&
721  "Registering a new type kind while in a multi-threaded execution "
722  "context");
723  auto *newInfo =
724  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
725  AbstractType(std::move(typeInfo));
726  if (!impl.registeredTypes.insert({typeID, newInfo}).second)
727  llvm::report_fatal_error("Dialect Type already registered.");
728  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)
729  llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +
730  " is already registered.");
731 }
732 
733 void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
734  auto &impl = context->getImpl();
735  assert(impl.multiThreadedExecutionContext == 0 &&
736  "Registering a new attribute kind while in a multi-threaded execution "
737  "context");
738  auto *newInfo =
739  new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
740  AbstractAttribute(std::move(attrInfo));
741  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
742  llvm::report_fatal_error("Dialect Attribute already registered.");
743  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)
744  llvm::report_fatal_error("Dialect Attribute with name " +
745  newInfo->getName() + " is already registered.");
746 }
747 
748 //===----------------------------------------------------------------------===//
749 // AbstractAttribute
750 //===----------------------------------------------------------------------===//
751 
752 /// Get the dialect that registered the attribute with the provided typeid.
754  MLIRContext *context) {
755  const AbstractAttribute *abstract = lookupMutable(typeID, context);
756  if (!abstract)
757  llvm::report_fatal_error("Trying to create an Attribute that was not "
758  "registered in this MLIRContext.");
759  return *abstract;
760 }
761 
762 AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
763  MLIRContext *context) {
764  auto &impl = context->getImpl();
765  return impl.registeredAttributes.lookup(typeID);
766 }
767 
768 std::optional<std::reference_wrapper<const AbstractAttribute>>
769 AbstractAttribute::lookup(StringRef name, MLIRContext *context) {
770  MLIRContextImpl &impl = context->getImpl();
771  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);
772 
773  if (!type)
774  return std::nullopt;
775  return {*type};
776 }
777 
778 //===----------------------------------------------------------------------===//
779 // OperationName
780 //===----------------------------------------------------------------------===//
781 
782 OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,
783  detail::InterfaceMap interfaceMap)
784  : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,
785  std::move(interfaceMap)) {}
786 
787 OperationName::OperationName(StringRef name, MLIRContext *context) {
788  MLIRContextImpl &ctxImpl = context->getImpl();
789 
790  // Check for an existing name in read-only mode.
791  bool isMultithreadingEnabled = context->isMultithreadingEnabled();
792  if (isMultithreadingEnabled) {
793  // Check the registered info map first. In the overwhelmingly common case,
794  // the entry will be in here and it also removes the need to acquire any
795  // locks.
796  auto registeredIt = ctxImpl.registeredOperationsByName.find(name);
797  if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {
798  impl = registeredIt->second.impl;
799  return;
800  }
801 
802  llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
803  auto it = ctxImpl.operations.find(name);
804  if (it != ctxImpl.operations.end()) {
805  impl = it->second.get();
806  return;
807  }
808  }
809 
810  // Acquire a writer-lock so that we can safely create the new instance.
811  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
812 
813  auto it = ctxImpl.operations.try_emplace(name);
814  if (it.second) {
815  auto nameAttr = StringAttr::get(context, name);
816  it.first->second = std::make_unique<UnregisteredOpModel>(
817  nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),
819  }
820  impl = it.first->second.get();
821 }
822 
824  if (Dialect *dialect = getDialect())
825  return dialect->getNamespace();
826  return getStringRef().split('.').first;
827 }
828 
829 LogicalResult
832  return failure();
833 }
837 
840  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");
841 }
843  const OperationName &, NamedAttrList &) {}
845  Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {
846  p.printGenericOp(op);
847 }
848 LogicalResult
850  return success();
851 }
852 LogicalResult
854  return success();
855 }
856 
857 std::optional<Attribute>
859  StringRef name) {
860  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
861  if (!dict)
862  return std::nullopt;
863  if (Attribute attr = dict.get(name))
864  return attr;
865  return std::nullopt;
866 }
868  StringAttr name,
869  Attribute value) {
870  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
871  assert(dict);
872  NamedAttrList attrs(dict);
873  attrs.set(name, value);
874  *op->getPropertiesStorage().as<Attribute *>() =
875  attrs.getDictionary(op->getContext());
876 }
878  Operation *op, NamedAttrList &attrs) {}
880  OperationName opName, NamedAttrList &attributes,
882  return success();
883 }
885  return sizeof(Attribute);
886 }
888  OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
889  new (storage.as<Attribute *>()) Attribute();
890 }
892  OpaqueProperties prop) {
893  prop.as<Attribute *>()->~Attribute();
894 }
896  OperationName opName, OpaqueProperties properties) {}
898  OperationName opName, OpaqueProperties properties, Attribute attr,
900  *properties.as<Attribute *>() = attr;
901  return success();
902 }
903 Attribute
905  return *op->getPropertiesStorage().as<Attribute *>();
906 }
908  OpaqueProperties rhs) {
909  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();
910 }
913  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();
914 }
915 llvm::hash_code
917  return llvm::hash_combine(*prop.as<Attribute *>());
918 }
919 
920 //===----------------------------------------------------------------------===//
921 // RegisteredOperationName
922 //===----------------------------------------------------------------------===//
923 
924 std::optional<RegisteredOperationName>
926  auto &impl = ctx->getImpl();
927  auto it = impl.registeredOperations.find(typeID);
928  if (it != impl.registeredOperations.end())
929  return it->second;
930  return std::nullopt;
931 }
932 
933 std::optional<RegisteredOperationName>
935  auto &impl = ctx->getImpl();
936  auto it = impl.registeredOperationsByName.find(name);
937  if (it != impl.registeredOperationsByName.end())
938  return it->getValue();
939  return std::nullopt;
940 }
941 
943  std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,
944  ArrayRef<StringRef> attrNames) {
945  RegisteredOperationName::Impl *impl = ownedImpl.get();
946  MLIRContext *ctx = impl->getDialect()->getContext();
947  auto &ctxImpl = ctx->getImpl();
948  assert(ctxImpl.multiThreadedExecutionContext == 0 &&
949  "registering a new operation kind while in a multi-threaded execution "
950  "context");
951 
952  // Register the attribute names of this operation.
953  MutableArrayRef<StringAttr> cachedAttrNames;
954  if (!attrNames.empty()) {
955  cachedAttrNames = MutableArrayRef<StringAttr>(
956  ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
957  attrNames.size()),
958  attrNames.size());
959  for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
960  new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
961  impl->attributeNames = cachedAttrNames;
962  }
963  StringRef name = impl->getName().strref();
964  // Insert the operation info if it doesn't exist yet.
965  ctxImpl.operations[name] = std::move(ownedImpl);
966 
967  // Update the registered info for this operation.
968  auto emplaced = ctxImpl.registeredOperations.try_emplace(
969  impl->getTypeID(), RegisteredOperationName(impl));
970  assert(emplaced.second && "operation name registration must be successful");
971  auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(
973  (void)emplacedByName;
974  assert(emplacedByName.second &&
975  "operation name registration must be successful");
976 
977  // Add emplaced operation name to the sorted operations container.
978  RegisteredOperationName &value = emplaced.first->second;
979  ctxImpl.sortedRegisteredOperations.insert(
980  llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
981  [](auto &lhs, auto &rhs) {
982  return lhs.getIdentifier().compare(
983  rhs.getIdentifier());
984  }),
985  value);
986 }
987 
988 //===----------------------------------------------------------------------===//
989 // AbstractType
990 //===----------------------------------------------------------------------===//
991 
993  const AbstractType *type = lookupMutable(typeID, context);
994  if (!type)
995  llvm::report_fatal_error(
996  "Trying to create a Type that was not registered in this MLIRContext.");
997  return *type;
998 }
999 
1000 AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
1001  auto &impl = context->getImpl();
1002  return impl.registeredTypes.lookup(typeID);
1003 }
1004 
1005 std::optional<std::reference_wrapper<const AbstractType>>
1006 AbstractType::lookup(StringRef name, MLIRContext *context) {
1007  MLIRContextImpl &impl = context->getImpl();
1008  const AbstractType *type = impl.nameToType.lookup(name);
1009 
1010  if (!type)
1011  return std::nullopt;
1012  return {*type};
1013 }
1014 
1015 //===----------------------------------------------------------------------===//
1016 // Type uniquing
1017 //===----------------------------------------------------------------------===//
1018 
1019 /// Returns the storage uniquer used for constructing type storage instances.
1020 /// This should not be used directly.
1022 
1023 BFloat16Type BFloat16Type::get(MLIRContext *context) {
1024  return context->getImpl().bf16Ty;
1025 }
1026 Float16Type Float16Type::get(MLIRContext *context) {
1027  return context->getImpl().f16Ty;
1028 }
1029 FloatTF32Type FloatTF32Type::get(MLIRContext *context) {
1030  return context->getImpl().tf32Ty;
1031 }
1032 Float32Type Float32Type::get(MLIRContext *context) {
1033  return context->getImpl().f32Ty;
1034 }
1035 Float64Type Float64Type::get(MLIRContext *context) {
1036  return context->getImpl().f64Ty;
1037 }
1038 Float80Type Float80Type::get(MLIRContext *context) {
1039  return context->getImpl().f80Ty;
1040 }
1041 Float128Type Float128Type::get(MLIRContext *context) {
1042  return context->getImpl().f128Ty;
1043 }
1044 
1045 /// Get an instance of the IndexType.
1046 IndexType IndexType::get(MLIRContext *context) {
1047  return context->getImpl().indexTy;
1048 }
1049 
1050 /// Return an existing integer type instance if one is cached within the
1051 /// context.
1052 static IntegerType
1053 getCachedIntegerType(unsigned width,
1054  IntegerType::SignednessSemantics signedness,
1055  MLIRContext *context) {
1056  if (signedness != IntegerType::Signless)
1057  return IntegerType();
1058 
1059  switch (width) {
1060  case 1:
1061  return context->getImpl().int1Ty;
1062  case 8:
1063  return context->getImpl().int8Ty;
1064  case 16:
1065  return context->getImpl().int16Ty;
1066  case 32:
1067  return context->getImpl().int32Ty;
1068  case 64:
1069  return context->getImpl().int64Ty;
1070  case 128:
1071  return context->getImpl().int128Ty;
1072  default:
1073  return IntegerType();
1074  }
1075 }
1076 
1077 IntegerType IntegerType::get(MLIRContext *context, unsigned width,
1078  IntegerType::SignednessSemantics signedness) {
1079  if (auto cached = getCachedIntegerType(width, signedness, context))
1080  return cached;
1081  return Base::get(context, width, signedness);
1082 }
1083 
1084 IntegerType
1085 IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
1086  MLIRContext *context, unsigned width,
1087  SignednessSemantics signedness) {
1088  if (auto cached = getCachedIntegerType(width, signedness, context))
1089  return cached;
1090  return Base::getChecked(emitError, context, width, signedness);
1091 }
1092 
1093 /// Get an instance of the NoneType.
1094 NoneType NoneType::get(MLIRContext *context) {
1095  if (NoneType cachedInst = context->getImpl().noneType)
1096  return cachedInst;
1097  // Note: May happen when initializing the singleton attributes of the builtin
1098  // dialect.
1099  return Base::get(context);
1100 }
1101 
1102 //===----------------------------------------------------------------------===//
1103 // Attribute uniquing
1104 //===----------------------------------------------------------------------===//
1105 
1106 /// Returns the storage uniquer used for constructing attribute storage
1107 /// instances. This should not be used directly.
1109  return getImpl().attributeUniquer;
1110 }
1111 
1112 /// Initialize the given attribute storage instance.
1113 void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
1114  MLIRContext *ctx,
1115  TypeID attrID) {
1117 }
1118 
1119 BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
1120  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
1121 }
1122 
1123 UnitAttr UnitAttr::get(MLIRContext *context) {
1124  return context->getImpl().unitAttr;
1125 }
1126 
1127 UnknownLoc UnknownLoc::get(MLIRContext *context) {
1128  return context->getImpl().unknownLocAttr;
1129 }
1130 
1132 detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,
1133  Attribute referencedAttr) {
1134  return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);
1135 }
1136 
1137 /// Return empty dictionary.
1138 DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
1139  return context->getImpl().emptyDictionaryAttr;
1140 }
1141 
1142 void StringAttrStorage::initialize(MLIRContext *context) {
1143  // Check for a dialect namespace prefix, if there isn't one we don't need to
1144  // do any additional initialization.
1145  auto dialectNamePair = value.split('.');
1146  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
1147  return;
1148 
1149  // If one exists, we check to see if this dialect is loaded. If it is, we set
1150  // the dialect now, if it isn't we record this storage for initialization
1151  // later if the dialect ever gets loaded.
1152  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
1153  return;
1154 
1155  MLIRContextImpl &impl = context->getImpl();
1156  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
1157  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
1158 }
1159 
1160 /// Return an empty string.
1161 StringAttr StringAttr::get(MLIRContext *context) {
1162  return context->getImpl().emptyStringAttr;
1163 }
1164 
1165 //===----------------------------------------------------------------------===//
1166 // AffineMap uniquing
1167 //===----------------------------------------------------------------------===//
1168 
1170  return getImpl().affineUniquer;
1171 }
1172 
1173 AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
1174  ArrayRef<AffineExpr> results,
1175  MLIRContext *context) {
1176  auto &impl = context->getImpl();
1177  auto *storage = impl.affineUniquer.get<AffineMapStorage>(
1178  [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
1179  symbolCount, results);
1180  return AffineMap(storage);
1181 }
1182 
1183 /// Check whether the arguments passed to the AffineMap::get() are consistent.
1184 /// This method checks whether the highest index of dimensional identifier
1185 /// present in result expressions is less than `dimCount` and the highest index
1186 /// of symbolic identifier present in result expressions is less than
1187 /// `symbolCount`.
1188 LLVM_ATTRIBUTE_UNUSED static bool
1189 willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
1190  ArrayRef<AffineExpr> results) {
1191  int64_t maxDimPosition = -1;
1192  int64_t maxSymbolPosition = -1;
1193  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
1194  maxSymbolPosition);
1195  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
1196  LLVM_DEBUG(
1197  llvm::dbgs()
1198  << "maximum dimensional identifier position in result expression must "
1199  "be less than `dimCount` and maximum symbolic identifier position "
1200  "in result expression must be less than `symbolCount`\n");
1201  return false;
1202  }
1203  return true;
1204 }
1205 
1207  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);
1208 }
1209 
1210 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1211  MLIRContext *context) {
1212  return getImpl(dimCount, symbolCount, /*results=*/{}, context);
1213 }
1214 
1215 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1216  AffineExpr result) {
1217  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
1218  return getImpl(dimCount, symbolCount, {result}, result.getContext());
1219 }
1220 
1221 AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
1222  ArrayRef<AffineExpr> results, MLIRContext *context) {
1223  assert(willBeValidAffineMap(dimCount, symbolCount, results));
1224  return getImpl(dimCount, symbolCount, results, context);
1225 }
1226 
1227 //===----------------------------------------------------------------------===//
1228 // Integer Sets: these are allocated into the bump pointer, and are immutable.
1229 // Unlike AffineMap's, these are uniqued only if they are small.
1230 //===----------------------------------------------------------------------===//
1231 
1232 IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
1233  ArrayRef<AffineExpr> constraints,
1234  ArrayRef<bool> eqFlags) {
1235  // The number of constraints can't be zero.
1236  assert(!constraints.empty());
1237  assert(constraints.size() == eqFlags.size());
1238 
1239  auto &impl = constraints[0].getContext()->getImpl();
1240  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
1241  [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
1242  return IntegerSet(storage);
1243 }
1244 
1245 //===----------------------------------------------------------------------===//
1246 // StorageUniquerSupport
1247 //===----------------------------------------------------------------------===//
1248 
1249 /// Utility method to generate a callback that can be used to generate a
1250 /// diagnostic when checking the construction invariants of a storage object.
1251 /// This is defined out-of-line to avoid the need to include Location.h.
1252 llvm::unique_function<InFlightDiagnostic()>
1254  return [ctx] { return emitError(UnknownLoc::get(ctx)); };
1255 }
1256 llvm::unique_function<InFlightDiagnostic()>
1258  return [=] { return emitError(loc); };
1259 }
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:76
This is the implementation of the MLIRContext class, using the pImpl idiom.
DictionaryAttr emptyDictionaryAttr
llvm::DenseMap< StringRef, AbstractAttribute * > nameToAttribute
This is a mapping from attribute name to the abstract attribute describing it.
DenseMap< StringRef, std::unique_ptr< Dialect > > loadedDialects
This is a list of dialects that are created referring to this context.
llvm::DenseMap< TypeID, RegisteredOperationName > registeredOperations
A vector of operation info specifically for registered operations.
BoolAttr falseAttr
Cached Attribute Instances.
llvm::sys::SmartRWMutex< true > operationInfoMutex
A mutex used when accessing operation information.
BFloat16Type bf16Ty
Cached Type Instances.
DenseMap< StringRef, SmallVector< StringAttrStorage * > > dialectReferencingStrAttrs
llvm::StringMap< RegisteredOperationName > registeredOperationsByName
StringAttr emptyStringAttr
std::function< void(function_ref< void()>, const tracing::Action &)> actionHandler
An action handler for handling actions that are dispatched through this context.
llvm::sys::SmartMutex< true > dialectRefStrAttrMutex
Map of string attributes that may reference a dialect, that are awaiting that dialect to be loaded.
llvm::DenseMap< StringRef, AbstractType * > nameToType
This is a mapping from type name to the abstract type describing it.
StorageUniquer typeUniquer
llvm::BumpPtrAllocator abstractDialectSymbolAllocator
An allocator used for AbstractAttribute and AbstractType objects.
DenseMap< TypeID, AbstractType * > registeredTypes
StorageUniquer affineUniquer
DiagnosticEngine diagEngine
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:900
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
A utility class to get or create instances of "storage classes".
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:107
An allocator for distinct attribute storage instances.
DistinctAttrStorage * allocate(Attribute referencedAttr)
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.