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