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 ®istry, 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 ®istry) {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