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