brintos

brintos / llvm-project-archived public Read only

0
0
Text · 48.9 KiB · 73219c6 Raw
1278 lines · cpp
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-exception6//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"19#include "mlir/IR/BuiltinAttributes.h"20#include "mlir/IR/BuiltinDialect.h"21#include "mlir/IR/Diagnostics.h"22#include "mlir/IR/Dialect.h"23#include "mlir/IR/ExtensibleDialect.h"24#include "mlir/IR/IntegerSet.h"25#include "mlir/IR/Location.h"26#include "mlir/IR/OpImplementation.h"27#include "mlir/IR/OperationSupport.h"28#include "mlir/IR/Remarks.h"29#include "llvm/ADT/DenseMap.h"30#include "llvm/ADT/Twine.h"31#include "llvm/Support/Allocator.h"32#include "llvm/Support/CommandLine.h"33#include "llvm/Support/Compiler.h"34#include "llvm/Support/DebugLog.h"35#include "llvm/Support/ManagedStatic.h"36#include "llvm/Support/Mutex.h"37#include "llvm/Support/RWMutex.h"38#include "llvm/Support/ThreadPool.h"39#include "llvm/Support/raw_ostream.h"40#include <memory>41#include <optional>42 43#define DEBUG_TYPE "mlircontext"44 45using namespace mlir;46using namespace mlir::detail;47 48//===----------------------------------------------------------------------===//49// MLIRContext CommandLine Options50//===----------------------------------------------------------------------===//51 52namespace {53/// This struct contains command line options that can be used to initialize54/// various bits of an MLIRContext. This uses a struct wrapper to avoid the need55/// for global command line options.56struct MLIRContextOptions {57  llvm::cl::opt<bool> disableThreading{58      "mlir-disable-threading",59      llvm::cl::desc("Disable multi-threading within MLIR, overrides any "60                     "further call to MLIRContext::enableMultiThreading()")};61 62  llvm::cl::opt<bool> printOpOnDiagnostic{63      "mlir-print-op-on-diagnostic",64      llvm::cl::desc("When a diagnostic is emitted on an operation, also print "65                     "the operation as an attached note"),66      llvm::cl::init(true)};67 68  llvm::cl::opt<bool> printStackTraceOnDiagnostic{69      "mlir-print-stacktrace-on-diagnostic",70      llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "71                     "as an attached note")};72};73} // namespace74 75static llvm::ManagedStatic<MLIRContextOptions> clOptions;76 77static bool isThreadingGloballyDisabled() {78#if LLVM_ENABLE_THREADS != 079  return clOptions.isConstructed() && clOptions->disableThreading;80#else81  return true;82#endif83}84 85/// Register a set of useful command-line options that can be used to configure86/// various flags within the MLIRContext. These flags are used when constructing87/// an MLIR context for initialization.88void mlir::registerMLIRContextCLOptions() {89  // Make sure that the options struct has been initialized.90  *clOptions;91}92 93//===----------------------------------------------------------------------===//94// Locking Utilities95//===----------------------------------------------------------------------===//96 97namespace {98/// Utility writer lock that takes a runtime flag that specifies if we really99/// need to lock.100struct ScopedWriterLock {101  ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)102      : mutex(shouldLock ? &mutexParam : nullptr) {103    if (mutex)104      mutex->lock();105  }106  ~ScopedWriterLock() {107    if (mutex)108      mutex->unlock();109  }110  llvm::sys::SmartRWMutex<true> *mutex;111};112} // namespace113 114//===----------------------------------------------------------------------===//115// MLIRContextImpl116//===----------------------------------------------------------------------===//117 118namespace mlir {119/// This is the implementation of the MLIRContext class, using the pImpl idiom.120/// This class is completely private to this file, so everything is public.121class MLIRContextImpl {122public:123  //===--------------------------------------------------------------------===//124  // Remark125  //===--------------------------------------------------------------------===//126  std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;127 128  //===--------------------------------------------------------------------===//129  // Debugging130  //===--------------------------------------------------------------------===//131 132  /// An action handler for handling actions that are dispatched through this133  /// context.134  std::function<void(function_ref<void()>, const tracing::Action &)>135      actionHandler;136 137  //===--------------------------------------------------------------------===//138  // Diagnostics139  //===--------------------------------------------------------------------===//140  DiagnosticEngine diagEngine;141 142  //===--------------------------------------------------------------------===//143  // Options144  //===--------------------------------------------------------------------===//145 146  /// In most cases, creating operation in unregistered dialect is not desired147  /// and indicate a misconfiguration of the compiler. This option enables to148  /// detect such use cases149  bool allowUnregisteredDialects = false;150 151  /// Enable support for multi-threading within MLIR.152  bool threadingIsEnabled = true;153 154  /// Track if we are currently executing in a threaded execution environment155  /// (like the pass-manager): this is only a debugging feature to help reducing156  /// the chances of data races one some context APIs.157#ifndef NDEBUG158  std::atomic<int> multiThreadedExecutionContext{0};159#endif160 161  /// If the operation should be attached to diagnostics printed via the162  /// Operation::emit methods.163  bool printOpOnDiagnostic = true;164 165  /// If the current stack trace should be attached when emitting diagnostics.166  bool printStackTraceOnDiagnostic = false;167 168  //===--------------------------------------------------------------------===//169  // Other170  //===--------------------------------------------------------------------===//171 172  /// This points to the ThreadPool used when processing MLIR tasks in parallel.173  /// It can't be nullptr when multi-threading is enabled. Otherwise if174  /// multi-threading is disabled, and the threadpool wasn't externally provided175  /// using `setThreadPool`, this will be nullptr.176  llvm::ThreadPoolInterface *threadPool = nullptr;177 178  /// In case where the thread pool is owned by the context, this ensures179  /// destruction with the context.180  std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;181 182  /// An allocator used for AbstractAttribute and AbstractType objects.183  llvm::BumpPtrAllocator abstractDialectSymbolAllocator;184 185  /// This is a mapping from operation name to the operation info describing it.186  llvm::StringMap<std::unique_ptr<OperationName::Impl>> operations;187 188  /// A vector of operation info specifically for registered operations.189  llvm::DenseMap<TypeID, RegisteredOperationName> registeredOperations;190  llvm::StringMap<RegisteredOperationName> registeredOperationsByName;191 192  /// This is a sorted container of registered operations for a deterministic193  /// and efficient `getRegisteredOperations` implementation.194  SmallVector<RegisteredOperationName, 0> sortedRegisteredOperations;195 196  /// This is a list of dialects that are created referring to this context.197  /// The MLIRContext owns the objects. These need to be declared after the198  /// registered operations to ensure correct destruction order.199  DenseMap<StringRef, std::unique_ptr<Dialect>> loadedDialects;200  DialectRegistry dialectsRegistry;201 202  /// A mutex used when accessing operation information.203  llvm::sys::SmartRWMutex<true> operationInfoMutex;204 205  //===--------------------------------------------------------------------===//206  // Affine uniquing207  //===--------------------------------------------------------------------===//208 209  // Affine expression, map and integer set uniquing.210  StorageUniquer affineUniquer;211 212  //===--------------------------------------------------------------------===//213  // Type uniquing214  //===--------------------------------------------------------------------===//215 216  DenseMap<TypeID, AbstractType *> registeredTypes;217  StorageUniquer typeUniquer;218 219  /// This is a mapping from type name to the abstract type describing it.220  /// It is used by `AbstractType::lookup` to get an `AbstractType` from a name.221  /// As this map needs to be populated before `StringAttr` is loaded, we222  /// cannot use `StringAttr` as the key. The context does not take ownership223  /// of the key, so the `StringRef` must outlive the context.224  llvm::DenseMap<StringRef, AbstractType *> nameToType;225 226  /// Cached Type Instances.227  BFloat16Type bf16Ty;228  Float16Type f16Ty;229  FloatTF32Type tf32Ty;230  Float32Type f32Ty;231  Float64Type f64Ty;232  Float80Type f80Ty;233  Float128Type f128Ty;234  IndexType indexTy;235  IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;236  NoneType noneType;237 238  //===--------------------------------------------------------------------===//239  // Attribute uniquing240  //===--------------------------------------------------------------------===//241 242  DenseMap<TypeID, AbstractAttribute *> registeredAttributes;243  StorageUniquer attributeUniquer;244 245  /// This is a mapping from attribute name to the abstract attribute describing246  /// it. It is used by `AbstractType::lookup` to get an `AbstractType` from a247  /// name.248  /// As this map needs to be populated before `StringAttr` is loaded, we249  /// cannot use `StringAttr` as the key. The context does not take ownership250  /// of the key, so the `StringRef` must outlive the context.251  llvm::DenseMap<StringRef, AbstractAttribute *> nameToAttribute;252 253  /// Cached Attribute Instances.254  BoolAttr falseAttr, trueAttr;255  UnitAttr unitAttr;256  UnknownLoc unknownLocAttr;257  DictionaryAttr emptyDictionaryAttr;258  StringAttr emptyStringAttr;259 260  /// Map of string attributes that may reference a dialect, that are awaiting261  /// that dialect to be loaded.262  llvm::sys::SmartMutex<true> dialectRefStrAttrMutex;263  DenseMap<StringRef, SmallVector<StringAttrStorage *>>264      dialectReferencingStrAttrs;265 266  /// A distinct attribute allocator that allocates every time since the267  /// address of the distinct attribute storage serves as unique identifier. The268  /// allocator is thread safe and frees the allocated storage after its269  /// destruction.270  DistinctAttributeAllocator distinctAttributeAllocator;271 272public:273  MLIRContextImpl(bool threadingIsEnabled)274      : threadingIsEnabled(threadingIsEnabled) {275    if (threadingIsEnabled) {276      ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();277      threadPool = ownedThreadPool.get();278    }279  }280  ~MLIRContextImpl() {281    for (auto typeMapping : registeredTypes)282      typeMapping.second->~AbstractType();283    for (auto attrMapping : registeredAttributes)284      attrMapping.second->~AbstractAttribute();285  }286};287} // namespace mlir288 289MLIRContext::MLIRContext(Threading setting)290    : MLIRContext(DialectRegistry(), setting) {}291 292MLIRContext::MLIRContext(const DialectRegistry &registry, Threading setting)293    : impl(new MLIRContextImpl(setting == Threading::ENABLED &&294                               !isThreadingGloballyDisabled())) {295  // Initialize values based on the command line flags if they were provided.296  if (clOptions.isConstructed()) {297    printOpOnDiagnostic(clOptions->printOpOnDiagnostic);298    printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);299  }300 301  // Pre-populate the registry.302  registry.appendTo(impl->dialectsRegistry);303 304  // Ensure the builtin dialect is always pre-loaded.305  getOrLoadDialect<BuiltinDialect>();306 307  // Initialize several common attributes and types to avoid the need to lock308  // the context when accessing them.309 310  //// Types.311  /// Floating-point Types.312  impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);313  impl->f16Ty = TypeUniquer::get<Float16Type>(this);314  impl->tf32Ty = TypeUniquer::get<FloatTF32Type>(this);315  impl->f32Ty = TypeUniquer::get<Float32Type>(this);316  impl->f64Ty = TypeUniquer::get<Float64Type>(this);317  impl->f80Ty = TypeUniquer::get<Float80Type>(this);318  impl->f128Ty = TypeUniquer::get<Float128Type>(this);319  /// Index Type.320  impl->indexTy = TypeUniquer::get<IndexType>(this);321  /// Integer Types.322  impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);323  impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);324  impl->int16Ty =325      TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);326  impl->int32Ty =327      TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);328  impl->int64Ty =329      TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);330  impl->int128Ty =331      TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);332  /// None Type.333  impl->noneType = TypeUniquer::get<NoneType>(this);334 335  //// Attributes.336  //// Note: These must be registered after the types as they may generate one337  //// of the above types internally.338  /// Unknown Location Attribute.339  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);340  /// Bool Attributes.341  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);342  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);343  /// Unit Attribute.344  impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);345  /// The empty dictionary attribute.346  impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);347  /// The empty string attribute.348  impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);349 350  // Register the affine storage objects with the uniquer.351  impl->affineUniquer352      .registerParametricStorageType<AffineBinaryOpExprStorage>();353  impl->affineUniquer354      .registerParametricStorageType<AffineConstantExprStorage>();355  impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();356  impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();357  impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();358}359 360MLIRContext::~MLIRContext() {361  // finalize remark engine before destroying anything else.362  impl->remarkEngine.reset();363}364 365/// Copy the specified array of elements into memory managed by the provided366/// bump pointer allocator.  This assumes the elements are all PODs.367template <typename T>368static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,369                                    ArrayRef<T> elements) {370  auto result = allocator.Allocate<T>(elements.size());371  llvm::uninitialized_copy(elements, result);372  return ArrayRef<T>(result, elements.size());373}374 375//===----------------------------------------------------------------------===//376// Action Handling377//===----------------------------------------------------------------------===//378 379void MLIRContext::registerActionHandler(HandlerTy handler) {380  getImpl().actionHandler = std::move(handler);381}382 383/// Dispatch the provided action to the handler if any, or just execute it.384void MLIRContext::executeActionInternal(function_ref<void()> actionFn,385                                        const tracing::Action &action) {386  assert(getImpl().actionHandler);387  getImpl().actionHandler(actionFn, action);388}389 390bool MLIRContext::hasActionHandler() { return (bool)getImpl().actionHandler; }391 392//===----------------------------------------------------------------------===//393// Diagnostic Handlers394//===----------------------------------------------------------------------===//395 396/// Returns the diagnostic engine for this context.397DiagnosticEngine &MLIRContext::getDiagEngine() { return getImpl().diagEngine; }398 399//===----------------------------------------------------------------------===//400// Remark Handlers401//===----------------------------------------------------------------------===//402 403void MLIRContext::setRemarkEngine(404    std::unique_ptr<remark::detail::RemarkEngine> engine) {405  getImpl().remarkEngine = std::move(engine);406}407 408remark::detail::RemarkEngine *MLIRContext::getRemarkEngine() {409  return getImpl().remarkEngine.get();410}411 412//===----------------------------------------------------------------------===//413// Dialect and Operation Registration414//===----------------------------------------------------------------------===//415 416void MLIRContext::appendDialectRegistry(const DialectRegistry &registry) {417  if (registry.isSubsetOf(impl->dialectsRegistry))418    return;419 420  assert(impl->multiThreadedExecutionContext == 0 &&421         "appending to the MLIRContext dialect registry while in a "422         "multi-threaded execution context");423  registry.appendTo(impl->dialectsRegistry);424 425  // For the already loaded dialects, apply any possible extensions immediately.426  registry.applyExtensions(this);427}428 429const DialectRegistry &MLIRContext::getDialectRegistry() {430  return impl->dialectsRegistry;431}432 433/// Return information about all registered IR dialects.434std::vector<Dialect *> MLIRContext::getLoadedDialects() {435  std::vector<Dialect *> result;436  result.reserve(impl->loadedDialects.size());437  for (auto &dialect : impl->loadedDialects)438    result.push_back(dialect.second.get());439  llvm::array_pod_sort(result.begin(), result.end(),440                       [](Dialect *const *lhs, Dialect *const *rhs) -> int {441                         return (*lhs)->getNamespace() < (*rhs)->getNamespace();442                       });443  return result;444}445std::vector<StringRef> MLIRContext::getAvailableDialects() {446  std::vector<StringRef> result;447  for (auto dialect : impl->dialectsRegistry.getDialectNames())448    result.push_back(dialect);449  return result;450}451 452/// Get a registered IR dialect with the given namespace. If none is found,453/// then return nullptr.454Dialect *MLIRContext::getLoadedDialect(StringRef name) {455  // Dialects are sorted by name, so we can use binary search for lookup.456  auto it = impl->loadedDialects.find(name);457  return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;458}459 460Dialect *MLIRContext::getOrLoadDialect(StringRef name) {461  Dialect *dialect = getLoadedDialect(name);462  if (dialect)463    return dialect;464  DialectAllocatorFunctionRef allocator =465      impl->dialectsRegistry.getDialectAllocator(name);466  return allocator ? allocator(this) : nullptr;467}468 469/// Get a dialect for the provided namespace and TypeID: abort the program if a470/// dialect exist for this namespace with different TypeID. Returns a pointer to471/// the dialect owned by the context.472Dialect *473MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,474                              function_ref<std::unique_ptr<Dialect>()> ctor) {475  auto &impl = getImpl();476  // Get the correct insertion position sorted by namespace.477  auto dialectIt = impl.loadedDialects.try_emplace(dialectNamespace, nullptr);478 479  if (dialectIt.second) {480    LDBG() << "Load new dialect in Context " << dialectNamespace;481#ifndef NDEBUG482    if (impl.multiThreadedExecutionContext != 0)483      llvm::report_fatal_error(484          "Loading a dialect (" + dialectNamespace +485          ") while in a multi-threaded execution context (maybe "486          "the PassManager): this can indicate a "487          "missing `dependentDialects` in a pass for example.");488#endif // NDEBUG489    // loadedDialects entry is initialized to nullptr, indicating that the490    // dialect is currently being loaded. Re-lookup the address in491    // loadedDialects because the table might have been rehashed by recursive492    // dialect loading in ctor().493    std::unique_ptr<Dialect> &dialectOwned =494        impl.loadedDialects[dialectNamespace] = ctor();495    Dialect *dialect = dialectOwned.get();496    assert(dialect && "dialect ctor failed");497 498    // Refresh all the identifiers dialect field, this catches cases where a499    // dialect may be loaded after identifier prefixed with this dialect name500    // were already created.501    auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);502    if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {503      for (StringAttrStorage *storage : stringAttrsIt->second)504        storage->referencedDialect = dialect;505      impl.dialectReferencingStrAttrs.erase(stringAttrsIt);506    }507 508    // Apply any extensions to this newly loaded dialect.509    impl.dialectsRegistry.applyExtensions(dialect);510    return dialect;511  }512 513#ifndef NDEBUG514  if (dialectIt.first->second == nullptr)515    llvm::report_fatal_error(516        "Loading (and getting) a dialect (" + dialectNamespace +517        ") while the same dialect is still loading: use loadDialect instead "518        "of getOrLoadDialect.");519#endif // NDEBUG520 521  // Abort if dialect with namespace has already been registered.522  std::unique_ptr<Dialect> &dialect = dialectIt.first->second;523  if (dialect->getTypeID() != dialectID)524    llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +525                             "' has already been registered");526 527  return dialect.get();528}529 530bool MLIRContext::isDialectLoading(StringRef dialectNamespace) {531  auto it = getImpl().loadedDialects.find(dialectNamespace);532  // nullptr indicates that the dialect is currently being loaded.533  return it != getImpl().loadedDialects.end() && it->second == nullptr;534}535 536DynamicDialect *MLIRContext::getOrLoadDynamicDialect(537    StringRef dialectNamespace, function_ref<void(DynamicDialect *)> ctor) {538  auto &impl = getImpl();539  // Get the correct insertion position sorted by namespace.540  auto dialectIt = impl.loadedDialects.find(dialectNamespace);541 542  if (dialectIt != impl.loadedDialects.end()) {543    if (auto *dynDialect = dyn_cast<DynamicDialect>(dialectIt->second.get()))544      return dynDialect;545    llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +546                             "' has already been registered");547  }548 549  LDBG() << "Load new dynamic dialect in Context " << dialectNamespace;550#ifndef NDEBUG551  if (impl.multiThreadedExecutionContext != 0)552    llvm::report_fatal_error(553        "Loading a dynamic dialect (" + dialectNamespace +554        ") while in a multi-threaded execution context (maybe "555        "the PassManager): this can indicate a "556        "missing `dependentDialects` in a pass for example.");557#endif558 559  auto name = StringAttr::get(this, dialectNamespace);560  auto *dialect = new DynamicDialect(name, this);561  (void)getOrLoadDialect(name, dialect->getTypeID(), [dialect, ctor]() {562    ctor(dialect);563    return std::unique_ptr<DynamicDialect>(dialect);564  });565  // This is the same result as `getOrLoadDialect` (if it didn't failed),566  // since it has the same TypeID, and TypeIDs are unique.567  return dialect;568}569 570void MLIRContext::loadAllAvailableDialects() {571  for (StringRef name : getAvailableDialects())572    getOrLoadDialect(name);573}574 575llvm::hash_code MLIRContext::getRegistryHash() {576  llvm::hash_code hash(0);577  // Factor in number of loaded dialects, attributes, operations, types.578  hash = llvm::hash_combine(hash, impl->loadedDialects.size());579  hash = llvm::hash_combine(hash, impl->registeredAttributes.size());580  hash = llvm::hash_combine(hash, impl->registeredOperations.size());581  hash = llvm::hash_combine(hash, impl->registeredTypes.size());582  return hash;583}584 585bool MLIRContext::allowsUnregisteredDialects() {586  return impl->allowUnregisteredDialects;587}588 589void MLIRContext::allowUnregisteredDialects(bool allowing) {590  assert(impl->multiThreadedExecutionContext == 0 &&591         "changing MLIRContext `allow-unregistered-dialects` configuration "592         "while in a multi-threaded execution context");593  impl->allowUnregisteredDialects = allowing;594}595 596/// Return true if multi-threading is enabled by the context.597bool MLIRContext::isMultithreadingEnabled() {598  return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();599}600 601/// Set the flag specifying if multi-threading is disabled by the context.602void MLIRContext::disableMultithreading(bool disable) {603  // This API can be overridden by the global debugging flag604  // --mlir-disable-threading605  if (isThreadingGloballyDisabled())606    return;607  assert(impl->multiThreadedExecutionContext == 0 &&608         "changing MLIRContext `disable-threading` configuration while "609         "in a multi-threaded execution context");610 611  impl->threadingIsEnabled = !disable;612 613  // Update the threading mode for each of the uniquers.614  impl->affineUniquer.disableMultithreading(disable);615  impl->attributeUniquer.disableMultithreading(disable);616  impl->typeUniquer.disableMultithreading(disable);617 618  // Destroy thread pool (stop all threads) if it is no longer needed, or create619  // a new one if multithreading was re-enabled.620  if (disable) {621    // If the thread pool is owned, explicitly set it to nullptr to avoid622    // keeping a dangling pointer around. If the thread pool is externally623    // owned, we don't do anything.624    if (impl->ownedThreadPool) {625      assert(impl->threadPool);626      impl->threadPool = nullptr;627      impl->ownedThreadPool.reset();628    }629  } else if (!impl->threadPool) {630    // The thread pool isn't externally provided.631    assert(!impl->ownedThreadPool);632    impl->ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();633    impl->threadPool = impl->ownedThreadPool.get();634  }635}636 637void MLIRContext::setThreadPool(llvm::ThreadPoolInterface &pool) {638  assert(!isMultithreadingEnabled() &&639         "expected multi-threading to be disabled when setting a ThreadPool");640  impl->threadPool = &pool;641  impl->ownedThreadPool.reset();642  enableMultithreading();643}644 645unsigned MLIRContext::getNumThreads() {646  if (isMultithreadingEnabled()) {647    assert(impl->threadPool &&648           "multi-threading is enabled but threadpool not set");649    return impl->threadPool->getMaxConcurrency();650  }651  // No multithreading or active thread pool. Return 1 thread.652  return 1;653}654 655llvm::ThreadPoolInterface &MLIRContext::getThreadPool() {656  assert(isMultithreadingEnabled() &&657         "expected multi-threading to be enabled within the context");658  assert(impl->threadPool &&659         "multi-threading is enabled but threadpool not set");660  return *impl->threadPool;661}662 663void MLIRContext::enterMultiThreadedExecution() {664#ifndef NDEBUG665  ++impl->multiThreadedExecutionContext;666#endif667}668void MLIRContext::exitMultiThreadedExecution() {669#ifndef NDEBUG670  --impl->multiThreadedExecutionContext;671#endif672}673 674/// Return true if we should attach the operation to diagnostics emitted via675/// Operation::emit.676bool MLIRContext::shouldPrintOpOnDiagnostic() {677  return impl->printOpOnDiagnostic;678}679 680/// Set the flag specifying if we should attach the operation to diagnostics681/// emitted via Operation::emit.682void MLIRContext::printOpOnDiagnostic(bool enable) {683  assert(impl->multiThreadedExecutionContext == 0 &&684         "changing MLIRContext `print-op-on-diagnostic` configuration while in "685         "a multi-threaded execution context");686  impl->printOpOnDiagnostic = enable;687}688 689/// Return true if we should attach the current stacktrace to diagnostics when690/// emitted.691bool MLIRContext::shouldPrintStackTraceOnDiagnostic() {692  return impl->printStackTraceOnDiagnostic;693}694 695/// Set the flag specifying if we should attach the current stacktrace when696/// emitting diagnostics.697void MLIRContext::printStackTraceOnDiagnostic(bool enable) {698  assert(impl->multiThreadedExecutionContext == 0 &&699         "changing MLIRContext `print-stacktrace-on-diagnostic` configuration "700         "while in a multi-threaded execution context");701  impl->printStackTraceOnDiagnostic = enable;702}703 704/// Return information about all registered operations.705ArrayRef<RegisteredOperationName> MLIRContext::getRegisteredOperations() {706  return impl->sortedRegisteredOperations;707}708 709/// Return information for registered operations by dialect.710ArrayRef<RegisteredOperationName>711MLIRContext::getRegisteredOperationsByDialect(StringRef dialectName) {712  auto *lowerBound = llvm::lower_bound(713      impl->sortedRegisteredOperations, dialectName, [](auto &lhs, auto &rhs) {714        return lhs.getDialect().getNamespace().compare(rhs);715      });716 717  if (lowerBound == impl->sortedRegisteredOperations.end() ||718      lowerBound->getDialect().getNamespace() != dialectName)719    return ArrayRef<RegisteredOperationName>();720 721  auto *upperBound =722      std::upper_bound(lowerBound, impl->sortedRegisteredOperations.end(),723                       dialectName, [](auto &lhs, auto &rhs) {724                         return lhs.compare(rhs.getDialect().getNamespace());725                       });726 727  size_t count = std::distance(lowerBound, upperBound);728  return ArrayRef(&*lowerBound, count);729}730 731bool MLIRContext::isOperationRegistered(StringRef name) {732  return RegisteredOperationName::lookup(name, this).has_value();733}734 735void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {736  auto &impl = context->getImpl();737  assert(impl.multiThreadedExecutionContext == 0 &&738         "Registering a new type kind while in a multi-threaded execution "739         "context");740  auto *newInfo =741      new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())742          AbstractType(std::move(typeInfo));743  if (!impl.registeredTypes.insert({typeID, newInfo}).second)744    llvm::report_fatal_error("Dialect Type already registered.");745  if (!impl.nameToType.insert({newInfo->getName(), newInfo}).second)746    llvm::report_fatal_error("Dialect Type with name " + newInfo->getName() +747                             " is already registered.");748}749 750void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {751  auto &impl = context->getImpl();752  assert(impl.multiThreadedExecutionContext == 0 &&753         "Registering a new attribute kind while in a multi-threaded execution "754         "context");755  auto *newInfo =756      new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())757          AbstractAttribute(std::move(attrInfo));758  if (!impl.registeredAttributes.insert({typeID, newInfo}).second)759    llvm::report_fatal_error("Dialect Attribute already registered.");760  if (!impl.nameToAttribute.insert({newInfo->getName(), newInfo}).second)761    llvm::report_fatal_error("Dialect Attribute with name " +762                             newInfo->getName() + " is already registered.");763}764 765//===----------------------------------------------------------------------===//766// AbstractAttribute767//===----------------------------------------------------------------------===//768 769/// Get the dialect that registered the attribute with the provided typeid.770const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,771                                                   MLIRContext *context) {772  const AbstractAttribute *abstract = lookupMutable(typeID, context);773  if (!abstract)774    llvm::report_fatal_error("Trying to create an Attribute that was not "775                             "registered in this MLIRContext.");776  return *abstract;777}778 779AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,780                                                    MLIRContext *context) {781  auto &impl = context->getImpl();782  return impl.registeredAttributes.lookup(typeID);783}784 785std::optional<std::reference_wrapper<const AbstractAttribute>>786AbstractAttribute::lookup(StringRef name, MLIRContext *context) {787  MLIRContextImpl &impl = context->getImpl();788  const AbstractAttribute *type = impl.nameToAttribute.lookup(name);789 790  if (!type)791    return std::nullopt;792  return {*type};793}794 795//===----------------------------------------------------------------------===//796// OperationName797//===----------------------------------------------------------------------===//798 799OperationName::Impl::Impl(StringRef name, Dialect *dialect, TypeID typeID,800                          detail::InterfaceMap interfaceMap)801    : Impl(StringAttr::get(dialect->getContext(), name), dialect, typeID,802           std::move(interfaceMap)) {}803 804OperationName::OperationName(StringRef name, MLIRContext *context) {805  MLIRContextImpl &ctxImpl = context->getImpl();806 807  // Check for an existing name in read-only mode.808  bool isMultithreadingEnabled = context->isMultithreadingEnabled();809  if (isMultithreadingEnabled) {810    // Check the registered info map first. In the overwhelmingly common case,811    // the entry will be in here and it also removes the need to acquire any812    // locks.813    auto registeredIt = ctxImpl.registeredOperationsByName.find(name);814    if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperationsByName.end())) {815      impl = registeredIt->second.impl;816      return;817    }818 819    llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);820    auto it = ctxImpl.operations.find(name);821    if (it != ctxImpl.operations.end()) {822      impl = it->second.get();823      return;824    }825  }826 827  // Acquire a writer-lock so that we can safely create the new instance.828  ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);829 830  auto it = ctxImpl.operations.try_emplace(name);831  if (it.second) {832    auto nameAttr = StringAttr::get(context, name);833    it.first->second = std::make_unique<UnregisteredOpModel>(834        nameAttr, nameAttr.getReferencedDialect(), TypeID::get<void>(),835        detail::InterfaceMap());836  }837  impl = it.first->second.get();838}839 840StringRef OperationName::getDialectNamespace() const {841  if (Dialect *dialect = getDialect())842    return dialect->getNamespace();843  return getStringRef().split('.').first;844}845 846LogicalResult847OperationName::UnregisteredOpModel::foldHook(Operation *, ArrayRef<Attribute>,848                                             SmallVectorImpl<OpFoldResult> &) {849  return failure();850}851void OperationName::UnregisteredOpModel::getCanonicalizationPatterns(852    RewritePatternSet &, MLIRContext *) {}853bool OperationName::UnregisteredOpModel::hasTrait(TypeID) { return false; }854 855OperationName::ParseAssemblyFn856OperationName::UnregisteredOpModel::getParseAssemblyFn() {857  llvm::report_fatal_error("getParseAssemblyFn hook called on unregistered op");858}859void OperationName::UnregisteredOpModel::populateDefaultAttrs(860    const OperationName &, NamedAttrList &) {}861void OperationName::UnregisteredOpModel::printAssembly(862    Operation *op, OpAsmPrinter &p, StringRef defaultDialect) {863  p.printGenericOp(op);864}865LogicalResult866OperationName::UnregisteredOpModel::verifyInvariants(Operation *) {867  return success();868}869LogicalResult870OperationName::UnregisteredOpModel::verifyRegionInvariants(Operation *) {871  return success();872}873 874std::optional<Attribute>875OperationName::UnregisteredOpModel::getInherentAttr(Operation *op,876                                                    StringRef name) {877  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));878  if (!dict)879    return std::nullopt;880  if (Attribute attr = dict.get(name))881    return attr;882  return std::nullopt;883}884void OperationName::UnregisteredOpModel::setInherentAttr(Operation *op,885                                                         StringAttr name,886                                                         Attribute value) {887  auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));888  assert(dict);889  NamedAttrList attrs(dict);890  attrs.set(name, value);891  *op->getPropertiesStorage().as<Attribute *>() =892      attrs.getDictionary(op->getContext());893}894void OperationName::UnregisteredOpModel::populateInherentAttrs(895    Operation *op, NamedAttrList &attrs) {}896LogicalResult OperationName::UnregisteredOpModel::verifyInherentAttrs(897    OperationName opName, NamedAttrList &attributes,898    function_ref<InFlightDiagnostic()> emitError) {899  return success();900}901int OperationName::UnregisteredOpModel::getOpPropertyByteSize() {902  return sizeof(Attribute);903}904void OperationName::UnregisteredOpModel::initProperties(905    OperationName opName, OpaqueProperties storage, OpaqueProperties init) {906  new (storage.as<Attribute *>()) Attribute();907  if (init)908    *storage.as<Attribute *>() = *init.as<Attribute *>();909}910void OperationName::UnregisteredOpModel::deleteProperties(911    OpaqueProperties prop) {912  prop.as<Attribute *>()->~Attribute();913}914void OperationName::UnregisteredOpModel::populateDefaultProperties(915    OperationName opName, OpaqueProperties properties) {}916LogicalResult OperationName::UnregisteredOpModel::setPropertiesFromAttr(917    OperationName opName, OpaqueProperties properties, Attribute attr,918    function_ref<InFlightDiagnostic()> emitError) {919  *properties.as<Attribute *>() = attr;920  return success();921}922Attribute923OperationName::UnregisteredOpModel::getPropertiesAsAttr(Operation *op) {924  return *op->getPropertiesStorage().as<Attribute *>();925}926void OperationName::UnregisteredOpModel::copyProperties(OpaqueProperties lhs,927                                                        OpaqueProperties rhs) {928  *lhs.as<Attribute *>() = *rhs.as<Attribute *>();929}930bool OperationName::UnregisteredOpModel::compareProperties(931    OpaqueProperties lhs, OpaqueProperties rhs) {932  return *lhs.as<Attribute *>() == *rhs.as<Attribute *>();933}934llvm::hash_code935OperationName::UnregisteredOpModel::hashProperties(OpaqueProperties prop) {936  return llvm::hash_combine(*prop.as<Attribute *>());937}938 939//===----------------------------------------------------------------------===//940// RegisteredOperationName941//===----------------------------------------------------------------------===//942 943std::optional<RegisteredOperationName>944RegisteredOperationName::lookup(TypeID typeID, MLIRContext *ctx) {945  auto &impl = ctx->getImpl();946  auto it = impl.registeredOperations.find(typeID);947  if (it != impl.registeredOperations.end())948    return it->second;949  return std::nullopt;950}951 952std::optional<RegisteredOperationName>953RegisteredOperationName::lookup(StringRef name, MLIRContext *ctx) {954  auto &impl = ctx->getImpl();955  auto it = impl.registeredOperationsByName.find(name);956  if (it != impl.registeredOperationsByName.end())957    return it->getValue();958  return std::nullopt;959}960 961void RegisteredOperationName::insert(962    std::unique_ptr<RegisteredOperationName::Impl> ownedImpl,963    ArrayRef<StringRef> attrNames) {964  RegisteredOperationName::Impl *impl = ownedImpl.get();965  MLIRContext *ctx = impl->getDialect()->getContext();966  auto &ctxImpl = ctx->getImpl();967  assert(ctxImpl.multiThreadedExecutionContext == 0 &&968         "registering a new operation kind while in a multi-threaded execution "969         "context");970 971  // Register the attribute names of this operation.972  MutableArrayRef<StringAttr> cachedAttrNames;973  if (!attrNames.empty()) {974    cachedAttrNames = MutableArrayRef<StringAttr>(975        ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(976            attrNames.size()),977        attrNames.size());978    for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))979      new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));980    impl->attributeNames = cachedAttrNames;981  }982  StringRef name = impl->getName().strref();983  // Insert the operation info if it doesn't exist yet.984  ctxImpl.operations[name] = std::move(ownedImpl);985 986  // Update the registered info for this operation.987  auto emplaced = ctxImpl.registeredOperations.try_emplace(988      impl->getTypeID(), RegisteredOperationName(impl));989  assert(emplaced.second && "operation name registration must be successful");990  auto emplacedByName = ctxImpl.registeredOperationsByName.try_emplace(991      name, RegisteredOperationName(impl));992  (void)emplacedByName;993  assert(emplacedByName.second &&994         "operation name registration must be successful");995 996  // Add emplaced operation name to the sorted operations container.997  RegisteredOperationName &value = emplaced.first->second;998  ctxImpl.sortedRegisteredOperations.insert(999      llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,1000                        [](auto &lhs, auto &rhs) {1001                          return lhs.getIdentifier().compare(1002                              rhs.getIdentifier());1003                        }),1004      value);1005}1006 1007//===----------------------------------------------------------------------===//1008// AbstractType1009//===----------------------------------------------------------------------===//1010 1011const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {1012  const AbstractType *type = lookupMutable(typeID, context);1013  if (!type)1014    llvm::report_fatal_error(1015        "Trying to create a Type that was not registered in this MLIRContext.");1016  return *type;1017}1018 1019AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {1020  auto &impl = context->getImpl();1021  return impl.registeredTypes.lookup(typeID);1022}1023 1024std::optional<std::reference_wrapper<const AbstractType>>1025AbstractType::lookup(StringRef name, MLIRContext *context) {1026  MLIRContextImpl &impl = context->getImpl();1027  const AbstractType *type = impl.nameToType.lookup(name);1028 1029  if (!type)1030    return std::nullopt;1031  return {*type};1032}1033 1034//===----------------------------------------------------------------------===//1035// Type uniquing1036//===----------------------------------------------------------------------===//1037 1038/// Returns the storage uniquer used for constructing type storage instances.1039/// This should not be used directly.1040StorageUniquer &MLIRContext::getTypeUniquer() { return getImpl().typeUniquer; }1041 1042BFloat16Type BFloat16Type::get(MLIRContext *context) {1043  return context->getImpl().bf16Ty;1044}1045Float16Type Float16Type::get(MLIRContext *context) {1046  return context->getImpl().f16Ty;1047}1048FloatTF32Type FloatTF32Type::get(MLIRContext *context) {1049  return context->getImpl().tf32Ty;1050}1051Float32Type Float32Type::get(MLIRContext *context) {1052  return context->getImpl().f32Ty;1053}1054Float64Type Float64Type::get(MLIRContext *context) {1055  return context->getImpl().f64Ty;1056}1057Float80Type Float80Type::get(MLIRContext *context) {1058  return context->getImpl().f80Ty;1059}1060Float128Type Float128Type::get(MLIRContext *context) {1061  return context->getImpl().f128Ty;1062}1063 1064/// Get an instance of the IndexType.1065IndexType IndexType::get(MLIRContext *context) {1066  return context->getImpl().indexTy;1067}1068 1069/// Return an existing integer type instance if one is cached within the1070/// context.1071static IntegerType1072getCachedIntegerType(unsigned width,1073                     IntegerType::SignednessSemantics signedness,1074                     MLIRContext *context) {1075  if (signedness != IntegerType::Signless)1076    return IntegerType();1077 1078  switch (width) {1079  case 1:1080    return context->getImpl().int1Ty;1081  case 8:1082    return context->getImpl().int8Ty;1083  case 16:1084    return context->getImpl().int16Ty;1085  case 32:1086    return context->getImpl().int32Ty;1087  case 64:1088    return context->getImpl().int64Ty;1089  case 128:1090    return context->getImpl().int128Ty;1091  default:1092    return IntegerType();1093  }1094}1095 1096IntegerType IntegerType::get(MLIRContext *context, unsigned width,1097                             IntegerType::SignednessSemantics signedness) {1098  if (auto cached = getCachedIntegerType(width, signedness, context))1099    return cached;1100  return Base::get(context, width, signedness);1101}1102 1103IntegerType1104IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,1105                        MLIRContext *context, unsigned width,1106                        SignednessSemantics signedness) {1107  if (auto cached = getCachedIntegerType(width, signedness, context))1108    return cached;1109  return Base::getChecked(emitError, context, width, signedness);1110}1111 1112/// Get an instance of the NoneType.1113NoneType NoneType::get(MLIRContext *context) {1114  if (NoneType cachedInst = context->getImpl().noneType)1115    return cachedInst;1116  // Note: May happen when initializing the singleton attributes of the builtin1117  // dialect.1118  return Base::get(context);1119}1120 1121//===----------------------------------------------------------------------===//1122// Attribute uniquing1123//===----------------------------------------------------------------------===//1124 1125/// Returns the storage uniquer used for constructing attribute storage1126/// instances. This should not be used directly.1127StorageUniquer &MLIRContext::getAttributeUniquer() {1128  return getImpl().attributeUniquer;1129}1130 1131/// Initialize the given attribute storage instance.1132void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,1133                                                  MLIRContext *ctx,1134                                                  TypeID attrID) {1135  storage->initializeAbstractAttribute(AbstractAttribute::lookup(attrID, ctx));1136}1137 1138BoolAttr BoolAttr::get(MLIRContext *context, bool value) {1139  return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;1140}1141 1142UnitAttr UnitAttr::get(MLIRContext *context) {1143  return context->getImpl().unitAttr;1144}1145 1146UnknownLoc UnknownLoc::get(MLIRContext *context) {1147  return context->getImpl().unknownLocAttr;1148}1149 1150DistinctAttrStorage *1151detail::DistinctAttributeUniquer::allocateStorage(MLIRContext *context,1152                                                  Attribute referencedAttr) {1153  return context->getImpl().distinctAttributeAllocator.allocate(referencedAttr);1154}1155 1156/// Return empty dictionary.1157DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {1158  return context->getImpl().emptyDictionaryAttr;1159}1160 1161void StringAttrStorage::initialize(MLIRContext *context) {1162  // Check for a dialect namespace prefix, if there isn't one we don't need to1163  // do any additional initialization.1164  auto dialectNamePair = value.split('.');1165  if (dialectNamePair.first.empty() || dialectNamePair.second.empty())1166    return;1167 1168  // If one exists, we check to see if this dialect is loaded. If it is, we set1169  // the dialect now, if it isn't we record this storage for initialization1170  // later if the dialect ever gets loaded.1171  if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))1172    return;1173 1174  MLIRContextImpl &impl = context->getImpl();1175  llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);1176  impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);1177}1178 1179/// Return an empty string.1180StringAttr StringAttr::get(MLIRContext *context) {1181  return context->getImpl().emptyStringAttr;1182}1183 1184//===----------------------------------------------------------------------===//1185// AffineMap uniquing1186//===----------------------------------------------------------------------===//1187 1188StorageUniquer &MLIRContext::getAffineUniquer() {1189  return getImpl().affineUniquer;1190}1191 1192AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,1193                             ArrayRef<AffineExpr> results,1194                             MLIRContext *context) {1195  auto &impl = context->getImpl();1196  auto *storage = impl.affineUniquer.get<AffineMapStorage>(1197      [&](AffineMapStorage *storage) { storage->context = context; }, dimCount,1198      symbolCount, results);1199  return AffineMap(storage);1200}1201 1202/// Check whether the arguments passed to the AffineMap::get() are consistent.1203/// This method checks whether the highest index of dimensional identifier1204/// present in result expressions is less than `dimCount` and the highest index1205/// of symbolic identifier present in result expressions is less than1206/// `symbolCount`.1207[[maybe_unused]] static bool1208willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,1209                     ArrayRef<AffineExpr> results) {1210  int64_t maxDimPosition = -1;1211  int64_t maxSymbolPosition = -1;1212  getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,1213                     maxSymbolPosition);1214  if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {1215    LDBG()1216        << "maximum dimensional identifier position in result expression must "1217           "be less than `dimCount` and maximum symbolic identifier position "1218           "in result expression must be less than `symbolCount`";1219    return false;1220  }1221  return true;1222}1223 1224AffineMap AffineMap::get(MLIRContext *context) {1225  return getImpl(/*dimCount=*/0, /*symbolCount=*/0, /*results=*/{}, context);1226}1227 1228AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,1229                         MLIRContext *context) {1230  return getImpl(dimCount, symbolCount, /*results=*/{}, context);1231}1232 1233AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,1234                         AffineExpr result) {1235  assert(willBeValidAffineMap(dimCount, symbolCount, {result}));1236  return getImpl(dimCount, symbolCount, {result}, result.getContext());1237}1238 1239AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,1240                         ArrayRef<AffineExpr> results, MLIRContext *context) {1241  assert(willBeValidAffineMap(dimCount, symbolCount, results));1242  return getImpl(dimCount, symbolCount, results, context);1243}1244 1245//===----------------------------------------------------------------------===//1246// Integer Sets: these are allocated into the bump pointer, and are immutable.1247// Unlike AffineMap's, these are uniqued only if they are small.1248//===----------------------------------------------------------------------===//1249 1250IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,1251                           ArrayRef<AffineExpr> constraints,1252                           ArrayRef<bool> eqFlags) {1253  // The number of constraints can't be zero.1254  assert(!constraints.empty());1255  assert(constraints.size() == eqFlags.size());1256 1257  auto &impl = constraints[0].getContext()->getImpl();1258  auto *storage = impl.affineUniquer.get<IntegerSetStorage>(1259      [](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);1260  return IntegerSet(storage);1261}1262 1263//===----------------------------------------------------------------------===//1264// StorageUniquerSupport1265//===----------------------------------------------------------------------===//1266 1267/// Utility method to generate a callback that can be used to generate a1268/// diagnostic when checking the construction invariants of a storage object.1269/// This is defined out-of-line to avoid the need to include Location.h.1270llvm::unique_function<InFlightDiagnostic()>1271mlir::detail::getDefaultDiagnosticEmitFn(MLIRContext *ctx) {1272  return [ctx] { return emitError(UnknownLoc::get(ctx)); };1273}1274llvm::unique_function<InFlightDiagnostic()>1275mlir::detail::getDefaultDiagnosticEmitFn(const Location &loc) {1276  return [=] { return emitError(loc); };1277}1278