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