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