/// Generate the parser for a enum attribute.
static void genEnumAttrParser(const NamedAttribute *var, MethodBody &body,
- FmtContext &attrTypeCtx) {
+ FmtContext &attrTypeCtx, bool parseAsOptional) {
Attribute baseAttr = var->attr.getBaseAttr();
const EnumAttr &enumAttr = cast<EnumAttr>(baseAttr);
std::vector<EnumAttrCase> cases = enumAttr.getAllCases();
// If the attribute is not optional, build an error message for the missing
// attribute.
std::string errorMessage;
- if (!var->attr.isOptional()) {
+ if (!parseAsOptional) {
llvm::raw_string_ostream errorMessageOS(errorMessage);
errorMessageOS
<< "return parser.emitError(loc, \"expected string or "
validCaseKeywordsStr, errorMessage);
}
+// Generate the parser for an attribute.
+static void genAttrParser(AttributeVariable *attr, MethodBody &body,
+ FmtContext &attrTypeCtx, bool parseAsOptional) {
+ const NamedAttribute *var = attr->getVar();
+
+ // Check to see if we can parse this as an enum attribute.
+ if (canFormatEnumAttr(var))
+ return genEnumAttrParser(var, body, attrTypeCtx, parseAsOptional);
+
+ // Check to see if we should parse this as a symbol name attribute.
+ if (shouldFormatSymbolNameAttr(var)) {
+ body << formatv(parseAsOptional ? optionalSymbolNameAttrParserCode
+ : symbolNameAttrParserCode,
+ var->name);
+ return;
+ }
+
+ // If this attribute has a buildable type, use that when parsing the
+ // attribute.
+ std::string attrTypeStr;
+ if (Optional<StringRef> typeBuilder = attr->getTypeBuilder()) {
+ llvm::raw_string_ostream os(attrTypeStr);
+ os << tgfmt(*typeBuilder, &attrTypeCtx);
+ } else {
+ attrTypeStr = "::mlir::Type{}";
+ }
+ if (parseAsOptional) {
+ body << formatv(optionalAttrParserCode, var->name, attrTypeStr);
+ } else {
+ if (attr->shouldBeQualified() ||
+ var->attr.getStorageType() == "::mlir::Attribute")
+ body << formatv(genericAttrParserCode, var->name, attrTypeStr);
+ else
+ body << formatv(attrParserCode, var->name, attrTypeStr);
+ }
+}
+
void OperationFormat::genParser(Operator &op, OpClass &opClass) {
SmallVector<MethodParameter> paramList;
paramList.emplace_back("::mlir::OpAsmParser &", "parser");
// parsing of the rest of the elements.
FormatElement *firstElement = thenElements.front();
if (auto *attrVar = dyn_cast<AttributeVariable>(firstElement)) {
- genElementParser(attrVar, body, attrTypeCtx);
+ genAttrParser(attrVar, body, attrTypeCtx, /*parseAsOptional=*/true);
body << " if (" << attrVar->getVar()->name << "Attr) {\n";
} else if (auto *literal = dyn_cast<LiteralElement>(firstElement)) {
body << " if (::mlir::succeeded(parser.parseOptional";
/// Arguments.
} else if (auto *attr = dyn_cast<AttributeVariable>(element)) {
- const NamedAttribute *var = attr->getVar();
-
- // Check to see if we can parse this as an enum attribute.
- if (canFormatEnumAttr(var))
- return genEnumAttrParser(var, body, attrTypeCtx);
-
- // Check to see if we should parse this as a symbol name attribute.
- if (shouldFormatSymbolNameAttr(var)) {
- body << formatv(var->attr.isOptional() ? optionalSymbolNameAttrParserCode
- : symbolNameAttrParserCode,
- var->name);
- return;
- }
-
- // If this attribute has a buildable type, use that when parsing the
- // attribute.
- std::string attrTypeStr;
- if (Optional<StringRef> typeBuilder = attr->getTypeBuilder()) {
- llvm::raw_string_ostream os(attrTypeStr);
- os << tgfmt(*typeBuilder, &attrTypeCtx);
- } else {
- attrTypeStr = "::mlir::Type{}";
- }
- if (genCtx == GenContext::Normal && var->attr.isOptional()) {
- body << formatv(optionalAttrParserCode, var->name, attrTypeStr);
- } else {
- if (attr->shouldBeQualified() ||
- var->attr.getStorageType() == "::mlir::Attribute")
- body << formatv(genericAttrParserCode, var->name, attrTypeStr);
- else
- body << formatv(attrParserCode, var->name, attrTypeStr);
- }
+ bool parseAsOptional =
+ (genCtx == GenContext::Normal && attr->getVar()->attr.isOptional());
+ genAttrParser(attr, body, attrTypeCtx, parseAsOptional);
} else if (auto *operand = dyn_cast<OperandVariable>(element)) {
ArgumentLengthKind lengthKind = getArgumentLengthKind(operand->getVar());
.Case<FunctionalTypeDirective>([&](FunctionalTypeDirective *element) {
genOptionalGroupPrinterAnchor(element->getInputs(), op, body);
})
- .Case<AttributeVariable>([&](AttributeVariable *attr) {
- body << "(*this)->getAttr(\"" << attr->getVar()->name << "\")";
+ .Case<AttributeVariable>([&](AttributeVariable *element) {
+ Attribute attr = element->getVar()->attr;
+ body << "(*this)->getAttr(\"" << element->getVar()->name << "\")";
+ if (attr.isOptional())
+ return; // done
+ if (attr.hasDefaultValue()) {
+ // Consider a default-valued attribute as present if it's not the
+ // default value.
+ FmtContext fctx;
+ fctx.withBuilder("::mlir::OpBuilder((*this)->getContext())");
+ body << " != "
+ << tgfmt(attr.getConstBuilderTemplate(), &fctx,
+ attr.getDefaultValue());
+ return;
+ }
+ llvm_unreachable("attribute must be optional or default-valued");
});
}
// All attributes can be within the optional group, but only optional
// attributes can be the anchor.
.Case([&](AttributeVariable *attrEle) {
- if (isAnchor && !attrEle->getVar()->attr.isOptional())
- return emitError(loc, "only optional attributes can be used to "
- "anchor an optional group");
+ Attribute attr = attrEle->getVar()->attr;
+ if (isAnchor && !(attr.isOptional() || attr.hasDefaultValue()))
+ return emitError(loc, "only optional or default-valued attributes "
+ "can be used to anchor an optional group");
return success();
})
// Only optional-like(i.e. variadic) operands can be within an optional