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