1 //===- OpDefinitionsGen.cpp - MLIR op definitions 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 // OpDefinitionsGen uses the description of operations to generate C++ 10 // definitions for ops. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "OpFormatGen.h" 15 #include "OpGenHelpers.h" 16 #include "mlir/TableGen/CodeGenHelpers.h" 17 #include "mlir/TableGen/Format.h" 18 #include "mlir/TableGen/GenInfo.h" 19 #include "mlir/TableGen/Interfaces.h" 20 #include "mlir/TableGen/OpClass.h" 21 #include "mlir/TableGen/Operator.h" 22 #include "mlir/TableGen/SideEffects.h" 23 #include "mlir/TableGen/Trait.h" 24 #include "llvm/ADT/MapVector.h" 25 #include "llvm/ADT/Sequence.h" 26 #include "llvm/ADT/StringExtras.h" 27 #include "llvm/ADT/StringSet.h" 28 #include "llvm/Support/Signals.h" 29 #include "llvm/TableGen/Error.h" 30 #include "llvm/TableGen/Record.h" 31 #include "llvm/TableGen/TableGenBackend.h" 32 33 #define DEBUG_TYPE "mlir-tblgen-opdefgen" 34 35 using namespace llvm; 36 using namespace mlir; 37 using namespace mlir::tblgen; 38 39 static const char *const tblgenNamePrefix = "tblgen_"; 40 static const char *const generatedArgName = "odsArg"; 41 static const char *const odsBuilder = "odsBuilder"; 42 static const char *const builderOpState = "odsState"; 43 44 // The logic to calculate the actual value range for a declared operand/result 45 // of an op with variadic operands/results. Note that this logic is not for 46 // general use; it assumes all variadic operands/results must have the same 47 // number of values. 48 // 49 // {0}: The list of whether each declared operand/result is variadic. 50 // {1}: The total number of non-variadic operands/results. 51 // {2}: The total number of variadic operands/results. 52 // {3}: The total number of actual values. 53 // {4}: "operand" or "result". 54 const char *sameVariadicSizeValueRangeCalcCode = R"( 55 bool isVariadic[] = {{{0}}; 56 int prevVariadicCount = 0; 57 for (unsigned i = 0; i < index; ++i) 58 if (isVariadic[i]) ++prevVariadicCount; 59 60 // Calculate how many dynamic values a static variadic {4} corresponds to. 61 // This assumes all static variadic {4}s have the same dynamic value count. 62 int variadicSize = ({3} - {1}) / {2}; 63 // `index` passed in as the parameter is the static index which counts each 64 // {4} (variadic or not) as size 1. So here for each previous static variadic 65 // {4}, we need to offset by (variadicSize - 1) to get where the dynamic 66 // value pack for this static {4} starts. 67 int start = index + (variadicSize - 1) * prevVariadicCount; 68 int size = isVariadic[index] ? variadicSize : 1; 69 return {{start, size}; 70 )"; 71 72 // The logic to calculate the actual value range for a declared operand/result 73 // of an op with variadic operands/results. Note that this logic is assumes 74 // the op has an attribute specifying the size of each operand/result segment 75 // (variadic or not). 76 // 77 // {0}: The name of the attribute specifying the segment sizes. 78 const char *adapterSegmentSizeAttrInitCode = R"( 79 assert(odsAttrs && "missing segment size attribute for op"); 80 auto sizeAttr = odsAttrs.get("{0}").cast<::mlir::DenseIntElementsAttr>(); 81 )"; 82 const char *opSegmentSizeAttrInitCode = R"( 83 auto sizeAttr = (*this)->getAttr({0}).cast<::mlir::DenseIntElementsAttr>(); 84 )"; 85 const char *attrSizedSegmentValueRangeCalcCode = R"( 86 const uint32_t *sizeAttrValueIt = &*sizeAttr.value_begin<uint32_t>(); 87 if (sizeAttr.isSplat()) 88 return {*sizeAttrValueIt * index, *sizeAttrValueIt}; 89 90 unsigned start = 0; 91 for (unsigned i = 0; i < index; ++i) 92 start += sizeAttrValueIt[i]; 93 return {start, sizeAttrValueIt[index]}; 94 )"; 95 // The logic to calculate the actual value range for a declared operand 96 // of an op with variadic of variadic operands within the OpAdaptor. 97 // 98 // {0}: The name of the segment attribute. 99 // {1}: The index of the main operand. 100 const char *variadicOfVariadicAdaptorCalcCode = R"( 101 auto tblgenTmpOperands = getODSOperands({1}); 102 auto sizeAttrValues = {0}().getValues<uint32_t>(); 103 auto sizeAttrIt = sizeAttrValues.begin(); 104 105 ::llvm::SmallVector<::mlir::ValueRange> tblgenTmpOperandGroups; 106 for (int i = 0, e = ::llvm::size(sizeAttrValues); i < e; ++i, ++sizeAttrIt) {{ 107 tblgenTmpOperandGroups.push_back(tblgenTmpOperands.take_front(*sizeAttrIt)); 108 tblgenTmpOperands = tblgenTmpOperands.drop_front(*sizeAttrIt); 109 } 110 return tblgenTmpOperandGroups; 111 )"; 112 113 // The logic to build a range of either operand or result values. 114 // 115 // {0}: The begin iterator of the actual values. 116 // {1}: The call to generate the start and length of the value range. 117 const char *valueRangeReturnCode = R"( 118 auto valueRange = {1}; 119 return {{std::next({0}, valueRange.first), 120 std::next({0}, valueRange.first + valueRange.second)}; 121 )"; 122 123 const char *typeVerifierSignature = 124 "static ::mlir::LogicalResult {0}(::mlir::Operation *op, ::mlir::Type " 125 "type, ::llvm::StringRef valueKind, unsigned valueGroupStartIndex)"; 126 127 const char *typeVerifierErrorHandler = 128 " op->emitOpError(valueKind) << \" #\" << valueGroupStartIndex << \" must " 129 "be {0}, but got \" << type"; 130 131 static const char *const opCommentHeader = R"( 132 //===----------------------------------------------------------------------===// 133 // {0} {1} 134 //===----------------------------------------------------------------------===// 135 136 )"; 137 138 //===----------------------------------------------------------------------===// 139 // Utility structs and functions 140 //===----------------------------------------------------------------------===// 141 142 // Replaces all occurrences of `match` in `str` with `substitute`. 143 static std::string replaceAllSubstrs(std::string str, const std::string &match, 144 const std::string &substitute) { 145 std::string::size_type scanLoc = 0, matchLoc = std::string::npos; 146 while ((matchLoc = str.find(match, scanLoc)) != std::string::npos) { 147 str = str.replace(matchLoc, match.size(), substitute); 148 scanLoc = matchLoc + substitute.size(); 149 } 150 return str; 151 } 152 153 // Returns whether the record has a value of the given name that can be returned 154 // via getValueAsString. 155 static inline bool hasStringAttribute(const Record &record, 156 StringRef fieldName) { 157 auto valueInit = record.getValueInit(fieldName); 158 return isa<StringInit>(valueInit); 159 } 160 161 static std::string getArgumentName(const Operator &op, int index) { 162 const auto &operand = op.getOperand(index); 163 if (!operand.name.empty()) 164 return std::string(operand.name); 165 else 166 return std::string(formatv("{0}_{1}", generatedArgName, index)); 167 } 168 169 // Returns true if we can use unwrapped value for the given `attr` in builders. 170 static bool canUseUnwrappedRawValue(const tblgen::Attribute &attr) { 171 return attr.getReturnType() != attr.getStorageType() && 172 // We need to wrap the raw value into an attribute in the builder impl 173 // so we need to make sure that the attribute specifies how to do that. 174 !attr.getConstBuilderTemplate().empty(); 175 } 176 177 //===----------------------------------------------------------------------===// 178 // Op emitter 179 //===----------------------------------------------------------------------===// 180 181 namespace { 182 // Helper class to emit a record into the given output stream. 183 class OpEmitter { 184 public: 185 static void 186 emitDecl(const Operator &op, raw_ostream &os, 187 const StaticVerifierFunctionEmitter &staticVerifierEmitter); 188 static void 189 emitDef(const Operator &op, raw_ostream &os, 190 const StaticVerifierFunctionEmitter &staticVerifierEmitter); 191 192 private: 193 OpEmitter(const Operator &op, 194 const StaticVerifierFunctionEmitter &staticVerifierEmitter); 195 196 void emitDecl(raw_ostream &os); 197 void emitDef(raw_ostream &os); 198 199 // Generate methods for accessing the attribute names of this operation. 200 void genAttrNameGetters(); 201 202 // Generates the OpAsmOpInterface for this operation if possible. 203 void genOpAsmInterface(); 204 205 // Generates the `getOperationName` method for this op. 206 void genOpNameGetter(); 207 208 // Generates getters for the attributes. 209 void genAttrGetters(); 210 211 // Generates setter for the attributes. 212 void genAttrSetters(); 213 214 // Generates removers for optional attributes. 215 void genOptionalAttrRemovers(); 216 217 // Generates getters for named operands. 218 void genNamedOperandGetters(); 219 220 // Generates setters for named operands. 221 void genNamedOperandSetters(); 222 223 // Generates getters for named results. 224 void genNamedResultGetters(); 225 226 // Generates getters for named regions. 227 void genNamedRegionGetters(); 228 229 // Generates getters for named successors. 230 void genNamedSuccessorGetters(); 231 232 // Generates builder methods for the operation. 233 void genBuilder(); 234 235 // Generates the build() method that takes each operand/attribute 236 // as a stand-alone parameter. 237 void genSeparateArgParamBuilder(); 238 239 // Generates the build() method that takes each operand/attribute as a 240 // stand-alone parameter. The generated build() method uses first operand's 241 // type as all results' types. 242 void genUseOperandAsResultTypeSeparateParamBuilder(); 243 244 // Generates the build() method that takes all operands/attributes 245 // collectively as one parameter. The generated build() method uses first 246 // operand's type as all results' types. 247 void genUseOperandAsResultTypeCollectiveParamBuilder(); 248 249 // Generates the build() method that takes aggregate operands/attributes 250 // parameters. This build() method uses inferred types as result types. 251 // Requires: The type needs to be inferable via InferTypeOpInterface. 252 void genInferredTypeCollectiveParamBuilder(); 253 254 // Generates the build() method that takes each operand/attribute as a 255 // stand-alone parameter. The generated build() method uses first attribute's 256 // type as all result's types. 257 void genUseAttrAsResultTypeBuilder(); 258 259 // Generates the build() method that takes all result types collectively as 260 // one parameter. Similarly for operands and attributes. 261 void genCollectiveParamBuilder(); 262 263 // The kind of parameter to generate for result types in builders. 264 enum class TypeParamKind { 265 None, // No result type in parameter list. 266 Separate, // A separate parameter for each result type. 267 Collective, // An ArrayRef<Type> for all result types. 268 }; 269 270 // The kind of parameter to generate for attributes in builders. 271 enum class AttrParamKind { 272 WrappedAttr, // A wrapped MLIR Attribute instance. 273 UnwrappedValue, // A raw value without MLIR Attribute wrapper. 274 }; 275 276 // Builds the parameter list for build() method of this op. This method writes 277 // to `paramList` the comma-separated parameter list and updates 278 // `resultTypeNames` with the names for parameters for specifying result 279 // types. `inferredAttributes` is populated with any attributes that are 280 // elided from the build list. The given `typeParamKind` and `attrParamKind` 281 // controls how result types and attributes are placed in the parameter list. 282 void buildParamList(llvm::SmallVectorImpl<OpMethodParameter> ¶mList, 283 llvm::StringSet<> &inferredAttributes, 284 SmallVectorImpl<std::string> &resultTypeNames, 285 TypeParamKind typeParamKind, 286 AttrParamKind attrParamKind = AttrParamKind::WrappedAttr); 287 288 // Adds op arguments and regions into operation state for build() methods. 289 void 290 genCodeForAddingArgAndRegionForBuilder(OpMethodBody &body, 291 llvm::StringSet<> &inferredAttributes, 292 bool isRawValueAttr = false); 293 294 // Generates canonicalizer declaration for the operation. 295 void genCanonicalizerDecls(); 296 297 // Generates the folder declaration for the operation. 298 void genFolderDecls(); 299 300 // Generates the parser for the operation. 301 void genParser(); 302 303 // Generates the printer for the operation. 304 void genPrinter(); 305 306 // Generates verify method for the operation. 307 void genVerifier(); 308 309 // Generates verify statements for operands and results in the operation. 310 // The generated code will be attached to `body`. 311 void genOperandResultVerifier(OpMethodBody &body, 312 Operator::value_range values, 313 StringRef valueKind); 314 315 // Generates verify statements for regions in the operation. 316 // The generated code will be attached to `body`. 317 void genRegionVerifier(OpMethodBody &body); 318 319 // Generates verify statements for successors in the operation. 320 // The generated code will be attached to `body`. 321 void genSuccessorVerifier(OpMethodBody &body); 322 323 // Generates the traits used by the object. 324 void genTraits(); 325 326 // Generate the OpInterface methods for all interfaces. 327 void genOpInterfaceMethods(); 328 329 // Generate op interface methods for the given interface. 330 void genOpInterfaceMethods(const tblgen::InterfaceTrait *trait); 331 332 // Generate op interface method for the given interface method. If 333 // 'declaration' is true, generates a declaration, else a definition. 334 OpMethod *genOpInterfaceMethod(const tblgen::InterfaceMethod &method, 335 bool declaration = true); 336 337 // Generate the side effect interface methods. 338 void genSideEffectInterfaceMethods(); 339 340 // Generate the type inference interface methods. 341 void genTypeInterfaceMethods(); 342 343 private: 344 // The TableGen record for this op. 345 // TODO: OpEmitter should not have a Record directly, 346 // it should rather go through the Operator for better abstraction. 347 const Record &def; 348 349 // The wrapper operator class for querying information from this op. 350 Operator op; 351 352 // The C++ code builder for this op 353 OpClass opClass; 354 355 // The format context for verification code generation. 356 FmtContext verifyCtx; 357 358 // The emitter containing all of the locally emitted verification functions. 359 const StaticVerifierFunctionEmitter &staticVerifierEmitter; 360 361 // A map of attribute names (including implicit attributes) registered to the 362 // current operation, to the relative order in which they were registered. 363 llvm::MapVector<StringRef, unsigned> attributeNames; 364 }; 365 } // end anonymous namespace 366 367 // Populate the format context `ctx` with substitutions of attributes, operands 368 // and results. 369 // - attrGet corresponds to the name of the function to call to get value of 370 // attribute (the generated function call returns an Attribute); 371 // - operandGet corresponds to the name of the function with which to retrieve 372 // an operand (the generated function call returns an OperandRange); 373 // - resultGet corresponds to the name of the function to get an result (the 374 // generated function call returns a ValueRange); 375 static void populateSubstitutions(const Operator &op, const char *attrGet, 376 const char *operandGet, const char *resultGet, 377 FmtContext &ctx) { 378 // Populate substitutions for attributes and named operands. 379 for (const auto &namedAttr : op.getAttributes()) 380 ctx.addSubst(namedAttr.name, 381 formatv("{0}(\"{1}\")", attrGet, namedAttr.name)); 382 for (int i = 0, e = op.getNumOperands(); i < e; ++i) { 383 auto &value = op.getOperand(i); 384 if (value.name.empty()) 385 continue; 386 387 if (value.isVariadic()) 388 ctx.addSubst(value.name, formatv("{0}({1})", operandGet, i)); 389 else 390 ctx.addSubst(value.name, formatv("(*{0}({1}).begin())", operandGet, i)); 391 } 392 393 // Populate substitutions for results. 394 for (int i = 0, e = op.getNumResults(); i < e; ++i) { 395 auto &value = op.getResult(i); 396 if (value.name.empty()) 397 continue; 398 399 if (value.isVariadic()) 400 ctx.addSubst(value.name, formatv("{0}({1})", resultGet, i)); 401 else 402 ctx.addSubst(value.name, formatv("(*{0}({1}).begin())", resultGet, i)); 403 } 404 } 405 406 // Generate attribute verification. If emitVerificationRequiringOp is set then 407 // only verification for attributes whose value depend on op being known are 408 // emitted, else only verification that doesn't depend on the op being known are 409 // generated. 410 // - emitErrorPrefix is the prefix for the error emitting call which consists 411 // of the entire function call up to start of error message fragment; 412 // - emitVerificationRequiringOp specifies whether verification should be 413 // emitted for verification that require the op to exist; 414 static void genAttributeVerifier(const Operator &op, const char *attrGet, 415 const Twine &emitErrorPrefix, 416 bool emitVerificationRequiringOp, 417 FmtContext &ctx, OpMethodBody &body) { 418 for (const auto &namedAttr : op.getAttributes()) { 419 const auto &attr = namedAttr.attr; 420 if (attr.isDerivedAttr()) 421 continue; 422 423 auto attrName = namedAttr.name; 424 bool allowMissingAttr = attr.hasDefaultValue() || attr.isOptional(); 425 auto attrPred = attr.getPredicate(); 426 auto condition = attrPred.isNull() ? "" : attrPred.getCondition(); 427 // There is a condition to emit only if the use of $_op and whether to 428 // emit verifications for op matches. 429 bool hasConditionToEmit = (!(condition.find("$_op") != StringRef::npos) ^ 430 emitVerificationRequiringOp); 431 432 // Prefix with `tblgen_` to avoid hiding the attribute accessor. 433 auto varName = tblgenNamePrefix + attrName; 434 435 // If the attribute is 436 // 1. Required (not allowed missing) and not in op verification, or 437 // 2. Has a condition that will get verified 438 // then the variable will be used. 439 // 440 // Therefore, for optional attributes whose verification requires that an 441 // op already exists for verification/emitVerificationRequiringOp is set 442 // has nothing that can be verified here. 443 if ((allowMissingAttr || emitVerificationRequiringOp) && 444 !hasConditionToEmit) 445 continue; 446 447 body << formatv(" {\n auto {0} = {1}(\"{2}\");\n", varName, attrGet, 448 attrName); 449 450 if (!emitVerificationRequiringOp && !allowMissingAttr) { 451 body << " if (!" << varName << ") return " << emitErrorPrefix 452 << "\"requires attribute '" << attrName << "'\");\n"; 453 } 454 455 if (!hasConditionToEmit) { 456 body << " }\n"; 457 continue; 458 } 459 460 if (allowMissingAttr) { 461 // If the attribute has a default value, then only verify the predicate if 462 // set. This does effectively assume that the default value is valid. 463 // TODO: verify the debug value is valid (perhaps in debug mode only). 464 body << " if (" << varName << ") {\n"; 465 } 466 467 body << tgfmt(" if (!($0)) return $1\"attribute '$2' " 468 "failed to satisfy constraint: $3\");\n", 469 /*ctx=*/nullptr, tgfmt(condition, &ctx.withSelf(varName)), 470 emitErrorPrefix, attrName, attr.getSummary()); 471 if (allowMissingAttr) 472 body << " }\n"; 473 body << " }\n"; 474 } 475 } 476 477 OpEmitter::OpEmitter(const Operator &op, 478 const StaticVerifierFunctionEmitter &staticVerifierEmitter) 479 : def(op.getDef()), op(op), 480 opClass(op.getCppClassName(), op.getExtraClassDeclaration()), 481 staticVerifierEmitter(staticVerifierEmitter) { 482 verifyCtx.withOp("(*this->getOperation())"); 483 verifyCtx.addSubst("_ctxt", "this->getOperation()->getContext()"); 484 485 genTraits(); 486 487 // Generate C++ code for various op methods. The order here determines the 488 // methods in the generated file. 489 genAttrNameGetters(); 490 genOpAsmInterface(); 491 genOpNameGetter(); 492 genNamedOperandGetters(); 493 genNamedOperandSetters(); 494 genNamedResultGetters(); 495 genNamedRegionGetters(); 496 genNamedSuccessorGetters(); 497 genAttrGetters(); 498 genAttrSetters(); 499 genOptionalAttrRemovers(); 500 genBuilder(); 501 genParser(); 502 genPrinter(); 503 genVerifier(); 504 genCanonicalizerDecls(); 505 genFolderDecls(); 506 genTypeInterfaceMethods(); 507 genOpInterfaceMethods(); 508 generateOpFormat(op, opClass); 509 genSideEffectInterfaceMethods(); 510 } 511 void OpEmitter::emitDecl( 512 const Operator &op, raw_ostream &os, 513 const StaticVerifierFunctionEmitter &staticVerifierEmitter) { 514 OpEmitter(op, staticVerifierEmitter).emitDecl(os); 515 } 516 517 void OpEmitter::emitDef( 518 const Operator &op, raw_ostream &os, 519 const StaticVerifierFunctionEmitter &staticVerifierEmitter) { 520 OpEmitter(op, staticVerifierEmitter).emitDef(os); 521 } 522 523 void OpEmitter::emitDecl(raw_ostream &os) { opClass.writeDeclTo(os); } 524 525 void OpEmitter::emitDef(raw_ostream &os) { opClass.writeDefTo(os); } 526 527 void OpEmitter::genAttrNameGetters() { 528 // Enumerate the attribute names of this op, assigning each a relative 529 // ordering. 530 auto addAttrName = [&](StringRef name) { 531 unsigned index = attributeNames.size(); 532 attributeNames.insert({name, index}); 533 }; 534 for (const NamedAttribute &namedAttr : op.getAttributes()) 535 addAttrName(namedAttr.name); 536 // Include key attributes from several traits as implicitly registered. 537 if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) 538 addAttrName("operand_segment_sizes"); 539 if (op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) 540 addAttrName("result_segment_sizes"); 541 542 // Emit the getAttributeNames method. 543 { 544 auto *method = opClass.addMethodAndPrune( 545 "::llvm::ArrayRef<::llvm::StringRef>", "getAttributeNames", 546 OpMethod::Property(OpMethod::MP_Static | OpMethod::MP_Inline)); 547 auto &body = method->body(); 548 if (attributeNames.empty()) { 549 body << " return {};"; 550 } else { 551 body << " static ::llvm::StringRef attrNames[] = {"; 552 llvm::interleaveComma(llvm::make_first_range(attributeNames), body, 553 [&](StringRef attrName) { 554 body << "::llvm::StringRef(\"" << attrName 555 << "\")"; 556 }); 557 body << "};\n return ::llvm::makeArrayRef(attrNames);"; 558 } 559 } 560 if (attributeNames.empty()) 561 return; 562 563 // Emit the getAttributeNameForIndex methods. 564 { 565 auto *method = opClass.addMethodAndPrune( 566 "::mlir::Identifier", "getAttributeNameForIndex", 567 OpMethod::Property(OpMethod::MP_Private | OpMethod::MP_Inline), 568 "unsigned", "index"); 569 method->body() 570 << " return getAttributeNameForIndex((*this)->getName(), index);"; 571 } 572 { 573 auto *method = opClass.addMethodAndPrune( 574 "::mlir::Identifier", "getAttributeNameForIndex", 575 OpMethod::Property(OpMethod::MP_Private | OpMethod::MP_Inline | 576 OpMethod::MP_Static), 577 "::mlir::OperationName name, unsigned index"); 578 method->body() << "assert(index < " << attributeNames.size() 579 << " && \"invalid attribute index\");\n" 580 " return name.getAbstractOperation()" 581 "->getAttributeNames()[index];"; 582 } 583 584 // Generate the <attr>AttrName methods, that expose the attribute names to 585 // users. 586 const char *attrNameMethodBody = " return getAttributeNameForIndex({0});"; 587 for (const std::pair<StringRef, unsigned> &attrIt : attributeNames) { 588 std::string methodName = (attrIt.first + "AttrName").str(); 589 590 // Generate the non-static variant. 591 { 592 auto *method = 593 opClass.addMethodAndPrune("::mlir::Identifier", methodName, 594 OpMethod::Property(OpMethod::MP_Inline)); 595 method->body() << llvm::formatv(attrNameMethodBody, attrIt.second).str(); 596 } 597 598 // Generate the static variant. 599 { 600 auto *method = opClass.addMethodAndPrune( 601 "::mlir::Identifier", methodName, 602 OpMethod::Property(OpMethod::MP_Inline | OpMethod::MP_Static), 603 "::mlir::OperationName", "name"); 604 method->body() << llvm::formatv(attrNameMethodBody, 605 "name, " + Twine(attrIt.second)) 606 .str(); 607 } 608 } 609 } 610 611 void OpEmitter::genAttrGetters() { 612 FmtContext fctx; 613 fctx.withBuilder("::mlir::Builder((*this)->getContext())"); 614 615 // Emit the derived attribute body. 616 auto emitDerivedAttr = [&](StringRef name, Attribute attr) { 617 if (auto *method = opClass.addMethodAndPrune(attr.getReturnType(), name)) 618 method->body() << " " << attr.getDerivedCodeBody() << "\n"; 619 }; 620 621 // Emit with return type specified. 622 auto emitAttrWithReturnType = [&](StringRef name, Attribute attr) { 623 auto *method = opClass.addMethodAndPrune(attr.getReturnType(), name); 624 auto &body = method->body(); 625 body << " auto attr = " << name << "Attr();\n"; 626 if (attr.hasDefaultValue()) { 627 // Returns the default value if not set. 628 // TODO: this is inefficient, we are recreating the attribute for every 629 // call. This should be set instead. 630 std::string defaultValue = std::string( 631 tgfmt(attr.getConstBuilderTemplate(), &fctx, attr.getDefaultValue())); 632 body << " if (!attr)\n return " 633 << tgfmt(attr.getConvertFromStorageCall(), 634 &fctx.withSelf(defaultValue)) 635 << ";\n"; 636 } 637 body << " return " 638 << tgfmt(attr.getConvertFromStorageCall(), &fctx.withSelf("attr")) 639 << ";\n"; 640 }; 641 642 // Generate raw named accessor type. This is a wrapper class that allows 643 // referring to the attributes via accessors instead of having to use 644 // the string interface for better compile time verification. 645 auto emitAttrWithStorageType = [&](StringRef name, Attribute attr) { 646 auto *method = 647 opClass.addMethodAndPrune(attr.getStorageType(), (name + "Attr").str()); 648 if (!method) 649 return; 650 auto &body = method->body(); 651 body << " return (*this)->getAttr(" << name << "AttrName()).template "; 652 if (attr.isOptional() || attr.hasDefaultValue()) 653 body << "dyn_cast_or_null<"; 654 else 655 body << "cast<"; 656 body << attr.getStorageType() << ">();"; 657 }; 658 659 for (const NamedAttribute &namedAttr : op.getAttributes()) { 660 if (namedAttr.attr.isDerivedAttr()) { 661 emitDerivedAttr(namedAttr.name, namedAttr.attr); 662 } else { 663 emitAttrWithStorageType(namedAttr.name, namedAttr.attr); 664 emitAttrWithReturnType(namedAttr.name, namedAttr.attr); 665 } 666 } 667 668 auto derivedAttrs = make_filter_range(op.getAttributes(), 669 [](const NamedAttribute &namedAttr) { 670 return namedAttr.attr.isDerivedAttr(); 671 }); 672 if (!derivedAttrs.empty()) { 673 opClass.addTrait("::mlir::DerivedAttributeOpInterface::Trait"); 674 // Generate helper method to query whether a named attribute is a derived 675 // attribute. This enables, for example, avoiding adding an attribute that 676 // overlaps with a derived attribute. 677 { 678 auto *method = opClass.addMethodAndPrune("bool", "isDerivedAttribute", 679 OpMethod::MP_Static, 680 "::llvm::StringRef", "name"); 681 auto &body = method->body(); 682 for (auto namedAttr : derivedAttrs) 683 body << " if (name == \"" << namedAttr.name << "\") return true;\n"; 684 body << " return false;"; 685 } 686 // Generate method to materialize derived attributes as a DictionaryAttr. 687 { 688 auto *method = opClass.addMethodAndPrune("::mlir::DictionaryAttr", 689 "materializeDerivedAttributes"); 690 auto &body = method->body(); 691 692 auto nonMaterializable = 693 make_filter_range(derivedAttrs, [](const NamedAttribute &namedAttr) { 694 return namedAttr.attr.getConvertFromStorageCall().empty(); 695 }); 696 if (!nonMaterializable.empty()) { 697 std::string attrs; 698 llvm::raw_string_ostream os(attrs); 699 interleaveComma(nonMaterializable, os, 700 [&](const NamedAttribute &attr) { os << attr.name; }); 701 PrintWarning( 702 op.getLoc(), 703 formatv( 704 "op has non-materializable derived attributes '{0}', skipping", 705 os.str())); 706 body << formatv(" emitOpError(\"op has non-materializable derived " 707 "attributes '{0}'\");\n", 708 attrs); 709 body << " return nullptr;"; 710 return; 711 } 712 713 body << " ::mlir::MLIRContext* ctx = getContext();\n"; 714 body << " ::mlir::Builder odsBuilder(ctx); (void)odsBuilder;\n"; 715 body << " return ::mlir::DictionaryAttr::get("; 716 body << " ctx, {\n"; 717 interleave( 718 derivedAttrs, body, 719 [&](const NamedAttribute &namedAttr) { 720 auto tmpl = namedAttr.attr.getConvertFromStorageCall(); 721 body << " {" << namedAttr.name << "AttrName(),\n" 722 << tgfmt(tmpl, &fctx.withSelf(namedAttr.name + "()") 723 .withBuilder("odsBuilder") 724 .addSubst("_ctx", "ctx")) 725 << "}"; 726 }, 727 ",\n"); 728 body << "});"; 729 } 730 } 731 } 732 733 void OpEmitter::genAttrSetters() { 734 // Generate raw named setter type. This is a wrapper class that allows setting 735 // to the attributes via setters instead of having to use the string interface 736 // for better compile time verification. 737 auto emitAttrWithStorageType = [&](StringRef name, Attribute attr) { 738 auto *method = opClass.addMethodAndPrune("void", (name + "Attr").str(), 739 attr.getStorageType(), "attr"); 740 if (method) 741 method->body() << " (*this)->setAttr(" << name << "AttrName(), attr);"; 742 }; 743 744 for (const NamedAttribute &namedAttr : op.getAttributes()) 745 if (!namedAttr.attr.isDerivedAttr()) 746 emitAttrWithStorageType(namedAttr.name, namedAttr.attr); 747 } 748 749 void OpEmitter::genOptionalAttrRemovers() { 750 // Generate methods for removing optional attributes, instead of having to 751 // use the string interface. Enables better compile time verification. 752 auto emitRemoveAttr = [&](StringRef name) { 753 auto upperInitial = name.take_front().upper(); 754 auto suffix = name.drop_front(); 755 auto *method = opClass.addMethodAndPrune( 756 "::mlir::Attribute", ("remove" + upperInitial + suffix + "Attr").str()); 757 if (!method) 758 return; 759 method->body() << " return (*this)->removeAttr(" << name << "AttrName());"; 760 }; 761 762 for (const NamedAttribute &namedAttr : op.getAttributes()) 763 if (namedAttr.attr.isOptional()) 764 emitRemoveAttr(namedAttr.name); 765 } 766 767 // Generates the code to compute the start and end index of an operand or result 768 // range. 769 template <typename RangeT> 770 static void 771 generateValueRangeStartAndEnd(Class &opClass, StringRef methodName, 772 int numVariadic, int numNonVariadic, 773 StringRef rangeSizeCall, bool hasAttrSegmentSize, 774 StringRef sizeAttrInit, RangeT &&odsValues) { 775 auto *method = opClass.addMethodAndPrune("std::pair<unsigned, unsigned>", 776 methodName, "unsigned", "index"); 777 if (!method) 778 return; 779 auto &body = method->body(); 780 if (numVariadic == 0) { 781 body << " return {index, 1};\n"; 782 } else if (hasAttrSegmentSize) { 783 body << sizeAttrInit << attrSizedSegmentValueRangeCalcCode; 784 } else { 785 // Because the op can have arbitrarily interleaved variadic and non-variadic 786 // operands, we need to embed a list in the "sink" getter method for 787 // calculation at run-time. 788 llvm::SmallVector<StringRef, 4> isVariadic; 789 isVariadic.reserve(llvm::size(odsValues)); 790 for (auto &it : odsValues) 791 isVariadic.push_back(it.isVariableLength() ? "true" : "false"); 792 std::string isVariadicList = llvm::join(isVariadic, ", "); 793 body << formatv(sameVariadicSizeValueRangeCalcCode, isVariadicList, 794 numNonVariadic, numVariadic, rangeSizeCall, "operand"); 795 } 796 } 797 798 // Generates the named operand getter methods for the given Operator `op` and 799 // puts them in `opClass`. Uses `rangeType` as the return type of getters that 800 // return a range of operands (individual operands are `Value ` and each 801 // element in the range must also be `Value `); use `rangeBeginCall` to get 802 // an iterator to the beginning of the operand range; use `rangeSizeCall` to 803 // obtain the number of operands. `getOperandCallPattern` contains the code 804 // necessary to obtain a single operand whose position will be substituted 805 // instead of 806 // "{0}" marker in the pattern. Note that the pattern should work for any kind 807 // of ops, in particular for one-operand ops that may not have the 808 // `getOperand(unsigned)` method. 809 static void generateNamedOperandGetters(const Operator &op, Class &opClass, 810 bool isAdaptor, StringRef sizeAttrInit, 811 StringRef rangeType, 812 StringRef rangeBeginCall, 813 StringRef rangeSizeCall, 814 StringRef getOperandCallPattern) { 815 const int numOperands = op.getNumOperands(); 816 const int numVariadicOperands = op.getNumVariableLengthOperands(); 817 const int numNormalOperands = numOperands - numVariadicOperands; 818 819 const auto *sameVariadicSize = 820 op.getTrait("::mlir::OpTrait::SameVariadicOperandSize"); 821 const auto *attrSizedOperands = 822 op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments"); 823 824 if (numVariadicOperands > 1 && !sameVariadicSize && !attrSizedOperands) { 825 PrintFatalError(op.getLoc(), "op has multiple variadic operands but no " 826 "specification over their sizes"); 827 } 828 829 if (numVariadicOperands < 2 && attrSizedOperands) { 830 PrintFatalError(op.getLoc(), "op must have at least two variadic operands " 831 "to use 'AttrSizedOperandSegments' trait"); 832 } 833 834 if (attrSizedOperands && sameVariadicSize) { 835 PrintFatalError(op.getLoc(), 836 "op cannot have both 'AttrSizedOperandSegments' and " 837 "'SameVariadicOperandSize' traits"); 838 } 839 840 // First emit a few "sink" getter methods upon which we layer all nicer named 841 // getter methods. 842 generateValueRangeStartAndEnd(opClass, "getODSOperandIndexAndLength", 843 numVariadicOperands, numNormalOperands, 844 rangeSizeCall, attrSizedOperands, sizeAttrInit, 845 const_cast<Operator &>(op).getOperands()); 846 847 auto *m = opClass.addMethodAndPrune(rangeType, "getODSOperands", "unsigned", 848 "index"); 849 auto &body = m->body(); 850 body << formatv(valueRangeReturnCode, rangeBeginCall, 851 "getODSOperandIndexAndLength(index)"); 852 853 // Then we emit nicer named getter methods by redirecting to the "sink" getter 854 // method. 855 for (int i = 0; i != numOperands; ++i) { 856 const auto &operand = op.getOperand(i); 857 if (operand.name.empty()) 858 continue; 859 if (operand.isOptional()) { 860 m = opClass.addMethodAndPrune("::mlir::Value", operand.name); 861 m->body() 862 << " auto operands = getODSOperands(" << i << ");\n" 863 << " return operands.empty() ? ::mlir::Value() : *operands.begin();"; 864 } else if (operand.isVariadicOfVariadic()) { 865 StringRef segmentAttr = 866 operand.constraint.getVariadicOfVariadicSegmentSizeAttr(); 867 if (isAdaptor) { 868 m = opClass.addMethodAndPrune("::llvm::SmallVector<::mlir::ValueRange>", 869 operand.name); 870 m->body() << llvm::formatv(variadicOfVariadicAdaptorCalcCode, 871 segmentAttr, i); 872 continue; 873 } 874 875 m = opClass.addMethodAndPrune("::mlir::OperandRangeRange", operand.name); 876 m->body() << " return getODSOperands(" << i << ").split(" << segmentAttr 877 << "Attr());"; 878 } else if (operand.isVariadic()) { 879 m = opClass.addMethodAndPrune(rangeType, operand.name); 880 m->body() << " return getODSOperands(" << i << ");"; 881 } else { 882 m = opClass.addMethodAndPrune("::mlir::Value", operand.name); 883 m->body() << " return *getODSOperands(" << i << ").begin();"; 884 } 885 } 886 } 887 888 void OpEmitter::genNamedOperandGetters() { 889 // Build the code snippet used for initializing the operand_segment_sizes 890 // array. 891 std::string attrSizeInitCode; 892 if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) { 893 attrSizeInitCode = 894 formatv(opSegmentSizeAttrInitCode, "operand_segment_sizesAttrName()") 895 .str(); 896 } 897 898 generateNamedOperandGetters( 899 op, opClass, 900 /*isAdaptor=*/false, 901 /*sizeAttrInit=*/attrSizeInitCode, 902 /*rangeType=*/"::mlir::Operation::operand_range", 903 /*rangeBeginCall=*/"getOperation()->operand_begin()", 904 /*rangeSizeCall=*/"getOperation()->getNumOperands()", 905 /*getOperandCallPattern=*/"getOperation()->getOperand({0})"); 906 } 907 908 void OpEmitter::genNamedOperandSetters() { 909 auto *attrSizedOperands = 910 op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments"); 911 for (int i = 0, e = op.getNumOperands(); i != e; ++i) { 912 const auto &operand = op.getOperand(i); 913 if (operand.name.empty()) 914 continue; 915 auto *m = opClass.addMethodAndPrune(operand.isVariadicOfVariadic() 916 ? "::mlir::MutableOperandRangeRange" 917 : "::mlir::MutableOperandRange", 918 (operand.name + "Mutable").str()); 919 auto &body = m->body(); 920 body << " auto range = getODSOperandIndexAndLength(" << i << ");\n" 921 << " auto mutableRange = ::mlir::MutableOperandRange(getOperation(), " 922 "range.first, range.second"; 923 if (attrSizedOperands) 924 body << ", ::mlir::MutableOperandRange::OperandSegment(" << i 925 << "u, *getOperation()->getAttrDictionary().getNamed(" 926 "operand_segment_sizesAttrName()))"; 927 body << ");\n"; 928 929 // If this operand is a nested variadic, we split the range into a 930 // MutableOperandRangeRange that provides a range over all of the 931 // sub-ranges. 932 if (operand.isVariadicOfVariadic()) { 933 body << " return " 934 "mutableRange.split(*(*this)->getAttrDictionary().getNamed(" 935 << operand.constraint.getVariadicOfVariadicSegmentSizeAttr() 936 << "AttrName()));\n"; 937 } else { 938 // Otherwise, we use the full range directly. 939 body << " return mutableRange;\n"; 940 } 941 } 942 } 943 944 void OpEmitter::genNamedResultGetters() { 945 const int numResults = op.getNumResults(); 946 const int numVariadicResults = op.getNumVariableLengthResults(); 947 const int numNormalResults = numResults - numVariadicResults; 948 949 // If we have more than one variadic results, we need more complicated logic 950 // to calculate the value range for each result. 951 952 const auto *sameVariadicSize = 953 op.getTrait("::mlir::OpTrait::SameVariadicResultSize"); 954 const auto *attrSizedResults = 955 op.getTrait("::mlir::OpTrait::AttrSizedResultSegments"); 956 957 if (numVariadicResults > 1 && !sameVariadicSize && !attrSizedResults) { 958 PrintFatalError(op.getLoc(), "op has multiple variadic results but no " 959 "specification over their sizes"); 960 } 961 962 if (numVariadicResults < 2 && attrSizedResults) { 963 PrintFatalError(op.getLoc(), "op must have at least two variadic results " 964 "to use 'AttrSizedResultSegments' trait"); 965 } 966 967 if (attrSizedResults && sameVariadicSize) { 968 PrintFatalError(op.getLoc(), 969 "op cannot have both 'AttrSizedResultSegments' and " 970 "'SameVariadicResultSize' traits"); 971 } 972 973 // Build the initializer string for the result segment size attribute. 974 std::string attrSizeInitCode; 975 if (attrSizedResults) { 976 attrSizeInitCode = 977 formatv(opSegmentSizeAttrInitCode, "result_segment_sizesAttrName()") 978 .str(); 979 } 980 981 generateValueRangeStartAndEnd( 982 opClass, "getODSResultIndexAndLength", numVariadicResults, 983 numNormalResults, "getOperation()->getNumResults()", attrSizedResults, 984 attrSizeInitCode, op.getResults()); 985 986 auto *m = opClass.addMethodAndPrune("::mlir::Operation::result_range", 987 "getODSResults", "unsigned", "index"); 988 m->body() << formatv(valueRangeReturnCode, "getOperation()->result_begin()", 989 "getODSResultIndexAndLength(index)"); 990 991 for (int i = 0; i != numResults; ++i) { 992 const auto &result = op.getResult(i); 993 if (result.name.empty()) 994 continue; 995 if (result.isOptional()) { 996 m = opClass.addMethodAndPrune("::mlir::Value", result.name); 997 m->body() 998 << " auto results = getODSResults(" << i << ");\n" 999 << " return results.empty() ? ::mlir::Value() : *results.begin();"; 1000 } else if (result.isVariadic()) { 1001 m = opClass.addMethodAndPrune("::mlir::Operation::result_range", 1002 result.name); 1003 m->body() << " return getODSResults(" << i << ");"; 1004 } else { 1005 m = opClass.addMethodAndPrune("::mlir::Value", result.name); 1006 m->body() << " return *getODSResults(" << i << ").begin();"; 1007 } 1008 } 1009 } 1010 1011 void OpEmitter::genNamedRegionGetters() { 1012 unsigned numRegions = op.getNumRegions(); 1013 for (unsigned i = 0; i < numRegions; ++i) { 1014 const auto ®ion = op.getRegion(i); 1015 if (region.name.empty()) 1016 continue; 1017 1018 // Generate the accessors for a variadic region. 1019 if (region.isVariadic()) { 1020 auto *m = opClass.addMethodAndPrune( 1021 "::mlir::MutableArrayRef<::mlir::Region>", region.name); 1022 m->body() << formatv(" return (*this)->getRegions().drop_front({0});", 1023 i); 1024 continue; 1025 } 1026 1027 auto *m = opClass.addMethodAndPrune("::mlir::Region &", region.name); 1028 m->body() << formatv(" return (*this)->getRegion({0});", i); 1029 } 1030 } 1031 1032 void OpEmitter::genNamedSuccessorGetters() { 1033 unsigned numSuccessors = op.getNumSuccessors(); 1034 for (unsigned i = 0; i < numSuccessors; ++i) { 1035 const NamedSuccessor &successor = op.getSuccessor(i); 1036 if (successor.name.empty()) 1037 continue; 1038 1039 // Generate the accessors for a variadic successor list. 1040 if (successor.isVariadic()) { 1041 auto *m = 1042 opClass.addMethodAndPrune("::mlir::SuccessorRange", successor.name); 1043 m->body() << formatv( 1044 " return {std::next((*this)->successor_begin(), {0}), " 1045 "(*this)->successor_end()};", 1046 i); 1047 continue; 1048 } 1049 1050 auto *m = opClass.addMethodAndPrune("::mlir::Block *", successor.name); 1051 m->body() << formatv(" return (*this)->getSuccessor({0});", i); 1052 } 1053 } 1054 1055 static bool canGenerateUnwrappedBuilder(Operator &op) { 1056 // If this op does not have native attributes at all, return directly to avoid 1057 // redefining builders. 1058 if (op.getNumNativeAttributes() == 0) 1059 return false; 1060 1061 bool canGenerate = false; 1062 // We are generating builders that take raw values for attributes. We need to 1063 // make sure the native attributes have a meaningful "unwrapped" value type 1064 // different from the wrapped mlir::Attribute type to avoid redefining 1065 // builders. This checks for the op has at least one such native attribute. 1066 for (int i = 0, e = op.getNumNativeAttributes(); i < e; ++i) { 1067 NamedAttribute &namedAttr = op.getAttribute(i); 1068 if (canUseUnwrappedRawValue(namedAttr.attr)) { 1069 canGenerate = true; 1070 break; 1071 } 1072 } 1073 return canGenerate; 1074 } 1075 1076 static bool canInferType(Operator &op) { 1077 return op.getTrait("::mlir::InferTypeOpInterface::Trait") && 1078 op.getNumRegions() == 0; 1079 } 1080 1081 void OpEmitter::genSeparateArgParamBuilder() { 1082 SmallVector<AttrParamKind, 2> attrBuilderType; 1083 attrBuilderType.push_back(AttrParamKind::WrappedAttr); 1084 if (canGenerateUnwrappedBuilder(op)) 1085 attrBuilderType.push_back(AttrParamKind::UnwrappedValue); 1086 1087 // Emit with separate builders with or without unwrapped attributes and/or 1088 // inferring result type. 1089 auto emit = [&](AttrParamKind attrType, TypeParamKind paramKind, 1090 bool inferType) { 1091 llvm::SmallVector<OpMethodParameter, 4> paramList; 1092 llvm::SmallVector<std::string, 4> resultNames; 1093 llvm::StringSet<> inferredAttributes; 1094 buildParamList(paramList, inferredAttributes, resultNames, paramKind, 1095 attrType); 1096 1097 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1098 std::move(paramList)); 1099 // If the builder is redundant, skip generating the method. 1100 if (!m) 1101 return; 1102 auto &body = m->body(); 1103 genCodeForAddingArgAndRegionForBuilder(body, inferredAttributes, 1104 /*isRawValueAttr=*/attrType == 1105 AttrParamKind::UnwrappedValue); 1106 1107 // Push all result types to the operation state 1108 1109 if (inferType) { 1110 // Generate builder that infers type too. 1111 // TODO: Subsume this with general checking if type can be 1112 // inferred automatically. 1113 // TODO: Expand to handle regions. 1114 body << formatv(R"( 1115 ::llvm::SmallVector<::mlir::Type, 2> inferredReturnTypes; 1116 if (::mlir::succeeded({0}::inferReturnTypes(odsBuilder.getContext(), 1117 {1}.location, {1}.operands, 1118 {1}.attributes.getDictionary({1}.getContext()), 1119 /*regions=*/{{}, inferredReturnTypes))) 1120 {1}.addTypes(inferredReturnTypes); 1121 else 1122 ::llvm::report_fatal_error("Failed to infer result type(s).");)", 1123 opClass.getClassName(), builderOpState); 1124 return; 1125 } 1126 1127 switch (paramKind) { 1128 case TypeParamKind::None: 1129 return; 1130 case TypeParamKind::Separate: 1131 for (int i = 0, e = op.getNumResults(); i < e; ++i) { 1132 if (op.getResult(i).isOptional()) 1133 body << " if (" << resultNames[i] << ")\n "; 1134 body << " " << builderOpState << ".addTypes(" << resultNames[i] 1135 << ");\n"; 1136 } 1137 return; 1138 case TypeParamKind::Collective: { 1139 int numResults = op.getNumResults(); 1140 int numVariadicResults = op.getNumVariableLengthResults(); 1141 int numNonVariadicResults = numResults - numVariadicResults; 1142 bool hasVariadicResult = numVariadicResults != 0; 1143 1144 // Avoid emitting "resultTypes.size() >= 0u" which is always true. 1145 if (!(hasVariadicResult && numNonVariadicResults == 0)) 1146 body << " " 1147 << "assert(resultTypes.size() " 1148 << (hasVariadicResult ? ">=" : "==") << " " 1149 << numNonVariadicResults 1150 << "u && \"mismatched number of results\");\n"; 1151 body << " " << builderOpState << ".addTypes(resultTypes);\n"; 1152 } 1153 return; 1154 } 1155 llvm_unreachable("unhandled TypeParamKind"); 1156 }; 1157 1158 // Some of the build methods generated here may be ambiguous, but TableGen's 1159 // ambiguous function detection will elide those ones. 1160 for (auto attrType : attrBuilderType) { 1161 emit(attrType, TypeParamKind::Separate, /*inferType=*/false); 1162 if (canInferType(op)) 1163 emit(attrType, TypeParamKind::None, /*inferType=*/true); 1164 emit(attrType, TypeParamKind::Collective, /*inferType=*/false); 1165 } 1166 } 1167 1168 void OpEmitter::genUseOperandAsResultTypeCollectiveParamBuilder() { 1169 int numResults = op.getNumResults(); 1170 1171 // Signature 1172 llvm::SmallVector<OpMethodParameter, 4> paramList; 1173 paramList.emplace_back("::mlir::OpBuilder &", "odsBuilder"); 1174 paramList.emplace_back("::mlir::OperationState &", builderOpState); 1175 paramList.emplace_back("::mlir::ValueRange", "operands"); 1176 // Provide default value for `attributes` when its the last parameter 1177 StringRef attributesDefaultValue = op.getNumVariadicRegions() ? "" : "{}"; 1178 paramList.emplace_back("::llvm::ArrayRef<::mlir::NamedAttribute>", 1179 "attributes", attributesDefaultValue); 1180 if (op.getNumVariadicRegions()) 1181 paramList.emplace_back("unsigned", "numRegions"); 1182 1183 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1184 std::move(paramList)); 1185 // If the builder is redundant, skip generating the method 1186 if (!m) 1187 return; 1188 auto &body = m->body(); 1189 1190 // Operands 1191 body << " " << builderOpState << ".addOperands(operands);\n"; 1192 1193 // Attributes 1194 body << " " << builderOpState << ".addAttributes(attributes);\n"; 1195 1196 // Create the correct number of regions 1197 if (int numRegions = op.getNumRegions()) { 1198 body << llvm::formatv( 1199 " for (unsigned i = 0; i != {0}; ++i)\n", 1200 (op.getNumVariadicRegions() ? "numRegions" : Twine(numRegions))); 1201 body << " (void)" << builderOpState << ".addRegion();\n"; 1202 } 1203 1204 // Result types 1205 SmallVector<std::string, 2> resultTypes(numResults, "operands[0].getType()"); 1206 body << " " << builderOpState << ".addTypes({" 1207 << llvm::join(resultTypes, ", ") << "});\n\n"; 1208 } 1209 1210 void OpEmitter::genInferredTypeCollectiveParamBuilder() { 1211 // TODO: Expand to support regions. 1212 SmallVector<OpMethodParameter, 4> paramList; 1213 paramList.emplace_back("::mlir::OpBuilder &", "odsBuilder"); 1214 paramList.emplace_back("::mlir::OperationState &", builderOpState); 1215 paramList.emplace_back("::mlir::ValueRange", "operands"); 1216 paramList.emplace_back("::llvm::ArrayRef<::mlir::NamedAttribute>", 1217 "attributes", "{}"); 1218 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1219 std::move(paramList)); 1220 // If the builder is redundant, skip generating the method 1221 if (!m) 1222 return; 1223 auto &body = m->body(); 1224 1225 int numResults = op.getNumResults(); 1226 int numVariadicResults = op.getNumVariableLengthResults(); 1227 int numNonVariadicResults = numResults - numVariadicResults; 1228 1229 int numOperands = op.getNumOperands(); 1230 int numVariadicOperands = op.getNumVariableLengthOperands(); 1231 int numNonVariadicOperands = numOperands - numVariadicOperands; 1232 1233 // Operands 1234 if (numVariadicOperands == 0 || numNonVariadicOperands != 0) 1235 body << " assert(operands.size()" 1236 << (numVariadicOperands != 0 ? " >= " : " == ") 1237 << numNonVariadicOperands 1238 << "u && \"mismatched number of parameters\");\n"; 1239 body << " " << builderOpState << ".addOperands(operands);\n"; 1240 body << " " << builderOpState << ".addAttributes(attributes);\n"; 1241 1242 // Create the correct number of regions 1243 if (int numRegions = op.getNumRegions()) { 1244 body << llvm::formatv( 1245 " for (unsigned i = 0; i != {0}; ++i)\n", 1246 (op.getNumVariadicRegions() ? "numRegions" : Twine(numRegions))); 1247 body << " (void)" << builderOpState << ".addRegion();\n"; 1248 } 1249 1250 // Result types 1251 body << formatv(R"( 1252 ::mlir::SmallVector<::mlir::Type, 2> inferredReturnTypes; 1253 if (::mlir::succeeded({0}::inferReturnTypes(odsBuilder.getContext(), 1254 {1}.location, operands, 1255 {1}.attributes.getDictionary({1}.getContext()), 1256 /*regions=*/{{}, inferredReturnTypes))) {{)", 1257 opClass.getClassName(), builderOpState); 1258 if (numVariadicResults == 0 || numNonVariadicResults != 0) 1259 body << " assert(inferredReturnTypes.size()" 1260 << (numVariadicResults != 0 ? " >= " : " == ") << numNonVariadicResults 1261 << "u && \"mismatched number of return types\");\n"; 1262 body << " " << builderOpState << ".addTypes(inferredReturnTypes);"; 1263 1264 body << formatv(R"( 1265 } else 1266 ::llvm::report_fatal_error("Failed to infer result type(s).");)", 1267 opClass.getClassName(), builderOpState); 1268 } 1269 1270 void OpEmitter::genUseOperandAsResultTypeSeparateParamBuilder() { 1271 llvm::SmallVector<OpMethodParameter, 4> paramList; 1272 llvm::SmallVector<std::string, 4> resultNames; 1273 llvm::StringSet<> inferredAttributes; 1274 buildParamList(paramList, inferredAttributes, resultNames, 1275 TypeParamKind::None); 1276 1277 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1278 std::move(paramList)); 1279 // If the builder is redundant, skip generating the method 1280 if (!m) 1281 return; 1282 auto &body = m->body(); 1283 genCodeForAddingArgAndRegionForBuilder(body, inferredAttributes); 1284 1285 auto numResults = op.getNumResults(); 1286 if (numResults == 0) 1287 return; 1288 1289 // Push all result types to the operation state 1290 const char *index = op.getOperand(0).isVariadic() ? ".front()" : ""; 1291 std::string resultType = 1292 formatv("{0}{1}.getType()", getArgumentName(op, 0), index).str(); 1293 body << " " << builderOpState << ".addTypes({" << resultType; 1294 for (int i = 1; i != numResults; ++i) 1295 body << ", " << resultType; 1296 body << "});\n\n"; 1297 } 1298 1299 void OpEmitter::genUseAttrAsResultTypeBuilder() { 1300 SmallVector<OpMethodParameter, 4> paramList; 1301 paramList.emplace_back("::mlir::OpBuilder &", "odsBuilder"); 1302 paramList.emplace_back("::mlir::OperationState &", builderOpState); 1303 paramList.emplace_back("::mlir::ValueRange", "operands"); 1304 paramList.emplace_back("::llvm::ArrayRef<::mlir::NamedAttribute>", 1305 "attributes", "{}"); 1306 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1307 std::move(paramList)); 1308 // If the builder is redundant, skip generating the method 1309 if (!m) 1310 return; 1311 1312 auto &body = m->body(); 1313 1314 // Push all result types to the operation state 1315 std::string resultType; 1316 const auto &namedAttr = op.getAttribute(0); 1317 1318 body << " auto attrName = " << namedAttr.name << "AttrName(" 1319 << builderOpState 1320 << ".name);\n" 1321 " for (auto attr : attributes) {\n" 1322 " if (attr.first != attrName) continue;\n"; 1323 if (namedAttr.attr.isTypeAttr()) { 1324 resultType = "attr.second.cast<::mlir::TypeAttr>().getValue()"; 1325 } else { 1326 resultType = "attr.second.getType()"; 1327 } 1328 1329 // Operands 1330 body << " " << builderOpState << ".addOperands(operands);\n"; 1331 1332 // Attributes 1333 body << " " << builderOpState << ".addAttributes(attributes);\n"; 1334 1335 // Result types 1336 SmallVector<std::string, 2> resultTypes(op.getNumResults(), resultType); 1337 body << " " << builderOpState << ".addTypes({" 1338 << llvm::join(resultTypes, ", ") << "});\n"; 1339 body << " }\n"; 1340 } 1341 1342 /// Returns a signature of the builder. Updates the context `fctx` to enable 1343 /// replacement of $_builder and $_state in the body. 1344 static std::string getBuilderSignature(const Builder &builder) { 1345 ArrayRef<Builder::Parameter> params(builder.getParameters()); 1346 1347 // Inject builder and state arguments. 1348 llvm::SmallVector<std::string, 8> arguments; 1349 arguments.reserve(params.size() + 2); 1350 arguments.push_back( 1351 llvm::formatv("::mlir::OpBuilder &{0}", odsBuilder).str()); 1352 arguments.push_back( 1353 llvm::formatv("::mlir::OperationState &{0}", builderOpState).str()); 1354 1355 for (unsigned i = 0, e = params.size(); i < e; ++i) { 1356 // If no name is provided, generate one. 1357 Optional<StringRef> paramName = params[i].getName(); 1358 std::string name = 1359 paramName ? paramName->str() : "odsArg" + std::to_string(i); 1360 1361 std::string defaultValue; 1362 if (Optional<StringRef> defaultParamValue = params[i].getDefaultValue()) 1363 defaultValue = llvm::formatv(" = {0}", *defaultParamValue).str(); 1364 arguments.push_back( 1365 llvm::formatv("{0} {1}{2}", params[i].getCppType(), name, defaultValue) 1366 .str()); 1367 } 1368 1369 return llvm::join(arguments, ", "); 1370 } 1371 1372 void OpEmitter::genBuilder() { 1373 // Handle custom builders if provided. 1374 for (const Builder &builder : op.getBuilders()) { 1375 std::string paramStr = getBuilderSignature(builder); 1376 1377 Optional<StringRef> body = builder.getBody(); 1378 OpMethod::Property properties = 1379 body ? OpMethod::MP_Static : OpMethod::MP_StaticDeclaration; 1380 auto *method = 1381 opClass.addMethodAndPrune("void", "build", properties, paramStr); 1382 1383 FmtContext fctx; 1384 fctx.withBuilder(odsBuilder); 1385 fctx.addSubst("_state", builderOpState); 1386 if (body) 1387 method->body() << tgfmt(*body, &fctx); 1388 } 1389 1390 // Generate default builders that requires all result type, operands, and 1391 // attributes as parameters. 1392 if (op.skipDefaultBuilders()) 1393 return; 1394 1395 // We generate three classes of builders here: 1396 // 1. one having a stand-alone parameter for each operand / attribute, and 1397 genSeparateArgParamBuilder(); 1398 // 2. one having an aggregated parameter for all result types / operands / 1399 // attributes, and 1400 genCollectiveParamBuilder(); 1401 // 3. one having a stand-alone parameter for each operand and attribute, 1402 // use the first operand or attribute's type as all result types 1403 // to facilitate different call patterns. 1404 if (op.getNumVariableLengthResults() == 0) { 1405 if (op.getTrait("::mlir::OpTrait::SameOperandsAndResultType")) { 1406 genUseOperandAsResultTypeSeparateParamBuilder(); 1407 genUseOperandAsResultTypeCollectiveParamBuilder(); 1408 } 1409 if (op.getTrait("::mlir::OpTrait::FirstAttrDerivedResultType")) 1410 genUseAttrAsResultTypeBuilder(); 1411 } 1412 } 1413 1414 void OpEmitter::genCollectiveParamBuilder() { 1415 int numResults = op.getNumResults(); 1416 int numVariadicResults = op.getNumVariableLengthResults(); 1417 int numNonVariadicResults = numResults - numVariadicResults; 1418 1419 int numOperands = op.getNumOperands(); 1420 int numVariadicOperands = op.getNumVariableLengthOperands(); 1421 int numNonVariadicOperands = numOperands - numVariadicOperands; 1422 1423 SmallVector<OpMethodParameter, 4> paramList; 1424 paramList.emplace_back("::mlir::OpBuilder &", ""); 1425 paramList.emplace_back("::mlir::OperationState &", builderOpState); 1426 paramList.emplace_back("::mlir::TypeRange", "resultTypes"); 1427 paramList.emplace_back("::mlir::ValueRange", "operands"); 1428 // Provide default value for `attributes` when its the last parameter 1429 StringRef attributesDefaultValue = op.getNumVariadicRegions() ? "" : "{}"; 1430 paramList.emplace_back("::llvm::ArrayRef<::mlir::NamedAttribute>", 1431 "attributes", attributesDefaultValue); 1432 if (op.getNumVariadicRegions()) 1433 paramList.emplace_back("unsigned", "numRegions"); 1434 1435 auto *m = opClass.addMethodAndPrune("void", "build", OpMethod::MP_Static, 1436 std::move(paramList)); 1437 // If the builder is redundant, skip generating the method 1438 if (!m) 1439 return; 1440 auto &body = m->body(); 1441 1442 // Operands 1443 if (numVariadicOperands == 0 || numNonVariadicOperands != 0) 1444 body << " assert(operands.size()" 1445 << (numVariadicOperands != 0 ? " >= " : " == ") 1446 << numNonVariadicOperands 1447 << "u && \"mismatched number of parameters\");\n"; 1448 body << " " << builderOpState << ".addOperands(operands);\n"; 1449 1450 // Attributes 1451 body << " " << builderOpState << ".addAttributes(attributes);\n"; 1452 1453 // Create the correct number of regions 1454 if (int numRegions = op.getNumRegions()) { 1455 body << llvm::formatv( 1456 " for (unsigned i = 0; i != {0}; ++i)\n", 1457 (op.getNumVariadicRegions() ? "numRegions" : Twine(numRegions))); 1458 body << " (void)" << builderOpState << ".addRegion();\n"; 1459 } 1460 1461 // Result types 1462 if (numVariadicResults == 0 || numNonVariadicResults != 0) 1463 body << " assert(resultTypes.size()" 1464 << (numVariadicResults != 0 ? " >= " : " == ") << numNonVariadicResults 1465 << "u && \"mismatched number of return types\");\n"; 1466 body << " " << builderOpState << ".addTypes(resultTypes);\n"; 1467 1468 // Generate builder that infers type too. 1469 // TODO: Expand to handle regions and successors. 1470 if (canInferType(op) && op.getNumSuccessors() == 0) 1471 genInferredTypeCollectiveParamBuilder(); 1472 } 1473 1474 void OpEmitter::buildParamList(SmallVectorImpl<OpMethodParameter> ¶mList, 1475 llvm::StringSet<> &inferredAttributes, 1476 SmallVectorImpl<std::string> &resultTypeNames, 1477 TypeParamKind typeParamKind, 1478 AttrParamKind attrParamKind) { 1479 resultTypeNames.clear(); 1480 auto numResults = op.getNumResults(); 1481 resultTypeNames.reserve(numResults); 1482 1483 paramList.emplace_back("::mlir::OpBuilder &", "odsBuilder"); 1484 paramList.emplace_back("::mlir::OperationState &", builderOpState); 1485 1486 switch (typeParamKind) { 1487 case TypeParamKind::None: 1488 break; 1489 case TypeParamKind::Separate: { 1490 // Add parameters for all return types 1491 for (int i = 0; i < numResults; ++i) { 1492 const auto &result = op.getResult(i); 1493 std::string resultName = std::string(result.name); 1494 if (resultName.empty()) 1495 resultName = std::string(formatv("resultType{0}", i)); 1496 1497 StringRef type = 1498 result.isVariadic() ? "::mlir::TypeRange" : "::mlir::Type"; 1499 OpMethodParameter::Property properties = OpMethodParameter::PP_None; 1500 if (result.isOptional()) 1501 properties = OpMethodParameter::PP_Optional; 1502 1503 paramList.emplace_back(type, resultName, properties); 1504 resultTypeNames.emplace_back(std::move(resultName)); 1505 } 1506 } break; 1507 case TypeParamKind::Collective: { 1508 paramList.emplace_back("::mlir::TypeRange", "resultTypes"); 1509 resultTypeNames.push_back("resultTypes"); 1510 } break; 1511 } 1512 1513 // Add parameters for all arguments (operands and attributes). 1514 int defaultValuedAttrStartIndex = op.getNumArgs(); 1515 // Successors and variadic regions go at the end of the parameter list, so no 1516 // default arguments are possible. 1517 bool hasTrailingParams = op.getNumSuccessors() || op.getNumVariadicRegions(); 1518 if (attrParamKind == AttrParamKind::UnwrappedValue && !hasTrailingParams) { 1519 // Calculate the start index from which we can attach default values in the 1520 // builder declaration. 1521 for (int i = op.getNumArgs() - 1; i >= 0; --i) { 1522 auto *namedAttr = op.getArg(i).dyn_cast<tblgen::NamedAttribute *>(); 1523 if (!namedAttr || !namedAttr->attr.hasDefaultValue()) 1524 break; 1525 1526 if (!canUseUnwrappedRawValue(namedAttr->attr)) 1527 break; 1528 1529 // Creating an APInt requires us to provide bitwidth, value, and 1530 // signedness, which is complicated compared to others. Similarly 1531 // for APFloat. 1532 // TODO: Adjust the 'returnType' field of such attributes 1533 // to support them. 1534 StringRef retType = namedAttr->attr.getReturnType(); 1535 if (retType == "::llvm::APInt" || retType == "::llvm::APFloat") 1536 break; 1537 1538 defaultValuedAttrStartIndex = i; 1539 } 1540 } 1541 1542 /// Collect any inferred attributes. 1543 for (const NamedTypeConstraint &operand : op.getOperands()) { 1544 if (operand.isVariadicOfVariadic()) { 1545 inferredAttributes.insert( 1546 operand.constraint.getVariadicOfVariadicSegmentSizeAttr()); 1547 } 1548 } 1549 1550 for (int i = 0, e = op.getNumArgs(), numOperands = 0; i < e; ++i) { 1551 Argument arg = op.getArg(i); 1552 if (const auto *operand = arg.dyn_cast<NamedTypeConstraint *>()) { 1553 StringRef type; 1554 if (operand->isVariadicOfVariadic()) 1555 type = "::llvm::ArrayRef<::mlir::ValueRange>"; 1556 else if (operand->isVariadic()) 1557 type = "::mlir::ValueRange"; 1558 else 1559 type = "::mlir::Value"; 1560 1561 OpMethodParameter::Property properties = OpMethodParameter::PP_None; 1562 if (operand->isOptional()) 1563 properties = OpMethodParameter::PP_Optional; 1564 paramList.emplace_back(type, getArgumentName(op, numOperands++), 1565 properties); 1566 continue; 1567 } 1568 const NamedAttribute &namedAttr = *arg.get<NamedAttribute *>(); 1569 const Attribute &attr = namedAttr.attr; 1570 1571 // inferred attributes don't need to be added to the param list. 1572 if (inferredAttributes.contains(namedAttr.name)) 1573 continue; 1574 1575 OpMethodParameter::Property properties = OpMethodParameter::PP_None; 1576 if (attr.isOptional()) 1577 properties = OpMethodParameter::PP_Optional; 1578 1579 StringRef type; 1580 switch (attrParamKind) { 1581 case AttrParamKind::WrappedAttr: 1582 type = attr.getStorageType(); 1583 break; 1584 case AttrParamKind::UnwrappedValue: 1585 if (canUseUnwrappedRawValue(attr)) 1586 type = attr.getReturnType(); 1587 else 1588 type = attr.getStorageType(); 1589 break; 1590 } 1591 1592 // Attach default value if requested and possible. 1593 std::string defaultValue; 1594 if (attrParamKind == AttrParamKind::UnwrappedValue && 1595 i >= defaultValuedAttrStartIndex) { 1596 bool isString = attr.getReturnType() == "::llvm::StringRef"; 1597 if (isString) 1598 defaultValue.append("\""); 1599 defaultValue += attr.getDefaultValue(); 1600 if (isString) 1601 defaultValue.append("\""); 1602 } 1603 paramList.emplace_back(type, namedAttr.name, defaultValue, properties); 1604 } 1605 1606 /// Insert parameters for each successor. 1607 for (const NamedSuccessor &succ : op.getSuccessors()) { 1608 StringRef type = 1609 succ.isVariadic() ? "::mlir::BlockRange" : "::mlir::Block *"; 1610 paramList.emplace_back(type, succ.name); 1611 } 1612 1613 /// Insert parameters for variadic regions. 1614 for (const NamedRegion ®ion : op.getRegions()) 1615 if (region.isVariadic()) 1616 paramList.emplace_back("unsigned", 1617 llvm::formatv("{0}Count", region.name).str()); 1618 } 1619 1620 void OpEmitter::genCodeForAddingArgAndRegionForBuilder( 1621 OpMethodBody &body, llvm::StringSet<> &inferredAttributes, 1622 bool isRawValueAttr) { 1623 // Push all operands to the result. 1624 for (int i = 0, e = op.getNumOperands(); i < e; ++i) { 1625 std::string argName = getArgumentName(op, i); 1626 NamedTypeConstraint &operand = op.getOperand(i); 1627 if (operand.constraint.isVariadicOfVariadic()) { 1628 body << " for (::mlir::ValueRange range : " << argName << ")\n " 1629 << builderOpState << ".addOperands(range);\n"; 1630 1631 // Add the segment attribute. 1632 body << " {\n" 1633 << " SmallVector<int32_t> rangeSegments;\n" 1634 << " for (::mlir::ValueRange range : " << argName << ")\n" 1635 << " rangeSegments.push_back(range.size());\n" 1636 << " " << builderOpState << ".addAttribute(" 1637 << operand.constraint.getVariadicOfVariadicSegmentSizeAttr() 1638 << "AttrName(" << builderOpState << ".name), " << odsBuilder 1639 << ".getI32TensorAttr(rangeSegments));" 1640 << " }\n"; 1641 continue; 1642 } 1643 1644 if (operand.isOptional()) 1645 body << " if (" << argName << ")\n "; 1646 body << " " << builderOpState << ".addOperands(" << argName << ");\n"; 1647 } 1648 1649 // If the operation has the operand segment size attribute, add it here. 1650 if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) { 1651 body << " " << builderOpState 1652 << ".addAttribute(operand_segment_sizesAttrName(" << builderOpState 1653 << ".name), " 1654 << "odsBuilder.getI32VectorAttr({"; 1655 interleaveComma(llvm::seq<int>(0, op.getNumOperands()), body, [&](int i) { 1656 const NamedTypeConstraint &operand = op.getOperand(i); 1657 if (!operand.isVariableLength()) { 1658 body << "1"; 1659 return; 1660 } 1661 1662 std::string operandName = getArgumentName(op, i); 1663 if (operand.isOptional()) { 1664 body << "(" << operandName << " ? 1 : 0)"; 1665 } else if (operand.isVariadicOfVariadic()) { 1666 body << llvm::formatv( 1667 "static_cast<int32_t>(std::accumulate({0}.begin(), {0}.end(), 0, " 1668 "[](int32_t curSum, ::mlir::ValueRange range) {{ return curSum + " 1669 "range.size(); }))", 1670 operandName); 1671 } else { 1672 body << "static_cast<int32_t>(" << getArgumentName(op, i) << ".size())"; 1673 } 1674 }); 1675 body << "}));\n"; 1676 } 1677 1678 // Push all attributes to the result. 1679 for (const auto &namedAttr : op.getAttributes()) { 1680 auto &attr = namedAttr.attr; 1681 if (attr.isDerivedAttr() || inferredAttributes.contains(namedAttr.name)) 1682 continue; 1683 1684 bool emitNotNullCheck = attr.isOptional(); 1685 if (emitNotNullCheck) 1686 body << formatv(" if ({0}) ", namedAttr.name) << "{\n"; 1687 1688 if (isRawValueAttr && canUseUnwrappedRawValue(attr)) { 1689 // If this is a raw value, then we need to wrap it in an Attribute 1690 // instance. 1691 FmtContext fctx; 1692 fctx.withBuilder("odsBuilder"); 1693 1694 std::string builderTemplate = std::string(attr.getConstBuilderTemplate()); 1695 1696 // For StringAttr, its constant builder call will wrap the input in 1697 // quotes, which is correct for normal string literals, but incorrect 1698 // here given we use function arguments. So we need to strip the 1699 // wrapping quotes. 1700 if (StringRef(builderTemplate).contains("\"$0\"")) 1701 builderTemplate = replaceAllSubstrs(builderTemplate, "\"$0\"", "$0"); 1702 1703 std::string value = 1704 std::string(tgfmt(builderTemplate, &fctx, namedAttr.name)); 1705 body << formatv(" {0}.addAttribute({1}AttrName({0}.name), {2});\n", 1706 builderOpState, namedAttr.name, value); 1707 } else { 1708 body << formatv(" {0}.addAttribute({1}AttrName({0}.name), {1});\n", 1709 builderOpState, namedAttr.name); 1710 } 1711 if (emitNotNullCheck) 1712 body << " }\n"; 1713 } 1714 1715 // Create the correct number of regions. 1716 for (const NamedRegion ®ion : op.getRegions()) { 1717 if (region.isVariadic()) 1718 body << formatv(" for (unsigned i = 0; i < {0}Count; ++i)\n ", 1719 region.name); 1720 1721 body << " (void)" << builderOpState << ".addRegion();\n"; 1722 } 1723 1724 // Push all successors to the result. 1725 for (const NamedSuccessor &namedSuccessor : op.getSuccessors()) { 1726 body << formatv(" {0}.addSuccessors({1});\n", builderOpState, 1727 namedSuccessor.name); 1728 } 1729 } 1730 1731 void OpEmitter::genCanonicalizerDecls() { 1732 bool hasCanonicalizeMethod = def.getValueAsBit("hasCanonicalizeMethod"); 1733 if (hasCanonicalizeMethod) { 1734 // static LogicResult FooOp:: 1735 // canonicalize(FooOp op, PatternRewriter &rewriter); 1736 SmallVector<OpMethodParameter, 2> paramList; 1737 paramList.emplace_back(op.getCppClassName(), "op"); 1738 paramList.emplace_back("::mlir::PatternRewriter &", "rewriter"); 1739 opClass.addMethodAndPrune("::mlir::LogicalResult", "canonicalize", 1740 OpMethod::MP_StaticDeclaration, 1741 std::move(paramList)); 1742 } 1743 1744 // We get a prototype for 'getCanonicalizationPatterns' if requested directly 1745 // or if using a 'canonicalize' method. 1746 bool hasCanonicalizer = def.getValueAsBit("hasCanonicalizer"); 1747 if (!hasCanonicalizeMethod && !hasCanonicalizer) 1748 return; 1749 1750 // We get a body for 'getCanonicalizationPatterns' when using a 'canonicalize' 1751 // method, but not implementing 'getCanonicalizationPatterns' manually. 1752 bool hasBody = hasCanonicalizeMethod && !hasCanonicalizer; 1753 1754 // Add a signature for getCanonicalizationPatterns if implemented by the 1755 // dialect or if synthesized to call 'canonicalize'. 1756 SmallVector<OpMethodParameter, 2> paramList; 1757 paramList.emplace_back("::mlir::RewritePatternSet &", "results"); 1758 paramList.emplace_back("::mlir::MLIRContext *", "context"); 1759 auto kind = hasBody ? OpMethod::MP_Static : OpMethod::MP_StaticDeclaration; 1760 auto *method = opClass.addMethodAndPrune( 1761 "void", "getCanonicalizationPatterns", kind, std::move(paramList)); 1762 1763 // If synthesizing the method, fill it it. 1764 if (hasBody) 1765 method->body() << " results.add(canonicalize);\n"; 1766 } 1767 1768 void OpEmitter::genFolderDecls() { 1769 bool hasSingleResult = 1770 op.getNumResults() == 1 && op.getNumVariableLengthResults() == 0; 1771 1772 if (def.getValueAsBit("hasFolder")) { 1773 if (hasSingleResult) { 1774 opClass.addMethodAndPrune( 1775 "::mlir::OpFoldResult", "fold", OpMethod::MP_Declaration, 1776 "::llvm::ArrayRef<::mlir::Attribute>", "operands"); 1777 } else { 1778 SmallVector<OpMethodParameter, 2> paramList; 1779 paramList.emplace_back("::llvm::ArrayRef<::mlir::Attribute>", "operands"); 1780 paramList.emplace_back("::llvm::SmallVectorImpl<::mlir::OpFoldResult> &", 1781 "results"); 1782 opClass.addMethodAndPrune("::mlir::LogicalResult", "fold", 1783 OpMethod::MP_Declaration, std::move(paramList)); 1784 } 1785 } 1786 } 1787 1788 void OpEmitter::genOpInterfaceMethods(const tblgen::InterfaceTrait *opTrait) { 1789 Interface interface = opTrait->getInterface(); 1790 1791 // Get the set of methods that should always be declared. 1792 auto alwaysDeclaredMethodsVec = opTrait->getAlwaysDeclaredMethods(); 1793 llvm::StringSet<> alwaysDeclaredMethods; 1794 alwaysDeclaredMethods.insert(alwaysDeclaredMethodsVec.begin(), 1795 alwaysDeclaredMethodsVec.end()); 1796 1797 for (const InterfaceMethod &method : interface.getMethods()) { 1798 // Don't declare if the method has a body. 1799 if (method.getBody()) 1800 continue; 1801 // Don't declare if the method has a default implementation and the op 1802 // didn't request that it always be declared. 1803 if (method.getDefaultImplementation() && 1804 !alwaysDeclaredMethods.count(method.getName())) 1805 continue; 1806 genOpInterfaceMethod(method); 1807 } 1808 } 1809 1810 OpMethod *OpEmitter::genOpInterfaceMethod(const InterfaceMethod &method, 1811 bool declaration) { 1812 SmallVector<OpMethodParameter, 4> paramList; 1813 for (const InterfaceMethod::Argument &arg : method.getArguments()) 1814 paramList.emplace_back(arg.type, arg.name); 1815 1816 auto properties = method.isStatic() ? OpMethod::MP_Static : OpMethod::MP_None; 1817 if (declaration) 1818 properties = 1819 static_cast<OpMethod::Property>(properties | OpMethod::MP_Declaration); 1820 return opClass.addMethodAndPrune(method.getReturnType(), method.getName(), 1821 properties, std::move(paramList)); 1822 } 1823 1824 void OpEmitter::genOpInterfaceMethods() { 1825 for (const auto &trait : op.getTraits()) { 1826 if (const auto *opTrait = dyn_cast<tblgen::InterfaceTrait>(&trait)) 1827 if (opTrait->shouldDeclareMethods()) 1828 genOpInterfaceMethods(opTrait); 1829 } 1830 } 1831 1832 void OpEmitter::genSideEffectInterfaceMethods() { 1833 enum EffectKind { Operand, Result, Symbol, Static }; 1834 struct EffectLocation { 1835 /// The effect applied. 1836 SideEffect effect; 1837 1838 /// The index if the kind is not static. 1839 unsigned index : 30; 1840 1841 /// The kind of the location. 1842 unsigned kind : 2; 1843 }; 1844 1845 StringMap<SmallVector<EffectLocation, 1>> interfaceEffects; 1846 auto resolveDecorators = [&](Operator::var_decorator_range decorators, 1847 unsigned index, unsigned kind) { 1848 for (auto decorator : decorators) 1849 if (SideEffect *effect = dyn_cast<SideEffect>(&decorator)) { 1850 opClass.addTrait(effect->getInterfaceTrait()); 1851 interfaceEffects[effect->getBaseEffectName()].push_back( 1852 EffectLocation{*effect, index, kind}); 1853 } 1854 }; 1855 1856 // Collect effects that were specified via: 1857 /// Traits. 1858 for (const auto &trait : op.getTraits()) { 1859 const auto *opTrait = dyn_cast<tblgen::SideEffectTrait>(&trait); 1860 if (!opTrait) 1861 continue; 1862 auto &effects = interfaceEffects[opTrait->getBaseEffectName()]; 1863 for (auto decorator : opTrait->getEffects()) 1864 effects.push_back(EffectLocation{cast<SideEffect>(decorator), 1865 /*index=*/0, EffectKind::Static}); 1866 } 1867 /// Attributes and Operands. 1868 for (unsigned i = 0, operandIt = 0, e = op.getNumArgs(); i != e; ++i) { 1869 Argument arg = op.getArg(i); 1870 if (arg.is<NamedTypeConstraint *>()) { 1871 resolveDecorators(op.getArgDecorators(i), operandIt, EffectKind::Operand); 1872 ++operandIt; 1873 continue; 1874 } 1875 const NamedAttribute *attr = arg.get<NamedAttribute *>(); 1876 if (attr->attr.getBaseAttr().isSymbolRefAttr()) 1877 resolveDecorators(op.getArgDecorators(i), i, EffectKind::Symbol); 1878 } 1879 /// Results. 1880 for (unsigned i = 0, e = op.getNumResults(); i != e; ++i) 1881 resolveDecorators(op.getResultDecorators(i), i, EffectKind::Result); 1882 1883 // The code used to add an effect instance. 1884 // {0}: The effect class. 1885 // {1}: Optional value or symbol reference. 1886 // {1}: The resource class. 1887 const char *addEffectCode = 1888 " effects.emplace_back({0}::get(), {1}{2}::get());\n"; 1889 1890 for (auto &it : interfaceEffects) { 1891 // Generate the 'getEffects' method. 1892 std::string type = llvm::formatv("::mlir::SmallVectorImpl<::mlir::" 1893 "SideEffects::EffectInstance<{0}>> &", 1894 it.first()) 1895 .str(); 1896 auto *getEffects = 1897 opClass.addMethodAndPrune("void", "getEffects", type, "effects"); 1898 auto &body = getEffects->body(); 1899 1900 // Add effect instances for each of the locations marked on the operation. 1901 for (auto &location : it.second) { 1902 StringRef effect = location.effect.getName(); 1903 StringRef resource = location.effect.getResource(); 1904 if (location.kind == EffectKind::Static) { 1905 // A static instance has no attached value. 1906 body << llvm::formatv(addEffectCode, effect, "", resource).str(); 1907 } else if (location.kind == EffectKind::Symbol) { 1908 // A symbol reference requires adding the proper attribute. 1909 const auto *attr = op.getArg(location.index).get<NamedAttribute *>(); 1910 if (attr->attr.isOptional()) { 1911 body << " if (auto symbolRef = " << attr->name << "Attr())\n " 1912 << llvm::formatv(addEffectCode, effect, "symbolRef, ", resource) 1913 .str(); 1914 } else { 1915 body << llvm::formatv(addEffectCode, effect, attr->name + "(), ", 1916 resource) 1917 .str(); 1918 } 1919 } else { 1920 // Otherwise this is an operand/result, so we need to attach the Value. 1921 body << " for (::mlir::Value value : getODS" 1922 << (location.kind == EffectKind::Operand ? "Operands" : "Results") 1923 << "(" << location.index << "))\n " 1924 << llvm::formatv(addEffectCode, effect, "value, ", resource).str(); 1925 } 1926 } 1927 } 1928 } 1929 1930 void OpEmitter::genTypeInterfaceMethods() { 1931 if (!op.allResultTypesKnown()) 1932 return; 1933 // Generate 'inferReturnTypes' method declaration using the interface method 1934 // declared in 'InferTypeOpInterface' op interface. 1935 const auto *trait = dyn_cast<InterfaceTrait>( 1936 op.getTrait("::mlir::InferTypeOpInterface::Trait")); 1937 Interface interface = trait->getInterface(); 1938 OpMethod *method = [&]() -> OpMethod * { 1939 for (const InterfaceMethod &interfaceMethod : interface.getMethods()) { 1940 if (interfaceMethod.getName() == "inferReturnTypes") { 1941 return genOpInterfaceMethod(interfaceMethod, /*declaration=*/false); 1942 } 1943 } 1944 assert(0 && "unable to find inferReturnTypes interface method"); 1945 return nullptr; 1946 }(); 1947 auto &body = method->body(); 1948 body << " inferredReturnTypes.resize(" << op.getNumResults() << ");\n"; 1949 1950 FmtContext fctx; 1951 fctx.withBuilder("odsBuilder"); 1952 body << " ::mlir::Builder odsBuilder(context);\n"; 1953 1954 auto emitType = 1955 [&](const tblgen::Operator::ArgOrType &type) -> OpMethodBody & { 1956 if (type.isArg()) { 1957 auto argIndex = type.getArg(); 1958 assert(!op.getArg(argIndex).is<NamedAttribute *>()); 1959 auto arg = op.getArgToOperandOrAttribute(argIndex); 1960 if (arg.kind() == Operator::OperandOrAttribute::Kind::Operand) 1961 return body << "operands[" << arg.operandOrAttributeIndex() 1962 << "].getType()"; 1963 return body << "attributes[" << arg.operandOrAttributeIndex() 1964 << "].getType()"; 1965 } else { 1966 return body << tgfmt(*type.getType().getBuilderCall(), &fctx); 1967 } 1968 }; 1969 1970 for (int i = 0, e = op.getNumResults(); i != e; ++i) { 1971 body << " inferredReturnTypes[" << i << "] = "; 1972 auto types = op.getSameTypeAsResult(i); 1973 emitType(types[0]) << ";\n"; 1974 if (types.size() == 1) 1975 continue; 1976 // TODO: We could verify equality here, but skipping that for verification. 1977 } 1978 body << " return ::mlir::success();"; 1979 } 1980 1981 void OpEmitter::genParser() { 1982 if (!hasStringAttribute(def, "parser") || 1983 hasStringAttribute(def, "assemblyFormat")) 1984 return; 1985 1986 SmallVector<OpMethodParameter, 2> paramList; 1987 paramList.emplace_back("::mlir::OpAsmParser &", "parser"); 1988 paramList.emplace_back("::mlir::OperationState &", "result"); 1989 auto *method = 1990 opClass.addMethodAndPrune("::mlir::ParseResult", "parse", 1991 OpMethod::MP_Static, std::move(paramList)); 1992 1993 FmtContext fctx; 1994 fctx.addSubst("cppClass", opClass.getClassName()); 1995 auto parser = def.getValueAsString("parser").ltrim().rtrim(" \t\v\f\r"); 1996 method->body() << " " << tgfmt(parser, &fctx); 1997 } 1998 1999 void OpEmitter::genPrinter() { 2000 if (hasStringAttribute(def, "assemblyFormat")) 2001 return; 2002 2003 auto valueInit = def.getValueInit("printer"); 2004 StringInit *stringInit = dyn_cast<StringInit>(valueInit); 2005 if (!stringInit) 2006 return; 2007 2008 auto *method = 2009 opClass.addMethodAndPrune("void", "print", "::mlir::OpAsmPrinter &", "p"); 2010 FmtContext fctx; 2011 fctx.addSubst("cppClass", opClass.getClassName()); 2012 auto printer = stringInit->getValue().ltrim().rtrim(" \t\v\f\r"); 2013 method->body() << " " << tgfmt(printer, &fctx); 2014 } 2015 2016 void OpEmitter::genVerifier() { 2017 auto *method = opClass.addMethodAndPrune("::mlir::LogicalResult", "verify"); 2018 auto &body = method->body(); 2019 body << " if (::mlir::failed(" << op.getAdaptorName() 2020 << "(*this).verify((*this)->getLoc()))) " 2021 << "return ::mlir::failure();\n"; 2022 2023 auto *valueInit = def.getValueInit("verifier"); 2024 StringInit *stringInit = dyn_cast<StringInit>(valueInit); 2025 bool hasCustomVerify = stringInit && !stringInit->getValue().empty(); 2026 populateSubstitutions(op, "(*this)->getAttr", "this->getODSOperands", 2027 "this->getODSResults", verifyCtx); 2028 2029 genAttributeVerifier(op, "(*this)->getAttr", "emitOpError(", 2030 /*emitVerificationRequiringOp=*/true, verifyCtx, body); 2031 genOperandResultVerifier(body, op.getOperands(), "operand"); 2032 genOperandResultVerifier(body, op.getResults(), "result"); 2033 2034 for (auto &trait : op.getTraits()) { 2035 if (auto *t = dyn_cast<tblgen::PredTrait>(&trait)) { 2036 body << tgfmt(" if (!($0))\n " 2037 "return emitOpError(\"failed to verify that $1\");\n", 2038 &verifyCtx, tgfmt(t->getPredTemplate(), &verifyCtx), 2039 t->getSummary()); 2040 } 2041 } 2042 2043 genRegionVerifier(body); 2044 genSuccessorVerifier(body); 2045 2046 if (hasCustomVerify) { 2047 FmtContext fctx; 2048 fctx.addSubst("cppClass", opClass.getClassName()); 2049 auto printer = stringInit->getValue().ltrim().rtrim(" \t\v\f\r"); 2050 body << " " << tgfmt(printer, &fctx); 2051 } else { 2052 body << " return ::mlir::success();\n"; 2053 } 2054 } 2055 2056 void OpEmitter::genOperandResultVerifier(OpMethodBody &body, 2057 Operator::value_range values, 2058 StringRef valueKind) { 2059 FmtContext fctx; 2060 2061 body << " {\n"; 2062 body << " unsigned index = 0; (void)index;\n"; 2063 2064 for (auto staticValue : llvm::enumerate(values)) { 2065 const NamedTypeConstraint &value = staticValue.value(); 2066 2067 bool hasPredicate = value.hasPredicate(); 2068 bool isOptional = value.isOptional(); 2069 bool isVariadicOfVariadic = value.isVariadicOfVariadic(); 2070 if (!hasPredicate && !isOptional && !isVariadicOfVariadic) 2071 continue; 2072 body << formatv(" auto valueGroup{2} = getODS{0}{1}s({2});\n", 2073 // Capitalize the first letter to match the function name 2074 valueKind.substr(0, 1).upper(), valueKind.substr(1), 2075 staticValue.index()); 2076 2077 // If the constraint is optional check that the value group has at most 1 2078 // value. 2079 if (isOptional) { 2080 body << formatv(" if (valueGroup{0}.size() > 1)\n" 2081 " return emitOpError(\"{1} group starting at #\") " 2082 "<< index << \" requires 0 or 1 element, but found \" << " 2083 "valueGroup{0}.size();\n", 2084 staticValue.index(), valueKind); 2085 } else if (isVariadicOfVariadic) { 2086 body << formatv( 2087 " if (::mlir::failed(::mlir::OpTrait::impl::verifyValueSizeAttr(" 2088 "*this, \"{0}\", \"{1}\", valueGroup{2}.size())))\n" 2089 " return ::mlir::failure();\n", 2090 value.constraint.getVariadicOfVariadicSegmentSizeAttr(), value.name, 2091 staticValue.index()); 2092 } 2093 2094 // Otherwise, if there is no predicate there is nothing left to do. 2095 if (!hasPredicate) 2096 continue; 2097 // Emit a loop to check all the dynamic values in the pack. 2098 StringRef constraintFn = 2099 staticVerifierEmitter.getTypeConstraintFn(value.constraint); 2100 body << " for (::mlir::Value v : valueGroup" << staticValue.index() 2101 << ") {\n" 2102 << " if (::mlir::failed(" << constraintFn 2103 << "(getOperation(), v.getType(), \"" << valueKind << "\", index)))\n" 2104 << " return ::mlir::failure();\n" 2105 << " ++index;\n" 2106 << " }\n"; 2107 } 2108 2109 body << " }\n"; 2110 } 2111 2112 void OpEmitter::genRegionVerifier(OpMethodBody &body) { 2113 // If we have no regions, there is nothing more to do. 2114 unsigned numRegions = op.getNumRegions(); 2115 if (numRegions == 0) 2116 return; 2117 2118 body << "{\n"; 2119 body << " unsigned index = 0; (void)index;\n"; 2120 2121 for (unsigned i = 0; i < numRegions; ++i) { 2122 const auto ®ion = op.getRegion(i); 2123 if (region.constraint.getPredicate().isNull()) 2124 continue; 2125 2126 body << " for (::mlir::Region ®ion : "; 2127 body << formatv(region.isVariadic() 2128 ? "{0}()" 2129 : "::mlir::MutableArrayRef<::mlir::Region>((*this)" 2130 "->getRegion({1}))", 2131 region.name, i); 2132 body << ") {\n"; 2133 auto constraint = tgfmt(region.constraint.getConditionTemplate(), 2134 &verifyCtx.withSelf("region")) 2135 .str(); 2136 2137 body << formatv(" (void)region;\n" 2138 " if (!({0})) {\n " 2139 "return emitOpError(\"region #\") << index << \" {1}" 2140 "failed to " 2141 "verify constraint: {2}\";\n }\n", 2142 constraint, 2143 region.name.empty() ? "" : "('" + region.name + "') ", 2144 region.constraint.getSummary()) 2145 << " ++index;\n" 2146 << " }\n"; 2147 } 2148 body << " }\n"; 2149 } 2150 2151 void OpEmitter::genSuccessorVerifier(OpMethodBody &body) { 2152 // If we have no successors, there is nothing more to do. 2153 unsigned numSuccessors = op.getNumSuccessors(); 2154 if (numSuccessors == 0) 2155 return; 2156 2157 body << "{\n"; 2158 body << " unsigned index = 0; (void)index;\n"; 2159 2160 for (unsigned i = 0; i < numSuccessors; ++i) { 2161 const auto &successor = op.getSuccessor(i); 2162 if (successor.constraint.getPredicate().isNull()) 2163 continue; 2164 2165 if (successor.isVariadic()) { 2166 body << formatv(" for (::mlir::Block *successor : {0}()) {\n", 2167 successor.name); 2168 } else { 2169 body << " {\n"; 2170 body << formatv(" ::mlir::Block *successor = {0}();\n", 2171 successor.name); 2172 } 2173 auto constraint = tgfmt(successor.constraint.getConditionTemplate(), 2174 &verifyCtx.withSelf("successor")) 2175 .str(); 2176 2177 body << formatv(" (void)successor;\n" 2178 " if (!({0})) {\n " 2179 "return emitOpError(\"successor #\") << index << \"('{1}') " 2180 "failed to " 2181 "verify constraint: {2}\";\n }\n", 2182 constraint, successor.name, 2183 successor.constraint.getSummary()) 2184 << " ++index;\n" 2185 << " }\n"; 2186 } 2187 body << " }\n"; 2188 } 2189 2190 /// Add a size count trait to the given operation class. 2191 static void addSizeCountTrait(OpClass &opClass, StringRef traitKind, 2192 int numTotal, int numVariadic) { 2193 if (numVariadic != 0) { 2194 if (numTotal == numVariadic) 2195 opClass.addTrait("::mlir::OpTrait::Variadic" + traitKind + "s"); 2196 else 2197 opClass.addTrait("::mlir::OpTrait::AtLeastN" + traitKind + "s<" + 2198 Twine(numTotal - numVariadic) + ">::Impl"); 2199 return; 2200 } 2201 switch (numTotal) { 2202 case 0: 2203 opClass.addTrait("::mlir::OpTrait::Zero" + traitKind); 2204 break; 2205 case 1: 2206 opClass.addTrait("::mlir::OpTrait::One" + traitKind); 2207 break; 2208 default: 2209 opClass.addTrait("::mlir::OpTrait::N" + traitKind + "s<" + Twine(numTotal) + 2210 ">::Impl"); 2211 break; 2212 } 2213 } 2214 2215 void OpEmitter::genTraits() { 2216 // Add region size trait. 2217 unsigned numRegions = op.getNumRegions(); 2218 unsigned numVariadicRegions = op.getNumVariadicRegions(); 2219 addSizeCountTrait(opClass, "Region", numRegions, numVariadicRegions); 2220 2221 // Add result size traits. 2222 int numResults = op.getNumResults(); 2223 int numVariadicResults = op.getNumVariableLengthResults(); 2224 addSizeCountTrait(opClass, "Result", numResults, numVariadicResults); 2225 2226 // For single result ops with a known specific type, generate a OneTypedResult 2227 // trait. 2228 if (numResults == 1 && numVariadicResults == 0) { 2229 auto cppName = op.getResults().begin()->constraint.getCPPClassName(); 2230 opClass.addTrait("::mlir::OpTrait::OneTypedResult<" + cppName + ">::Impl"); 2231 } 2232 2233 // Add successor size trait. 2234 unsigned numSuccessors = op.getNumSuccessors(); 2235 unsigned numVariadicSuccessors = op.getNumVariadicSuccessors(); 2236 addSizeCountTrait(opClass, "Successor", numSuccessors, numVariadicSuccessors); 2237 2238 // Add variadic size trait and normal op traits. 2239 int numOperands = op.getNumOperands(); 2240 int numVariadicOperands = op.getNumVariableLengthOperands(); 2241 2242 // Add operand size trait. 2243 if (numVariadicOperands != 0) { 2244 if (numOperands == numVariadicOperands) 2245 opClass.addTrait("::mlir::OpTrait::VariadicOperands"); 2246 else 2247 opClass.addTrait("::mlir::OpTrait::AtLeastNOperands<" + 2248 Twine(numOperands - numVariadicOperands) + ">::Impl"); 2249 } else { 2250 switch (numOperands) { 2251 case 0: 2252 opClass.addTrait("::mlir::OpTrait::ZeroOperands"); 2253 break; 2254 case 1: 2255 opClass.addTrait("::mlir::OpTrait::OneOperand"); 2256 break; 2257 default: 2258 opClass.addTrait("::mlir::OpTrait::NOperands<" + Twine(numOperands) + 2259 ">::Impl"); 2260 break; 2261 } 2262 } 2263 2264 // Add the native and interface traits. 2265 for (const auto &trait : op.getTraits()) { 2266 if (auto opTrait = dyn_cast<tblgen::NativeTrait>(&trait)) 2267 opClass.addTrait(opTrait->getFullyQualifiedTraitName()); 2268 else if (auto opTrait = dyn_cast<tblgen::InterfaceTrait>(&trait)) 2269 opClass.addTrait(opTrait->getFullyQualifiedTraitName()); 2270 } 2271 } 2272 2273 void OpEmitter::genOpNameGetter() { 2274 auto *method = opClass.addMethodAndPrune( 2275 "::llvm::StringLiteral", "getOperationName", 2276 OpMethod::Property(OpMethod::MP_Static | OpMethod::MP_Constexpr)); 2277 method->body() << " return ::llvm::StringLiteral(\"" << op.getOperationName() 2278 << "\");"; 2279 } 2280 2281 void OpEmitter::genOpAsmInterface() { 2282 // If the user only has one results or specifically added the Asm trait, 2283 // then don't generate it for them. We specifically only handle multi result 2284 // operations, because the name of a single result in the common case is not 2285 // interesting(generally 'result'/'output'/etc.). 2286 // TODO: We could also add a flag to allow operations to opt in to this 2287 // generation, even if they only have a single operation. 2288 int numResults = op.getNumResults(); 2289 if (numResults <= 1 || op.getTrait("::mlir::OpAsmOpInterface::Trait")) 2290 return; 2291 2292 SmallVector<StringRef, 4> resultNames(numResults); 2293 for (int i = 0; i != numResults; ++i) 2294 resultNames[i] = op.getResultName(i); 2295 2296 // Don't add the trait if none of the results have a valid name. 2297 if (llvm::all_of(resultNames, [](StringRef name) { return name.empty(); })) 2298 return; 2299 opClass.addTrait("::mlir::OpAsmOpInterface::Trait"); 2300 2301 // Generate the right accessor for the number of results. 2302 auto *method = opClass.addMethodAndPrune( 2303 "void", "getAsmResultNames", "::mlir::OpAsmSetValueNameFn", "setNameFn"); 2304 auto &body = method->body(); 2305 for (int i = 0; i != numResults; ++i) { 2306 body << " auto resultGroup" << i << " = getODSResults(" << i << ");\n" 2307 << " if (!llvm::empty(resultGroup" << i << "))\n" 2308 << " setNameFn(*resultGroup" << i << ".begin(), \"" 2309 << resultNames[i] << "\");\n"; 2310 } 2311 } 2312 2313 //===----------------------------------------------------------------------===// 2314 // OpOperandAdaptor emitter 2315 //===----------------------------------------------------------------------===// 2316 2317 namespace { 2318 // Helper class to emit Op operand adaptors to an output stream. Operand 2319 // adaptors are wrappers around ArrayRef<Value> that provide named operand 2320 // getters identical to those defined in the Op. 2321 class OpOperandAdaptorEmitter { 2322 public: 2323 static void emitDecl(const Operator &op, raw_ostream &os); 2324 static void emitDef(const Operator &op, raw_ostream &os); 2325 2326 private: 2327 explicit OpOperandAdaptorEmitter(const Operator &op); 2328 2329 // Add verification function. This generates a verify method for the adaptor 2330 // which verifies all the op-independent attribute constraints. 2331 void addVerification(); 2332 2333 const Operator &op; 2334 Class adaptor; 2335 }; 2336 } // end namespace 2337 2338 OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(const Operator &op) 2339 : op(op), adaptor(op.getAdaptorName()) { 2340 adaptor.newField("::mlir::ValueRange", "odsOperands"); 2341 adaptor.newField("::mlir::DictionaryAttr", "odsAttrs"); 2342 adaptor.newField("::mlir::RegionRange", "odsRegions"); 2343 const auto *attrSizedOperands = 2344 op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments"); 2345 { 2346 SmallVector<OpMethodParameter, 2> paramList; 2347 paramList.emplace_back("::mlir::ValueRange", "values"); 2348 paramList.emplace_back("::mlir::DictionaryAttr", "attrs", 2349 attrSizedOperands ? "" : "nullptr"); 2350 paramList.emplace_back("::mlir::RegionRange", "regions", "{}"); 2351 auto *constructor = adaptor.addConstructorAndPrune(std::move(paramList)); 2352 2353 constructor->addMemberInitializer("odsOperands", "values"); 2354 constructor->addMemberInitializer("odsAttrs", "attrs"); 2355 constructor->addMemberInitializer("odsRegions", "regions"); 2356 } 2357 2358 { 2359 auto *constructor = adaptor.addConstructorAndPrune( 2360 llvm::formatv("{0}&", op.getCppClassName()).str(), "op"); 2361 constructor->addMemberInitializer("odsOperands", "op->getOperands()"); 2362 constructor->addMemberInitializer("odsAttrs", "op->getAttrDictionary()"); 2363 constructor->addMemberInitializer("odsRegions", "op->getRegions()"); 2364 } 2365 2366 { 2367 auto *m = adaptor.addMethodAndPrune("::mlir::ValueRange", "getOperands"); 2368 m->body() << " return odsOperands;"; 2369 } 2370 std::string sizeAttrInit = 2371 formatv(adapterSegmentSizeAttrInitCode, "operand_segment_sizes"); 2372 generateNamedOperandGetters(op, adaptor, 2373 /*isAdaptor=*/true, sizeAttrInit, 2374 /*rangeType=*/"::mlir::ValueRange", 2375 /*rangeBeginCall=*/"odsOperands.begin()", 2376 /*rangeSizeCall=*/"odsOperands.size()", 2377 /*getOperandCallPattern=*/"odsOperands[{0}]"); 2378 2379 FmtContext fctx; 2380 fctx.withBuilder("::mlir::Builder(odsAttrs.getContext())"); 2381 2382 auto emitAttr = [&](StringRef name, Attribute attr) { 2383 auto &body = adaptor.addMethodAndPrune(attr.getStorageType(), name)->body(); 2384 body << " assert(odsAttrs && \"no attributes when constructing adapter\");" 2385 << "\n " << attr.getStorageType() << " attr = " 2386 << "odsAttrs.get(\"" << name << "\")."; 2387 if (attr.hasDefaultValue() || attr.isOptional()) 2388 body << "dyn_cast_or_null<"; 2389 else 2390 body << "cast<"; 2391 body << attr.getStorageType() << ">();\n"; 2392 2393 if (attr.hasDefaultValue()) { 2394 // Use the default value if attribute is not set. 2395 // TODO: this is inefficient, we are recreating the attribute for every 2396 // call. This should be set instead. 2397 std::string defaultValue = std::string( 2398 tgfmt(attr.getConstBuilderTemplate(), &fctx, attr.getDefaultValue())); 2399 body << " if (!attr)\n attr = " << defaultValue << ";\n"; 2400 } 2401 body << " return attr;\n"; 2402 }; 2403 2404 { 2405 auto *m = 2406 adaptor.addMethodAndPrune("::mlir::DictionaryAttr", "getAttributes"); 2407 m->body() << " return odsAttrs;"; 2408 } 2409 for (auto &namedAttr : op.getAttributes()) { 2410 const auto &name = namedAttr.name; 2411 const auto &attr = namedAttr.attr; 2412 if (!attr.isDerivedAttr()) 2413 emitAttr(name, attr); 2414 } 2415 2416 unsigned numRegions = op.getNumRegions(); 2417 if (numRegions > 0) { 2418 auto *m = adaptor.addMethodAndPrune("::mlir::RegionRange", "getRegions"); 2419 m->body() << " return odsRegions;"; 2420 } 2421 for (unsigned i = 0; i < numRegions; ++i) { 2422 const auto ®ion = op.getRegion(i); 2423 if (region.name.empty()) 2424 continue; 2425 2426 // Generate the accessors for a variadic region. 2427 if (region.isVariadic()) { 2428 auto *m = adaptor.addMethodAndPrune("::mlir::RegionRange", region.name); 2429 m->body() << formatv(" return odsRegions.drop_front({0});", i); 2430 continue; 2431 } 2432 2433 auto *m = adaptor.addMethodAndPrune("::mlir::Region &", region.name); 2434 m->body() << formatv(" return *odsRegions[{0}];", i); 2435 } 2436 2437 // Add verification function. 2438 addVerification(); 2439 } 2440 2441 void OpOperandAdaptorEmitter::addVerification() { 2442 auto *method = adaptor.addMethodAndPrune("::mlir::LogicalResult", "verify", 2443 "::mlir::Location", "loc"); 2444 auto &body = method->body(); 2445 2446 const char *checkAttrSizedValueSegmentsCode = R"( 2447 { 2448 auto sizeAttr = odsAttrs.get("{0}").cast<::mlir::DenseIntElementsAttr>(); 2449 auto numElements = sizeAttr.getType().cast<::mlir::ShapedType>().getNumElements(); 2450 if (numElements != {1}) 2451 return emitError(loc, "'{0}' attribute for specifying {2} segments " 2452 "must have {1} elements, but got ") << numElements; 2453 } 2454 )"; 2455 2456 // Verify a few traits first so that we can use 2457 // getODSOperands()/getODSResults() in the rest of the verifier. 2458 for (auto &trait : op.getTraits()) { 2459 if (auto *t = dyn_cast<tblgen::NativeTrait>(&trait)) { 2460 if (t->getFullyQualifiedTraitName() == 2461 "::mlir::OpTrait::AttrSizedOperandSegments") { 2462 body << formatv(checkAttrSizedValueSegmentsCode, 2463 "operand_segment_sizes", op.getNumOperands(), 2464 "operand"); 2465 } else if (t->getFullyQualifiedTraitName() == 2466 "::mlir::OpTrait::AttrSizedResultSegments") { 2467 body << formatv(checkAttrSizedValueSegmentsCode, "result_segment_sizes", 2468 op.getNumResults(), "result"); 2469 } 2470 } 2471 } 2472 2473 FmtContext verifyCtx; 2474 populateSubstitutions(op, "odsAttrs.get", "getODSOperands", 2475 "<no results should be generated>", verifyCtx); 2476 genAttributeVerifier(op, "odsAttrs.get", 2477 Twine("emitError(loc, \"'") + op.getOperationName() + 2478 "' op \"", 2479 /*emitVerificationRequiringOp*/ false, verifyCtx, body); 2480 2481 body << " return ::mlir::success();"; 2482 } 2483 2484 void OpOperandAdaptorEmitter::emitDecl(const Operator &op, raw_ostream &os) { 2485 OpOperandAdaptorEmitter(op).adaptor.writeDeclTo(os); 2486 } 2487 2488 void OpOperandAdaptorEmitter::emitDef(const Operator &op, raw_ostream &os) { 2489 OpOperandAdaptorEmitter(op).adaptor.writeDefTo(os); 2490 } 2491 2492 // Emits the opcode enum and op classes. 2493 static void emitOpClasses(const RecordKeeper &recordKeeper, 2494 const std::vector<Record *> &defs, raw_ostream &os, 2495 bool emitDecl) { 2496 // First emit forward declaration for each class, this allows them to refer 2497 // to each others in traits for example. 2498 if (emitDecl) { 2499 os << "#if defined(GET_OP_CLASSES) || defined(GET_OP_FWD_DEFINES)\n"; 2500 os << "#undef GET_OP_FWD_DEFINES\n"; 2501 for (auto *def : defs) { 2502 Operator op(*def); 2503 NamespaceEmitter emitter(os, op.getCppNamespace()); 2504 os << "class " << op.getCppClassName() << ";\n"; 2505 } 2506 os << "#endif\n\n"; 2507 } 2508 2509 IfDefScope scope("GET_OP_CLASSES", os); 2510 if (defs.empty()) 2511 return; 2512 2513 // Generate all of the locally instantiated methods first. 2514 StaticVerifierFunctionEmitter staticVerifierEmitter(recordKeeper, os); 2515 os << formatv(opCommentHeader, "Local Utility Method", "Definitions"); 2516 staticVerifierEmitter.emitFunctionsFor( 2517 typeVerifierSignature, typeVerifierErrorHandler, /*typeArgName=*/"type", 2518 defs, emitDecl); 2519 2520 for (auto *def : defs) { 2521 Operator op(*def); 2522 if (emitDecl) { 2523 { 2524 NamespaceEmitter emitter(os, op.getCppNamespace()); 2525 os << formatv(opCommentHeader, op.getQualCppClassName(), 2526 "declarations"); 2527 OpOperandAdaptorEmitter::emitDecl(op, os); 2528 OpEmitter::emitDecl(op, os, staticVerifierEmitter); 2529 } 2530 // Emit the TypeID explicit specialization to have a single definition. 2531 if (!op.getCppNamespace().empty()) 2532 os << "DECLARE_EXPLICIT_TYPE_ID(" << op.getCppNamespace() 2533 << "::" << op.getCppClassName() << ")\n\n"; 2534 } else { 2535 { 2536 NamespaceEmitter emitter(os, op.getCppNamespace()); 2537 os << formatv(opCommentHeader, op.getQualCppClassName(), "definitions"); 2538 OpOperandAdaptorEmitter::emitDef(op, os); 2539 OpEmitter::emitDef(op, os, staticVerifierEmitter); 2540 } 2541 // Emit the TypeID explicit specialization to have a single definition. 2542 if (!op.getCppNamespace().empty()) 2543 os << "DEFINE_EXPLICIT_TYPE_ID(" << op.getCppNamespace() 2544 << "::" << op.getCppClassName() << ")\n\n"; 2545 } 2546 } 2547 } 2548 2549 // Emits a comma-separated list of the ops. 2550 static void emitOpList(const std::vector<Record *> &defs, raw_ostream &os) { 2551 IfDefScope scope("GET_OP_LIST", os); 2552 2553 interleave( 2554 // TODO: We are constructing the Operator wrapper instance just for 2555 // getting it's qualified class name here. Reduce the overhead by having a 2556 // lightweight version of Operator class just for that purpose. 2557 defs, [&os](Record *def) { os << Operator(def).getQualCppClassName(); }, 2558 [&os]() { os << ",\n"; }); 2559 } 2560 2561 static bool emitOpDecls(const RecordKeeper &recordKeeper, raw_ostream &os) { 2562 emitSourceFileHeader("Op Declarations", os); 2563 2564 std::vector<Record *> defs = getRequestedOpDefinitions(recordKeeper); 2565 emitOpClasses(recordKeeper, defs, os, /*emitDecl=*/true); 2566 2567 return false; 2568 } 2569 2570 static bool emitOpDefs(const RecordKeeper &recordKeeper, raw_ostream &os) { 2571 emitSourceFileHeader("Op Definitions", os); 2572 2573 std::vector<Record *> defs = getRequestedOpDefinitions(recordKeeper); 2574 emitOpList(defs, os); 2575 emitOpClasses(recordKeeper, defs, os, /*emitDecl=*/false); 2576 2577 return false; 2578 } 2579 2580 static mlir::GenRegistration 2581 genOpDecls("gen-op-decls", "Generate op declarations", 2582 [](const RecordKeeper &records, raw_ostream &os) { 2583 return emitOpDecls(records, os); 2584 }); 2585 2586 static mlir::GenRegistration genOpDefs("gen-op-defs", "Generate op definitions", 2587 [](const RecordKeeper &records, 2588 raw_ostream &os) { 2589 return emitOpDefs(records, os); 2590 }); 2591