This streamlines the implementation and makes it so that the virtual tables are in the binary instead of dynamically assembled during initialization. The dynamic allocation size of op registration is also smaller with this change. Differential Revision: https://reviews.llvm.org/D141492
584 lines
21 KiB
C++
584 lines
21 KiB
C++
//===- ExtensibleDialect.cpp - Extensible dialect ---------------*- C++ -*-===//
|
|
//
|
|
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/IR/ExtensibleDialect.h"
|
|
#include "mlir/IR/AttributeSupport.h"
|
|
#include "mlir/IR/DialectImplementation.h"
|
|
#include "mlir/IR/OperationSupport.h"
|
|
#include "mlir/IR/StorageUniquerSupport.h"
|
|
#include "mlir/Support/LogicalResult.h"
|
|
|
|
using namespace mlir;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic types and attributes shared functions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Default parser for dynamic attribute or type parameters.
|
|
/// Parse in the format '(<>)?' or '<attr (,attr)*>'.
|
|
static LogicalResult
|
|
typeOrAttrParser(AsmParser &parser, SmallVectorImpl<Attribute> &parsedParams) {
|
|
// No parameters
|
|
if (parser.parseOptionalLess() || !parser.parseOptionalGreater())
|
|
return success();
|
|
|
|
Attribute attr;
|
|
if (parser.parseAttribute(attr))
|
|
return failure();
|
|
parsedParams.push_back(attr);
|
|
|
|
while (parser.parseOptionalGreater()) {
|
|
Attribute attr;
|
|
if (parser.parseComma() || parser.parseAttribute(attr))
|
|
return failure();
|
|
parsedParams.push_back(attr);
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
/// Default printer for dynamic attribute or type parameters.
|
|
/// Print in the format '(<>)?' or '<attr (,attr)*>'.
|
|
static void typeOrAttrPrinter(AsmPrinter &printer, ArrayRef<Attribute> params) {
|
|
if (params.empty())
|
|
return;
|
|
|
|
printer << "<";
|
|
interleaveComma(params, printer.getStream());
|
|
printer << ">";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic type
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::unique_ptr<DynamicTypeDefinition>
|
|
DynamicTypeDefinition::get(StringRef name, ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier) {
|
|
return DynamicTypeDefinition::get(name, dialect, std::move(verifier),
|
|
typeOrAttrParser, typeOrAttrPrinter);
|
|
}
|
|
|
|
std::unique_ptr<DynamicTypeDefinition>
|
|
DynamicTypeDefinition::get(StringRef name, ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier, ParserFn &&parser,
|
|
PrinterFn &&printer) {
|
|
return std::unique_ptr<DynamicTypeDefinition>(
|
|
new DynamicTypeDefinition(name, dialect, std::move(verifier),
|
|
std::move(parser), std::move(printer)));
|
|
}
|
|
|
|
DynamicTypeDefinition::DynamicTypeDefinition(StringRef nameRef,
|
|
ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier,
|
|
ParserFn &&parser,
|
|
PrinterFn &&printer)
|
|
: name(nameRef), dialect(dialect), verifier(std::move(verifier)),
|
|
parser(std::move(parser)), printer(std::move(printer)),
|
|
ctx(dialect->getContext()) {}
|
|
|
|
DynamicTypeDefinition::DynamicTypeDefinition(ExtensibleDialect *dialect,
|
|
StringRef nameRef)
|
|
: name(nameRef), dialect(dialect), ctx(dialect->getContext()) {}
|
|
|
|
void DynamicTypeDefinition::registerInTypeUniquer() {
|
|
detail::TypeUniquer::registerType<DynamicType>(&getContext(), getTypeID());
|
|
}
|
|
|
|
namespace mlir {
|
|
namespace detail {
|
|
/// Storage of DynamicType.
|
|
/// Contains a pointer to the type definition and type parameters.
|
|
struct DynamicTypeStorage : public TypeStorage {
|
|
|
|
using KeyTy = std::pair<DynamicTypeDefinition *, ArrayRef<Attribute>>;
|
|
|
|
explicit DynamicTypeStorage(DynamicTypeDefinition *typeDef,
|
|
ArrayRef<Attribute> params)
|
|
: typeDef(typeDef), params(params) {}
|
|
|
|
bool operator==(const KeyTy &key) const {
|
|
return typeDef == key.first && params == key.second;
|
|
}
|
|
|
|
static llvm::hash_code hashKey(const KeyTy &key) {
|
|
return llvm::hash_value(key);
|
|
}
|
|
|
|
static DynamicTypeStorage *construct(TypeStorageAllocator &alloc,
|
|
const KeyTy &key) {
|
|
return new (alloc.allocate<DynamicTypeStorage>())
|
|
DynamicTypeStorage(key.first, alloc.copyInto(key.second));
|
|
}
|
|
|
|
/// Definition of the type.
|
|
DynamicTypeDefinition *typeDef;
|
|
|
|
/// The type parameters.
|
|
ArrayRef<Attribute> params;
|
|
};
|
|
} // namespace detail
|
|
} // namespace mlir
|
|
|
|
DynamicType DynamicType::get(DynamicTypeDefinition *typeDef,
|
|
ArrayRef<Attribute> params) {
|
|
auto &ctx = typeDef->getContext();
|
|
auto emitError = detail::getDefaultDiagnosticEmitFn(&ctx);
|
|
assert(succeeded(typeDef->verify(emitError, params)));
|
|
return detail::TypeUniquer::getWithTypeID<DynamicType>(
|
|
&ctx, typeDef->getTypeID(), typeDef, params);
|
|
}
|
|
|
|
DynamicType
|
|
DynamicType::getChecked(function_ref<InFlightDiagnostic()> emitError,
|
|
DynamicTypeDefinition *typeDef,
|
|
ArrayRef<Attribute> params) {
|
|
if (failed(typeDef->verify(emitError, params)))
|
|
return {};
|
|
auto &ctx = typeDef->getContext();
|
|
return detail::TypeUniquer::getWithTypeID<DynamicType>(
|
|
&ctx, typeDef->getTypeID(), typeDef, params);
|
|
}
|
|
|
|
DynamicTypeDefinition *DynamicType::getTypeDef() { return getImpl()->typeDef; }
|
|
|
|
ArrayRef<Attribute> DynamicType::getParams() { return getImpl()->params; }
|
|
|
|
bool DynamicType::classof(Type type) {
|
|
return type.hasTrait<TypeTrait::IsDynamicType>();
|
|
}
|
|
|
|
ParseResult DynamicType::parse(AsmParser &parser,
|
|
DynamicTypeDefinition *typeDef,
|
|
DynamicType &parsedType) {
|
|
SmallVector<Attribute> params;
|
|
if (failed(typeDef->parser(parser, params)))
|
|
return failure();
|
|
parsedType = parser.getChecked<DynamicType>(typeDef, params);
|
|
if (!parsedType)
|
|
return failure();
|
|
return success();
|
|
}
|
|
|
|
void DynamicType::print(AsmPrinter &printer) {
|
|
printer << getTypeDef()->getName();
|
|
getTypeDef()->printer(printer, getParams());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic attribute
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::unique_ptr<DynamicAttrDefinition>
|
|
DynamicAttrDefinition::get(StringRef name, ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier) {
|
|
return DynamicAttrDefinition::get(name, dialect, std::move(verifier),
|
|
typeOrAttrParser, typeOrAttrPrinter);
|
|
}
|
|
|
|
std::unique_ptr<DynamicAttrDefinition>
|
|
DynamicAttrDefinition::get(StringRef name, ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier, ParserFn &&parser,
|
|
PrinterFn &&printer) {
|
|
return std::unique_ptr<DynamicAttrDefinition>(
|
|
new DynamicAttrDefinition(name, dialect, std::move(verifier),
|
|
std::move(parser), std::move(printer)));
|
|
}
|
|
|
|
DynamicAttrDefinition::DynamicAttrDefinition(StringRef nameRef,
|
|
ExtensibleDialect *dialect,
|
|
VerifierFn &&verifier,
|
|
ParserFn &&parser,
|
|
PrinterFn &&printer)
|
|
: name(nameRef), dialect(dialect), verifier(std::move(verifier)),
|
|
parser(std::move(parser)), printer(std::move(printer)),
|
|
ctx(dialect->getContext()) {}
|
|
|
|
DynamicAttrDefinition::DynamicAttrDefinition(ExtensibleDialect *dialect,
|
|
StringRef nameRef)
|
|
: name(nameRef), dialect(dialect), ctx(dialect->getContext()) {}
|
|
|
|
void DynamicAttrDefinition::registerInAttrUniquer() {
|
|
detail::AttributeUniquer::registerAttribute<DynamicAttr>(&getContext(),
|
|
getTypeID());
|
|
}
|
|
|
|
namespace mlir {
|
|
namespace detail {
|
|
/// Storage of DynamicAttr.
|
|
/// Contains a pointer to the attribute definition and attribute parameters.
|
|
struct DynamicAttrStorage : public AttributeStorage {
|
|
using KeyTy = std::pair<DynamicAttrDefinition *, ArrayRef<Attribute>>;
|
|
|
|
explicit DynamicAttrStorage(DynamicAttrDefinition *attrDef,
|
|
ArrayRef<Attribute> params)
|
|
: attrDef(attrDef), params(params) {}
|
|
|
|
bool operator==(const KeyTy &key) const {
|
|
return attrDef == key.first && params == key.second;
|
|
}
|
|
|
|
static llvm::hash_code hashKey(const KeyTy &key) {
|
|
return llvm::hash_value(key);
|
|
}
|
|
|
|
static DynamicAttrStorage *construct(AttributeStorageAllocator &alloc,
|
|
const KeyTy &key) {
|
|
return new (alloc.allocate<DynamicAttrStorage>())
|
|
DynamicAttrStorage(key.first, alloc.copyInto(key.second));
|
|
}
|
|
|
|
/// Definition of the type.
|
|
DynamicAttrDefinition *attrDef;
|
|
|
|
/// The type parameters.
|
|
ArrayRef<Attribute> params;
|
|
};
|
|
} // namespace detail
|
|
} // namespace mlir
|
|
|
|
DynamicAttr DynamicAttr::get(DynamicAttrDefinition *attrDef,
|
|
ArrayRef<Attribute> params) {
|
|
auto &ctx = attrDef->getContext();
|
|
return detail::AttributeUniquer::getWithTypeID<DynamicAttr>(
|
|
&ctx, attrDef->getTypeID(), attrDef, params);
|
|
}
|
|
|
|
DynamicAttr
|
|
DynamicAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
|
|
DynamicAttrDefinition *attrDef,
|
|
ArrayRef<Attribute> params) {
|
|
if (failed(attrDef->verify(emitError, params)))
|
|
return {};
|
|
return get(attrDef, params);
|
|
}
|
|
|
|
DynamicAttrDefinition *DynamicAttr::getAttrDef() { return getImpl()->attrDef; }
|
|
|
|
ArrayRef<Attribute> DynamicAttr::getParams() { return getImpl()->params; }
|
|
|
|
bool DynamicAttr::classof(Attribute attr) {
|
|
return attr.hasTrait<AttributeTrait::IsDynamicAttr>();
|
|
}
|
|
|
|
ParseResult DynamicAttr::parse(AsmParser &parser,
|
|
DynamicAttrDefinition *attrDef,
|
|
DynamicAttr &parsedAttr) {
|
|
SmallVector<Attribute> params;
|
|
if (failed(attrDef->parser(parser, params)))
|
|
return failure();
|
|
parsedAttr = parser.getChecked<DynamicAttr>(attrDef, params);
|
|
if (!parsedAttr)
|
|
return failure();
|
|
return success();
|
|
}
|
|
|
|
void DynamicAttr::print(AsmPrinter &printer) {
|
|
printer << getAttrDef()->getName();
|
|
getAttrDef()->printer(printer, getParams());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic operation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
DynamicOpDefinition::DynamicOpDefinition(
|
|
StringRef name, ExtensibleDialect *dialect,
|
|
OperationName::VerifyInvariantsFn &&verifyFn,
|
|
OperationName::VerifyRegionInvariantsFn &&verifyRegionFn,
|
|
OperationName::ParseAssemblyFn &&parseFn,
|
|
OperationName::PrintAssemblyFn &&printFn,
|
|
OperationName::FoldHookFn &&foldHookFn,
|
|
GetCanonicalizationPatternsFn &&getCanonicalizationPatternsFn,
|
|
OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn)
|
|
: Impl(StringAttr::get(dialect->getContext(),
|
|
(dialect->getNamespace() + "." + name).str()),
|
|
dialect, dialect->allocateTypeID(),
|
|
/*interfaceMap=*/detail::InterfaceMap(std::nullopt)),
|
|
verifyFn(std::move(verifyFn)), verifyRegionFn(std::move(verifyRegionFn)),
|
|
parseFn(std::move(parseFn)), printFn(std::move(printFn)),
|
|
foldHookFn(std::move(foldHookFn)),
|
|
getCanonicalizationPatternsFn(std::move(getCanonicalizationPatternsFn)),
|
|
populateDefaultAttrsFn(std::move(populateDefaultAttrsFn)) {
|
|
typeID = dialect->allocateTypeID();
|
|
}
|
|
|
|
std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
|
|
StringRef name, ExtensibleDialect *dialect,
|
|
OperationName::VerifyInvariantsFn &&verifyFn,
|
|
OperationName::VerifyRegionInvariantsFn &&verifyRegionFn) {
|
|
auto parseFn = [](OpAsmParser &parser, OperationState &result) {
|
|
return parser.emitError(
|
|
parser.getCurrentLocation(),
|
|
"dynamic operation do not define any parser function");
|
|
};
|
|
|
|
auto printFn = [](Operation *op, OpAsmPrinter &printer, StringRef) {
|
|
printer.printGenericOp(op);
|
|
};
|
|
|
|
return DynamicOpDefinition::get(name, dialect, std::move(verifyFn),
|
|
std::move(verifyRegionFn), std::move(parseFn),
|
|
std::move(printFn));
|
|
}
|
|
|
|
std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
|
|
StringRef name, ExtensibleDialect *dialect,
|
|
OperationName::VerifyInvariantsFn &&verifyFn,
|
|
OperationName::VerifyRegionInvariantsFn &&verifyRegionFn,
|
|
OperationName::ParseAssemblyFn &&parseFn,
|
|
OperationName::PrintAssemblyFn &&printFn) {
|
|
auto foldHookFn = [](Operation *op, ArrayRef<Attribute> operands,
|
|
SmallVectorImpl<OpFoldResult> &results) {
|
|
return failure();
|
|
};
|
|
|
|
auto getCanonicalizationPatternsFn = [](RewritePatternSet &, MLIRContext *) {
|
|
};
|
|
|
|
auto populateDefaultAttrsFn = [](const OperationName &, NamedAttrList &) {};
|
|
|
|
return DynamicOpDefinition::get(name, dialect, std::move(verifyFn),
|
|
std::move(verifyRegionFn), std::move(parseFn),
|
|
std::move(printFn), std::move(foldHookFn),
|
|
std::move(getCanonicalizationPatternsFn),
|
|
std::move(populateDefaultAttrsFn));
|
|
}
|
|
|
|
std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
|
|
StringRef name, ExtensibleDialect *dialect,
|
|
OperationName::VerifyInvariantsFn &&verifyFn,
|
|
OperationName::VerifyInvariantsFn &&verifyRegionFn,
|
|
OperationName::ParseAssemblyFn &&parseFn,
|
|
OperationName::PrintAssemblyFn &&printFn,
|
|
OperationName::FoldHookFn &&foldHookFn,
|
|
GetCanonicalizationPatternsFn &&getCanonicalizationPatternsFn,
|
|
OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn) {
|
|
return std::unique_ptr<DynamicOpDefinition>(new DynamicOpDefinition(
|
|
name, dialect, std::move(verifyFn), std::move(verifyRegionFn),
|
|
std::move(parseFn), std::move(printFn), std::move(foldHookFn),
|
|
std::move(getCanonicalizationPatternsFn),
|
|
std::move(populateDefaultAttrsFn)));
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Extensible dialect
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
/// Interface that can only be implemented by extensible dialects.
|
|
/// The interface is used to check if a dialect is extensible or not.
|
|
class IsExtensibleDialect : public DialectInterface::Base<IsExtensibleDialect> {
|
|
public:
|
|
IsExtensibleDialect(Dialect *dialect) : Base(dialect) {}
|
|
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(IsExtensibleDialect)
|
|
};
|
|
} // namespace
|
|
|
|
ExtensibleDialect::ExtensibleDialect(StringRef name, MLIRContext *ctx,
|
|
TypeID typeID)
|
|
: Dialect(name, ctx, typeID) {
|
|
addInterfaces<IsExtensibleDialect>();
|
|
}
|
|
|
|
void ExtensibleDialect::registerDynamicType(
|
|
std::unique_ptr<DynamicTypeDefinition> &&type) {
|
|
DynamicTypeDefinition *typePtr = type.get();
|
|
TypeID typeID = type->getTypeID();
|
|
StringRef name = type->getName();
|
|
ExtensibleDialect *dialect = type->getDialect();
|
|
|
|
assert(dialect == this &&
|
|
"trying to register a dynamic type in the wrong dialect");
|
|
|
|
// If a type with the same name is already defined, fail.
|
|
auto registered = dynTypes.try_emplace(typeID, std::move(type)).second;
|
|
(void)registered;
|
|
assert(registered && "type TypeID was not unique");
|
|
|
|
registered = nameToDynTypes.insert({name, typePtr}).second;
|
|
(void)registered;
|
|
assert(registered &&
|
|
"Trying to create a new dynamic type with an existing name");
|
|
|
|
auto abstractType =
|
|
AbstractType::get(*dialect, DynamicAttr::getInterfaceMap(),
|
|
DynamicType::getHasTraitFn(), typeID);
|
|
|
|
/// Add the type to the dialect and the type uniquer.
|
|
addType(typeID, std::move(abstractType));
|
|
typePtr->registerInTypeUniquer();
|
|
}
|
|
|
|
void ExtensibleDialect::registerDynamicAttr(
|
|
std::unique_ptr<DynamicAttrDefinition> &&attr) {
|
|
auto *attrPtr = attr.get();
|
|
auto typeID = attr->getTypeID();
|
|
auto name = attr->getName();
|
|
auto *dialect = attr->getDialect();
|
|
|
|
assert(dialect == this &&
|
|
"trying to register a dynamic attribute in the wrong dialect");
|
|
|
|
// If an attribute with the same name is already defined, fail.
|
|
auto registered = dynAttrs.try_emplace(typeID, std::move(attr)).second;
|
|
(void)registered;
|
|
assert(registered && "attribute TypeID was not unique");
|
|
|
|
registered = nameToDynAttrs.insert({name, attrPtr}).second;
|
|
(void)registered;
|
|
assert(registered &&
|
|
"Trying to create a new dynamic attribute with an existing name");
|
|
|
|
auto abstractAttr =
|
|
AbstractAttribute::get(*dialect, DynamicAttr::getInterfaceMap(),
|
|
DynamicAttr::getHasTraitFn(), typeID);
|
|
|
|
/// Add the type to the dialect and the type uniquer.
|
|
addAttribute(typeID, std::move(abstractAttr));
|
|
attrPtr->registerInAttrUniquer();
|
|
}
|
|
|
|
void ExtensibleDialect::registerDynamicOp(
|
|
std::unique_ptr<DynamicOpDefinition> &&op) {
|
|
assert(op->dialect == this &&
|
|
"trying to register a dynamic op in the wrong dialect");
|
|
RegisteredOperationName::insert(std::move(op), /*attrNames=*/{});
|
|
}
|
|
|
|
bool ExtensibleDialect::classof(const Dialect *dialect) {
|
|
return const_cast<Dialect *>(dialect)
|
|
->getRegisteredInterface<IsExtensibleDialect>();
|
|
}
|
|
|
|
OptionalParseResult ExtensibleDialect::parseOptionalDynamicType(
|
|
StringRef typeName, AsmParser &parser, Type &resultType) const {
|
|
DynamicTypeDefinition *typeDef = lookupTypeDefinition(typeName);
|
|
if (!typeDef)
|
|
return std::nullopt;
|
|
|
|
DynamicType dynType;
|
|
if (DynamicType::parse(parser, typeDef, dynType))
|
|
return failure();
|
|
resultType = dynType;
|
|
return success();
|
|
}
|
|
|
|
LogicalResult ExtensibleDialect::printIfDynamicType(Type type,
|
|
AsmPrinter &printer) {
|
|
if (auto dynType = type.dyn_cast<DynamicType>()) {
|
|
dynType.print(printer);
|
|
return success();
|
|
}
|
|
return failure();
|
|
}
|
|
|
|
OptionalParseResult ExtensibleDialect::parseOptionalDynamicAttr(
|
|
StringRef attrName, AsmParser &parser, Attribute &resultAttr) const {
|
|
DynamicAttrDefinition *attrDef = lookupAttrDefinition(attrName);
|
|
if (!attrDef)
|
|
return std::nullopt;
|
|
|
|
DynamicAttr dynAttr;
|
|
if (DynamicAttr::parse(parser, attrDef, dynAttr))
|
|
return failure();
|
|
resultAttr = dynAttr;
|
|
return success();
|
|
}
|
|
|
|
LogicalResult ExtensibleDialect::printIfDynamicAttr(Attribute attribute,
|
|
AsmPrinter &printer) {
|
|
if (auto dynAttr = attribute.dyn_cast<DynamicAttr>()) {
|
|
dynAttr.print(printer);
|
|
return success();
|
|
}
|
|
return failure();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic dialect
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
/// Interface that can only be implemented by extensible dialects.
|
|
/// The interface is used to check if a dialect is extensible or not.
|
|
class IsDynamicDialect : public DialectInterface::Base<IsDynamicDialect> {
|
|
public:
|
|
IsDynamicDialect(Dialect *dialect) : Base(dialect) {}
|
|
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(IsDynamicDialect)
|
|
};
|
|
} // namespace
|
|
|
|
DynamicDialect::DynamicDialect(StringRef name, MLIRContext *ctx)
|
|
: SelfOwningTypeID(),
|
|
ExtensibleDialect(name, ctx, SelfOwningTypeID::getTypeID()) {
|
|
addInterfaces<IsDynamicDialect>();
|
|
}
|
|
|
|
bool DynamicDialect::classof(const Dialect *dialect) {
|
|
return const_cast<Dialect *>(dialect)
|
|
->getRegisteredInterface<IsDynamicDialect>();
|
|
}
|
|
|
|
Type DynamicDialect::parseType(DialectAsmParser &parser) const {
|
|
auto loc = parser.getCurrentLocation();
|
|
StringRef typeTag;
|
|
if (failed(parser.parseKeyword(&typeTag)))
|
|
return Type();
|
|
|
|
{
|
|
Type dynType;
|
|
auto parseResult = parseOptionalDynamicType(typeTag, parser, dynType);
|
|
if (parseResult.has_value()) {
|
|
if (succeeded(parseResult.value()))
|
|
return dynType;
|
|
return Type();
|
|
}
|
|
}
|
|
|
|
parser.emitError(loc, "expected dynamic type");
|
|
return Type();
|
|
}
|
|
|
|
void DynamicDialect::printType(Type type, DialectAsmPrinter &printer) const {
|
|
auto wasDynamic = printIfDynamicType(type, printer);
|
|
(void)wasDynamic;
|
|
assert(succeeded(wasDynamic) &&
|
|
"non-dynamic type defined in dynamic dialect");
|
|
}
|
|
|
|
Attribute DynamicDialect::parseAttribute(DialectAsmParser &parser,
|
|
Type type) const {
|
|
auto loc = parser.getCurrentLocation();
|
|
StringRef typeTag;
|
|
if (failed(parser.parseKeyword(&typeTag)))
|
|
return Attribute();
|
|
|
|
{
|
|
Attribute dynAttr;
|
|
auto parseResult = parseOptionalDynamicAttr(typeTag, parser, dynAttr);
|
|
if (parseResult.has_value()) {
|
|
if (succeeded(parseResult.value()))
|
|
return dynAttr;
|
|
return Attribute();
|
|
}
|
|
}
|
|
|
|
parser.emitError(loc, "expected dynamic attribute");
|
|
return Attribute();
|
|
}
|
|
void DynamicDialect::printAttribute(Attribute attr,
|
|
DialectAsmPrinter &printer) const {
|
|
auto wasDynamic = printIfDynamicAttr(attr, printer);
|
|
(void)wasDynamic;
|
|
assert(succeeded(wasDynamic) &&
|
|
"non-dynamic attribute defined in dynamic dialect");
|
|
}
|