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