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