#include "mlir/IR/MLIRContext.h"
#include "AffineExprDetail.h"
#include "AffineMapDetail.h"
#include "AttributeDetail.h"
#include "IntegerSetDetail.h"
#include "TypeDetail.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/Types.h"
#include "mlir/Support/DebugAction.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/RWMutex.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#define DEBUG_TYPE "mlircontext"
using namespace mlir;
using namespace mlir::detail;
namespace {
struct MLIRContextOptions {
llvm::cl::opt<bool> disableThreading{
"mlir-disable-threading",
llvm::cl::desc("Disable multi-threading within MLIR, overrides any "
"further call to MLIRContext::enableMultiThreading()")};
llvm::cl::opt<bool> printOpOnDiagnostic{
"mlir-print-op-on-diagnostic",
llvm::cl::desc("When a diagnostic is emitted on an operation, also print "
"the operation as an attached note"),
llvm::cl::init(true)};
llvm::cl::opt<bool> printStackTraceOnDiagnostic{
"mlir-print-stacktrace-on-diagnostic",
llvm::cl::desc("When a diagnostic is emitted, also print the stack trace "
"as an attached note")};
};
}
static llvm::ManagedStatic<MLIRContextOptions> clOptions;
static bool isThreadingGloballyDisabled() {
#if LLVM_ENABLE_THREADS != 0
return clOptions.isConstructed() && clOptions->disableThreading;
#else
return true;
#endif
}
void mlir::registerMLIRContextCLOptions() {
*clOptions;
}
namespace {
struct ScopedWriterLock {
ScopedWriterLock(llvm::sys::SmartRWMutex<true> &mutexParam, bool shouldLock)
: mutex(shouldLock ? &mutexParam : nullptr) {
if (mutex)
mutex->lock();
}
~ScopedWriterLock() {
if (mutex)
mutex->unlock();
}
llvm::sys::SmartRWMutex<true> *mutex;
};
}
namespace mlir {
class MLIRContextImpl {
public:
DebugActionManager debugActionManager;
DiagnosticEngine diagEngine;
bool allowUnregisteredDialects = false;
bool threadingIsEnabled = true;
#ifndef NDEBUG
std::atomic<int> multiThreadedExecutionContext{0};
#endif
bool printOpOnDiagnostic = true;
bool printStackTraceOnDiagnostic = false;
llvm::ThreadPool *threadPool = nullptr;
std::unique_ptr<llvm::ThreadPool> ownedThreadPool;
DenseMap<StringRef, std::unique_ptr<Dialect>> loadedDialects;
DialectRegistry dialectsRegistry;
llvm::BumpPtrAllocator abstractDialectSymbolAllocator;
llvm::StringMap<OperationName::Impl> operations;
llvm::StringMap<RegisteredOperationName> registeredOperations;
SmallVector<RegisteredOperationName, 0> sortedRegisteredOperations;
llvm::sys::SmartRWMutex<true> operationInfoMutex;
StorageUniquer affineUniquer;
DenseMap<TypeID, AbstractType *> registeredTypes;
StorageUniquer typeUniquer;
BFloat16Type bf16Ty;
Float16Type f16Ty;
Float32Type f32Ty;
Float64Type f64Ty;
Float80Type f80Ty;
Float128Type f128Ty;
IndexType indexTy;
IntegerType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty;
NoneType noneType;
DenseMap<TypeID, AbstractAttribute *> registeredAttributes;
StorageUniquer attributeUniquer;
BoolAttr falseAttr, trueAttr;
UnitAttr unitAttr;
UnknownLoc unknownLocAttr;
DictionaryAttr emptyDictionaryAttr;
StringAttr emptyStringAttr;
llvm::sys::SmartMutex<true> dialectRefStrAttrMutex;
DenseMap<StringRef, SmallVector<StringAttrStorage *>>
dialectReferencingStrAttrs;
public:
MLIRContextImpl(bool threadingIsEnabled)
: threadingIsEnabled(threadingIsEnabled) {
if (threadingIsEnabled) {
ownedThreadPool = std::make_unique<llvm::ThreadPool>();
threadPool = ownedThreadPool.get();
}
}
~MLIRContextImpl() {
for (auto typeMapping : registeredTypes)
typeMapping.second->~AbstractType();
for (auto attrMapping : registeredAttributes)
attrMapping.second->~AbstractAttribute();
}
};
}
MLIRContext::MLIRContext(Threading setting)
: MLIRContext(DialectRegistry(), setting) {}
MLIRContext::MLIRContext(const DialectRegistry ®istry, Threading setting)
: impl(new MLIRContextImpl(setting == Threading::ENABLED &&
!isThreadingGloballyDisabled())) {
if (clOptions.isConstructed()) {
printOpOnDiagnostic(clOptions->printOpOnDiagnostic);
printStackTraceOnDiagnostic(clOptions->printStackTraceOnDiagnostic);
}
registry.appendTo(impl->dialectsRegistry);
getOrLoadDialect<BuiltinDialect>();
impl->bf16Ty = TypeUniquer::get<BFloat16Type>(this);
impl->f16Ty = TypeUniquer::get<Float16Type>(this);
impl->f32Ty = TypeUniquer::get<Float32Type>(this);
impl->f64Ty = TypeUniquer::get<Float64Type>(this);
impl->f80Ty = TypeUniquer::get<Float80Type>(this);
impl->f128Ty = TypeUniquer::get<Float128Type>(this);
impl->indexTy = TypeUniquer::get<IndexType>(this);
impl->int1Ty = TypeUniquer::get<IntegerType>(this, 1, IntegerType::Signless);
impl->int8Ty = TypeUniquer::get<IntegerType>(this, 8, IntegerType::Signless);
impl->int16Ty =
TypeUniquer::get<IntegerType>(this, 16, IntegerType::Signless);
impl->int32Ty =
TypeUniquer::get<IntegerType>(this, 32, IntegerType::Signless);
impl->int64Ty =
TypeUniquer::get<IntegerType>(this, 64, IntegerType::Signless);
impl->int128Ty =
TypeUniquer::get<IntegerType>(this, 128, IntegerType::Signless);
impl->noneType = TypeUniquer::get<NoneType>(this);
impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
impl->emptyStringAttr = StringAttr::getEmptyStringAttrUnchecked(this);
impl->affineUniquer
.registerParametricStorageType<AffineBinaryOpExprStorage>();
impl->affineUniquer
.registerParametricStorageType<AffineConstantExprStorage>();
impl->affineUniquer.registerParametricStorageType<AffineDimExprStorage>();
impl->affineUniquer.registerParametricStorageType<AffineMapStorage>();
impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
}
MLIRContext::~MLIRContext() = default;
template <typename T>
static ArrayRef<T> copyArrayRefInto(llvm::BumpPtrAllocator &allocator,
ArrayRef<T> elements) {
auto result = allocator.Allocate<T>(elements.size());
std::uninitialized_copy(elements.begin(), elements.end(), result);
return ArrayRef<T>(result, elements.size());
}
DebugActionManager &MLIRContext::getDebugActionManager() {
return getImpl().debugActionManager;
}
DiagnosticEngine &MLIRContext::getDiagEngine() { return getImpl().diagEngine; }
void MLIRContext::appendDialectRegistry(const DialectRegistry ®istry) {
if (registry.isSubsetOf(impl->dialectsRegistry))
return;
assert(impl->multiThreadedExecutionContext == 0 &&
"appending to the MLIRContext dialect registry while in a "
"multi-threaded execution context");
registry.appendTo(impl->dialectsRegistry);
registry.applyExtensions(this);
}
const DialectRegistry &MLIRContext::getDialectRegistry() {
return impl->dialectsRegistry;
}
std::vector<Dialect *> MLIRContext::getLoadedDialects() {
std::vector<Dialect *> result;
result.reserve(impl->loadedDialects.size());
for (auto &dialect : impl->loadedDialects)
result.push_back(dialect.second.get());
llvm::array_pod_sort(result.begin(), result.end(),
[](Dialect *const *lhs, Dialect *const *rhs) -> int {
return (*lhs)->getNamespace() < (*rhs)->getNamespace();
});
return result;
}
std::vector<StringRef> MLIRContext::getAvailableDialects() {
std::vector<StringRef> result;
for (auto dialect : impl->dialectsRegistry.getDialectNames())
result.push_back(dialect);
return result;
}
Dialect *MLIRContext::getLoadedDialect(StringRef name) {
auto it = impl->loadedDialects.find(name);
return (it != impl->loadedDialects.end()) ? it->second.get() : nullptr;
}
Dialect *MLIRContext::getOrLoadDialect(StringRef name) {
Dialect *dialect = getLoadedDialect(name);
if (dialect)
return dialect;
DialectAllocatorFunctionRef allocator =
impl->dialectsRegistry.getDialectAllocator(name);
return allocator ? allocator(this) : nullptr;
}
Dialect *
MLIRContext::getOrLoadDialect(StringRef dialectNamespace, TypeID dialectID,
function_ref<std::unique_ptr<Dialect>()> ctor) {
auto &impl = getImpl();
auto dialectIt = impl.loadedDialects.find(dialectNamespace);
if (dialectIt == impl.loadedDialects.end()) {
LLVM_DEBUG(llvm::dbgs()
<< "Load new dialect in Context " << dialectNamespace << "\n");
#ifndef NDEBUG
if (impl.multiThreadedExecutionContext != 0)
llvm::report_fatal_error(
"Loading a dialect (" + dialectNamespace +
") while in a multi-threaded execution context (maybe "
"the PassManager): this can indicate a "
"missing `dependentDialects` in a pass for example.");
#endif
std::unique_ptr<Dialect> &dialect =
impl.loadedDialects.insert({dialectNamespace, ctor()}).first->second;
assert(dialect && "dialect ctor failed");
auto stringAttrsIt = impl.dialectReferencingStrAttrs.find(dialectNamespace);
if (stringAttrsIt != impl.dialectReferencingStrAttrs.end()) {
for (StringAttrStorage *storage : stringAttrsIt->second)
storage->referencedDialect = dialect.get();
impl.dialectReferencingStrAttrs.erase(stringAttrsIt);
}
impl.dialectsRegistry.applyExtensions(dialect.get());
return dialect.get();
}
std::unique_ptr<Dialect> &dialect = dialectIt->second;
if (dialect->getTypeID() != dialectID)
llvm::report_fatal_error("a dialect with namespace '" + dialectNamespace +
"' has already been registered");
return dialect.get();
}
void MLIRContext::loadAllAvailableDialects() {
for (StringRef name : getAvailableDialects())
getOrLoadDialect(name);
}
llvm::hash_code MLIRContext::getRegistryHash() {
llvm::hash_code hash(0);
hash = llvm::hash_combine(hash, impl->loadedDialects.size());
hash = llvm::hash_combine(hash, impl->registeredAttributes.size());
hash = llvm::hash_combine(hash, impl->registeredOperations.size());
hash = llvm::hash_combine(hash, impl->registeredTypes.size());
return hash;
}
bool MLIRContext::allowsUnregisteredDialects() {
return impl->allowUnregisteredDialects;
}
void MLIRContext::allowUnregisteredDialects(bool allowing) {
assert(impl->multiThreadedExecutionContext == 0 &&
"changing MLIRContext `allow-unregistered-dialects` configuration "
"while in a multi-threaded execution context");
impl->allowUnregisteredDialects = allowing;
}
bool MLIRContext::isMultithreadingEnabled() {
return impl->threadingIsEnabled && llvm::llvm_is_multithreaded();
}
void MLIRContext::disableMultithreading(bool disable) {
if (isThreadingGloballyDisabled())
return;
assert(impl->multiThreadedExecutionContext == 0 &&
"changing MLIRContext `disable-threading` configuration while "
"in a multi-threaded execution context");
impl->threadingIsEnabled = !disable;
impl->affineUniquer.disableMultithreading(disable);
impl->attributeUniquer.disableMultithreading(disable);
impl->typeUniquer.disableMultithreading(disable);
if (disable) {
if (impl->ownedThreadPool) {
assert(impl->threadPool);
impl->threadPool = nullptr;
impl->ownedThreadPool.reset();
}
} else if (!impl->threadPool) {
assert(!impl->ownedThreadPool);
impl->ownedThreadPool = std::make_unique<llvm::ThreadPool>();
impl->threadPool = impl->ownedThreadPool.get();
}
}
void MLIRContext::setThreadPool(llvm::ThreadPool &pool) {
assert(!isMultithreadingEnabled() &&
"expected multi-threading to be disabled when setting a ThreadPool");
impl->threadPool = &pool;
impl->ownedThreadPool.reset();
enableMultithreading();
}
unsigned MLIRContext::getNumThreads() {
if (isMultithreadingEnabled()) {
assert(impl->threadPool &&
"multi-threading is enabled but threadpool not set");
return impl->threadPool->getThreadCount();
}
return 1;
}
llvm::ThreadPool &MLIRContext::getThreadPool() {
assert(isMultithreadingEnabled() &&
"expected multi-threading to be enabled within the context");
assert(impl->threadPool &&
"multi-threading is enabled but threadpool not set");
return *impl->threadPool;
}
void MLIRContext::enterMultiThreadedExecution() {
#ifndef NDEBUG
++impl->multiThreadedExecutionContext;
#endif
}
void MLIRContext::exitMultiThreadedExecution() {
#ifndef NDEBUG
--impl->multiThreadedExecutionContext;
#endif
}
bool MLIRContext::shouldPrintOpOnDiagnostic() {
return impl->printOpOnDiagnostic;
}
void MLIRContext::printOpOnDiagnostic(bool enable) {
assert(impl->multiThreadedExecutionContext == 0 &&
"changing MLIRContext `print-op-on-diagnostic` configuration while in "
"a multi-threaded execution context");
impl->printOpOnDiagnostic = enable;
}
bool MLIRContext::shouldPrintStackTraceOnDiagnostic() {
return impl->printStackTraceOnDiagnostic;
}
void MLIRContext::printStackTraceOnDiagnostic(bool enable) {
assert(impl->multiThreadedExecutionContext == 0 &&
"changing MLIRContext `print-stacktrace-on-diagnostic` configuration "
"while in a multi-threaded execution context");
impl->printStackTraceOnDiagnostic = enable;
}
ArrayRef<RegisteredOperationName> MLIRContext::getRegisteredOperations() {
return impl->sortedRegisteredOperations;
}
bool MLIRContext::isOperationRegistered(StringRef name) {
return RegisteredOperationName::lookup(name, this).has_value();
}
void Dialect::addType(TypeID typeID, AbstractType &&typeInfo) {
auto &impl = context->getImpl();
assert(impl.multiThreadedExecutionContext == 0 &&
"Registering a new type kind while in a multi-threaded execution "
"context");
auto *newInfo =
new (impl.abstractDialectSymbolAllocator.Allocate<AbstractType>())
AbstractType(std::move(typeInfo));
if (!impl.registeredTypes.insert({typeID, newInfo}).second)
llvm::report_fatal_error("Dialect Type already registered.");
}
void Dialect::addAttribute(TypeID typeID, AbstractAttribute &&attrInfo) {
auto &impl = context->getImpl();
assert(impl.multiThreadedExecutionContext == 0 &&
"Registering a new attribute kind while in a multi-threaded execution "
"context");
auto *newInfo =
new (impl.abstractDialectSymbolAllocator.Allocate<AbstractAttribute>())
AbstractAttribute(std::move(attrInfo));
if (!impl.registeredAttributes.insert({typeID, newInfo}).second)
llvm::report_fatal_error("Dialect Attribute already registered.");
}
const AbstractAttribute &AbstractAttribute::lookup(TypeID typeID,
MLIRContext *context) {
const AbstractAttribute *abstract = lookupMutable(typeID, context);
if (!abstract)
llvm::report_fatal_error("Trying to create an Attribute that was not "
"registered in this MLIRContext.");
return *abstract;
}
AbstractAttribute *AbstractAttribute::lookupMutable(TypeID typeID,
MLIRContext *context) {
auto &impl = context->getImpl();
auto it = impl.registeredAttributes.find(typeID);
if (it == impl.registeredAttributes.end())
return nullptr;
return it->second;
}
OperationName::OperationName(StringRef name, MLIRContext *context) {
MLIRContextImpl &ctxImpl = context->getImpl();
bool isMultithreadingEnabled = context->isMultithreadingEnabled();
if (isMultithreadingEnabled) {
auto registeredIt = ctxImpl.registeredOperations.find(name);
if (LLVM_LIKELY(registeredIt != ctxImpl.registeredOperations.end())) {
impl = registeredIt->second.impl;
return;
}
llvm::sys::SmartScopedReader<true> contextLock(ctxImpl.operationInfoMutex);
auto it = ctxImpl.operations.find(name);
if (it != ctxImpl.operations.end()) {
impl = &it->second;
return;
}
}
ScopedWriterLock lock(ctxImpl.operationInfoMutex, isMultithreadingEnabled);
auto it = ctxImpl.operations.insert({name, OperationName::Impl(nullptr)});
if (it.second)
it.first->second.name = StringAttr::get(context, name);
impl = &it.first->second;
}
StringRef OperationName::getDialectNamespace() const {
if (Dialect *dialect = getDialect())
return dialect->getNamespace();
return getStringRef().split('.').first;
}
Optional<RegisteredOperationName>
RegisteredOperationName::lookup(StringRef name, MLIRContext *ctx) {
auto &impl = ctx->getImpl();
auto it = impl.registeredOperations.find(name);
if (it != impl.registeredOperations.end())
return it->getValue();
return llvm::None;
}
ParseResult
RegisteredOperationName::parseAssembly(OpAsmParser &parser,
OperationState &result) const {
return impl->parseAssemblyFn(parser, result);
}
void RegisteredOperationName::populateDefaultAttrs(NamedAttrList &attrs) const {
impl->populateDefaultAttrsFn(*this, attrs);
}
void RegisteredOperationName::insert(
StringRef name, Dialect &dialect, TypeID typeID,
ParseAssemblyFn &&parseAssembly, PrintAssemblyFn &&printAssembly,
VerifyInvariantsFn &&verifyInvariants,
VerifyRegionInvariantsFn &&verifyRegionInvariants, FoldHookFn &&foldHook,
GetCanonicalizationPatternsFn &&getCanonicalizationPatterns,
detail::InterfaceMap &&interfaceMap, HasTraitFn &&hasTrait,
ArrayRef<StringRef> attrNames,
PopulateDefaultAttrsFn &&populateDefaultAttrs) {
MLIRContext *ctx = dialect.getContext();
auto &ctxImpl = ctx->getImpl();
assert(ctxImpl.multiThreadedExecutionContext == 0 &&
"registering a new operation kind while in a multi-threaded execution "
"context");
MutableArrayRef<StringAttr> cachedAttrNames;
if (!attrNames.empty()) {
cachedAttrNames = MutableArrayRef<StringAttr>(
ctxImpl.abstractDialectSymbolAllocator.Allocate<StringAttr>(
attrNames.size()),
attrNames.size());
for (unsigned i : llvm::seq<unsigned>(0, attrNames.size()))
new (&cachedAttrNames[i]) StringAttr(StringAttr::get(ctx, attrNames[i]));
}
auto it = ctxImpl.operations.insert({name, OperationName::Impl(nullptr)});
if (it.second)
it.first->second.name = StringAttr::get(ctx, name);
OperationName::Impl &impl = it.first->second;
if (impl.isRegistered()) {
llvm::errs() << "error: operation named '" << name
<< "' is already registered.\n";
abort();
}
auto emplaced = ctxImpl.registeredOperations.try_emplace(
name, RegisteredOperationName(&impl));
assert(emplaced.second && "operation name registration must be successful");
RegisteredOperationName &value = emplaced.first->getValue();
ctxImpl.sortedRegisteredOperations.insert(
llvm::upper_bound(ctxImpl.sortedRegisteredOperations, value,
[](auto &lhs, auto &rhs) {
return lhs.getIdentifier().compare(
rhs.getIdentifier());
}),
value);
impl.dialect = &dialect;
impl.typeID = typeID;
impl.interfaceMap = std::move(interfaceMap);
impl.foldHookFn = std::move(foldHook);
impl.getCanonicalizationPatternsFn = std::move(getCanonicalizationPatterns);
impl.hasTraitFn = std::move(hasTrait);
impl.parseAssemblyFn = std::move(parseAssembly);
impl.printAssemblyFn = std::move(printAssembly);
impl.verifyInvariantsFn = std::move(verifyInvariants);
impl.verifyRegionInvariantsFn = std::move(verifyRegionInvariants);
impl.attributeNames = cachedAttrNames;
impl.populateDefaultAttrsFn = std::move(populateDefaultAttrs);
}
const AbstractType &AbstractType::lookup(TypeID typeID, MLIRContext *context) {
const AbstractType *type = lookupMutable(typeID, context);
if (!type)
llvm::report_fatal_error(
"Trying to create a Type that was not registered in this MLIRContext.");
return *type;
}
AbstractType *AbstractType::lookupMutable(TypeID typeID, MLIRContext *context) {
auto &impl = context->getImpl();
auto it = impl.registeredTypes.find(typeID);
if (it == impl.registeredTypes.end())
return nullptr;
return it->second;
}
StorageUniquer &MLIRContext::getTypeUniquer() { return getImpl().typeUniquer; }
BFloat16Type BFloat16Type::get(MLIRContext *context) {
return context->getImpl().bf16Ty;
}
Float16Type Float16Type::get(MLIRContext *context) {
return context->getImpl().f16Ty;
}
Float32Type Float32Type::get(MLIRContext *context) {
return context->getImpl().f32Ty;
}
Float64Type Float64Type::get(MLIRContext *context) {
return context->getImpl().f64Ty;
}
Float80Type Float80Type::get(MLIRContext *context) {
return context->getImpl().f80Ty;
}
Float128Type Float128Type::get(MLIRContext *context) {
return context->getImpl().f128Ty;
}
IndexType IndexType::get(MLIRContext *context) {
return context->getImpl().indexTy;
}
static IntegerType
getCachedIntegerType(unsigned width,
IntegerType::SignednessSemantics signedness,
MLIRContext *context) {
if (signedness != IntegerType::Signless)
return IntegerType();
switch (width) {
case 1:
return context->getImpl().int1Ty;
case 8:
return context->getImpl().int8Ty;
case 16:
return context->getImpl().int16Ty;
case 32:
return context->getImpl().int32Ty;
case 64:
return context->getImpl().int64Ty;
case 128:
return context->getImpl().int128Ty;
default:
return IntegerType();
}
}
IntegerType IntegerType::get(MLIRContext *context, unsigned width,
IntegerType::SignednessSemantics signedness) {
if (auto cached = getCachedIntegerType(width, signedness, context))
return cached;
return Base::get(context, width, signedness);
}
IntegerType
IntegerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
MLIRContext *context, unsigned width,
SignednessSemantics signedness) {
if (auto cached = getCachedIntegerType(width, signedness, context))
return cached;
return Base::getChecked(emitError, context, width, signedness);
}
NoneType NoneType::get(MLIRContext *context) {
if (NoneType cachedInst = context->getImpl().noneType)
return cachedInst;
return Base::get(context);
}
StorageUniquer &MLIRContext::getAttributeUniquer() {
return getImpl().attributeUniquer;
}
void AttributeUniquer::initializeAttributeStorage(AttributeStorage *storage,
MLIRContext *ctx,
TypeID attrID) {
storage->initializeAbstractAttribute(AbstractAttribute::lookup(attrID, ctx));
if (!storage->getType())
storage->setType(NoneType::get(ctx));
}
BoolAttr BoolAttr::get(MLIRContext *context, bool value) {
return value ? context->getImpl().trueAttr : context->getImpl().falseAttr;
}
UnitAttr UnitAttr::get(MLIRContext *context) {
return context->getImpl().unitAttr;
}
UnknownLoc UnknownLoc::get(MLIRContext *context) {
return context->getImpl().unknownLocAttr;
}
DictionaryAttr DictionaryAttr::getEmpty(MLIRContext *context) {
return context->getImpl().emptyDictionaryAttr;
}
void StringAttrStorage::initialize(MLIRContext *context) {
auto dialectNamePair = value.split('.');
if (dialectNamePair.first.empty() || dialectNamePair.second.empty())
return;
if ((referencedDialect = context->getLoadedDialect(dialectNamePair.first)))
return;
MLIRContextImpl &impl = context->getImpl();
llvm::sys::SmartScopedLock<true> lock(impl.dialectRefStrAttrMutex);
impl.dialectReferencingStrAttrs[dialectNamePair.first].push_back(this);
}
StringAttr StringAttr::get(MLIRContext *context) {
return context->getImpl().emptyStringAttr;
}
StorageUniquer &MLIRContext::getAffineUniquer() {
return getImpl().affineUniquer;
}
AffineMap AffineMap::getImpl(unsigned dimCount, unsigned symbolCount,
ArrayRef<AffineExpr> results,
MLIRContext *context) {
auto &impl = context->getImpl();
auto *storage = impl.affineUniquer.get<AffineMapStorage>(
[&](AffineMapStorage *storage) { storage->context = context; }, dimCount,
symbolCount, results);
return AffineMap(storage);
}
LLVM_ATTRIBUTE_UNUSED static bool
willBeValidAffineMap(unsigned dimCount, unsigned symbolCount,
ArrayRef<AffineExpr> results) {
int64_t maxDimPosition = -1;
int64_t maxSymbolPosition = -1;
getMaxDimAndSymbol(ArrayRef<ArrayRef<AffineExpr>>(results), maxDimPosition,
maxSymbolPosition);
if ((maxDimPosition >= dimCount) || (maxSymbolPosition >= symbolCount)) {
LLVM_DEBUG(
llvm::dbgs()
<< "maximum dimensional identifier position in result expression must "
"be less than `dimCount` and maximum symbolic identifier position "
"in result expression must be less than `symbolCount`\n");
return false;
}
return true;
}
AffineMap AffineMap::get(MLIRContext *context) {
return getImpl(0, 0, {}, context);
}
AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
MLIRContext *context) {
return getImpl(dimCount, symbolCount, {}, context);
}
AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
AffineExpr result) {
assert(willBeValidAffineMap(dimCount, symbolCount, {result}));
return getImpl(dimCount, symbolCount, {result}, result.getContext());
}
AffineMap AffineMap::get(unsigned dimCount, unsigned symbolCount,
ArrayRef<AffineExpr> results, MLIRContext *context) {
assert(willBeValidAffineMap(dimCount, symbolCount, results));
return getImpl(dimCount, symbolCount, results, context);
}
IntegerSet IntegerSet::get(unsigned dimCount, unsigned symbolCount,
ArrayRef<AffineExpr> constraints,
ArrayRef<bool> eqFlags) {
assert(!constraints.empty());
assert(constraints.size() == eqFlags.size());
auto &impl = constraints[0].getContext()->getImpl();
auto *storage = impl.affineUniquer.get<IntegerSetStorage>(
[](IntegerSetStorage *) {}, dimCount, symbolCount, constraints, eqFlags);
return IntegerSet(storage);
}
llvm::unique_function<InFlightDiagnostic()>
mlir::detail::getDefaultDiagnosticEmitFn(MLIRContext *ctx) {
return [ctx] { return emitError(UnknownLoc::get(ctx)); };
}
llvm::unique_function<InFlightDiagnostic()>
mlir::detail::getDefaultDiagnosticEmitFn(const Location &loc) {
return [=] { return emitError(loc); };
}