1 //===- OpFormatGen.cpp - MLIR operation asm format generator --------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "OpFormatGen.h" 10 #include "FormatGen.h" 11 #include "OpClass.h" 12 #include "mlir/Support/LLVM.h" 13 #include "mlir/Support/LogicalResult.h" 14 #include "mlir/TableGen/Class.h" 15 #include "mlir/TableGen/Format.h" 16 #include "mlir/TableGen/GenInfo.h" 17 #include "mlir/TableGen/Interfaces.h" 18 #include "mlir/TableGen/Operator.h" 19 #include "mlir/TableGen/Trait.h" 20 #include "llvm/ADT/MapVector.h" 21 #include "llvm/ADT/Sequence.h" 22 #include "llvm/ADT/SetVector.h" 23 #include "llvm/ADT/SmallBitVector.h" 24 #include "llvm/ADT/StringExtras.h" 25 #include "llvm/ADT/StringSwitch.h" 26 #include "llvm/ADT/TypeSwitch.h" 27 #include "llvm/Support/Signals.h" 28 #include "llvm/TableGen/Error.h" 29 #include "llvm/TableGen/Record.h" 30 31 #define DEBUG_TYPE "mlir-tblgen-opformatgen" 32 33 using namespace mlir; 34 using namespace mlir::tblgen; 35 36 //===----------------------------------------------------------------------===// 37 // VariableElement 38 39 namespace { 40 /// This class represents an instance of an op variable element. A variable 41 /// refers to something registered on the operation itself, e.g. an operand, 42 /// result, attribute, region, or successor. 43 template <typename VarT, VariableElement::Kind VariableKind> 44 class OpVariableElement : public VariableElementBase<VariableKind> { 45 public: 46 using Base = OpVariableElement<VarT, VariableKind>; 47 48 /// Create an op variable element with the variable value. 49 OpVariableElement(const VarT *var) : var(var) {} 50 51 /// Get the variable. 52 const VarT *getVar() { return var; } 53 54 protected: 55 /// The op variable, e.g. a type or attribute constraint. 56 const VarT *var; 57 }; 58 59 /// This class represents a variable that refers to an attribute argument. 60 struct AttributeVariable 61 : public OpVariableElement<NamedAttribute, VariableElement::Attribute> { 62 using Base::Base; 63 64 /// Return the constant builder call for the type of this attribute, or None 65 /// if it doesn't have one. 66 llvm::Optional<StringRef> getTypeBuilder() const { 67 llvm::Optional<Type> attrType = var->attr.getValueType(); 68 return attrType ? attrType->getBuilderCall() : llvm::None; 69 } 70 71 /// Return if this attribute refers to a UnitAttr. 72 bool isUnitAttr() const { 73 return var->attr.getBaseAttr().getAttrDefName() == "UnitAttr"; 74 } 75 76 /// Indicate if this attribute is printed "qualified" (that is it is 77 /// prefixed with the `#dialect.mnemonic`). 78 bool shouldBeQualified() { return shouldBeQualifiedFlag; } 79 void setShouldBeQualified(bool qualified = true) { 80 shouldBeQualifiedFlag = qualified; 81 } 82 83 private: 84 bool shouldBeQualifiedFlag = false; 85 }; 86 87 /// This class represents a variable that refers to an operand argument. 88 using OperandVariable = 89 OpVariableElement<NamedTypeConstraint, VariableElement::Operand>; 90 91 /// This class represents a variable that refers to a result. 92 using ResultVariable = 93 OpVariableElement<NamedTypeConstraint, VariableElement::Result>; 94 95 /// This class represents a variable that refers to a region. 96 using RegionVariable = OpVariableElement<NamedRegion, VariableElement::Region>; 97 98 /// This class represents a variable that refers to a successor. 99 using SuccessorVariable = 100 OpVariableElement<NamedSuccessor, VariableElement::Successor>; 101 } // namespace 102 103 //===----------------------------------------------------------------------===// 104 // DirectiveElement 105 106 namespace { 107 /// This class represents the `operands` directive. This directive represents 108 /// all of the operands of an operation. 109 using OperandsDirective = DirectiveElementBase<DirectiveElement::Operands>; 110 111 /// This class represents the `results` directive. This directive represents 112 /// all of the results of an operation. 113 using ResultsDirective = DirectiveElementBase<DirectiveElement::Results>; 114 115 /// This class represents the `regions` directive. This directive represents 116 /// all of the regions of an operation. 117 using RegionsDirective = DirectiveElementBase<DirectiveElement::Regions>; 118 119 /// This class represents the `successors` directive. This directive represents 120 /// all of the successors of an operation. 121 using SuccessorsDirective = DirectiveElementBase<DirectiveElement::Successors>; 122 123 /// This class represents the `attr-dict` directive. This directive represents 124 /// the attribute dictionary of the operation. 125 class AttrDictDirective 126 : public DirectiveElementBase<DirectiveElement::AttrDict> { 127 public: 128 explicit AttrDictDirective(bool withKeyword) : withKeyword(withKeyword) {} 129 130 /// Return whether the dictionary should be printed with the 'attributes' 131 /// keyword. 132 bool isWithKeyword() const { return withKeyword; } 133 134 private: 135 /// If the dictionary should be printed with the 'attributes' keyword. 136 bool withKeyword; 137 }; 138 139 /// This class represents the `functional-type` directive. This directive takes 140 /// two arguments and formats them, respectively, as the inputs and results of a 141 /// FunctionType. 142 class FunctionalTypeDirective 143 : public DirectiveElementBase<DirectiveElement::FunctionalType> { 144 public: 145 FunctionalTypeDirective(FormatElement *inputs, FormatElement *results) 146 : inputs(inputs), results(results) {} 147 148 FormatElement *getInputs() const { return inputs; } 149 FormatElement *getResults() const { return results; } 150 151 private: 152 /// The input and result arguments. 153 FormatElement *inputs, *results; 154 }; 155 156 /// This class represents the `type` directive. 157 class TypeDirective : public DirectiveElementBase<DirectiveElement::Type> { 158 public: 159 TypeDirective(FormatElement *arg) : arg(arg) {} 160 161 FormatElement *getArg() const { return arg; } 162 163 /// Indicate if this type is printed "qualified" (that is it is 164 /// prefixed with the `!dialect.mnemonic`). 165 bool shouldBeQualified() { return shouldBeQualifiedFlag; } 166 void setShouldBeQualified(bool qualified = true) { 167 shouldBeQualifiedFlag = qualified; 168 } 169 170 private: 171 /// The argument that is used to format the directive. 172 FormatElement *arg; 173 174 bool shouldBeQualifiedFlag = false; 175 }; 176 177 /// This class represents a group of order-independent optional clauses. Each 178 /// clause starts with a literal element and has a coressponding parsing 179 /// element. A parsing element is a continous sequence of format elements. 180 /// Each clause can appear 0 or 1 time. 181 class OIListElement : public DirectiveElementBase<DirectiveElement::OIList> { 182 public: 183 OIListElement(std::vector<FormatElement *> &&literalElements, 184 std::vector<std::vector<FormatElement *>> &&parsingElements) 185 : literalElements(std::move(literalElements)), 186 parsingElements(std::move(parsingElements)) {} 187 188 /// Returns a range to iterate over the LiteralElements. 189 auto getLiteralElements() const { 190 // The use of std::function is unfortunate but necessary here. Lambda 191 // functions cannot be copied but std::function can be copied. This copy 192 // constructor is used in llvm::zip. 193 std::function<LiteralElement *(FormatElement * el)> 194 literalElementCastConverter = 195 [](FormatElement *el) { return cast<LiteralElement>(el); }; 196 return llvm::map_range(literalElements, literalElementCastConverter); 197 } 198 199 /// Returns a range to iterate over the parsing elements corresponding to the 200 /// clauses. 201 ArrayRef<std::vector<FormatElement *>> getParsingElements() const { 202 return parsingElements; 203 } 204 205 /// Returns a range to iterate over tuples of parsing and literal elements. 206 auto getClauses() const { 207 return llvm::zip(getLiteralElements(), getParsingElements()); 208 } 209 210 /// If the parsing element is a single UnitAttr element, then it returns the 211 /// attribute variable. Otherwise, returns nullptr. 212 AttributeVariable * 213 getUnitAttrParsingElement(ArrayRef<FormatElement *> pelement) { 214 if (pelement.size() == 1) { 215 auto attrElem = dyn_cast<AttributeVariable>(pelement[0]); 216 if (attrElem && attrElem->isUnitAttr()) 217 return attrElem; 218 } 219 return nullptr; 220 } 221 222 private: 223 /// A vector of `LiteralElement` objects. Each element stores the keyword 224 /// for one case of oilist element. For example, an oilist element along with 225 /// the `literalElements` vector: 226 /// ``` 227 /// oilist [ `keyword` `=` `(` $arg0 `)` | `otherKeyword` `<` $arg1 `>`] 228 /// literalElements = { `keyword`, `otherKeyword` } 229 /// ``` 230 std::vector<FormatElement *> literalElements; 231 232 /// A vector of valid declarative assembly format vectors. Each object in 233 /// parsing elements is a vector of elements in assembly format syntax. 234 /// For example, an oilist element along with the parsingElements vector: 235 /// ``` 236 /// oilist [ `keyword` `=` `(` $arg0 `)` | `otherKeyword` `<` $arg1 `>`] 237 /// parsingElements = { 238 /// { `=`, `(`, $arg0, `)` }, 239 /// { `<`, $arg1, `>` } 240 /// } 241 /// ``` 242 std::vector<std::vector<FormatElement *>> parsingElements; 243 }; 244 } // namespace 245 246 //===----------------------------------------------------------------------===// 247 // OperationFormat 248 //===----------------------------------------------------------------------===// 249 250 namespace { 251 252 using ConstArgument = 253 llvm::PointerUnion<const NamedAttribute *, const NamedTypeConstraint *>; 254 255 struct OperationFormat { 256 /// This class represents a specific resolver for an operand or result type. 257 class TypeResolution { 258 public: 259 TypeResolution() = default; 260 261 /// Get the index into the buildable types for this type, or None. 262 Optional<int> getBuilderIdx() const { return builderIdx; } 263 void setBuilderIdx(int idx) { builderIdx = idx; } 264 265 /// Get the variable this type is resolved to, or nullptr. 266 const NamedTypeConstraint *getVariable() const { 267 return resolver.dyn_cast<const NamedTypeConstraint *>(); 268 } 269 /// Get the attribute this type is resolved to, or nullptr. 270 const NamedAttribute *getAttribute() const { 271 return resolver.dyn_cast<const NamedAttribute *>(); 272 } 273 /// Get the transformer for the type of the variable, or None. 274 Optional<StringRef> getVarTransformer() const { 275 return variableTransformer; 276 } 277 void setResolver(ConstArgument arg, Optional<StringRef> transformer) { 278 resolver = arg; 279 variableTransformer = transformer; 280 assert(getVariable() || getAttribute()); 281 } 282 283 private: 284 /// If the type is resolved with a buildable type, this is the index into 285 /// 'buildableTypes' in the parent format. 286 Optional<int> builderIdx; 287 /// If the type is resolved based upon another operand or result, this is 288 /// the variable or the attribute that this type is resolved to. 289 ConstArgument resolver; 290 /// If the type is resolved based upon another operand or result, this is 291 /// a transformer to apply to the variable when resolving. 292 Optional<StringRef> variableTransformer; 293 }; 294 295 /// The context in which an element is generated. 296 enum class GenContext { 297 /// The element is generated at the top-level or with the same behaviour. 298 Normal, 299 /// The element is generated inside an optional group. 300 Optional 301 }; 302 303 OperationFormat(const Operator &op) 304 305 { 306 operandTypes.resize(op.getNumOperands(), TypeResolution()); 307 resultTypes.resize(op.getNumResults(), TypeResolution()); 308 309 hasImplicitTermTrait = llvm::any_of(op.getTraits(), [](const Trait &trait) { 310 return trait.getDef().isSubClassOf("SingleBlockImplicitTerminator"); 311 }); 312 313 hasSingleBlockTrait = 314 hasImplicitTermTrait || op.getTrait("::mlir::OpTrait::SingleBlock"); 315 } 316 317 /// Generate the operation parser from this format. 318 void genParser(Operator &op, OpClass &opClass); 319 /// Generate the parser code for a specific format element. 320 void genElementParser(FormatElement *element, MethodBody &body, 321 FmtContext &attrTypeCtx, 322 GenContext genCtx = GenContext::Normal); 323 /// Generate the C++ to resolve the types of operands and results during 324 /// parsing. 325 void genParserTypeResolution(Operator &op, MethodBody &body); 326 /// Generate the C++ to resolve the types of the operands during parsing. 327 void genParserOperandTypeResolution( 328 Operator &op, MethodBody &body, 329 function_ref<void(TypeResolution &, StringRef)> emitTypeResolver); 330 /// Generate the C++ to resolve regions during parsing. 331 void genParserRegionResolution(Operator &op, MethodBody &body); 332 /// Generate the C++ to resolve successors during parsing. 333 void genParserSuccessorResolution(Operator &op, MethodBody &body); 334 /// Generate the C++ to handling variadic segment size traits. 335 void genParserVariadicSegmentResolution(Operator &op, MethodBody &body); 336 337 /// Generate the operation printer from this format. 338 void genPrinter(Operator &op, OpClass &opClass); 339 340 /// Generate the printer code for a specific format element. 341 void genElementPrinter(FormatElement *element, MethodBody &body, Operator &op, 342 bool &shouldEmitSpace, bool &lastWasPunctuation); 343 344 /// The various elements in this format. 345 std::vector<FormatElement *> elements; 346 347 /// A flag indicating if all operand/result types were seen. If the format 348 /// contains these, it can not contain individual type resolvers. 349 bool allOperands = false, allOperandTypes = false, allResultTypes = false; 350 351 /// A flag indicating if this operation infers its result types 352 bool infersResultTypes = false; 353 354 /// A flag indicating if this operation has the SingleBlockImplicitTerminator 355 /// trait. 356 bool hasImplicitTermTrait; 357 358 /// A flag indicating if this operation has the SingleBlock trait. 359 bool hasSingleBlockTrait; 360 361 /// A map of buildable types to indices. 362 llvm::MapVector<StringRef, int, llvm::StringMap<int>> buildableTypes; 363 364 /// The index of the buildable type, if valid, for every operand and result. 365 std::vector<TypeResolution> operandTypes, resultTypes; 366 367 /// The set of attributes explicitly used within the format. 368 SmallVector<const NamedAttribute *, 8> usedAttributes; 369 llvm::StringSet<> inferredAttributes; 370 }; 371 } // namespace 372 373 //===----------------------------------------------------------------------===// 374 // Parser Gen 375 376 /// Returns true if we can format the given attribute as an EnumAttr in the 377 /// parser format. 378 static bool canFormatEnumAttr(const NamedAttribute *attr) { 379 Attribute baseAttr = attr->attr.getBaseAttr(); 380 const EnumAttr *enumAttr = dyn_cast<EnumAttr>(&baseAttr); 381 if (!enumAttr) 382 return false; 383 384 // The attribute must have a valid underlying type and a constant builder. 385 return !enumAttr->getUnderlyingType().empty() && 386 !enumAttr->getConstBuilderTemplate().empty(); 387 } 388 389 /// Returns if we should format the given attribute as an SymbolNameAttr. 390 static bool shouldFormatSymbolNameAttr(const NamedAttribute *attr) { 391 return attr->attr.getBaseAttr().getAttrDefName() == "SymbolNameAttr"; 392 } 393 394 /// The code snippet used to generate a parser call for an attribute. 395 /// 396 /// {0}: The name of the attribute. 397 /// {1}: The type for the attribute. 398 const char *const attrParserCode = R"( 399 if (parser.parseCustomAttributeWithFallback({0}Attr, {1}, "{0}", 400 result.attributes)) {{ 401 return ::mlir::failure(); 402 } 403 )"; 404 405 /// The code snippet used to generate a parser call for an attribute. 406 /// 407 /// {0}: The name of the attribute. 408 /// {1}: The type for the attribute. 409 const char *const genericAttrParserCode = R"( 410 if (parser.parseAttribute({0}Attr, {1}, "{0}", result.attributes)) 411 return ::mlir::failure(); 412 )"; 413 414 const char *const optionalAttrParserCode = R"( 415 { 416 ::mlir::OptionalParseResult parseResult = 417 parser.parseOptionalAttribute({0}Attr, {1}, "{0}", result.attributes); 418 if (parseResult.hasValue() && failed(*parseResult)) 419 return ::mlir::failure(); 420 } 421 )"; 422 423 /// The code snippet used to generate a parser call for a symbol name attribute. 424 /// 425 /// {0}: The name of the attribute. 426 const char *const symbolNameAttrParserCode = R"( 427 if (parser.parseSymbolName({0}Attr, "{0}", result.attributes)) 428 return ::mlir::failure(); 429 )"; 430 const char *const optionalSymbolNameAttrParserCode = R"( 431 // Parsing an optional symbol name doesn't fail, so no need to check the 432 // result. 433 (void)parser.parseOptionalSymbolName({0}Attr, "{0}", result.attributes); 434 )"; 435 436 /// The code snippet used to generate a parser call for an enum attribute. 437 /// 438 /// {0}: The name of the attribute. 439 /// {1}: The c++ namespace for the enum symbolize functions. 440 /// {2}: The function to symbolize a string of the enum. 441 /// {3}: The constant builder call to create an attribute of the enum type. 442 /// {4}: The set of allowed enum keywords. 443 /// {5}: The error message on failure when the enum isn't present. 444 const char *const enumAttrParserCode = R"( 445 { 446 ::llvm::StringRef attrStr; 447 ::mlir::NamedAttrList attrStorage; 448 auto loc = parser.getCurrentLocation(); 449 if (parser.parseOptionalKeyword(&attrStr, {4})) { 450 ::mlir::StringAttr attrVal; 451 ::mlir::OptionalParseResult parseResult = 452 parser.parseOptionalAttribute(attrVal, 453 parser.getBuilder().getNoneType(), 454 "{0}", attrStorage); 455 if (parseResult.hasValue()) {{ 456 if (failed(*parseResult)) 457 return ::mlir::failure(); 458 attrStr = attrVal.getValue(); 459 } else { 460 {5} 461 } 462 } 463 if (!attrStr.empty()) { 464 auto attrOptional = {1}::{2}(attrStr); 465 if (!attrOptional) 466 return parser.emitError(loc, "invalid ") 467 << "{0} attribute specification: \"" << attrStr << '"';; 468 469 {0}Attr = {3}; 470 result.addAttribute("{0}", {0}Attr); 471 } 472 } 473 )"; 474 475 /// The code snippet used to generate a parser call for an operand. 476 /// 477 /// {0}: The name of the operand. 478 const char *const variadicOperandParserCode = R"( 479 {0}OperandsLoc = parser.getCurrentLocation(); 480 if (parser.parseOperandList({0}Operands)) 481 return ::mlir::failure(); 482 )"; 483 const char *const optionalOperandParserCode = R"( 484 { 485 {0}OperandsLoc = parser.getCurrentLocation(); 486 ::mlir::OpAsmParser::UnresolvedOperand operand; 487 ::mlir::OptionalParseResult parseResult = 488 parser.parseOptionalOperand(operand); 489 if (parseResult.hasValue()) { 490 if (failed(*parseResult)) 491 return ::mlir::failure(); 492 {0}Operands.push_back(operand); 493 } 494 } 495 )"; 496 const char *const operandParserCode = R"( 497 {0}OperandsLoc = parser.getCurrentLocation(); 498 if (parser.parseOperand({0}RawOperands[0])) 499 return ::mlir::failure(); 500 )"; 501 /// The code snippet used to generate a parser call for a VariadicOfVariadic 502 /// operand. 503 /// 504 /// {0}: The name of the operand. 505 /// {1}: The name of segment size attribute. 506 const char *const variadicOfVariadicOperandParserCode = R"( 507 { 508 {0}OperandsLoc = parser.getCurrentLocation(); 509 int32_t curSize = 0; 510 do { 511 if (parser.parseOptionalLParen()) 512 break; 513 if (parser.parseOperandList({0}Operands) || parser.parseRParen()) 514 return ::mlir::failure(); 515 {0}OperandGroupSizes.push_back({0}Operands.size() - curSize); 516 curSize = {0}Operands.size(); 517 } while (succeeded(parser.parseOptionalComma())); 518 } 519 )"; 520 521 /// The code snippet used to generate a parser call for a type list. 522 /// 523 /// {0}: The name for the type list. 524 const char *const variadicOfVariadicTypeParserCode = R"( 525 do { 526 if (parser.parseOptionalLParen()) 527 break; 528 if (parser.parseOptionalRParen() && 529 (parser.parseTypeList({0}Types) || parser.parseRParen())) 530 return ::mlir::failure(); 531 } while (succeeded(parser.parseOptionalComma())); 532 )"; 533 const char *const variadicTypeParserCode = R"( 534 if (parser.parseTypeList({0}Types)) 535 return ::mlir::failure(); 536 )"; 537 const char *const optionalTypeParserCode = R"( 538 { 539 ::mlir::Type optionalType; 540 ::mlir::OptionalParseResult parseResult = 541 parser.parseOptionalType(optionalType); 542 if (parseResult.hasValue()) { 543 if (failed(*parseResult)) 544 return ::mlir::failure(); 545 {0}Types.push_back(optionalType); 546 } 547 } 548 )"; 549 const char *const typeParserCode = R"( 550 { 551 {0} type; 552 if (parser.parseCustomTypeWithFallback(type)) 553 return ::mlir::failure(); 554 {1}RawTypes[0] = type; 555 } 556 )"; 557 const char *const qualifiedTypeParserCode = R"( 558 if (parser.parseType({1}RawTypes[0])) 559 return ::mlir::failure(); 560 )"; 561 562 /// The code snippet used to generate a parser call for a functional type. 563 /// 564 /// {0}: The name for the input type list. 565 /// {1}: The name for the result type list. 566 const char *const functionalTypeParserCode = R"( 567 ::mlir::FunctionType {0}__{1}_functionType; 568 if (parser.parseType({0}__{1}_functionType)) 569 return ::mlir::failure(); 570 {0}Types = {0}__{1}_functionType.getInputs(); 571 {1}Types = {0}__{1}_functionType.getResults(); 572 )"; 573 574 /// The code snippet used to generate a parser call to infer return types. 575 /// 576 /// {0}: The operation class name 577 const char *const inferReturnTypesParserCode = R"( 578 ::llvm::SmallVector<::mlir::Type> inferredReturnTypes; 579 if (::mlir::failed({0}::inferReturnTypes(parser.getContext(), 580 result.location, result.operands, 581 result.attributes.getDictionary(parser.getContext()), 582 result.regions, inferredReturnTypes))) 583 return ::mlir::failure(); 584 result.addTypes(inferredReturnTypes); 585 )"; 586 587 /// The code snippet used to generate a parser call for a region list. 588 /// 589 /// {0}: The name for the region list. 590 const char *regionListParserCode = R"( 591 { 592 std::unique_ptr<::mlir::Region> region; 593 auto firstRegionResult = parser.parseOptionalRegion(region); 594 if (firstRegionResult.hasValue()) { 595 if (failed(*firstRegionResult)) 596 return ::mlir::failure(); 597 {0}Regions.emplace_back(std::move(region)); 598 599 // Parse any trailing regions. 600 while (succeeded(parser.parseOptionalComma())) { 601 region = std::make_unique<::mlir::Region>(); 602 if (parser.parseRegion(*region)) 603 return ::mlir::failure(); 604 {0}Regions.emplace_back(std::move(region)); 605 } 606 } 607 } 608 )"; 609 610 /// The code snippet used to ensure a list of regions have terminators. 611 /// 612 /// {0}: The name of the region list. 613 const char *regionListEnsureTerminatorParserCode = R"( 614 for (auto ®ion : {0}Regions) 615 ensureTerminator(*region, parser.getBuilder(), result.location); 616 )"; 617 618 /// The code snippet used to ensure a list of regions have a block. 619 /// 620 /// {0}: The name of the region list. 621 const char *regionListEnsureSingleBlockParserCode = R"( 622 for (auto ®ion : {0}Regions) 623 if (region->empty()) region->emplaceBlock(); 624 )"; 625 626 /// The code snippet used to generate a parser call for an optional region. 627 /// 628 /// {0}: The name of the region. 629 const char *optionalRegionParserCode = R"( 630 { 631 auto parseResult = parser.parseOptionalRegion(*{0}Region); 632 if (parseResult.hasValue() && failed(*parseResult)) 633 return ::mlir::failure(); 634 } 635 )"; 636 637 /// The code snippet used to generate a parser call for a region. 638 /// 639 /// {0}: The name of the region. 640 const char *regionParserCode = R"( 641 if (parser.parseRegion(*{0}Region)) 642 return ::mlir::failure(); 643 )"; 644 645 /// The code snippet used to ensure a region has a terminator. 646 /// 647 /// {0}: The name of the region. 648 const char *regionEnsureTerminatorParserCode = R"( 649 ensureTerminator(*{0}Region, parser.getBuilder(), result.location); 650 )"; 651 652 /// The code snippet used to ensure a region has a block. 653 /// 654 /// {0}: The name of the region. 655 const char *regionEnsureSingleBlockParserCode = R"( 656 if ({0}Region->empty()) {0}Region->emplaceBlock(); 657 )"; 658 659 /// The code snippet used to generate a parser call for a successor list. 660 /// 661 /// {0}: The name for the successor list. 662 const char *successorListParserCode = R"( 663 { 664 ::mlir::Block *succ; 665 auto firstSucc = parser.parseOptionalSuccessor(succ); 666 if (firstSucc.hasValue()) { 667 if (failed(*firstSucc)) 668 return ::mlir::failure(); 669 {0}Successors.emplace_back(succ); 670 671 // Parse any trailing successors. 672 while (succeeded(parser.parseOptionalComma())) { 673 if (parser.parseSuccessor(succ)) 674 return ::mlir::failure(); 675 {0}Successors.emplace_back(succ); 676 } 677 } 678 } 679 )"; 680 681 /// The code snippet used to generate a parser call for a successor. 682 /// 683 /// {0}: The name of the successor. 684 const char *successorParserCode = R"( 685 if (parser.parseSuccessor({0}Successor)) 686 return ::mlir::failure(); 687 )"; 688 689 /// The code snippet used to generate a parser for OIList 690 /// 691 /// {0}: literal keyword corresponding to a case for oilist 692 const char *oilistParserCode = R"( 693 if ({0}Clause) { 694 return parser.emitError(parser.getNameLoc()) 695 << "`{0}` clause can appear at most once in the expansion of the " 696 "oilist directive"; 697 } 698 {0}Clause = true; 699 )"; 700 701 namespace { 702 /// The type of length for a given parse argument. 703 enum class ArgumentLengthKind { 704 /// The argument is a variadic of a variadic, and may contain 0->N range 705 /// elements. 706 VariadicOfVariadic, 707 /// The argument is variadic, and may contain 0->N elements. 708 Variadic, 709 /// The argument is optional, and may contain 0 or 1 elements. 710 Optional, 711 /// The argument is a single element, i.e. always represents 1 element. 712 Single 713 }; 714 } // namespace 715 716 /// Get the length kind for the given constraint. 717 static ArgumentLengthKind 718 getArgumentLengthKind(const NamedTypeConstraint *var) { 719 if (var->isOptional()) 720 return ArgumentLengthKind::Optional; 721 if (var->isVariadicOfVariadic()) 722 return ArgumentLengthKind::VariadicOfVariadic; 723 if (var->isVariadic()) 724 return ArgumentLengthKind::Variadic; 725 return ArgumentLengthKind::Single; 726 } 727 728 /// Get the name used for the type list for the given type directive operand. 729 /// 'lengthKind' to the corresponding kind for the given argument. 730 static StringRef getTypeListName(FormatElement *arg, 731 ArgumentLengthKind &lengthKind) { 732 if (auto *operand = dyn_cast<OperandVariable>(arg)) { 733 lengthKind = getArgumentLengthKind(operand->getVar()); 734 return operand->getVar()->name; 735 } 736 if (auto *result = dyn_cast<ResultVariable>(arg)) { 737 lengthKind = getArgumentLengthKind(result->getVar()); 738 return result->getVar()->name; 739 } 740 lengthKind = ArgumentLengthKind::Variadic; 741 if (isa<OperandsDirective>(arg)) 742 return "allOperand"; 743 if (isa<ResultsDirective>(arg)) 744 return "allResult"; 745 llvm_unreachable("unknown 'type' directive argument"); 746 } 747 748 /// Generate the parser for a literal value. 749 static void genLiteralParser(StringRef value, MethodBody &body) { 750 // Handle the case of a keyword/identifier. 751 if (value.front() == '_' || isalpha(value.front())) { 752 body << "Keyword(\"" << value << "\")"; 753 return; 754 } 755 body << (StringRef)StringSwitch<StringRef>(value) 756 .Case("->", "Arrow()") 757 .Case(":", "Colon()") 758 .Case(",", "Comma()") 759 .Case("=", "Equal()") 760 .Case("<", "Less()") 761 .Case(">", "Greater()") 762 .Case("{", "LBrace()") 763 .Case("}", "RBrace()") 764 .Case("(", "LParen()") 765 .Case(")", "RParen()") 766 .Case("[", "LSquare()") 767 .Case("]", "RSquare()") 768 .Case("?", "Question()") 769 .Case("+", "Plus()") 770 .Case("*", "Star()"); 771 } 772 773 /// Generate the storage code required for parsing the given element. 774 static void genElementParserStorage(FormatElement *element, const Operator &op, 775 MethodBody &body) { 776 if (auto *optional = dyn_cast<OptionalElement>(element)) { 777 ArrayRef<FormatElement *> elements = optional->getThenElements(); 778 779 // If the anchor is a unit attribute, it won't be parsed directly so elide 780 // it. 781 auto *anchor = dyn_cast<AttributeVariable>(optional->getAnchor()); 782 FormatElement *elidedAnchorElement = nullptr; 783 if (anchor && anchor != elements.front() && anchor->isUnitAttr()) 784 elidedAnchorElement = anchor; 785 for (FormatElement *childElement : elements) 786 if (childElement != elidedAnchorElement) 787 genElementParserStorage(childElement, op, body); 788 for (FormatElement *childElement : optional->getElseElements()) 789 genElementParserStorage(childElement, op, body); 790 791 } else if (auto *oilist = dyn_cast<OIListElement>(element)) { 792 for (ArrayRef<FormatElement *> pelement : oilist->getParsingElements()) { 793 if (!oilist->getUnitAttrParsingElement(pelement)) 794 for (FormatElement *element : pelement) 795 genElementParserStorage(element, op, body); 796 } 797 798 } else if (auto *custom = dyn_cast<CustomDirective>(element)) { 799 for (FormatElement *paramElement : custom->getArguments()) 800 genElementParserStorage(paramElement, op, body); 801 802 } else if (isa<OperandsDirective>(element)) { 803 body << " ::mlir::SmallVector<::mlir::OpAsmParser::UnresolvedOperand, 4> " 804 "allOperands;\n"; 805 806 } else if (isa<RegionsDirective>(element)) { 807 body << " ::llvm::SmallVector<std::unique_ptr<::mlir::Region>, 2> " 808 "fullRegions;\n"; 809 810 } else if (isa<SuccessorsDirective>(element)) { 811 body << " ::llvm::SmallVector<::mlir::Block *, 2> fullSuccessors;\n"; 812 813 } else if (auto *attr = dyn_cast<AttributeVariable>(element)) { 814 const NamedAttribute *var = attr->getVar(); 815 body << llvm::formatv(" {0} {1}Attr;\n", var->attr.getStorageType(), 816 var->name); 817 818 } else if (auto *operand = dyn_cast<OperandVariable>(element)) { 819 StringRef name = operand->getVar()->name; 820 if (operand->getVar()->isVariableLength()) { 821 body 822 << " ::mlir::SmallVector<::mlir::OpAsmParser::UnresolvedOperand, 4> " 823 << name << "Operands;\n"; 824 if (operand->getVar()->isVariadicOfVariadic()) { 825 body << " llvm::SmallVector<int32_t> " << name 826 << "OperandGroupSizes;\n"; 827 } 828 } else { 829 body << " ::mlir::OpAsmParser::UnresolvedOperand " << name 830 << "RawOperands[1];\n" 831 << " ::llvm::ArrayRef<::mlir::OpAsmParser::UnresolvedOperand> " 832 << name << "Operands(" << name << "RawOperands);"; 833 } 834 body << llvm::formatv(" ::llvm::SMLoc {0}OperandsLoc;\n" 835 " (void){0}OperandsLoc;\n", 836 name); 837 838 } else if (auto *region = dyn_cast<RegionVariable>(element)) { 839 StringRef name = region->getVar()->name; 840 if (region->getVar()->isVariadic()) { 841 body << llvm::formatv( 842 " ::llvm::SmallVector<std::unique_ptr<::mlir::Region>, 2> " 843 "{0}Regions;\n", 844 name); 845 } else { 846 body << llvm::formatv(" std::unique_ptr<::mlir::Region> {0}Region = " 847 "std::make_unique<::mlir::Region>();\n", 848 name); 849 } 850 851 } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) { 852 StringRef name = successor->getVar()->name; 853 if (successor->getVar()->isVariadic()) { 854 body << llvm::formatv(" ::llvm::SmallVector<::mlir::Block *, 2> " 855 "{0}Successors;\n", 856 name); 857 } else { 858 body << llvm::formatv(" ::mlir::Block *{0}Successor = nullptr;\n", name); 859 } 860 861 } else if (auto *dir = dyn_cast<TypeDirective>(element)) { 862 ArgumentLengthKind lengthKind; 863 StringRef name = getTypeListName(dir->getArg(), lengthKind); 864 if (lengthKind != ArgumentLengthKind::Single) 865 body << " ::mlir::SmallVector<::mlir::Type, 1> " << name << "Types;\n"; 866 else 867 body << llvm::formatv(" ::mlir::Type {0}RawTypes[1];\n", name) 868 << llvm::formatv( 869 " ::llvm::ArrayRef<::mlir::Type> {0}Types({0}RawTypes);\n", 870 name); 871 } else if (auto *dir = dyn_cast<FunctionalTypeDirective>(element)) { 872 ArgumentLengthKind ignored; 873 body << " ::llvm::ArrayRef<::mlir::Type> " 874 << getTypeListName(dir->getInputs(), ignored) << "Types;\n"; 875 body << " ::llvm::ArrayRef<::mlir::Type> " 876 << getTypeListName(dir->getResults(), ignored) << "Types;\n"; 877 } 878 } 879 880 /// Generate the parser for a parameter to a custom directive. 881 static void genCustomParameterParser(FormatElement *param, MethodBody &body) { 882 if (auto *attr = dyn_cast<AttributeVariable>(param)) { 883 body << attr->getVar()->name << "Attr"; 884 } else if (isa<AttrDictDirective>(param)) { 885 body << "result.attributes"; 886 } else if (auto *operand = dyn_cast<OperandVariable>(param)) { 887 StringRef name = operand->getVar()->name; 888 ArgumentLengthKind lengthKind = getArgumentLengthKind(operand->getVar()); 889 if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) 890 body << llvm::formatv("{0}OperandGroups", name); 891 else if (lengthKind == ArgumentLengthKind::Variadic) 892 body << llvm::formatv("{0}Operands", name); 893 else if (lengthKind == ArgumentLengthKind::Optional) 894 body << llvm::formatv("{0}Operand", name); 895 else 896 body << formatv("{0}RawOperands[0]", name); 897 898 } else if (auto *region = dyn_cast<RegionVariable>(param)) { 899 StringRef name = region->getVar()->name; 900 if (region->getVar()->isVariadic()) 901 body << llvm::formatv("{0}Regions", name); 902 else 903 body << llvm::formatv("*{0}Region", name); 904 905 } else if (auto *successor = dyn_cast<SuccessorVariable>(param)) { 906 StringRef name = successor->getVar()->name; 907 if (successor->getVar()->isVariadic()) 908 body << llvm::formatv("{0}Successors", name); 909 else 910 body << llvm::formatv("{0}Successor", name); 911 912 } else if (auto *dir = dyn_cast<RefDirective>(param)) { 913 genCustomParameterParser(dir->getArg(), body); 914 915 } else if (auto *dir = dyn_cast<TypeDirective>(param)) { 916 ArgumentLengthKind lengthKind; 917 StringRef listName = getTypeListName(dir->getArg(), lengthKind); 918 if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) 919 body << llvm::formatv("{0}TypeGroups", listName); 920 else if (lengthKind == ArgumentLengthKind::Variadic) 921 body << llvm::formatv("{0}Types", listName); 922 else if (lengthKind == ArgumentLengthKind::Optional) 923 body << llvm::formatv("{0}Type", listName); 924 else 925 body << formatv("{0}RawTypes[0]", listName); 926 } else { 927 llvm_unreachable("unknown custom directive parameter"); 928 } 929 } 930 931 /// Generate the parser for a custom directive. 932 static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body) { 933 body << " {\n"; 934 935 // Preprocess the directive variables. 936 // * Add a local variable for optional operands and types. This provides a 937 // better API to the user defined parser methods. 938 // * Set the location of operand variables. 939 for (FormatElement *param : dir->getArguments()) { 940 if (auto *operand = dyn_cast<OperandVariable>(param)) { 941 auto *var = operand->getVar(); 942 body << " " << var->name 943 << "OperandsLoc = parser.getCurrentLocation();\n"; 944 if (var->isOptional()) { 945 body << llvm::formatv( 946 " ::llvm::Optional<::mlir::OpAsmParser::UnresolvedOperand> " 947 "{0}Operand;\n", 948 var->name); 949 } else if (var->isVariadicOfVariadic()) { 950 body << llvm::formatv(" " 951 "::llvm::SmallVector<::llvm::SmallVector<::mlir::" 952 "OpAsmParser::UnresolvedOperand>> " 953 "{0}OperandGroups;\n", 954 var->name); 955 } 956 } else if (auto *dir = dyn_cast<TypeDirective>(param)) { 957 ArgumentLengthKind lengthKind; 958 StringRef listName = getTypeListName(dir->getArg(), lengthKind); 959 if (lengthKind == ArgumentLengthKind::Optional) { 960 body << llvm::formatv(" ::mlir::Type {0}Type;\n", listName); 961 } else if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) { 962 body << llvm::formatv( 963 " ::llvm::SmallVector<llvm::SmallVector<::mlir::Type>> " 964 "{0}TypeGroups;\n", 965 listName); 966 } 967 } else if (auto *dir = dyn_cast<RefDirective>(param)) { 968 FormatElement *input = dir->getArg(); 969 if (auto *operand = dyn_cast<OperandVariable>(input)) { 970 if (!operand->getVar()->isOptional()) 971 continue; 972 body << llvm::formatv( 973 " {0} {1}Operand = {1}Operands.empty() ? {0}() : " 974 "{1}Operands[0];\n", 975 "::llvm::Optional<::mlir::OpAsmParser::UnresolvedOperand>", 976 operand->getVar()->name); 977 978 } else if (auto *type = dyn_cast<TypeDirective>(input)) { 979 ArgumentLengthKind lengthKind; 980 StringRef listName = getTypeListName(type->getArg(), lengthKind); 981 if (lengthKind == ArgumentLengthKind::Optional) { 982 body << llvm::formatv(" ::mlir::Type {0}Type = {0}Types.empty() ? " 983 "::mlir::Type() : {0}Types[0];\n", 984 listName); 985 } 986 } 987 } 988 } 989 990 body << " if (parse" << dir->getName() << "(parser"; 991 for (FormatElement *param : dir->getArguments()) { 992 body << ", "; 993 genCustomParameterParser(param, body); 994 } 995 996 body << "))\n" 997 << " return ::mlir::failure();\n"; 998 999 // After parsing, add handling for any of the optional constructs. 1000 for (FormatElement *param : dir->getArguments()) { 1001 if (auto *attr = dyn_cast<AttributeVariable>(param)) { 1002 const NamedAttribute *var = attr->getVar(); 1003 if (var->attr.isOptional()) 1004 body << llvm::formatv(" if ({0}Attr)\n ", var->name); 1005 1006 body << llvm::formatv(" result.addAttribute(\"{0}\", {0}Attr);\n", 1007 var->name); 1008 } else if (auto *operand = dyn_cast<OperandVariable>(param)) { 1009 const NamedTypeConstraint *var = operand->getVar(); 1010 if (var->isOptional()) { 1011 body << llvm::formatv(" if ({0}Operand.hasValue())\n" 1012 " {0}Operands.push_back(*{0}Operand);\n", 1013 var->name); 1014 } else if (var->isVariadicOfVariadic()) { 1015 body << llvm::formatv( 1016 " for (const auto &subRange : {0}OperandGroups) {{\n" 1017 " {0}Operands.append(subRange.begin(), subRange.end());\n" 1018 " {0}OperandGroupSizes.push_back(subRange.size());\n" 1019 " }\n", 1020 var->name, var->constraint.getVariadicOfVariadicSegmentSizeAttr()); 1021 } 1022 } else if (auto *dir = dyn_cast<TypeDirective>(param)) { 1023 ArgumentLengthKind lengthKind; 1024 StringRef listName = getTypeListName(dir->getArg(), lengthKind); 1025 if (lengthKind == ArgumentLengthKind::Optional) { 1026 body << llvm::formatv(" if ({0}Type)\n" 1027 " {0}Types.push_back({0}Type);\n", 1028 listName); 1029 } else if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) { 1030 body << llvm::formatv( 1031 " for (const auto &subRange : {0}TypeGroups)\n" 1032 " {0}Types.append(subRange.begin(), subRange.end());\n", 1033 listName); 1034 } 1035 } 1036 } 1037 1038 body << " }\n"; 1039 } 1040 1041 /// Generate the parser for a enum attribute. 1042 static void genEnumAttrParser(const NamedAttribute *var, MethodBody &body, 1043 FmtContext &attrTypeCtx) { 1044 Attribute baseAttr = var->attr.getBaseAttr(); 1045 const EnumAttr &enumAttr = cast<EnumAttr>(baseAttr); 1046 std::vector<EnumAttrCase> cases = enumAttr.getAllCases(); 1047 1048 // Generate the code for building an attribute for this enum. 1049 std::string attrBuilderStr; 1050 { 1051 llvm::raw_string_ostream os(attrBuilderStr); 1052 os << tgfmt(enumAttr.getConstBuilderTemplate(), &attrTypeCtx, 1053 "attrOptional.getValue()"); 1054 } 1055 1056 // Build a string containing the cases that can be formatted as a keyword. 1057 std::string validCaseKeywordsStr = "{"; 1058 llvm::raw_string_ostream validCaseKeywordsOS(validCaseKeywordsStr); 1059 for (const EnumAttrCase &attrCase : cases) 1060 if (canFormatStringAsKeyword(attrCase.getStr())) 1061 validCaseKeywordsOS << '"' << attrCase.getStr() << "\","; 1062 validCaseKeywordsOS.str().back() = '}'; 1063 1064 // If the attribute is not optional, build an error message for the missing 1065 // attribute. 1066 std::string errorMessage; 1067 if (!var->attr.isOptional()) { 1068 llvm::raw_string_ostream errorMessageOS(errorMessage); 1069 errorMessageOS 1070 << "return parser.emitError(loc, \"expected string or " 1071 "keyword containing one of the following enum values for attribute '" 1072 << var->name << "' ["; 1073 llvm::interleaveComma(cases, errorMessageOS, [&](const auto &attrCase) { 1074 errorMessageOS << attrCase.getStr(); 1075 }); 1076 errorMessageOS << "]\");"; 1077 } 1078 1079 body << formatv(enumAttrParserCode, var->name, enumAttr.getCppNamespace(), 1080 enumAttr.getStringToSymbolFnName(), attrBuilderStr, 1081 validCaseKeywordsStr, errorMessage); 1082 } 1083 1084 void OperationFormat::genParser(Operator &op, OpClass &opClass) { 1085 SmallVector<MethodParameter> paramList; 1086 paramList.emplace_back("::mlir::OpAsmParser &", "parser"); 1087 paramList.emplace_back("::mlir::OperationState &", "result"); 1088 1089 auto *method = opClass.addStaticMethod("::mlir::ParseResult", "parse", 1090 std::move(paramList)); 1091 auto &body = method->body(); 1092 1093 // Generate variables to store the operands and type within the format. This 1094 // allows for referencing these variables in the presence of optional 1095 // groupings. 1096 for (FormatElement *element : elements) 1097 genElementParserStorage(element, op, body); 1098 1099 // A format context used when parsing attributes with buildable types. 1100 FmtContext attrTypeCtx; 1101 attrTypeCtx.withBuilder("parser.getBuilder()"); 1102 1103 // Generate parsers for each of the elements. 1104 for (FormatElement *element : elements) 1105 genElementParser(element, body, attrTypeCtx); 1106 1107 // Generate the code to resolve the operand/result types and successors now 1108 // that they have been parsed. 1109 genParserRegionResolution(op, body); 1110 genParserSuccessorResolution(op, body); 1111 genParserVariadicSegmentResolution(op, body); 1112 genParserTypeResolution(op, body); 1113 1114 body << " return ::mlir::success();\n"; 1115 } 1116 1117 void OperationFormat::genElementParser(FormatElement *element, MethodBody &body, 1118 FmtContext &attrTypeCtx, 1119 GenContext genCtx) { 1120 /// Optional Group. 1121 if (auto *optional = dyn_cast<OptionalElement>(element)) { 1122 ArrayRef<FormatElement *> elements = 1123 optional->getThenElements().drop_front(optional->getParseStart()); 1124 1125 // Generate a special optional parser for the first element to gate the 1126 // parsing of the rest of the elements. 1127 FormatElement *firstElement = elements.front(); 1128 if (auto *attrVar = dyn_cast<AttributeVariable>(firstElement)) { 1129 genElementParser(attrVar, body, attrTypeCtx); 1130 body << " if (" << attrVar->getVar()->name << "Attr) {\n"; 1131 } else if (auto *literal = dyn_cast<LiteralElement>(firstElement)) { 1132 body << " if (succeeded(parser.parseOptional"; 1133 genLiteralParser(literal->getSpelling(), body); 1134 body << ")) {\n"; 1135 } else if (auto *opVar = dyn_cast<OperandVariable>(firstElement)) { 1136 genElementParser(opVar, body, attrTypeCtx); 1137 body << " if (!" << opVar->getVar()->name << "Operands.empty()) {\n"; 1138 } else if (auto *regionVar = dyn_cast<RegionVariable>(firstElement)) { 1139 const NamedRegion *region = regionVar->getVar(); 1140 if (region->isVariadic()) { 1141 genElementParser(regionVar, body, attrTypeCtx); 1142 body << " if (!" << region->name << "Regions.empty()) {\n"; 1143 } else { 1144 body << llvm::formatv(optionalRegionParserCode, region->name); 1145 body << " if (!" << region->name << "Region->empty()) {\n "; 1146 if (hasImplicitTermTrait) 1147 body << llvm::formatv(regionEnsureTerminatorParserCode, region->name); 1148 else if (hasSingleBlockTrait) 1149 body << llvm::formatv(regionEnsureSingleBlockParserCode, 1150 region->name); 1151 } 1152 } 1153 1154 // If the anchor is a unit attribute, we don't need to print it. When 1155 // parsing, we will add this attribute if this group is present. 1156 FormatElement *elidedAnchorElement = nullptr; 1157 auto *anchorAttr = dyn_cast<AttributeVariable>(optional->getAnchor()); 1158 if (anchorAttr && anchorAttr != firstElement && anchorAttr->isUnitAttr()) { 1159 elidedAnchorElement = anchorAttr; 1160 1161 // Add the anchor unit attribute to the operation state. 1162 body << " result.addAttribute(\"" << anchorAttr->getVar()->name 1163 << "\", parser.getBuilder().getUnitAttr());\n"; 1164 } 1165 1166 // Generate the rest of the elements inside an optional group. Elements in 1167 // an optional group after the guard are parsed as required. 1168 for (FormatElement *childElement : llvm::drop_begin(elements, 1)) 1169 if (childElement != elidedAnchorElement) 1170 genElementParser(childElement, body, attrTypeCtx, GenContext::Optional); 1171 body << " }"; 1172 1173 // Generate the else elements. 1174 auto elseElements = optional->getElseElements(); 1175 if (!elseElements.empty()) { 1176 body << " else {\n"; 1177 for (FormatElement *childElement : elseElements) 1178 genElementParser(childElement, body, attrTypeCtx); 1179 body << " }"; 1180 } 1181 body << "\n"; 1182 1183 /// OIList Directive 1184 } else if (OIListElement *oilist = dyn_cast<OIListElement>(element)) { 1185 for (LiteralElement *le : oilist->getLiteralElements()) 1186 body << " bool " << le->getSpelling() << "Clause = false;\n"; 1187 1188 // Generate the parsing loop 1189 body << " while(true) {\n"; 1190 for (auto clause : oilist->getClauses()) { 1191 LiteralElement *lelement = std::get<0>(clause); 1192 ArrayRef<FormatElement *> pelement = std::get<1>(clause); 1193 body << "if (succeeded(parser.parseOptional"; 1194 genLiteralParser(lelement->getSpelling(), body); 1195 body << ")) {\n"; 1196 StringRef lelementName = lelement->getSpelling(); 1197 body << formatv(oilistParserCode, lelementName); 1198 if (AttributeVariable *unitAttrElem = 1199 oilist->getUnitAttrParsingElement(pelement)) { 1200 body << " result.addAttribute(\"" << unitAttrElem->getVar()->name 1201 << "\", UnitAttr::get(parser.getContext()));\n"; 1202 } else { 1203 for (FormatElement *el : pelement) 1204 genElementParser(el, body, attrTypeCtx); 1205 } 1206 body << " } else "; 1207 } 1208 body << " {\n"; 1209 body << " break;\n"; 1210 body << " }\n"; 1211 body << "}\n"; 1212 1213 /// Literals. 1214 } else if (LiteralElement *literal = dyn_cast<LiteralElement>(element)) { 1215 body << " if (parser.parse"; 1216 genLiteralParser(literal->getSpelling(), body); 1217 body << ")\n return ::mlir::failure();\n"; 1218 1219 /// Whitespaces. 1220 } else if (isa<WhitespaceElement>(element)) { 1221 // Nothing to parse. 1222 1223 /// Arguments. 1224 } else if (auto *attr = dyn_cast<AttributeVariable>(element)) { 1225 const NamedAttribute *var = attr->getVar(); 1226 1227 // Check to see if we can parse this as an enum attribute. 1228 if (canFormatEnumAttr(var)) 1229 return genEnumAttrParser(var, body, attrTypeCtx); 1230 1231 // Check to see if we should parse this as a symbol name attribute. 1232 if (shouldFormatSymbolNameAttr(var)) { 1233 body << formatv(var->attr.isOptional() ? optionalSymbolNameAttrParserCode 1234 : symbolNameAttrParserCode, 1235 var->name); 1236 return; 1237 } 1238 1239 // If this attribute has a buildable type, use that when parsing the 1240 // attribute. 1241 std::string attrTypeStr; 1242 if (Optional<StringRef> typeBuilder = attr->getTypeBuilder()) { 1243 llvm::raw_string_ostream os(attrTypeStr); 1244 os << tgfmt(*typeBuilder, &attrTypeCtx); 1245 } else { 1246 attrTypeStr = "::mlir::Type{}"; 1247 } 1248 if (genCtx == GenContext::Normal && var->attr.isOptional()) { 1249 body << formatv(optionalAttrParserCode, var->name, attrTypeStr); 1250 } else { 1251 if (attr->shouldBeQualified() || 1252 var->attr.getStorageType() == "::mlir::Attribute") 1253 body << formatv(genericAttrParserCode, var->name, attrTypeStr); 1254 else 1255 body << formatv(attrParserCode, var->name, attrTypeStr); 1256 } 1257 1258 } else if (auto *operand = dyn_cast<OperandVariable>(element)) { 1259 ArgumentLengthKind lengthKind = getArgumentLengthKind(operand->getVar()); 1260 StringRef name = operand->getVar()->name; 1261 if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) 1262 body << llvm::formatv( 1263 variadicOfVariadicOperandParserCode, name, 1264 operand->getVar()->constraint.getVariadicOfVariadicSegmentSizeAttr()); 1265 else if (lengthKind == ArgumentLengthKind::Variadic) 1266 body << llvm::formatv(variadicOperandParserCode, name); 1267 else if (lengthKind == ArgumentLengthKind::Optional) 1268 body << llvm::formatv(optionalOperandParserCode, name); 1269 else 1270 body << formatv(operandParserCode, name); 1271 1272 } else if (auto *region = dyn_cast<RegionVariable>(element)) { 1273 bool isVariadic = region->getVar()->isVariadic(); 1274 body << llvm::formatv(isVariadic ? regionListParserCode : regionParserCode, 1275 region->getVar()->name); 1276 if (hasImplicitTermTrait) 1277 body << llvm::formatv(isVariadic ? regionListEnsureTerminatorParserCode 1278 : regionEnsureTerminatorParserCode, 1279 region->getVar()->name); 1280 else if (hasSingleBlockTrait) 1281 body << llvm::formatv(isVariadic ? regionListEnsureSingleBlockParserCode 1282 : regionEnsureSingleBlockParserCode, 1283 region->getVar()->name); 1284 1285 } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) { 1286 bool isVariadic = successor->getVar()->isVariadic(); 1287 body << formatv(isVariadic ? successorListParserCode : successorParserCode, 1288 successor->getVar()->name); 1289 1290 /// Directives. 1291 } else if (auto *attrDict = dyn_cast<AttrDictDirective>(element)) { 1292 body << " if (parser.parseOptionalAttrDict" 1293 << (attrDict->isWithKeyword() ? "WithKeyword" : "") 1294 << "(result.attributes))\n" 1295 << " return ::mlir::failure();\n"; 1296 } else if (auto *customDir = dyn_cast<CustomDirective>(element)) { 1297 genCustomDirectiveParser(customDir, body); 1298 1299 } else if (isa<OperandsDirective>(element)) { 1300 body << " ::llvm::SMLoc allOperandLoc = parser.getCurrentLocation();\n" 1301 << " if (parser.parseOperandList(allOperands))\n" 1302 << " return ::mlir::failure();\n"; 1303 1304 } else if (isa<RegionsDirective>(element)) { 1305 body << llvm::formatv(regionListParserCode, "full"); 1306 if (hasImplicitTermTrait) 1307 body << llvm::formatv(regionListEnsureTerminatorParserCode, "full"); 1308 else if (hasSingleBlockTrait) 1309 body << llvm::formatv(regionListEnsureSingleBlockParserCode, "full"); 1310 1311 } else if (isa<SuccessorsDirective>(element)) { 1312 body << llvm::formatv(successorListParserCode, "full"); 1313 1314 } else if (auto *dir = dyn_cast<TypeDirective>(element)) { 1315 ArgumentLengthKind lengthKind; 1316 StringRef listName = getTypeListName(dir->getArg(), lengthKind); 1317 if (lengthKind == ArgumentLengthKind::VariadicOfVariadic) { 1318 body << llvm::formatv(variadicOfVariadicTypeParserCode, listName); 1319 } else if (lengthKind == ArgumentLengthKind::Variadic) { 1320 body << llvm::formatv(variadicTypeParserCode, listName); 1321 } else if (lengthKind == ArgumentLengthKind::Optional) { 1322 body << llvm::formatv(optionalTypeParserCode, listName); 1323 } else { 1324 const char *parserCode = 1325 dir->shouldBeQualified() ? qualifiedTypeParserCode : typeParserCode; 1326 TypeSwitch<FormatElement *>(dir->getArg()) 1327 .Case<OperandVariable, ResultVariable>([&](auto operand) { 1328 body << formatv(parserCode, 1329 operand->getVar()->constraint.getCPPClassName(), 1330 listName); 1331 }) 1332 .Default([&](auto operand) { 1333 body << formatv(parserCode, "::mlir::Type", listName); 1334 }); 1335 } 1336 } else if (auto *dir = dyn_cast<FunctionalTypeDirective>(element)) { 1337 ArgumentLengthKind ignored; 1338 body << formatv(functionalTypeParserCode, 1339 getTypeListName(dir->getInputs(), ignored), 1340 getTypeListName(dir->getResults(), ignored)); 1341 } else { 1342 llvm_unreachable("unknown format element"); 1343 } 1344 } 1345 1346 void OperationFormat::genParserTypeResolution(Operator &op, MethodBody &body) { 1347 // If any of type resolutions use transformed variables, make sure that the 1348 // types of those variables are resolved. 1349 SmallPtrSet<const NamedTypeConstraint *, 8> verifiedVariables; 1350 FmtContext verifierFCtx; 1351 for (TypeResolution &resolver : 1352 llvm::concat<TypeResolution>(resultTypes, operandTypes)) { 1353 Optional<StringRef> transformer = resolver.getVarTransformer(); 1354 if (!transformer) 1355 continue; 1356 // Ensure that we don't verify the same variables twice. 1357 const NamedTypeConstraint *variable = resolver.getVariable(); 1358 if (!variable || !verifiedVariables.insert(variable).second) 1359 continue; 1360 1361 auto constraint = variable->constraint; 1362 body << " for (::mlir::Type type : " << variable->name << "Types) {\n" 1363 << " (void)type;\n" 1364 << " if (!(" 1365 << tgfmt(constraint.getConditionTemplate(), 1366 &verifierFCtx.withSelf("type")) 1367 << ")) {\n" 1368 << formatv(" return parser.emitError(parser.getNameLoc()) << " 1369 "\"'{0}' must be {1}, but got \" << type;\n", 1370 variable->name, constraint.getSummary()) 1371 << " }\n" 1372 << " }\n"; 1373 } 1374 1375 // Initialize the set of buildable types. 1376 if (!buildableTypes.empty()) { 1377 FmtContext typeBuilderCtx; 1378 typeBuilderCtx.withBuilder("parser.getBuilder()"); 1379 for (auto &it : buildableTypes) 1380 body << " ::mlir::Type odsBuildableType" << it.second << " = " 1381 << tgfmt(it.first, &typeBuilderCtx) << ";\n"; 1382 } 1383 1384 // Emit the code necessary for a type resolver. 1385 auto emitTypeResolver = [&](TypeResolution &resolver, StringRef curVar) { 1386 if (Optional<int> val = resolver.getBuilderIdx()) { 1387 body << "odsBuildableType" << *val; 1388 } else if (const NamedTypeConstraint *var = resolver.getVariable()) { 1389 if (Optional<StringRef> tform = resolver.getVarTransformer()) { 1390 FmtContext fmtContext; 1391 fmtContext.addSubst("_ctxt", "parser.getContext()"); 1392 if (var->isVariadic()) 1393 fmtContext.withSelf(var->name + "Types"); 1394 else 1395 fmtContext.withSelf(var->name + "Types[0]"); 1396 body << tgfmt(*tform, &fmtContext); 1397 } else { 1398 body << var->name << "Types"; 1399 } 1400 } else if (const NamedAttribute *attr = resolver.getAttribute()) { 1401 if (Optional<StringRef> tform = resolver.getVarTransformer()) 1402 body << tgfmt(*tform, 1403 &FmtContext().withSelf(attr->name + "Attr.getType()")); 1404 else 1405 body << attr->name << "Attr.getType()"; 1406 } else { 1407 body << curVar << "Types"; 1408 } 1409 }; 1410 1411 // Resolve each of the result types. 1412 if (!infersResultTypes) { 1413 if (allResultTypes) { 1414 body << " result.addTypes(allResultTypes);\n"; 1415 } else { 1416 for (unsigned i = 0, e = op.getNumResults(); i != e; ++i) { 1417 body << " result.addTypes("; 1418 emitTypeResolver(resultTypes[i], op.getResultName(i)); 1419 body << ");\n"; 1420 } 1421 } 1422 } 1423 1424 // Emit the operand type resolutions. 1425 genParserOperandTypeResolution(op, body, emitTypeResolver); 1426 1427 // Handle return type inference once all operands have been resolved 1428 if (infersResultTypes) 1429 body << formatv(inferReturnTypesParserCode, op.getCppClassName()); 1430 } 1431 1432 void OperationFormat::genParserOperandTypeResolution( 1433 Operator &op, MethodBody &body, 1434 function_ref<void(TypeResolution &, StringRef)> emitTypeResolver) { 1435 // Early exit if there are no operands. 1436 if (op.getNumOperands() == 0) 1437 return; 1438 1439 // Handle the case where all operand types are grouped together with 1440 // "types(operands)". 1441 if (allOperandTypes) { 1442 // If `operands` was specified, use the full operand list directly. 1443 if (allOperands) { 1444 body << " if (parser.resolveOperands(allOperands, allOperandTypes, " 1445 "allOperandLoc, result.operands))\n" 1446 " return ::mlir::failure();\n"; 1447 return; 1448 } 1449 1450 // Otherwise, use llvm::concat to merge the disjoint operand lists together. 1451 // llvm::concat does not allow the case of a single range, so guard it here. 1452 body << " if (parser.resolveOperands("; 1453 if (op.getNumOperands() > 1) { 1454 body << "::llvm::concat<const ::mlir::OpAsmParser::UnresolvedOperand>("; 1455 llvm::interleaveComma(op.getOperands(), body, [&](auto &operand) { 1456 body << operand.name << "Operands"; 1457 }); 1458 body << ")"; 1459 } else { 1460 body << op.operand_begin()->name << "Operands"; 1461 } 1462 body << ", allOperandTypes, parser.getNameLoc(), result.operands))\n" 1463 << " return ::mlir::failure();\n"; 1464 return; 1465 } 1466 1467 // Handle the case where all operands are grouped together with "operands". 1468 if (allOperands) { 1469 body << " if (parser.resolveOperands(allOperands, "; 1470 1471 // Group all of the operand types together to perform the resolution all at 1472 // once. Use llvm::concat to perform the merge. llvm::concat does not allow 1473 // the case of a single range, so guard it here. 1474 if (op.getNumOperands() > 1) { 1475 body << "::llvm::concat<const ::mlir::Type>("; 1476 llvm::interleaveComma( 1477 llvm::seq<int>(0, op.getNumOperands()), body, [&](int i) { 1478 body << "::llvm::ArrayRef<::mlir::Type>("; 1479 emitTypeResolver(operandTypes[i], op.getOperand(i).name); 1480 body << ")"; 1481 }); 1482 body << ")"; 1483 } else { 1484 emitTypeResolver(operandTypes.front(), op.getOperand(0).name); 1485 } 1486 1487 body << ", allOperandLoc, result.operands))\n" 1488 << " return ::mlir::failure();\n"; 1489 return; 1490 } 1491 1492 // The final case is the one where each of the operands types are resolved 1493 // separately. 1494 for (unsigned i = 0, e = op.getNumOperands(); i != e; ++i) { 1495 NamedTypeConstraint &operand = op.getOperand(i); 1496 body << " if (parser.resolveOperands(" << operand.name << "Operands, "; 1497 1498 // Resolve the type of this operand. 1499 TypeResolution &operandType = operandTypes[i]; 1500 emitTypeResolver(operandType, operand.name); 1501 1502 // If the type is resolved by a non-variadic variable, index into the 1503 // resolved type list. This allows for resolving the types of a variadic 1504 // operand list from a non-variadic variable. 1505 bool verifyOperandAndTypeSize = true; 1506 if (auto *resolverVar = operandType.getVariable()) { 1507 if (!resolverVar->isVariadic() && !operandType.getVarTransformer()) { 1508 body << "[0]"; 1509 verifyOperandAndTypeSize = false; 1510 } 1511 } else { 1512 verifyOperandAndTypeSize = !operandType.getBuilderIdx(); 1513 } 1514 1515 // Check to see if the sizes between the types and operands must match. If 1516 // they do, provide the operand location to select the proper resolution 1517 // overload. 1518 if (verifyOperandAndTypeSize) 1519 body << ", " << operand.name << "OperandsLoc"; 1520 body << ", result.operands))\n return ::mlir::failure();\n"; 1521 } 1522 } 1523 1524 void OperationFormat::genParserRegionResolution(Operator &op, 1525 MethodBody &body) { 1526 // Check for the case where all regions were parsed. 1527 bool hasAllRegions = llvm::any_of( 1528 elements, [](FormatElement *elt) { return isa<RegionsDirective>(elt); }); 1529 if (hasAllRegions) { 1530 body << " result.addRegions(fullRegions);\n"; 1531 return; 1532 } 1533 1534 // Otherwise, handle each region individually. 1535 for (const NamedRegion ®ion : op.getRegions()) { 1536 if (region.isVariadic()) 1537 body << " result.addRegions(" << region.name << "Regions);\n"; 1538 else 1539 body << " result.addRegion(std::move(" << region.name << "Region));\n"; 1540 } 1541 } 1542 1543 void OperationFormat::genParserSuccessorResolution(Operator &op, 1544 MethodBody &body) { 1545 // Check for the case where all successors were parsed. 1546 bool hasAllSuccessors = llvm::any_of(elements, [](FormatElement *elt) { 1547 return isa<SuccessorsDirective>(elt); 1548 }); 1549 if (hasAllSuccessors) { 1550 body << " result.addSuccessors(fullSuccessors);\n"; 1551 return; 1552 } 1553 1554 // Otherwise, handle each successor individually. 1555 for (const NamedSuccessor &successor : op.getSuccessors()) { 1556 if (successor.isVariadic()) 1557 body << " result.addSuccessors(" << successor.name << "Successors);\n"; 1558 else 1559 body << " result.addSuccessors(" << successor.name << "Successor);\n"; 1560 } 1561 } 1562 1563 void OperationFormat::genParserVariadicSegmentResolution(Operator &op, 1564 MethodBody &body) { 1565 if (!allOperands) { 1566 if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) { 1567 body << " result.addAttribute(\"operand_segment_sizes\", " 1568 << "parser.getBuilder().getI32VectorAttr({"; 1569 auto interleaveFn = [&](const NamedTypeConstraint &operand) { 1570 // If the operand is variadic emit the parsed size. 1571 if (operand.isVariableLength()) 1572 body << "static_cast<int32_t>(" << operand.name << "Operands.size())"; 1573 else 1574 body << "1"; 1575 }; 1576 llvm::interleaveComma(op.getOperands(), body, interleaveFn); 1577 body << "}));\n"; 1578 } 1579 for (const NamedTypeConstraint &operand : op.getOperands()) { 1580 if (!operand.isVariadicOfVariadic()) 1581 continue; 1582 body << llvm::formatv( 1583 " result.addAttribute(\"{0}\", " 1584 "parser.getBuilder().getI32TensorAttr({1}OperandGroupSizes));\n", 1585 operand.constraint.getVariadicOfVariadicSegmentSizeAttr(), 1586 operand.name); 1587 } 1588 } 1589 1590 if (!allResultTypes && 1591 op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) { 1592 body << " result.addAttribute(\"result_segment_sizes\", " 1593 << "parser.getBuilder().getI32VectorAttr({"; 1594 auto interleaveFn = [&](const NamedTypeConstraint &result) { 1595 // If the result is variadic emit the parsed size. 1596 if (result.isVariableLength()) 1597 body << "static_cast<int32_t>(" << result.name << "Types.size())"; 1598 else 1599 body << "1"; 1600 }; 1601 llvm::interleaveComma(op.getResults(), body, interleaveFn); 1602 body << "}));\n"; 1603 } 1604 } 1605 1606 //===----------------------------------------------------------------------===// 1607 // PrinterGen 1608 1609 /// The code snippet used to generate a printer call for a region of an 1610 // operation that has the SingleBlockImplicitTerminator trait. 1611 /// 1612 /// {0}: The name of the region. 1613 const char *regionSingleBlockImplicitTerminatorPrinterCode = R"( 1614 { 1615 bool printTerminator = true; 1616 if (auto *term = {0}.empty() ? nullptr : {0}.begin()->getTerminator()) {{ 1617 printTerminator = !term->getAttrDictionary().empty() || 1618 term->getNumOperands() != 0 || 1619 term->getNumResults() != 0; 1620 } 1621 _odsPrinter.printRegion({0}, /*printEntryBlockArgs=*/true, 1622 /*printBlockTerminators=*/printTerminator); 1623 } 1624 )"; 1625 1626 /// The code snippet used to generate a printer call for an enum that has cases 1627 /// that can't be represented with a keyword. 1628 /// 1629 /// {0}: The name of the enum attribute. 1630 /// {1}: The name of the enum attributes symbolToString function. 1631 const char *enumAttrBeginPrinterCode = R"( 1632 { 1633 auto caseValue = {0}(); 1634 auto caseValueStr = {1}(caseValue); 1635 )"; 1636 1637 /// Generate the printer for the 'attr-dict' directive. 1638 static void genAttrDictPrinter(OperationFormat &fmt, Operator &op, 1639 MethodBody &body, bool withKeyword) { 1640 body << " _odsPrinter.printOptionalAttrDict" 1641 << (withKeyword ? "WithKeyword" : "") 1642 << "((*this)->getAttrs(), /*elidedAttrs=*/{"; 1643 // Elide the variadic segment size attributes if necessary. 1644 if (!fmt.allOperands && 1645 op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) 1646 body << "\"operand_segment_sizes\", "; 1647 if (!fmt.allResultTypes && 1648 op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) 1649 body << "\"result_segment_sizes\", "; 1650 if (!fmt.inferredAttributes.empty()) { 1651 for (const auto &attr : fmt.inferredAttributes) 1652 body << "\"" << attr.getKey() << "\", "; 1653 } 1654 llvm::interleaveComma( 1655 fmt.usedAttributes, body, 1656 [&](const NamedAttribute *attr) { body << "\"" << attr->name << "\""; }); 1657 body << "});\n"; 1658 } 1659 1660 /// Generate the printer for a literal value. `shouldEmitSpace` is true if a 1661 /// space should be emitted before this element. `lastWasPunctuation` is true if 1662 /// the previous element was a punctuation literal. 1663 static void genLiteralPrinter(StringRef value, MethodBody &body, 1664 bool &shouldEmitSpace, bool &lastWasPunctuation) { 1665 body << " _odsPrinter"; 1666 1667 // Don't insert a space for certain punctuation. 1668 if (shouldEmitSpace && shouldEmitSpaceBefore(value, lastWasPunctuation)) 1669 body << " << ' '"; 1670 body << " << \"" << value << "\";\n"; 1671 1672 // Insert a space after certain literals. 1673 shouldEmitSpace = 1674 value.size() != 1 || !StringRef("<({[").contains(value.front()); 1675 lastWasPunctuation = !(value.front() == '_' || isalpha(value.front())); 1676 } 1677 1678 /// Generate the printer for a space. `shouldEmitSpace` and `lastWasPunctuation` 1679 /// are set to false. 1680 static void genSpacePrinter(bool value, MethodBody &body, bool &shouldEmitSpace, 1681 bool &lastWasPunctuation) { 1682 if (value) { 1683 body << " _odsPrinter << ' ';\n"; 1684 lastWasPunctuation = false; 1685 } else { 1686 lastWasPunctuation = true; 1687 } 1688 shouldEmitSpace = false; 1689 } 1690 1691 /// Generate the printer for a custom directive parameter. 1692 static void genCustomDirectiveParameterPrinter(FormatElement *element, 1693 const Operator &op, 1694 MethodBody &body) { 1695 if (auto *attr = dyn_cast<AttributeVariable>(element)) { 1696 body << op.getGetterName(attr->getVar()->name) << "Attr()"; 1697 1698 } else if (isa<AttrDictDirective>(element)) { 1699 body << "getOperation()->getAttrDictionary()"; 1700 1701 } else if (auto *operand = dyn_cast<OperandVariable>(element)) { 1702 body << op.getGetterName(operand->getVar()->name) << "()"; 1703 1704 } else if (auto *region = dyn_cast<RegionVariable>(element)) { 1705 body << op.getGetterName(region->getVar()->name) << "()"; 1706 1707 } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) { 1708 body << op.getGetterName(successor->getVar()->name) << "()"; 1709 1710 } else if (auto *dir = dyn_cast<RefDirective>(element)) { 1711 genCustomDirectiveParameterPrinter(dir->getArg(), op, body); 1712 1713 } else if (auto *dir = dyn_cast<TypeDirective>(element)) { 1714 auto *typeOperand = dir->getArg(); 1715 auto *operand = dyn_cast<OperandVariable>(typeOperand); 1716 auto *var = operand ? operand->getVar() 1717 : cast<ResultVariable>(typeOperand)->getVar(); 1718 std::string name = op.getGetterName(var->name); 1719 if (var->isVariadic()) 1720 body << name << "().getTypes()"; 1721 else if (var->isOptional()) 1722 body << llvm::formatv("({0}() ? {0}().getType() : Type())", name); 1723 else 1724 body << name << "().getType()"; 1725 } else { 1726 llvm_unreachable("unknown custom directive parameter"); 1727 } 1728 } 1729 1730 /// Generate the printer for a custom directive. 1731 static void genCustomDirectivePrinter(CustomDirective *customDir, 1732 const Operator &op, MethodBody &body) { 1733 body << " print" << customDir->getName() << "(_odsPrinter, *this"; 1734 for (FormatElement *param : customDir->getArguments()) { 1735 body << ", "; 1736 genCustomDirectiveParameterPrinter(param, op, body); 1737 } 1738 body << ");\n"; 1739 } 1740 1741 /// Generate the printer for a region with the given variable name. 1742 static void genRegionPrinter(const Twine ®ionName, MethodBody &body, 1743 bool hasImplicitTermTrait) { 1744 if (hasImplicitTermTrait) 1745 body << llvm::formatv(regionSingleBlockImplicitTerminatorPrinterCode, 1746 regionName); 1747 else 1748 body << " _odsPrinter.printRegion(" << regionName << ");\n"; 1749 } 1750 static void genVariadicRegionPrinter(const Twine ®ionListName, 1751 MethodBody &body, 1752 bool hasImplicitTermTrait) { 1753 body << " llvm::interleaveComma(" << regionListName 1754 << ", _odsPrinter, [&](::mlir::Region ®ion) {\n "; 1755 genRegionPrinter("region", body, hasImplicitTermTrait); 1756 body << " });\n"; 1757 } 1758 1759 /// Generate the C++ for an operand to a (*-)type directive. 1760 static MethodBody &genTypeOperandPrinter(FormatElement *arg, const Operator &op, 1761 MethodBody &body, 1762 bool useArrayRef = true) { 1763 if (isa<OperandsDirective>(arg)) 1764 return body << "getOperation()->getOperandTypes()"; 1765 if (isa<ResultsDirective>(arg)) 1766 return body << "getOperation()->getResultTypes()"; 1767 auto *operand = dyn_cast<OperandVariable>(arg); 1768 auto *var = operand ? operand->getVar() : cast<ResultVariable>(arg)->getVar(); 1769 if (var->isVariadicOfVariadic()) 1770 return body << llvm::formatv("{0}().join().getTypes()", 1771 op.getGetterName(var->name)); 1772 if (var->isVariadic()) 1773 return body << op.getGetterName(var->name) << "().getTypes()"; 1774 if (var->isOptional()) 1775 return body << llvm::formatv( 1776 "({0}() ? ::llvm::ArrayRef<::mlir::Type>({0}().getType()) : " 1777 "::llvm::ArrayRef<::mlir::Type>())", 1778 op.getGetterName(var->name)); 1779 if (useArrayRef) 1780 return body << "::llvm::ArrayRef<::mlir::Type>(" 1781 << op.getGetterName(var->name) << "().getType())"; 1782 return body << op.getGetterName(var->name) << "().getType()"; 1783 } 1784 1785 /// Generate the printer for an enum attribute. 1786 static void genEnumAttrPrinter(const NamedAttribute *var, const Operator &op, 1787 MethodBody &body) { 1788 Attribute baseAttr = var->attr.getBaseAttr(); 1789 const EnumAttr &enumAttr = cast<EnumAttr>(baseAttr); 1790 std::vector<EnumAttrCase> cases = enumAttr.getAllCases(); 1791 1792 body << llvm::formatv(enumAttrBeginPrinterCode, 1793 (var->attr.isOptional() ? "*" : "") + 1794 op.getGetterName(var->name), 1795 enumAttr.getSymbolToStringFnName()); 1796 1797 // Get a string containing all of the cases that can't be represented with a 1798 // keyword. 1799 BitVector nonKeywordCases(cases.size()); 1800 bool hasStrCase = false; 1801 for (auto &it : llvm::enumerate(cases)) { 1802 hasStrCase = it.value().isStrCase(); 1803 if (!canFormatStringAsKeyword(it.value().getStr())) 1804 nonKeywordCases.set(it.index()); 1805 } 1806 1807 // If this is a string enum, use the case string to determine which cases 1808 // need to use the string form. 1809 if (hasStrCase) { 1810 if (nonKeywordCases.any()) { 1811 body << " if (llvm::is_contained(llvm::ArrayRef<llvm::StringRef>("; 1812 llvm::interleaveComma(nonKeywordCases.set_bits(), body, [&](unsigned it) { 1813 body << '"' << cases[it].getStr() << '"'; 1814 }); 1815 body << ")))\n" 1816 " _odsPrinter << '\"' << caseValueStr << '\"';\n" 1817 " else\n "; 1818 } 1819 body << " _odsPrinter << caseValueStr;\n" 1820 " }\n"; 1821 return; 1822 } 1823 1824 // Otherwise if this is a bit enum attribute, don't allow cases that may 1825 // overlap with other cases. For simplicity sake, only allow cases with a 1826 // single bit value. 1827 if (enumAttr.isBitEnum()) { 1828 for (auto &it : llvm::enumerate(cases)) { 1829 int64_t value = it.value().getValue(); 1830 if (value < 0 || !llvm::isPowerOf2_64(value)) 1831 nonKeywordCases.set(it.index()); 1832 } 1833 } 1834 1835 // If there are any cases that can't be used with a keyword, switch on the 1836 // case value to determine when to print in the string form. 1837 if (nonKeywordCases.any()) { 1838 body << " switch (caseValue) {\n"; 1839 StringRef cppNamespace = enumAttr.getCppNamespace(); 1840 StringRef enumName = enumAttr.getEnumClassName(); 1841 for (auto &it : llvm::enumerate(cases)) { 1842 if (nonKeywordCases.test(it.index())) 1843 continue; 1844 StringRef symbol = it.value().getSymbol(); 1845 body << llvm::formatv(" case {0}::{1}::{2}:\n", cppNamespace, enumName, 1846 llvm::isDigit(symbol.front()) ? ("_" + symbol) 1847 : symbol); 1848 } 1849 body << " _odsPrinter << caseValueStr;\n" 1850 " break;\n" 1851 " default:\n" 1852 " _odsPrinter << '\"' << caseValueStr << '\"';\n" 1853 " break;\n" 1854 " }\n" 1855 " }\n"; 1856 return; 1857 } 1858 1859 body << " _odsPrinter << caseValueStr;\n" 1860 " }\n"; 1861 } 1862 1863 /// Generate the check for the anchor of an optional group. 1864 static void genOptionalGroupPrinterAnchor(FormatElement *anchor, 1865 const Operator &op, 1866 MethodBody &body) { 1867 TypeSwitch<FormatElement *>(anchor) 1868 .Case<OperandVariable, ResultVariable>([&](auto *element) { 1869 const NamedTypeConstraint *var = element->getVar(); 1870 std::string name = op.getGetterName(var->name); 1871 if (var->isOptional()) 1872 body << " if (" << name << "()) {\n"; 1873 else if (var->isVariadic()) 1874 body << " if (!" << name << "().empty()) {\n"; 1875 }) 1876 .Case<RegionVariable>([&](RegionVariable *element) { 1877 const NamedRegion *var = element->getVar(); 1878 std::string name = op.getGetterName(var->name); 1879 // TODO: Add a check for optional regions here when ODS supports it. 1880 body << " if (!" << name << "().empty()) {\n"; 1881 }) 1882 .Case<TypeDirective>([&](TypeDirective *element) { 1883 genOptionalGroupPrinterAnchor(element->getArg(), op, body); 1884 }) 1885 .Case<FunctionalTypeDirective>([&](FunctionalTypeDirective *element) { 1886 genOptionalGroupPrinterAnchor(element->getInputs(), op, body); 1887 }) 1888 .Case<AttributeVariable>([&](AttributeVariable *attr) { 1889 body << " if ((*this)->getAttr(\"" << attr->getVar()->name 1890 << "\")) {\n"; 1891 }); 1892 } 1893 1894 void collect(FormatElement *element, 1895 SmallVectorImpl<VariableElement *> &variables) { 1896 TypeSwitch<FormatElement *>(element) 1897 .Case([&](VariableElement *var) { variables.emplace_back(var); }) 1898 .Case([&](CustomDirective *ele) { 1899 for (FormatElement *arg : ele->getArguments()) 1900 collect(arg, variables); 1901 }) 1902 .Case([&](OptionalElement *ele) { 1903 for (FormatElement *arg : ele->getThenElements()) 1904 collect(arg, variables); 1905 for (FormatElement *arg : ele->getElseElements()) 1906 collect(arg, variables); 1907 }) 1908 .Case([&](FunctionalTypeDirective *funcType) { 1909 collect(funcType->getInputs(), variables); 1910 collect(funcType->getResults(), variables); 1911 }) 1912 .Case([&](OIListElement *oilist) { 1913 for (ArrayRef<FormatElement *> arg : oilist->getParsingElements()) 1914 for (FormatElement *arg_ : arg) 1915 collect(arg_, variables); 1916 }); 1917 } 1918 1919 void OperationFormat::genElementPrinter(FormatElement *element, 1920 MethodBody &body, Operator &op, 1921 bool &shouldEmitSpace, 1922 bool &lastWasPunctuation) { 1923 if (LiteralElement *literal = dyn_cast<LiteralElement>(element)) 1924 return genLiteralPrinter(literal->getSpelling(), body, shouldEmitSpace, 1925 lastWasPunctuation); 1926 1927 // Emit a whitespace element. 1928 if (auto *space = dyn_cast<WhitespaceElement>(element)) { 1929 if (space->getValue() == "\\n") { 1930 body << " _odsPrinter.printNewline();\n"; 1931 } else { 1932 genSpacePrinter(!space->getValue().empty(), body, shouldEmitSpace, 1933 lastWasPunctuation); 1934 } 1935 return; 1936 } 1937 1938 // Emit an optional group. 1939 if (OptionalElement *optional = dyn_cast<OptionalElement>(element)) { 1940 // Emit the check for the presence of the anchor element. 1941 FormatElement *anchor = optional->getAnchor(); 1942 genOptionalGroupPrinterAnchor(anchor, op, body); 1943 1944 // If the anchor is a unit attribute, we don't need to print it. When 1945 // parsing, we will add this attribute if this group is present. 1946 auto elements = optional->getThenElements(); 1947 FormatElement *elidedAnchorElement = nullptr; 1948 auto *anchorAttr = dyn_cast<AttributeVariable>(anchor); 1949 if (anchorAttr && anchorAttr != elements.front() && 1950 anchorAttr->isUnitAttr()) { 1951 elidedAnchorElement = anchorAttr; 1952 } 1953 1954 // Emit each of the elements. 1955 for (FormatElement *childElement : elements) { 1956 if (childElement != elidedAnchorElement) { 1957 genElementPrinter(childElement, body, op, shouldEmitSpace, 1958 lastWasPunctuation); 1959 } 1960 } 1961 body << " }"; 1962 1963 // Emit each of the else elements. 1964 auto elseElements = optional->getElseElements(); 1965 if (!elseElements.empty()) { 1966 body << " else {\n"; 1967 for (FormatElement *childElement : elseElements) { 1968 genElementPrinter(childElement, body, op, shouldEmitSpace, 1969 lastWasPunctuation); 1970 } 1971 body << " }"; 1972 } 1973 1974 body << "\n"; 1975 return; 1976 } 1977 1978 // Emit the OIList 1979 if (auto *oilist = dyn_cast<OIListElement>(element)) { 1980 genLiteralPrinter(" ", body, shouldEmitSpace, lastWasPunctuation); 1981 for (auto clause : oilist->getClauses()) { 1982 LiteralElement *lelement = std::get<0>(clause); 1983 ArrayRef<FormatElement *> pelement = std::get<1>(clause); 1984 1985 SmallVector<VariableElement *> vars; 1986 for (FormatElement *el : pelement) 1987 collect(el, vars); 1988 body << " if (false"; 1989 for (VariableElement *var : vars) { 1990 TypeSwitch<FormatElement *>(var) 1991 .Case([&](AttributeVariable *attrEle) { 1992 body << " || " << op.getGetterName(attrEle->getVar()->name) 1993 << "Attr()"; 1994 }) 1995 .Case([&](OperandVariable *ele) { 1996 if (ele->getVar()->isVariadic()) { 1997 body << " || " << op.getGetterName(ele->getVar()->name) 1998 << "().size()"; 1999 } else { 2000 body << " || " << op.getGetterName(ele->getVar()->name) << "()"; 2001 } 2002 }) 2003 .Case([&](ResultVariable *ele) { 2004 if (ele->getVar()->isVariadic()) { 2005 body << " || " << op.getGetterName(ele->getVar()->name) 2006 << "().size()"; 2007 } else { 2008 body << " || " << op.getGetterName(ele->getVar()->name) << "()"; 2009 } 2010 }) 2011 .Case([&](RegionVariable *reg) { 2012 body << " || " << op.getGetterName(reg->getVar()->name) << "()"; 2013 }); 2014 } 2015 2016 body << ") {\n"; 2017 genLiteralPrinter(lelement->getSpelling(), body, shouldEmitSpace, 2018 lastWasPunctuation); 2019 if (oilist->getUnitAttrParsingElement(pelement) == nullptr) { 2020 for (FormatElement *element : pelement) 2021 genElementPrinter(element, body, op, shouldEmitSpace, 2022 lastWasPunctuation); 2023 } 2024 body << " }\n"; 2025 } 2026 return; 2027 } 2028 2029 // Emit the attribute dictionary. 2030 if (auto *attrDict = dyn_cast<AttrDictDirective>(element)) { 2031 genAttrDictPrinter(*this, op, body, attrDict->isWithKeyword()); 2032 lastWasPunctuation = false; 2033 return; 2034 } 2035 2036 // Optionally insert a space before the next element. The AttrDict printer 2037 // already adds a space as necessary. 2038 if (shouldEmitSpace || !lastWasPunctuation) 2039 body << " _odsPrinter << ' ';\n"; 2040 lastWasPunctuation = false; 2041 shouldEmitSpace = true; 2042 2043 if (auto *attr = dyn_cast<AttributeVariable>(element)) { 2044 const NamedAttribute *var = attr->getVar(); 2045 2046 // If we are formatting as an enum, symbolize the attribute as a string. 2047 if (canFormatEnumAttr(var)) 2048 return genEnumAttrPrinter(var, op, body); 2049 2050 // If we are formatting as a symbol name, handle it as a symbol name. 2051 if (shouldFormatSymbolNameAttr(var)) { 2052 body << " _odsPrinter.printSymbolName(" << op.getGetterName(var->name) 2053 << "Attr().getValue());\n"; 2054 return; 2055 } 2056 2057 // Elide the attribute type if it is buildable. 2058 if (attr->getTypeBuilder()) 2059 body << " _odsPrinter.printAttributeWithoutType(" 2060 << op.getGetterName(var->name) << "Attr());\n"; 2061 else if (attr->shouldBeQualified() || 2062 var->attr.getStorageType() == "::mlir::Attribute") 2063 body << " _odsPrinter.printAttribute(" << op.getGetterName(var->name) 2064 << "Attr());\n"; 2065 else 2066 body << "_odsPrinter.printStrippedAttrOrType(" 2067 << op.getGetterName(var->name) << "Attr());\n"; 2068 } else if (auto *operand = dyn_cast<OperandVariable>(element)) { 2069 if (operand->getVar()->isVariadicOfVariadic()) { 2070 body << " ::llvm::interleaveComma(" 2071 << op.getGetterName(operand->getVar()->name) 2072 << "(), _odsPrinter, [&](const auto &operands) { _odsPrinter << " 2073 "\"(\" << operands << " 2074 "\")\"; });\n"; 2075 2076 } else if (operand->getVar()->isOptional()) { 2077 body << " if (::mlir::Value value = " 2078 << op.getGetterName(operand->getVar()->name) << "())\n" 2079 << " _odsPrinter << value;\n"; 2080 } else { 2081 body << " _odsPrinter << " << op.getGetterName(operand->getVar()->name) 2082 << "();\n"; 2083 } 2084 } else if (auto *region = dyn_cast<RegionVariable>(element)) { 2085 const NamedRegion *var = region->getVar(); 2086 std::string name = op.getGetterName(var->name); 2087 if (var->isVariadic()) { 2088 genVariadicRegionPrinter(name + "()", body, hasImplicitTermTrait); 2089 } else { 2090 genRegionPrinter(name + "()", body, hasImplicitTermTrait); 2091 } 2092 } else if (auto *successor = dyn_cast<SuccessorVariable>(element)) { 2093 const NamedSuccessor *var = successor->getVar(); 2094 std::string name = op.getGetterName(var->name); 2095 if (var->isVariadic()) 2096 body << " ::llvm::interleaveComma(" << name << "(), _odsPrinter);\n"; 2097 else 2098 body << " _odsPrinter << " << name << "();\n"; 2099 } else if (auto *dir = dyn_cast<CustomDirective>(element)) { 2100 genCustomDirectivePrinter(dir, op, body); 2101 } else if (isa<OperandsDirective>(element)) { 2102 body << " _odsPrinter << getOperation()->getOperands();\n"; 2103 } else if (isa<RegionsDirective>(element)) { 2104 genVariadicRegionPrinter("getOperation()->getRegions()", body, 2105 hasImplicitTermTrait); 2106 } else if (isa<SuccessorsDirective>(element)) { 2107 body << " ::llvm::interleaveComma(getOperation()->getSuccessors(), " 2108 "_odsPrinter);\n"; 2109 } else if (auto *dir = dyn_cast<TypeDirective>(element)) { 2110 if (auto *operand = dyn_cast<OperandVariable>(dir->getArg())) { 2111 if (operand->getVar()->isVariadicOfVariadic()) { 2112 body << llvm::formatv( 2113 " ::llvm::interleaveComma({0}().getTypes(), _odsPrinter, " 2114 "[&](::mlir::TypeRange types) {{ _odsPrinter << \"(\" << " 2115 "types << \")\"; });\n", 2116 op.getGetterName(operand->getVar()->name)); 2117 return; 2118 } 2119 } 2120 const NamedTypeConstraint *var = nullptr; 2121 { 2122 if (auto *operand = dyn_cast<OperandVariable>(dir->getArg())) 2123 var = operand->getVar(); 2124 else if (auto *operand = dyn_cast<ResultVariable>(dir->getArg())) 2125 var = operand->getVar(); 2126 } 2127 if (var && !var->isVariadicOfVariadic() && !var->isVariadic() && 2128 !var->isOptional()) { 2129 std::string cppClass = var->constraint.getCPPClassName(); 2130 if (dir->shouldBeQualified()) { 2131 body << " _odsPrinter << " << op.getGetterName(var->name) 2132 << "().getType();\n"; 2133 return; 2134 } 2135 body << " {\n" 2136 << " auto type = " << op.getGetterName(var->name) 2137 << "().getType();\n" 2138 << " if (auto validType = type.dyn_cast<" << cppClass << ">())\n" 2139 << " _odsPrinter.printStrippedAttrOrType(validType);\n" 2140 << " else\n" 2141 << " _odsPrinter << type;\n" 2142 << " }\n"; 2143 return; 2144 } 2145 body << " _odsPrinter << "; 2146 genTypeOperandPrinter(dir->getArg(), op, body, /*useArrayRef=*/false) 2147 << ";\n"; 2148 } else if (auto *dir = dyn_cast<FunctionalTypeDirective>(element)) { 2149 body << " _odsPrinter.printFunctionalType("; 2150 genTypeOperandPrinter(dir->getInputs(), op, body) << ", "; 2151 genTypeOperandPrinter(dir->getResults(), op, body) << ");\n"; 2152 } else { 2153 llvm_unreachable("unknown format element"); 2154 } 2155 } 2156 2157 void OperationFormat::genPrinter(Operator &op, OpClass &opClass) { 2158 auto *method = opClass.addMethod( 2159 "void", "print", 2160 MethodParameter("::mlir::OpAsmPrinter &", "_odsPrinter")); 2161 auto &body = method->body(); 2162 2163 // Flags for if we should emit a space, and if the last element was 2164 // punctuation. 2165 bool shouldEmitSpace = true, lastWasPunctuation = false; 2166 for (FormatElement *element : elements) 2167 genElementPrinter(element, body, op, shouldEmitSpace, lastWasPunctuation); 2168 } 2169 2170 //===----------------------------------------------------------------------===// 2171 // OpFormatParser 2172 //===----------------------------------------------------------------------===// 2173 2174 /// Function to find an element within the given range that has the same name as 2175 /// 'name'. 2176 template <typename RangeT> static auto findArg(RangeT &&range, StringRef name) { 2177 auto it = llvm::find_if(range, [=](auto &arg) { return arg.name == name; }); 2178 return it != range.end() ? &*it : nullptr; 2179 } 2180 2181 namespace { 2182 /// This class implements a parser for an instance of an operation assembly 2183 /// format. 2184 class OpFormatParser : public FormatParser { 2185 public: 2186 OpFormatParser(llvm::SourceMgr &mgr, OperationFormat &format, Operator &op) 2187 : FormatParser(mgr, op.getLoc()[0]), fmt(format), op(op), 2188 seenOperandTypes(op.getNumOperands()), 2189 seenResultTypes(op.getNumResults()) {} 2190 2191 protected: 2192 /// Verify the format elements. 2193 LogicalResult verify(SMLoc loc, ArrayRef<FormatElement *> elements) override; 2194 /// Verify the arguments to a custom directive. 2195 LogicalResult 2196 verifyCustomDirectiveArguments(SMLoc loc, 2197 ArrayRef<FormatElement *> arguments) override; 2198 /// Verify the elements of an optional group. 2199 LogicalResult 2200 verifyOptionalGroupElements(SMLoc loc, ArrayRef<FormatElement *> elements, 2201 Optional<unsigned> anchorIndex) override; 2202 LogicalResult verifyOptionalGroupElement(SMLoc loc, FormatElement *element, 2203 bool isAnchor); 2204 2205 /// Parse an operation variable. 2206 FailureOr<FormatElement *> parseVariableImpl(SMLoc loc, StringRef name, 2207 Context ctx) override; 2208 /// Parse an operation format directive. 2209 FailureOr<FormatElement *> 2210 parseDirectiveImpl(SMLoc loc, FormatToken::Kind kind, Context ctx) override; 2211 2212 private: 2213 /// This struct represents a type resolution instance. It includes a specific 2214 /// type as well as an optional transformer to apply to that type in order to 2215 /// properly resolve the type of a variable. 2216 struct TypeResolutionInstance { 2217 ConstArgument resolver; 2218 Optional<StringRef> transformer; 2219 }; 2220 2221 using ElementsItT = ArrayRef<FormatElement *>::iterator; 2222 2223 /// Verify the state of operation attributes within the format. 2224 LogicalResult verifyAttributes(SMLoc loc, ArrayRef<FormatElement *> elements); 2225 /// Verify the attribute elements at the back of the given stack of iterators. 2226 LogicalResult verifyAttributes( 2227 SMLoc loc, 2228 SmallVectorImpl<std::pair<ElementsItT, ElementsItT>> &iteratorStack); 2229 2230 /// Verify the state of operation operands within the format. 2231 LogicalResult 2232 verifyOperands(SMLoc loc, 2233 llvm::StringMap<TypeResolutionInstance> &variableTyResolver); 2234 2235 /// Verify the state of operation regions within the format. 2236 LogicalResult verifyRegions(SMLoc loc); 2237 2238 /// Verify the state of operation results within the format. 2239 LogicalResult 2240 verifyResults(SMLoc loc, 2241 llvm::StringMap<TypeResolutionInstance> &variableTyResolver); 2242 2243 /// Verify the state of operation successors within the format. 2244 LogicalResult verifySuccessors(SMLoc loc); 2245 2246 LogicalResult verifyOIListElements(SMLoc loc, 2247 ArrayRef<FormatElement *> elements); 2248 2249 /// Given the values of an `AllTypesMatch` trait, check for inferable type 2250 /// resolution. 2251 void handleAllTypesMatchConstraint( 2252 ArrayRef<StringRef> values, 2253 llvm::StringMap<TypeResolutionInstance> &variableTyResolver); 2254 /// Check for inferable type resolution given all operands, and or results, 2255 /// have the same type. If 'includeResults' is true, the results also have the 2256 /// same type as all of the operands. 2257 void handleSameTypesConstraint( 2258 llvm::StringMap<TypeResolutionInstance> &variableTyResolver, 2259 bool includeResults); 2260 /// Check for inferable type resolution based on another operand, result, or 2261 /// attribute. 2262 void handleTypesMatchConstraint( 2263 llvm::StringMap<TypeResolutionInstance> &variableTyResolver, 2264 const llvm::Record &def); 2265 2266 /// Returns an argument or attribute with the given name that has been seen 2267 /// within the format. 2268 ConstArgument findSeenArg(StringRef name); 2269 2270 /// Parse the various different directives. 2271 FailureOr<FormatElement *> parseAttrDictDirective(SMLoc loc, Context context, 2272 bool withKeyword); 2273 FailureOr<FormatElement *> parseFunctionalTypeDirective(SMLoc loc, 2274 Context context); 2275 FailureOr<FormatElement *> parseOIListDirective(SMLoc loc, Context context); 2276 LogicalResult verifyOIListParsingElement(FormatElement *element, SMLoc loc); 2277 FailureOr<FormatElement *> parseOperandsDirective(SMLoc loc, Context context); 2278 FailureOr<FormatElement *> parseQualifiedDirective(SMLoc loc, 2279 Context context); 2280 FailureOr<FormatElement *> parseReferenceDirective(SMLoc loc, 2281 Context context); 2282 FailureOr<FormatElement *> parseRegionsDirective(SMLoc loc, Context context); 2283 FailureOr<FormatElement *> parseResultsDirective(SMLoc loc, Context context); 2284 FailureOr<FormatElement *> parseSuccessorsDirective(SMLoc loc, 2285 Context context); 2286 FailureOr<FormatElement *> parseTypeDirective(SMLoc loc, Context context); 2287 FailureOr<FormatElement *> parseTypeDirectiveOperand(SMLoc loc, 2288 bool isRefChild = false); 2289 2290 //===--------------------------------------------------------------------===// 2291 // Fields 2292 //===--------------------------------------------------------------------===// 2293 2294 OperationFormat &fmt; 2295 Operator &op; 2296 2297 // The following are various bits of format state used for verification 2298 // during parsing. 2299 bool hasAttrDict = false; 2300 bool hasAllRegions = false, hasAllSuccessors = false; 2301 bool canInferResultTypes = false; 2302 llvm::SmallBitVector seenOperandTypes, seenResultTypes; 2303 llvm::SmallSetVector<const NamedAttribute *, 8> seenAttrs; 2304 llvm::DenseSet<const NamedTypeConstraint *> seenOperands; 2305 llvm::DenseSet<const NamedRegion *> seenRegions; 2306 llvm::DenseSet<const NamedSuccessor *> seenSuccessors; 2307 }; 2308 } // namespace 2309 2310 LogicalResult OpFormatParser::verify(SMLoc loc, 2311 ArrayRef<FormatElement *> elements) { 2312 // Check that the attribute dictionary is in the format. 2313 if (!hasAttrDict) 2314 return emitError(loc, "'attr-dict' directive not found in " 2315 "custom assembly format"); 2316 2317 // Check for any type traits that we can use for inferring types. 2318 llvm::StringMap<TypeResolutionInstance> variableTyResolver; 2319 for (const Trait &trait : op.getTraits()) { 2320 const llvm::Record &def = trait.getDef(); 2321 if (def.isSubClassOf("AllTypesMatch")) { 2322 handleAllTypesMatchConstraint(def.getValueAsListOfStrings("values"), 2323 variableTyResolver); 2324 } else if (def.getName() == "SameTypeOperands") { 2325 handleSameTypesConstraint(variableTyResolver, /*includeResults=*/false); 2326 } else if (def.getName() == "SameOperandsAndResultType") { 2327 handleSameTypesConstraint(variableTyResolver, /*includeResults=*/true); 2328 } else if (def.isSubClassOf("TypesMatchWith")) { 2329 handleTypesMatchConstraint(variableTyResolver, def); 2330 } else if (!op.allResultTypesKnown()) { 2331 // This doesn't check the name directly to handle 2332 // DeclareOpInterfaceMethods<InferTypeOpInterface> 2333 // and the like. 2334 // TODO: Add hasCppInterface check. 2335 if (auto name = def.getValueAsOptionalString("cppClassName")) { 2336 if (*name == "InferTypeOpInterface" && 2337 def.getValueAsString("cppNamespace") == "::mlir") 2338 canInferResultTypes = true; 2339 } 2340 } 2341 } 2342 2343 // Verify the state of the various operation components. 2344 if (failed(verifyAttributes(loc, elements)) || 2345 failed(verifyResults(loc, variableTyResolver)) || 2346 failed(verifyOperands(loc, variableTyResolver)) || 2347 failed(verifyRegions(loc)) || failed(verifySuccessors(loc)) || 2348 failed(verifyOIListElements(loc, elements))) 2349 return failure(); 2350 2351 // Collect the set of used attributes in the format. 2352 fmt.usedAttributes = seenAttrs.takeVector(); 2353 return success(); 2354 } 2355 2356 LogicalResult 2357 OpFormatParser::verifyAttributes(SMLoc loc, 2358 ArrayRef<FormatElement *> elements) { 2359 // Check that there are no `:` literals after an attribute without a constant 2360 // type. The attribute grammar contains an optional trailing colon type, which 2361 // can lead to unexpected and generally unintended behavior. Given that, it is 2362 // better to just error out here instead. 2363 SmallVector<std::pair<ElementsItT, ElementsItT>, 1> iteratorStack; 2364 iteratorStack.emplace_back(elements.begin(), elements.end()); 2365 while (!iteratorStack.empty()) 2366 if (failed(verifyAttributes(loc, iteratorStack))) 2367 return ::failure(); 2368 2369 // Check for VariadicOfVariadic variables. The segment attribute of those 2370 // variables will be infered. 2371 for (const NamedTypeConstraint *var : seenOperands) { 2372 if (var->constraint.isVariadicOfVariadic()) { 2373 fmt.inferredAttributes.insert( 2374 var->constraint.getVariadicOfVariadicSegmentSizeAttr()); 2375 } 2376 } 2377 2378 return success(); 2379 } 2380 /// Verify the attribute elements at the back of the given stack of iterators. 2381 LogicalResult OpFormatParser::verifyAttributes( 2382 SMLoc loc, 2383 SmallVectorImpl<std::pair<ElementsItT, ElementsItT>> &iteratorStack) { 2384 auto &stackIt = iteratorStack.back(); 2385 ElementsItT &it = stackIt.first, e = stackIt.second; 2386 while (it != e) { 2387 FormatElement *element = *(it++); 2388 2389 // Traverse into optional groups. 2390 if (auto *optional = dyn_cast<OptionalElement>(element)) { 2391 auto thenElements = optional->getThenElements(); 2392 iteratorStack.emplace_back(thenElements.begin(), thenElements.end()); 2393 2394 auto elseElements = optional->getElseElements(); 2395 iteratorStack.emplace_back(elseElements.begin(), elseElements.end()); 2396 return success(); 2397 } 2398 2399 // We are checking for an attribute element followed by a `:`, so there is 2400 // no need to check the end. 2401 if (it == e && iteratorStack.size() == 1) 2402 break; 2403 2404 // Check for an attribute with a constant type builder, followed by a `:`. 2405 auto *prevAttr = dyn_cast<AttributeVariable>(element); 2406 if (!prevAttr || prevAttr->getTypeBuilder()) 2407 continue; 2408 2409 // Check the next iterator within the stack for literal elements. 2410 for (auto &nextItPair : iteratorStack) { 2411 ElementsItT nextIt = nextItPair.first, nextE = nextItPair.second; 2412 for (; nextIt != nextE; ++nextIt) { 2413 // Skip any trailing whitespace, attribute dictionaries, or optional 2414 // groups. 2415 if (isa<WhitespaceElement>(*nextIt) || 2416 isa<AttrDictDirective>(*nextIt) || isa<OptionalElement>(*nextIt)) 2417 continue; 2418 2419 // We are only interested in `:` literals. 2420 auto *literal = dyn_cast<LiteralElement>(*nextIt); 2421 if (!literal || literal->getSpelling() != ":") 2422 break; 2423 2424 // TODO: Use the location of the literal element itself. 2425 return emitError( 2426 loc, llvm::formatv("format ambiguity caused by `:` literal found " 2427 "after attribute `{0}` which does not have " 2428 "a buildable type", 2429 prevAttr->getVar()->name)); 2430 } 2431 } 2432 } 2433 iteratorStack.pop_back(); 2434 return success(); 2435 } 2436 2437 LogicalResult OpFormatParser::verifyOperands( 2438 SMLoc loc, llvm::StringMap<TypeResolutionInstance> &variableTyResolver) { 2439 // Check that all of the operands are within the format, and their types can 2440 // be inferred. 2441 auto &buildableTypes = fmt.buildableTypes; 2442 for (unsigned i = 0, e = op.getNumOperands(); i != e; ++i) { 2443 NamedTypeConstraint &operand = op.getOperand(i); 2444 2445 // Check that the operand itself is in the format. 2446 if (!fmt.allOperands && !seenOperands.count(&operand)) { 2447 return emitErrorAndNote(loc, 2448 "operand #" + Twine(i) + ", named '" + 2449 operand.name + "', not found", 2450 "suggest adding a '$" + operand.name + 2451 "' directive to the custom assembly format"); 2452 } 2453 2454 // Check that the operand type is in the format, or that it can be inferred. 2455 if (fmt.allOperandTypes || seenOperandTypes.test(i)) 2456 continue; 2457 2458 // Check to see if we can infer this type from another variable. 2459 auto varResolverIt = variableTyResolver.find(op.getOperand(i).name); 2460 if (varResolverIt != variableTyResolver.end()) { 2461 TypeResolutionInstance &resolver = varResolverIt->second; 2462 fmt.operandTypes[i].setResolver(resolver.resolver, resolver.transformer); 2463 continue; 2464 } 2465 2466 // Similarly to results, allow a custom builder for resolving the type if 2467 // we aren't using the 'operands' directive. 2468 Optional<StringRef> builder = operand.constraint.getBuilderCall(); 2469 if (!builder || (fmt.allOperands && operand.isVariableLength())) { 2470 return emitErrorAndNote( 2471 loc, 2472 "type of operand #" + Twine(i) + ", named '" + operand.name + 2473 "', is not buildable and a buildable type cannot be inferred", 2474 "suggest adding a type constraint to the operation or adding a " 2475 "'type($" + 2476 operand.name + ")' directive to the " + "custom assembly format"); 2477 } 2478 auto it = buildableTypes.insert({*builder, buildableTypes.size()}); 2479 fmt.operandTypes[i].setBuilderIdx(it.first->second); 2480 } 2481 return success(); 2482 } 2483 2484 LogicalResult OpFormatParser::verifyRegions(SMLoc loc) { 2485 // Check that all of the regions are within the format. 2486 if (hasAllRegions) 2487 return success(); 2488 2489 for (unsigned i = 0, e = op.getNumRegions(); i != e; ++i) { 2490 const NamedRegion ®ion = op.getRegion(i); 2491 if (!seenRegions.count(®ion)) { 2492 return emitErrorAndNote(loc, 2493 "region #" + Twine(i) + ", named '" + 2494 region.name + "', not found", 2495 "suggest adding a '$" + region.name + 2496 "' directive to the custom assembly format"); 2497 } 2498 } 2499 return success(); 2500 } 2501 2502 LogicalResult OpFormatParser::verifyResults( 2503 SMLoc loc, llvm::StringMap<TypeResolutionInstance> &variableTyResolver) { 2504 // If we format all of the types together, there is nothing to check. 2505 if (fmt.allResultTypes) 2506 return success(); 2507 2508 // If no result types are specified and we can infer them, infer all result 2509 // types 2510 if (op.getNumResults() > 0 && seenResultTypes.count() == 0 && 2511 canInferResultTypes) { 2512 fmt.infersResultTypes = true; 2513 return success(); 2514 } 2515 2516 // Check that all of the result types can be inferred. 2517 auto &buildableTypes = fmt.buildableTypes; 2518 for (unsigned i = 0, e = op.getNumResults(); i != e; ++i) { 2519 if (seenResultTypes.test(i)) 2520 continue; 2521 2522 // Check to see if we can infer this type from another variable. 2523 auto varResolverIt = variableTyResolver.find(op.getResultName(i)); 2524 if (varResolverIt != variableTyResolver.end()) { 2525 TypeResolutionInstance resolver = varResolverIt->second; 2526 fmt.resultTypes[i].setResolver(resolver.resolver, resolver.transformer); 2527 continue; 2528 } 2529 2530 // If the result is not variable length, allow for the case where the type 2531 // has a builder that we can use. 2532 NamedTypeConstraint &result = op.getResult(i); 2533 Optional<StringRef> builder = result.constraint.getBuilderCall(); 2534 if (!builder || result.isVariableLength()) { 2535 return emitErrorAndNote( 2536 loc, 2537 "type of result #" + Twine(i) + ", named '" + result.name + 2538 "', is not buildable and a buildable type cannot be inferred", 2539 "suggest adding a type constraint to the operation or adding a " 2540 "'type($" + 2541 result.name + ")' directive to the " + "custom assembly format"); 2542 } 2543 // Note in the format that this result uses the custom builder. 2544 auto it = buildableTypes.insert({*builder, buildableTypes.size()}); 2545 fmt.resultTypes[i].setBuilderIdx(it.first->second); 2546 } 2547 return success(); 2548 } 2549 2550 LogicalResult OpFormatParser::verifySuccessors(SMLoc loc) { 2551 // Check that all of the successors are within the format. 2552 if (hasAllSuccessors) 2553 return success(); 2554 2555 for (unsigned i = 0, e = op.getNumSuccessors(); i != e; ++i) { 2556 const NamedSuccessor &successor = op.getSuccessor(i); 2557 if (!seenSuccessors.count(&successor)) { 2558 return emitErrorAndNote(loc, 2559 "successor #" + Twine(i) + ", named '" + 2560 successor.name + "', not found", 2561 "suggest adding a '$" + successor.name + 2562 "' directive to the custom assembly format"); 2563 } 2564 } 2565 return success(); 2566 } 2567 2568 LogicalResult 2569 OpFormatParser::verifyOIListElements(SMLoc loc, 2570 ArrayRef<FormatElement *> elements) { 2571 // Check that all of the successors are within the format. 2572 SmallVector<StringRef> prohibitedLiterals; 2573 for (FormatElement *it : elements) { 2574 if (auto *oilist = dyn_cast<OIListElement>(it)) { 2575 if (!prohibitedLiterals.empty()) { 2576 // We just saw an oilist element in last iteration. Literals should not 2577 // match. 2578 for (LiteralElement *literal : oilist->getLiteralElements()) { 2579 if (find(prohibitedLiterals, literal->getSpelling()) != 2580 prohibitedLiterals.end()) { 2581 return emitError( 2582 loc, "format ambiguity because " + literal->getSpelling() + 2583 " is used in two adjacent oilist elements."); 2584 } 2585 } 2586 } 2587 for (LiteralElement *literal : oilist->getLiteralElements()) 2588 prohibitedLiterals.push_back(literal->getSpelling()); 2589 } else if (auto *literal = dyn_cast<LiteralElement>(it)) { 2590 if (find(prohibitedLiterals, literal->getSpelling()) != 2591 prohibitedLiterals.end()) { 2592 return emitError( 2593 loc, 2594 "format ambiguity because " + literal->getSpelling() + 2595 " is used both in oilist element and the adjacent literal."); 2596 } 2597 prohibitedLiterals.clear(); 2598 } else { 2599 prohibitedLiterals.clear(); 2600 } 2601 } 2602 return success(); 2603 } 2604 2605 void OpFormatParser::handleAllTypesMatchConstraint( 2606 ArrayRef<StringRef> values, 2607 llvm::StringMap<TypeResolutionInstance> &variableTyResolver) { 2608 for (unsigned i = 0, e = values.size(); i != e; ++i) { 2609 // Check to see if this value matches a resolved operand or result type. 2610 ConstArgument arg = findSeenArg(values[i]); 2611 if (!arg) 2612 continue; 2613 2614 // Mark this value as the type resolver for the other variables. 2615 for (unsigned j = 0; j != i; ++j) 2616 variableTyResolver[values[j]] = {arg, llvm::None}; 2617 for (unsigned j = i + 1; j != e; ++j) 2618 variableTyResolver[values[j]] = {arg, llvm::None}; 2619 } 2620 } 2621 2622 void OpFormatParser::handleSameTypesConstraint( 2623 llvm::StringMap<TypeResolutionInstance> &variableTyResolver, 2624 bool includeResults) { 2625 const NamedTypeConstraint *resolver = nullptr; 2626 int resolvedIt = -1; 2627 2628 // Check to see if there is an operand or result to use for the resolution. 2629 if ((resolvedIt = seenOperandTypes.find_first()) != -1) 2630 resolver = &op.getOperand(resolvedIt); 2631 else if (includeResults && (resolvedIt = seenResultTypes.find_first()) != -1) 2632 resolver = &op.getResult(resolvedIt); 2633 else 2634 return; 2635 2636 // Set the resolvers for each operand and result. 2637 for (unsigned i = 0, e = op.getNumOperands(); i != e; ++i) 2638 if (!seenOperandTypes.test(i) && !op.getOperand(i).name.empty()) 2639 variableTyResolver[op.getOperand(i).name] = {resolver, llvm::None}; 2640 if (includeResults) { 2641 for (unsigned i = 0, e = op.getNumResults(); i != e; ++i) 2642 if (!seenResultTypes.test(i) && !op.getResultName(i).empty()) 2643 variableTyResolver[op.getResultName(i)] = {resolver, llvm::None}; 2644 } 2645 } 2646 2647 void OpFormatParser::handleTypesMatchConstraint( 2648 llvm::StringMap<TypeResolutionInstance> &variableTyResolver, 2649 const llvm::Record &def) { 2650 StringRef lhsName = def.getValueAsString("lhs"); 2651 StringRef rhsName = def.getValueAsString("rhs"); 2652 StringRef transformer = def.getValueAsString("transformer"); 2653 if (ConstArgument arg = findSeenArg(lhsName)) 2654 variableTyResolver[rhsName] = {arg, transformer}; 2655 } 2656 2657 ConstArgument OpFormatParser::findSeenArg(StringRef name) { 2658 if (const NamedTypeConstraint *arg = findArg(op.getOperands(), name)) 2659 return seenOperandTypes.test(arg - op.operand_begin()) ? arg : nullptr; 2660 if (const NamedTypeConstraint *arg = findArg(op.getResults(), name)) 2661 return seenResultTypes.test(arg - op.result_begin()) ? arg : nullptr; 2662 if (const NamedAttribute *attr = findArg(op.getAttributes(), name)) 2663 return seenAttrs.count(attr) ? attr : nullptr; 2664 return nullptr; 2665 } 2666 2667 FailureOr<FormatElement *> 2668 OpFormatParser::parseVariableImpl(SMLoc loc, StringRef name, Context ctx) { 2669 // Check that the parsed argument is something actually registered on the op. 2670 // Attributes 2671 if (const NamedAttribute *attr = findArg(op.getAttributes(), name)) { 2672 if (ctx == TypeDirectiveContext) 2673 return emitError( 2674 loc, "attributes cannot be used as children to a `type` directive"); 2675 if (ctx == RefDirectiveContext) { 2676 if (!seenAttrs.count(attr)) 2677 return emitError(loc, "attribute '" + name + 2678 "' must be bound before it is referenced"); 2679 } else if (!seenAttrs.insert(attr)) { 2680 return emitError(loc, "attribute '" + name + "' is already bound"); 2681 } 2682 2683 return create<AttributeVariable>(attr); 2684 } 2685 // Operands 2686 if (const NamedTypeConstraint *operand = findArg(op.getOperands(), name)) { 2687 if (ctx == TopLevelContext || ctx == CustomDirectiveContext) { 2688 if (fmt.allOperands || !seenOperands.insert(operand).second) 2689 return emitError(loc, "operand '" + name + "' is already bound"); 2690 } else if (ctx == RefDirectiveContext && !seenOperands.count(operand)) { 2691 return emitError(loc, "operand '" + name + 2692 "' must be bound before it is referenced"); 2693 } 2694 return create<OperandVariable>(operand); 2695 } 2696 // Regions 2697 if (const NamedRegion *region = findArg(op.getRegions(), name)) { 2698 if (ctx == TopLevelContext || ctx == CustomDirectiveContext) { 2699 if (hasAllRegions || !seenRegions.insert(region).second) 2700 return emitError(loc, "region '" + name + "' is already bound"); 2701 } else if (ctx == RefDirectiveContext && !seenRegions.count(region)) { 2702 return emitError(loc, "region '" + name + 2703 "' must be bound before it is referenced"); 2704 } else { 2705 return emitError(loc, "regions can only be used at the top level"); 2706 } 2707 return create<RegionVariable>(region); 2708 } 2709 // Results. 2710 if (const auto *result = findArg(op.getResults(), name)) { 2711 if (ctx != TypeDirectiveContext) 2712 return emitError(loc, "result variables can can only be used as a child " 2713 "to a 'type' directive"); 2714 return create<ResultVariable>(result); 2715 } 2716 // Successors. 2717 if (const auto *successor = findArg(op.getSuccessors(), name)) { 2718 if (ctx == TopLevelContext || ctx == CustomDirectiveContext) { 2719 if (hasAllSuccessors || !seenSuccessors.insert(successor).second) 2720 return emitError(loc, "successor '" + name + "' is already bound"); 2721 } else if (ctx == RefDirectiveContext && !seenSuccessors.count(successor)) { 2722 return emitError(loc, "successor '" + name + 2723 "' must be bound before it is referenced"); 2724 } else { 2725 return emitError(loc, "successors can only be used at the top level"); 2726 } 2727 2728 return create<SuccessorVariable>(successor); 2729 } 2730 return emitError(loc, "expected variable to refer to an argument, region, " 2731 "result, or successor"); 2732 } 2733 2734 FailureOr<FormatElement *> 2735 OpFormatParser::parseDirectiveImpl(SMLoc loc, FormatToken::Kind kind, 2736 Context ctx) { 2737 switch (kind) { 2738 case FormatToken::kw_attr_dict: 2739 return parseAttrDictDirective(loc, ctx, 2740 /*withKeyword=*/false); 2741 case FormatToken::kw_attr_dict_w_keyword: 2742 return parseAttrDictDirective(loc, ctx, 2743 /*withKeyword=*/true); 2744 case FormatToken::kw_functional_type: 2745 return parseFunctionalTypeDirective(loc, ctx); 2746 case FormatToken::kw_operands: 2747 return parseOperandsDirective(loc, ctx); 2748 case FormatToken::kw_qualified: 2749 return parseQualifiedDirective(loc, ctx); 2750 case FormatToken::kw_regions: 2751 return parseRegionsDirective(loc, ctx); 2752 case FormatToken::kw_results: 2753 return parseResultsDirective(loc, ctx); 2754 case FormatToken::kw_successors: 2755 return parseSuccessorsDirective(loc, ctx); 2756 case FormatToken::kw_ref: 2757 return parseReferenceDirective(loc, ctx); 2758 case FormatToken::kw_type: 2759 return parseTypeDirective(loc, ctx); 2760 case FormatToken::kw_oilist: 2761 return parseOIListDirective(loc, ctx); 2762 2763 default: 2764 return emitError(loc, "unsupported directive kind"); 2765 } 2766 } 2767 2768 FailureOr<FormatElement *> 2769 OpFormatParser::parseAttrDictDirective(SMLoc loc, Context context, 2770 bool withKeyword) { 2771 if (context == TypeDirectiveContext) 2772 return emitError(loc, "'attr-dict' directive can only be used as a " 2773 "top-level directive"); 2774 2775 if (context == RefDirectiveContext) { 2776 if (!hasAttrDict) 2777 return emitError(loc, "'ref' of 'attr-dict' is not bound by a prior " 2778 "'attr-dict' directive"); 2779 2780 // Otherwise, this is a top-level context. 2781 } else { 2782 if (hasAttrDict) 2783 return emitError(loc, "'attr-dict' directive has already been seen"); 2784 hasAttrDict = true; 2785 } 2786 2787 return create<AttrDictDirective>(withKeyword); 2788 } 2789 2790 LogicalResult OpFormatParser::verifyCustomDirectiveArguments( 2791 SMLoc loc, ArrayRef<FormatElement *> arguments) { 2792 for (FormatElement *argument : arguments) { 2793 if (!isa<RefDirective, TypeDirective, AttrDictDirective, AttributeVariable, 2794 OperandVariable, RegionVariable, SuccessorVariable>(argument)) { 2795 // TODO: FormatElement should have location info attached. 2796 return emitError(loc, "only variables and types may be used as " 2797 "parameters to a custom directive"); 2798 } 2799 if (auto *type = dyn_cast<TypeDirective>(argument)) { 2800 if (!isa<OperandVariable, ResultVariable>(type->getArg())) { 2801 return emitError(loc, "type directives within a custom directive may " 2802 "only refer to variables"); 2803 } 2804 } 2805 } 2806 return success(); 2807 } 2808 2809 FailureOr<FormatElement *> 2810 OpFormatParser::parseFunctionalTypeDirective(SMLoc loc, Context context) { 2811 if (context != TopLevelContext) 2812 return emitError( 2813 loc, "'functional-type' is only valid as a top-level directive"); 2814 2815 // Parse the main operand. 2816 FailureOr<FormatElement *> inputs, results; 2817 if (failed(parseToken(FormatToken::l_paren, 2818 "expected '(' before argument list")) || 2819 failed(inputs = parseTypeDirectiveOperand(loc)) || 2820 failed(parseToken(FormatToken::comma, 2821 "expected ',' after inputs argument")) || 2822 failed(results = parseTypeDirectiveOperand(loc)) || 2823 failed( 2824 parseToken(FormatToken::r_paren, "expected ')' after argument list"))) 2825 return failure(); 2826 return create<FunctionalTypeDirective>(*inputs, *results); 2827 } 2828 2829 FailureOr<FormatElement *> 2830 OpFormatParser::parseOperandsDirective(SMLoc loc, Context context) { 2831 if (context == RefDirectiveContext) { 2832 if (!fmt.allOperands) 2833 return emitError(loc, "'ref' of 'operands' is not bound by a prior " 2834 "'operands' directive"); 2835 2836 } else if (context == TopLevelContext || context == CustomDirectiveContext) { 2837 if (fmt.allOperands || !seenOperands.empty()) 2838 return emitError(loc, "'operands' directive creates overlap in format"); 2839 fmt.allOperands = true; 2840 } 2841 return create<OperandsDirective>(); 2842 } 2843 2844 FailureOr<FormatElement *> 2845 OpFormatParser::parseReferenceDirective(SMLoc loc, Context context) { 2846 if (context != CustomDirectiveContext) 2847 return emitError(loc, "'ref' is only valid within a `custom` directive"); 2848 2849 FailureOr<FormatElement *> arg; 2850 if (failed(parseToken(FormatToken::l_paren, 2851 "expected '(' before argument list")) || 2852 failed(arg = parseElement(RefDirectiveContext)) || 2853 failed( 2854 parseToken(FormatToken::r_paren, "expected ')' after argument list"))) 2855 return failure(); 2856 2857 return create<RefDirective>(*arg); 2858 } 2859 2860 FailureOr<FormatElement *> 2861 OpFormatParser::parseRegionsDirective(SMLoc loc, Context context) { 2862 if (context == TypeDirectiveContext) 2863 return emitError(loc, "'regions' is only valid as a top-level directive"); 2864 if (context == RefDirectiveContext) { 2865 if (!hasAllRegions) 2866 return emitError(loc, "'ref' of 'regions' is not bound by a prior " 2867 "'regions' directive"); 2868 2869 // Otherwise, this is a TopLevel directive. 2870 } else { 2871 if (hasAllRegions || !seenRegions.empty()) 2872 return emitError(loc, "'regions' directive creates overlap in format"); 2873 hasAllRegions = true; 2874 } 2875 return create<RegionsDirective>(); 2876 } 2877 2878 FailureOr<FormatElement *> 2879 OpFormatParser::parseResultsDirective(SMLoc loc, Context context) { 2880 if (context != TypeDirectiveContext) 2881 return emitError(loc, "'results' directive can can only be used as a child " 2882 "to a 'type' directive"); 2883 return create<ResultsDirective>(); 2884 } 2885 2886 FailureOr<FormatElement *> 2887 OpFormatParser::parseSuccessorsDirective(SMLoc loc, Context context) { 2888 if (context == TypeDirectiveContext) 2889 return emitError(loc, 2890 "'successors' is only valid as a top-level directive"); 2891 if (context == RefDirectiveContext) { 2892 if (!hasAllSuccessors) 2893 return emitError(loc, "'ref' of 'successors' is not bound by a prior " 2894 "'successors' directive"); 2895 2896 // Otherwise, this is a TopLevel directive. 2897 } else { 2898 if (hasAllSuccessors || !seenSuccessors.empty()) 2899 return emitError(loc, "'successors' directive creates overlap in format"); 2900 hasAllSuccessors = true; 2901 } 2902 return create<SuccessorsDirective>(); 2903 } 2904 2905 FailureOr<FormatElement *> 2906 OpFormatParser::parseOIListDirective(SMLoc loc, Context context) { 2907 if (failed(parseToken(FormatToken::l_paren, 2908 "expected '(' before oilist argument list"))) 2909 return failure(); 2910 std::vector<FormatElement *> literalElements; 2911 std::vector<std::vector<FormatElement *>> parsingElements; 2912 do { 2913 FailureOr<FormatElement *> lelement = parseLiteral(context); 2914 if (failed(lelement)) 2915 return failure(); 2916 literalElements.push_back(*lelement); 2917 parsingElements.emplace_back(); 2918 std::vector<FormatElement *> &currParsingElements = parsingElements.back(); 2919 while (peekToken().getKind() != FormatToken::pipe && 2920 peekToken().getKind() != FormatToken::r_paren) { 2921 FailureOr<FormatElement *> pelement = parseElement(context); 2922 if (failed(pelement) || 2923 failed(verifyOIListParsingElement(*pelement, loc))) 2924 return failure(); 2925 currParsingElements.push_back(*pelement); 2926 } 2927 if (peekToken().getKind() == FormatToken::pipe) { 2928 consumeToken(); 2929 continue; 2930 } 2931 if (peekToken().getKind() == FormatToken::r_paren) { 2932 consumeToken(); 2933 break; 2934 } 2935 } while (true); 2936 2937 return create<OIListElement>(std::move(literalElements), 2938 std::move(parsingElements)); 2939 } 2940 2941 LogicalResult OpFormatParser::verifyOIListParsingElement(FormatElement *element, 2942 SMLoc loc) { 2943 SmallVector<VariableElement *> vars; 2944 collect(element, vars); 2945 for (VariableElement *elem : vars) { 2946 LogicalResult res = 2947 TypeSwitch<FormatElement *, LogicalResult>(elem) 2948 // Only optional attributes can be within an oilist parsing group. 2949 .Case([&](AttributeVariable *attrEle) { 2950 if (!attrEle->getVar()->attr.isOptional() && 2951 !attrEle->getVar()->attr.hasDefaultValue()) 2952 return emitError(loc, "only optional attributes can be used in " 2953 "an oilist parsing group"); 2954 return success(); 2955 }) 2956 // Only optional-like(i.e. variadic) operands can be within an 2957 // oilist parsing group. 2958 .Case([&](OperandVariable *ele) { 2959 if (!ele->getVar()->isVariableLength()) 2960 return emitError(loc, "only variable length operands can be " 2961 "used within an oilist parsing group"); 2962 return success(); 2963 }) 2964 // Only optional-like(i.e. variadic) results can be within an oilist 2965 // parsing group. 2966 .Case([&](ResultVariable *ele) { 2967 if (!ele->getVar()->isVariableLength()) 2968 return emitError(loc, "only variable length results can be " 2969 "used within an oilist parsing group"); 2970 return success(); 2971 }) 2972 .Case([&](RegionVariable *) { return success(); }) 2973 .Default([&](FormatElement *) { 2974 return emitError(loc, 2975 "only literals, types, and variables can be " 2976 "used within an oilist group"); 2977 }); 2978 if (failed(res)) 2979 return failure(); 2980 } 2981 return success(); 2982 } 2983 2984 FailureOr<FormatElement *> OpFormatParser::parseTypeDirective(SMLoc loc, 2985 Context context) { 2986 if (context == TypeDirectiveContext) 2987 return emitError(loc, "'type' cannot be used as a child of another `type`"); 2988 2989 bool isRefChild = context == RefDirectiveContext; 2990 FailureOr<FormatElement *> operand; 2991 if (failed(parseToken(FormatToken::l_paren, 2992 "expected '(' before argument list")) || 2993 failed(operand = parseTypeDirectiveOperand(loc, isRefChild)) || 2994 failed( 2995 parseToken(FormatToken::r_paren, "expected ')' after argument list"))) 2996 return failure(); 2997 2998 return create<TypeDirective>(*operand); 2999 } 3000 3001 FailureOr<FormatElement *> 3002 OpFormatParser::parseQualifiedDirective(SMLoc loc, Context context) { 3003 FailureOr<FormatElement *> element; 3004 if (failed(parseToken(FormatToken::l_paren, 3005 "expected '(' before argument list")) || 3006 failed(element = parseElement(context)) || 3007 failed( 3008 parseToken(FormatToken::r_paren, "expected ')' after argument list"))) 3009 return failure(); 3010 return TypeSwitch<FormatElement *, FailureOr<FormatElement *>>(*element) 3011 .Case<AttributeVariable, TypeDirective>([](auto *element) { 3012 element->setShouldBeQualified(); 3013 return element; 3014 }) 3015 .Default([&](auto *element) { 3016 return this->emitError( 3017 loc, 3018 "'qualified' directive expects an attribute or a `type` directive"); 3019 }); 3020 } 3021 3022 FailureOr<FormatElement *> 3023 OpFormatParser::parseTypeDirectiveOperand(SMLoc loc, bool isRefChild) { 3024 FailureOr<FormatElement *> result = parseElement(TypeDirectiveContext); 3025 if (failed(result)) 3026 return failure(); 3027 3028 FormatElement *element = *result; 3029 if (isa<LiteralElement>(element)) 3030 return emitError( 3031 loc, "'type' directive operand expects variable or directive operand"); 3032 3033 if (auto *var = dyn_cast<OperandVariable>(element)) { 3034 unsigned opIdx = var->getVar() - op.operand_begin(); 3035 if (!isRefChild && (fmt.allOperandTypes || seenOperandTypes.test(opIdx))) 3036 return emitError(loc, "'type' of '" + var->getVar()->name + 3037 "' is already bound"); 3038 if (isRefChild && !(fmt.allOperandTypes || seenOperandTypes.test(opIdx))) 3039 return emitError(loc, "'ref' of 'type($" + var->getVar()->name + 3040 ")' is not bound by a prior 'type' directive"); 3041 seenOperandTypes.set(opIdx); 3042 } else if (auto *var = dyn_cast<ResultVariable>(element)) { 3043 unsigned resIdx = var->getVar() - op.result_begin(); 3044 if (!isRefChild && (fmt.allResultTypes || seenResultTypes.test(resIdx))) 3045 return emitError(loc, "'type' of '" + var->getVar()->name + 3046 "' is already bound"); 3047 if (isRefChild && !(fmt.allResultTypes || seenResultTypes.test(resIdx))) 3048 return emitError(loc, "'ref' of 'type($" + var->getVar()->name + 3049 ")' is not bound by a prior 'type' directive"); 3050 seenResultTypes.set(resIdx); 3051 } else if (isa<OperandsDirective>(&*element)) { 3052 if (!isRefChild && (fmt.allOperandTypes || seenOperandTypes.any())) 3053 return emitError(loc, "'operands' 'type' is already bound"); 3054 if (isRefChild && !fmt.allOperandTypes) 3055 return emitError(loc, "'ref' of 'type(operands)' is not bound by a prior " 3056 "'type' directive"); 3057 fmt.allOperandTypes = true; 3058 } else if (isa<ResultsDirective>(&*element)) { 3059 if (!isRefChild && (fmt.allResultTypes || seenResultTypes.any())) 3060 return emitError(loc, "'results' 'type' is already bound"); 3061 if (isRefChild && !fmt.allResultTypes) 3062 return emitError(loc, "'ref' of 'type(results)' is not bound by a prior " 3063 "'type' directive"); 3064 fmt.allResultTypes = true; 3065 } else { 3066 return emitError(loc, "invalid argument to 'type' directive"); 3067 } 3068 return element; 3069 } 3070 3071 LogicalResult 3072 OpFormatParser::verifyOptionalGroupElements(SMLoc loc, 3073 ArrayRef<FormatElement *> elements, 3074 Optional<unsigned> anchorIndex) { 3075 for (auto &it : llvm::enumerate(elements)) { 3076 if (failed(verifyOptionalGroupElement( 3077 loc, it.value(), anchorIndex && *anchorIndex == it.index()))) 3078 return failure(); 3079 } 3080 return success(); 3081 } 3082 3083 LogicalResult OpFormatParser::verifyOptionalGroupElement(SMLoc loc, 3084 FormatElement *element, 3085 bool isAnchor) { 3086 return TypeSwitch<FormatElement *, LogicalResult>(element) 3087 // All attributes can be within the optional group, but only optional 3088 // attributes can be the anchor. 3089 .Case([&](AttributeVariable *attrEle) { 3090 if (isAnchor && !attrEle->getVar()->attr.isOptional()) 3091 return emitError(loc, "only optional attributes can be used to " 3092 "anchor an optional group"); 3093 return success(); 3094 }) 3095 // Only optional-like(i.e. variadic) operands can be within an optional 3096 // group. 3097 .Case([&](OperandVariable *ele) { 3098 if (!ele->getVar()->isVariableLength()) 3099 return emitError(loc, "only variable length operands can be used " 3100 "within an optional group"); 3101 return success(); 3102 }) 3103 // Only optional-like(i.e. variadic) results can be within an optional 3104 // group. 3105 .Case([&](ResultVariable *ele) { 3106 if (!ele->getVar()->isVariableLength()) 3107 return emitError(loc, "only variable length results can be used " 3108 "within an optional group"); 3109 return success(); 3110 }) 3111 .Case([&](RegionVariable *) { 3112 // TODO: When ODS has proper support for marking "optional" regions, add 3113 // a check here. 3114 return success(); 3115 }) 3116 .Case([&](TypeDirective *ele) { 3117 return verifyOptionalGroupElement(loc, ele->getArg(), 3118 /*isAnchor=*/false); 3119 }) 3120 .Case([&](FunctionalTypeDirective *ele) { 3121 if (failed(verifyOptionalGroupElement(loc, ele->getInputs(), 3122 /*isAnchor=*/false))) 3123 return failure(); 3124 return verifyOptionalGroupElement(loc, ele->getResults(), 3125 /*isAnchor=*/false); 3126 }) 3127 // Literals, whitespace, and custom directives may be used, but they can't 3128 // anchor the group. 3129 .Case<LiteralElement, WhitespaceElement, CustomDirective, 3130 FunctionalTypeDirective, OptionalElement>([&](FormatElement *) { 3131 if (isAnchor) 3132 return emitError(loc, "only variables and types can be used " 3133 "to anchor an optional group"); 3134 return success(); 3135 }) 3136 .Default([&](FormatElement *) { 3137 return emitError(loc, "only literals, types, and variables can be " 3138 "used within an optional group"); 3139 }); 3140 } 3141 3142 //===----------------------------------------------------------------------===// 3143 // Interface 3144 //===----------------------------------------------------------------------===// 3145 3146 void mlir::tblgen::generateOpFormat(const Operator &constOp, OpClass &opClass) { 3147 // TODO: Operator doesn't expose all necessary functionality via 3148 // the const interface. 3149 Operator &op = const_cast<Operator &>(constOp); 3150 if (!op.hasAssemblyFormat()) 3151 return; 3152 3153 // Parse the format description. 3154 llvm::SourceMgr mgr; 3155 mgr.AddNewSourceBuffer( 3156 llvm::MemoryBuffer::getMemBuffer(op.getAssemblyFormat()), SMLoc()); 3157 OperationFormat format(op); 3158 OpFormatParser parser(mgr, format, op); 3159 FailureOr<std::vector<FormatElement *>> elements = parser.parse(); 3160 if (failed(elements)) { 3161 // Exit the process if format errors are treated as fatal. 3162 if (formatErrorIsFatal) { 3163 // Invoke the interrupt handlers to run the file cleanup handlers. 3164 llvm::sys::RunInterruptHandlers(); 3165 std::exit(1); 3166 } 3167 return; 3168 } 3169 format.elements = std::move(*elements); 3170 3171 // Generate the printer and parser based on the parsed format. 3172 format.genParser(op, opClass); 3173 format.genPrinter(op, opClass); 3174 } 3175