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