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