1 //===- Operator.cpp - Operator class --------------------------------------===// 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 // Operator wrapper to simplify using TableGen Record defining a MLIR Op. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/TableGen/Operator.h" 14 #include "mlir/TableGen/Predicate.h" 15 #include "mlir/TableGen/Trait.h" 16 #include "mlir/TableGen/Type.h" 17 #include "llvm/ADT/EquivalenceClasses.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/Sequence.h" 20 #include "llvm/ADT/SmallPtrSet.h" 21 #include "llvm/ADT/StringExtras.h" 22 #include "llvm/ADT/TypeSwitch.h" 23 #include "llvm/Support/Debug.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/FormatVariadic.h" 26 #include "llvm/TableGen/Error.h" 27 #include "llvm/TableGen/Record.h" 28 29 #define DEBUG_TYPE "mlir-tblgen-operator" 30 31 using namespace mlir; 32 using namespace mlir::tblgen; 33 34 using llvm::DagInit; 35 using llvm::DefInit; 36 using llvm::Record; 37 38 Operator::Operator(const llvm::Record &def) 39 : dialect(def.getValueAsDef("opDialect")), def(def) { 40 // The first `_` in the op's TableGen def name is treated as separating the 41 // dialect prefix and the op class name. The dialect prefix will be ignored if 42 // not empty. Otherwise, if def name starts with a `_`, the `_` is considered 43 // as part of the class name. 44 StringRef prefix; 45 std::tie(prefix, cppClassName) = def.getName().split('_'); 46 if (prefix.empty()) { 47 // Class name with a leading underscore and without dialect prefix 48 cppClassName = def.getName(); 49 } else if (cppClassName.empty()) { 50 // Class name without dialect prefix 51 cppClassName = prefix; 52 } 53 54 cppNamespace = def.getValueAsString("cppNamespace"); 55 56 populateOpStructure(); 57 assertInvariants(); 58 } 59 60 std::string Operator::getOperationName() const { 61 auto prefix = dialect.getName(); 62 auto opName = def.getValueAsString("opName"); 63 if (prefix.empty()) 64 return std::string(opName); 65 return std::string(llvm::formatv("{0}.{1}", prefix, opName)); 66 } 67 68 std::string Operator::getAdaptorName() const { 69 return std::string(llvm::formatv("{0}Adaptor", getCppClassName())); 70 } 71 72 void Operator::assertInvariants() const { 73 // Check that the name of arguments/results/regions/successors don't overlap. 74 DenseMap<StringRef, StringRef> existingNames; 75 auto checkName = [&](StringRef name, StringRef entity) { 76 if (name.empty()) 77 return; 78 auto insertion = existingNames.insert({name, entity}); 79 if (insertion.second) 80 return; 81 if (entity == insertion.first->second) 82 PrintFatalError(getLoc(), "op has a conflict with two " + entity + 83 " having the same name '" + name + "'"); 84 PrintFatalError(getLoc(), "op has a conflict with " + 85 insertion.first->second + " and " + entity + 86 " both having an entry with the name '" + 87 name + "'"); 88 }; 89 // Check operands amongst themselves. 90 for (int i : llvm::seq<int>(0, getNumOperands())) 91 checkName(getOperand(i).name, "operands"); 92 93 // Check results amongst themselves and against operands. 94 for (int i : llvm::seq<int>(0, getNumResults())) 95 checkName(getResult(i).name, "results"); 96 97 // Check regions amongst themselves and against operands and results. 98 for (int i : llvm::seq<int>(0, getNumRegions())) 99 checkName(getRegion(i).name, "regions"); 100 101 // Check successors amongst themselves and against operands, results, and 102 // regions. 103 for (int i : llvm::seq<int>(0, getNumSuccessors())) 104 checkName(getSuccessor(i).name, "successors"); 105 } 106 107 StringRef Operator::getDialectName() const { return dialect.getName(); } 108 109 StringRef Operator::getCppClassName() const { return cppClassName; } 110 111 std::string Operator::getQualCppClassName() const { 112 if (cppNamespace.empty()) 113 return std::string(cppClassName); 114 return std::string(llvm::formatv("{0}::{1}", cppNamespace, cppClassName)); 115 } 116 117 StringRef Operator::getCppNamespace() const { return cppNamespace; } 118 119 int Operator::getNumResults() const { 120 DagInit *results = def.getValueAsDag("results"); 121 return results->getNumArgs(); 122 } 123 124 StringRef Operator::getExtraClassDeclaration() const { 125 constexpr auto attr = "extraClassDeclaration"; 126 if (def.isValueUnset(attr)) 127 return {}; 128 return def.getValueAsString(attr); 129 } 130 131 StringRef Operator::getExtraClassDefinition() const { 132 constexpr auto attr = "extraClassDefinition"; 133 if (def.isValueUnset(attr)) 134 return {}; 135 return def.getValueAsString(attr); 136 } 137 138 const llvm::Record &Operator::getDef() const { return def; } 139 140 bool Operator::skipDefaultBuilders() const { 141 return def.getValueAsBit("skipDefaultBuilders"); 142 } 143 144 auto Operator::result_begin() const -> const_value_iterator { 145 return results.begin(); 146 } 147 148 auto Operator::result_end() const -> const_value_iterator { 149 return results.end(); 150 } 151 152 auto Operator::getResults() const -> const_value_range { 153 return {result_begin(), result_end()}; 154 } 155 156 TypeConstraint Operator::getResultTypeConstraint(int index) const { 157 DagInit *results = def.getValueAsDag("results"); 158 return TypeConstraint(cast<DefInit>(results->getArg(index))); 159 } 160 161 StringRef Operator::getResultName(int index) const { 162 DagInit *results = def.getValueAsDag("results"); 163 return results->getArgNameStr(index); 164 } 165 166 auto Operator::getResultDecorators(int index) const -> var_decorator_range { 167 Record *result = 168 cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef(); 169 if (!result->isSubClassOf("OpVariable")) 170 return var_decorator_range(nullptr, nullptr); 171 return *result->getValueAsListInit("decorators"); 172 } 173 174 unsigned Operator::getNumVariableLengthResults() const { 175 return llvm::count_if(results, [](const NamedTypeConstraint &c) { 176 return c.constraint.isVariableLength(); 177 }); 178 } 179 180 unsigned Operator::getNumVariableLengthOperands() const { 181 return llvm::count_if(operands, [](const NamedTypeConstraint &c) { 182 return c.constraint.isVariableLength(); 183 }); 184 } 185 186 bool Operator::hasSingleVariadicArg() const { 187 return getNumArgs() == 1 && getArg(0).is<NamedTypeConstraint *>() && 188 getOperand(0).isVariadic(); 189 } 190 191 Operator::arg_iterator Operator::arg_begin() const { return arguments.begin(); } 192 193 Operator::arg_iterator Operator::arg_end() const { return arguments.end(); } 194 195 Operator::arg_range Operator::getArgs() const { 196 return {arg_begin(), arg_end()}; 197 } 198 199 StringRef Operator::getArgName(int index) const { 200 DagInit *argumentValues = def.getValueAsDag("arguments"); 201 return argumentValues->getArgNameStr(index); 202 } 203 204 auto Operator::getArgDecorators(int index) const -> var_decorator_range { 205 Record *arg = 206 cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef(); 207 if (!arg->isSubClassOf("OpVariable")) 208 return var_decorator_range(nullptr, nullptr); 209 return *arg->getValueAsListInit("decorators"); 210 } 211 212 const Trait *Operator::getTrait(StringRef trait) const { 213 for (const auto &t : traits) { 214 if (const auto *traitDef = dyn_cast<NativeTrait>(&t)) { 215 if (traitDef->getFullyQualifiedTraitName() == trait) 216 return traitDef; 217 } else if (const auto *traitDef = dyn_cast<InternalTrait>(&t)) { 218 if (traitDef->getFullyQualifiedTraitName() == trait) 219 return traitDef; 220 } else if (const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) { 221 if (traitDef->getFullyQualifiedTraitName() == trait) 222 return traitDef; 223 } 224 } 225 return nullptr; 226 } 227 228 auto Operator::region_begin() const -> const_region_iterator { 229 return regions.begin(); 230 } 231 auto Operator::region_end() const -> const_region_iterator { 232 return regions.end(); 233 } 234 auto Operator::getRegions() const 235 -> llvm::iterator_range<const_region_iterator> { 236 return {region_begin(), region_end()}; 237 } 238 239 unsigned Operator::getNumRegions() const { return regions.size(); } 240 241 const NamedRegion &Operator::getRegion(unsigned index) const { 242 return regions[index]; 243 } 244 245 unsigned Operator::getNumVariadicRegions() const { 246 return llvm::count_if(regions, 247 [](const NamedRegion &c) { return c.isVariadic(); }); 248 } 249 250 auto Operator::successor_begin() const -> const_successor_iterator { 251 return successors.begin(); 252 } 253 auto Operator::successor_end() const -> const_successor_iterator { 254 return successors.end(); 255 } 256 auto Operator::getSuccessors() const 257 -> llvm::iterator_range<const_successor_iterator> { 258 return {successor_begin(), successor_end()}; 259 } 260 261 unsigned Operator::getNumSuccessors() const { return successors.size(); } 262 263 const NamedSuccessor &Operator::getSuccessor(unsigned index) const { 264 return successors[index]; 265 } 266 267 unsigned Operator::getNumVariadicSuccessors() const { 268 return llvm::count_if(successors, 269 [](const NamedSuccessor &c) { return c.isVariadic(); }); 270 } 271 272 auto Operator::trait_begin() const -> const_trait_iterator { 273 return traits.begin(); 274 } 275 auto Operator::trait_end() const -> const_trait_iterator { 276 return traits.end(); 277 } 278 auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> { 279 return {trait_begin(), trait_end()}; 280 } 281 282 auto Operator::attribute_begin() const -> attribute_iterator { 283 return attributes.begin(); 284 } 285 auto Operator::attribute_end() const -> attribute_iterator { 286 return attributes.end(); 287 } 288 auto Operator::getAttributes() const 289 -> llvm::iterator_range<attribute_iterator> { 290 return {attribute_begin(), attribute_end()}; 291 } 292 293 auto Operator::operand_begin() const -> const_value_iterator { 294 return operands.begin(); 295 } 296 auto Operator::operand_end() const -> const_value_iterator { 297 return operands.end(); 298 } 299 auto Operator::getOperands() const -> const_value_range { 300 return {operand_begin(), operand_end()}; 301 } 302 303 auto Operator::getArg(int index) const -> Argument { return arguments[index]; } 304 305 // Mapping from result index to combined argument and result index. Arguments 306 // are indexed to match getArg index, while the result indexes are mapped to 307 // avoid overlap. 308 static int resultIndex(int i) { return -1 - i; } 309 310 bool Operator::isVariadic() const { 311 return any_of(llvm::concat<const NamedTypeConstraint>(operands, results), 312 [](const NamedTypeConstraint &op) { return op.isVariadic(); }); 313 } 314 315 void Operator::populateTypeInferenceInfo( 316 const llvm::StringMap<int> &argumentsAndResultsIndex) { 317 // If the type inference op interface is not registered, then do not attempt 318 // to determine if the result types an be inferred. 319 auto &recordKeeper = def.getRecords(); 320 auto *inferTrait = recordKeeper.getDef(inferTypeOpInterface); 321 allResultsHaveKnownTypes = false; 322 if (!inferTrait) 323 return; 324 325 // If there are no results, the skip this else the build method generated 326 // overlaps with another autogenerated builder. 327 if (getNumResults() == 0) 328 return; 329 330 // Skip ops with variadic or optional results. 331 if (getNumVariableLengthResults() > 0) 332 return; 333 334 // Skip cases currently being custom generated. 335 // TODO: Remove special cases. 336 if (getTrait("::mlir::OpTrait::SameOperandsAndResultType")) { 337 // Check for a non-variable length operand to use as the type anchor. 338 auto *operandI = llvm::find_if(arguments, [](const Argument &arg) { 339 NamedTypeConstraint *operand = arg.dyn_cast<NamedTypeConstraint *>(); 340 return operand && !operand->isVariableLength(); 341 }); 342 if (operandI == arguments.end()) 343 return; 344 345 // Map each of the result types to the anchor operation. 346 int operandIdx = operandI - arguments.begin(); 347 resultTypeMapping.resize(getNumResults()); 348 for (int i = 0; i < getNumResults(); ++i) 349 resultTypeMapping[i].emplace_back(operandIdx); 350 351 allResultsHaveKnownTypes = true; 352 traits.push_back(Trait::create(inferTrait->getDefInit())); 353 return; 354 } 355 356 // We create equivalence classes of argument/result types where arguments 357 // and results are mapped into the same index space and indices corresponding 358 // to the same type are in the same equivalence class. 359 llvm::EquivalenceClasses<int> ecs; 360 resultTypeMapping.resize(getNumResults()); 361 // Captures the argument whose type matches a given result type. Preference 362 // towards capturing operands first before attributes. 363 auto captureMapping = [&](int i) { 364 bool found = false; 365 ecs.insert(resultIndex(i)); 366 auto mi = ecs.findLeader(resultIndex(i)); 367 for (auto me = ecs.member_end(); mi != me; ++mi) { 368 if (*mi < 0) { 369 auto tc = getResultTypeConstraint(i); 370 if (tc.getBuilderCall()) { 371 resultTypeMapping[i].emplace_back(tc); 372 found = true; 373 } 374 continue; 375 } 376 377 resultTypeMapping[i].emplace_back(*mi); 378 found = true; 379 } 380 return found; 381 }; 382 383 for (const Trait &trait : traits) { 384 const llvm::Record &def = trait.getDef(); 385 // If the infer type op interface was manually added, then treat it as 386 // intention that the op needs special handling. 387 // TODO: Reconsider whether to always generate, this is more conservative 388 // and keeps existing behavior so starting that way for now. 389 if (def.isSubClassOf( 390 llvm::formatv("{0}::Trait", inferTypeOpInterface).str())) 391 return; 392 if (const auto *traitDef = dyn_cast<InterfaceTrait>(&trait)) 393 if (&traitDef->getDef() == inferTrait) 394 return; 395 396 if (!def.isSubClassOf("AllTypesMatch")) 397 continue; 398 399 auto values = def.getValueAsListOfStrings("values"); 400 auto root = argumentsAndResultsIndex.lookup(values.front()); 401 for (StringRef str : values) 402 ecs.unionSets(argumentsAndResultsIndex.lookup(str), root); 403 } 404 405 // Verifies that all output types have a corresponding known input type 406 // and chooses matching operand or attribute (in that order) that 407 // matches it. 408 allResultsHaveKnownTypes = 409 all_of(llvm::seq<int>(0, getNumResults()), captureMapping); 410 411 // If the types could be computed, then add type inference trait. 412 if (allResultsHaveKnownTypes) 413 traits.push_back(Trait::create(inferTrait->getDefInit())); 414 } 415 416 void Operator::populateOpStructure() { 417 auto &recordKeeper = def.getRecords(); 418 auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint"); 419 auto *attrClass = recordKeeper.getClass("Attr"); 420 auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr"); 421 auto *opVarClass = recordKeeper.getClass("OpVariable"); 422 numNativeAttributes = 0; 423 424 DagInit *argumentValues = def.getValueAsDag("arguments"); 425 unsigned numArgs = argumentValues->getNumArgs(); 426 427 // Mapping from name of to argument or result index. Arguments are indexed 428 // to match getArg index, while the results are negatively indexed. 429 llvm::StringMap<int> argumentsAndResultsIndex; 430 431 // Handle operands and native attributes. 432 for (unsigned i = 0; i != numArgs; ++i) { 433 auto *arg = argumentValues->getArg(i); 434 auto givenName = argumentValues->getArgNameStr(i); 435 auto *argDefInit = dyn_cast<DefInit>(arg); 436 if (!argDefInit) 437 PrintFatalError(def.getLoc(), 438 Twine("undefined type for argument #") + Twine(i)); 439 Record *argDef = argDefInit->getDef(); 440 if (argDef->isSubClassOf(opVarClass)) 441 argDef = argDef->getValueAsDef("constraint"); 442 443 if (argDef->isSubClassOf(typeConstraintClass)) { 444 operands.push_back( 445 NamedTypeConstraint{givenName, TypeConstraint(argDef)}); 446 } else if (argDef->isSubClassOf(attrClass)) { 447 if (givenName.empty()) 448 PrintFatalError(argDef->getLoc(), "attributes must be named"); 449 if (argDef->isSubClassOf(derivedAttrClass)) 450 PrintFatalError(argDef->getLoc(), 451 "derived attributes not allowed in argument list"); 452 attributes.push_back({givenName, Attribute(argDef)}); 453 ++numNativeAttributes; 454 } else { 455 PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving " 456 "from TypeConstraint or Attr are allowed"); 457 } 458 if (!givenName.empty()) 459 argumentsAndResultsIndex[givenName] = i; 460 } 461 462 // Handle derived attributes. 463 for (const auto &val : def.getValues()) { 464 if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) { 465 if (!record->isSubClassOf(attrClass)) 466 continue; 467 if (!record->isSubClassOf(derivedAttrClass)) 468 PrintFatalError(def.getLoc(), 469 "unexpected Attr where only DerivedAttr is allowed"); 470 471 if (record->getClasses().size() != 1) { 472 PrintFatalError( 473 def.getLoc(), 474 "unsupported attribute modelling, only single class expected"); 475 } 476 attributes.push_back( 477 {cast<llvm::StringInit>(val.getNameInit())->getValue(), 478 Attribute(cast<DefInit>(val.getValue()))}); 479 } 480 } 481 482 // Populate `arguments`. This must happen after we've finalized `operands` and 483 // `attributes` because we will put their elements' pointers in `arguments`. 484 // SmallVector may perform re-allocation under the hood when adding new 485 // elements. 486 int operandIndex = 0, attrIndex = 0; 487 for (unsigned i = 0; i != numArgs; ++i) { 488 Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef(); 489 if (argDef->isSubClassOf(opVarClass)) 490 argDef = argDef->getValueAsDef("constraint"); 491 492 if (argDef->isSubClassOf(typeConstraintClass)) { 493 attrOrOperandMapping.push_back( 494 {OperandOrAttribute::Kind::Operand, operandIndex}); 495 arguments.emplace_back(&operands[operandIndex++]); 496 } else { 497 assert(argDef->isSubClassOf(attrClass)); 498 attrOrOperandMapping.push_back( 499 {OperandOrAttribute::Kind::Attribute, attrIndex}); 500 arguments.emplace_back(&attributes[attrIndex++]); 501 } 502 } 503 504 auto *resultsDag = def.getValueAsDag("results"); 505 auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator()); 506 if (!outsOp || outsOp->getDef()->getName() != "outs") { 507 PrintFatalError(def.getLoc(), "'results' must have 'outs' directive"); 508 } 509 510 // Handle results. 511 for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) { 512 auto name = resultsDag->getArgNameStr(i); 513 auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i)); 514 if (!resultInit) { 515 PrintFatalError(def.getLoc(), 516 Twine("undefined type for result #") + Twine(i)); 517 } 518 auto *resultDef = resultInit->getDef(); 519 if (resultDef->isSubClassOf(opVarClass)) 520 resultDef = resultDef->getValueAsDef("constraint"); 521 results.push_back({name, TypeConstraint(resultDef)}); 522 if (!name.empty()) 523 argumentsAndResultsIndex[name] = resultIndex(i); 524 525 // We currently only support VariadicOfVariadic operands. 526 if (results.back().constraint.isVariadicOfVariadic()) { 527 PrintFatalError( 528 def.getLoc(), 529 "'VariadicOfVariadic' results are currently not supported"); 530 } 531 } 532 533 // Handle successors 534 auto *successorsDag = def.getValueAsDag("successors"); 535 auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator()); 536 if (!successorsOp || successorsOp->getDef()->getName() != "successor") { 537 PrintFatalError(def.getLoc(), 538 "'successors' must have 'successor' directive"); 539 } 540 541 for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) { 542 auto name = successorsDag->getArgNameStr(i); 543 auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i)); 544 if (!successorInit) { 545 PrintFatalError(def.getLoc(), 546 Twine("undefined kind for successor #") + Twine(i)); 547 } 548 Successor successor(successorInit->getDef()); 549 550 // Only support variadic successors if it is the last one for now. 551 if (i != e - 1 && successor.isVariadic()) 552 PrintFatalError(def.getLoc(), "only the last successor can be variadic"); 553 successors.push_back({name, successor}); 554 } 555 556 // Create list of traits, skipping over duplicates: appending to lists in 557 // tablegen is easy, making them unique less so, so dedupe here. 558 if (auto *traitList = def.getValueAsListInit("traits")) { 559 // This is uniquing based on pointers of the trait. 560 SmallPtrSet<const llvm::Init *, 32> traitSet; 561 traits.reserve(traitSet.size()); 562 563 // The declaration order of traits imply the verification order of traits. 564 // Some traits may require other traits to be verified first then they can 565 // do further verification based on those verified facts. If you see this 566 // error, fix the traits declaration order by checking the `dependentTraits` 567 // field. 568 auto verifyTraitValidity = [&](Record *trait) { 569 auto *dependentTraits = trait->getValueAsListInit("dependentTraits"); 570 for (auto *traitInit : *dependentTraits) 571 if (traitSet.find(traitInit) == traitSet.end()) 572 PrintFatalError( 573 def.getLoc(), 574 trait->getValueAsString("trait") + " requires " + 575 cast<DefInit>(traitInit)->getDef()->getValueAsString( 576 "trait") + 577 " to precede it in traits list"); 578 }; 579 580 std::function<void(llvm::ListInit *)> insert; 581 insert = [&](llvm::ListInit *traitList) { 582 for (auto *traitInit : *traitList) { 583 auto *def = cast<DefInit>(traitInit)->getDef(); 584 if (def->isSubClassOf("TraitList")) { 585 insert(def->getValueAsListInit("traits")); 586 continue; 587 } 588 589 // Verify if the trait has all the dependent traits declared before 590 // itself. 591 verifyTraitValidity(def); 592 593 // Keep traits in the same order while skipping over duplicates. 594 if (traitSet.insert(traitInit).second) 595 traits.push_back(Trait::create(traitInit)); 596 } 597 }; 598 insert(traitList); 599 } 600 601 populateTypeInferenceInfo(argumentsAndResultsIndex); 602 603 // Handle regions 604 auto *regionsDag = def.getValueAsDag("regions"); 605 auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator()); 606 if (!regionsOp || regionsOp->getDef()->getName() != "region") { 607 PrintFatalError(def.getLoc(), "'regions' must have 'region' directive"); 608 } 609 610 for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) { 611 auto name = regionsDag->getArgNameStr(i); 612 auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i)); 613 if (!regionInit) { 614 PrintFatalError(def.getLoc(), 615 Twine("undefined kind for region #") + Twine(i)); 616 } 617 Region region(regionInit->getDef()); 618 if (region.isVariadic()) { 619 // Only support variadic regions if it is the last one for now. 620 if (i != e - 1) 621 PrintFatalError(def.getLoc(), "only the last region can be variadic"); 622 if (name.empty()) 623 PrintFatalError(def.getLoc(), "variadic regions must be named"); 624 } 625 626 regions.push_back({name, region}); 627 } 628 629 // Populate the builders. 630 auto *builderList = 631 dyn_cast_or_null<llvm::ListInit>(def.getValueInit("builders")); 632 if (builderList && !builderList->empty()) { 633 for (llvm::Init *init : builderList->getValues()) 634 builders.emplace_back(cast<llvm::DefInit>(init)->getDef(), def.getLoc()); 635 } else if (skipDefaultBuilders()) { 636 PrintFatalError( 637 def.getLoc(), 638 "default builders are skipped and no custom builders provided"); 639 } 640 641 LLVM_DEBUG(print(llvm::dbgs())); 642 } 643 644 auto Operator::getSameTypeAsResult(int index) const -> ArrayRef<ArgOrType> { 645 assert(allResultTypesKnown()); 646 return resultTypeMapping[index]; 647 } 648 649 ArrayRef<SMLoc> Operator::getLoc() const { return def.getLoc(); } 650 651 bool Operator::hasDescription() const { 652 return def.getValue("description") != nullptr; 653 } 654 655 StringRef Operator::getDescription() const { 656 return def.getValueAsString("description"); 657 } 658 659 bool Operator::hasSummary() const { return def.getValue("summary") != nullptr; } 660 661 StringRef Operator::getSummary() const { 662 return def.getValueAsString("summary"); 663 } 664 665 bool Operator::hasAssemblyFormat() const { 666 auto *valueInit = def.getValueInit("assemblyFormat"); 667 return isa<llvm::StringInit>(valueInit); 668 } 669 670 StringRef Operator::getAssemblyFormat() const { 671 return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat")) 672 .Case<llvm::StringInit>([&](auto *init) { return init->getValue(); }); 673 } 674 675 void Operator::print(llvm::raw_ostream &os) const { 676 os << "op '" << getOperationName() << "'\n"; 677 for (Argument arg : arguments) { 678 if (auto *attr = arg.dyn_cast<NamedAttribute *>()) 679 os << "[attribute] " << attr->name << '\n'; 680 else 681 os << "[operand] " << arg.get<NamedTypeConstraint *>()->name << '\n'; 682 } 683 } 684 685 auto Operator::VariableDecoratorIterator::unwrap(llvm::Init *init) 686 -> VariableDecorator { 687 return VariableDecorator(cast<llvm::DefInit>(init)->getDef()); 688 } 689 690 auto Operator::getArgToOperandOrAttribute(int index) const 691 -> OperandOrAttribute { 692 return attrOrOperandMapping[index]; 693 } 694 695 // Helper to return the names for accessor. 696 static SmallVector<std::string, 2> 697 getGetterOrSetterNames(bool isGetter, const Operator &op, StringRef name) { 698 Dialect::EmitPrefix prefixType = op.getDialect().getEmitAccessorPrefix(); 699 std::string prefix; 700 if (prefixType != Dialect::EmitPrefix::Raw) 701 prefix = isGetter ? "get" : "set"; 702 703 SmallVector<std::string, 2> names; 704 bool rawToo = prefixType == Dialect::EmitPrefix::Both; 705 706 // Whether to skip generating prefixed form for argument. This just does some 707 // basic checks. 708 // 709 // There are a little bit more invasive checks possible for cases where not 710 // all ops have the trait that would cause overlap. For many cases here, 711 // renaming would be better (e.g., we can only guard in limited manner against 712 // methods from traits and interfaces here, so avoiding these in op definition 713 // is safer). 714 auto skip = [&](StringRef newName) { 715 bool shouldSkip = newName == "getAttributeNames" || 716 newName == "getAttributes" || newName == "getOperation"; 717 if (newName == "getOperands") { 718 // To reduce noise, skip generating the prefixed form and the warning if 719 // $operands correspond to single variadic argument. 720 if (op.getNumOperands() == 1 && op.getNumVariableLengthOperands() == 1) 721 return true; 722 shouldSkip = true; 723 } 724 if (newName == "getRegions") { 725 if (op.getNumRegions() == 1 && op.getNumVariadicRegions() == 1) 726 return true; 727 shouldSkip = true; 728 } 729 if (newName == "getType") { 730 if (op.getNumResults() == 0) 731 return false; 732 shouldSkip = true; 733 } 734 if (!shouldSkip) 735 return false; 736 737 // This note could be avoided where the final function generated would 738 // have been identical. But preferably in the op definition avoiding using 739 // the generic name and then getting a more specialize type is better. 740 PrintNote(op.getLoc(), 741 "Skipping generation of prefixed accessor `" + newName + 742 "` as it overlaps with default one; generating raw form (`" + 743 name + "`) still"); 744 return true; 745 }; 746 747 if (!prefix.empty()) { 748 names.push_back( 749 prefix + convertToCamelFromSnakeCase(name, /*capitalizeFirst=*/true)); 750 // Skip cases which would overlap with default ones for now. 751 if (skip(names.back())) { 752 rawToo = true; 753 names.clear(); 754 } else if (rawToo) { 755 LLVM_DEBUG(llvm::errs() << "WITH_GETTER(\"" << op.getQualCppClassName() 756 << "::" << name << "\")\n" 757 << "WITH_GETTER(\"" << op.getQualCppClassName() 758 << "Adaptor::" << name << "\")\n";); 759 } 760 } 761 762 if (prefix.empty() || rawToo) 763 names.push_back(name.str()); 764 return names; 765 } 766 767 SmallVector<std::string, 2> Operator::getGetterNames(StringRef name) const { 768 return getGetterOrSetterNames(/*isGetter=*/true, *this, name); 769 } 770 771 SmallVector<std::string, 2> Operator::getSetterNames(StringRef name) const { 772 return getGetterOrSetterNames(/*isGetter=*/false, *this, name); 773 } 774