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"
29#define DEBUG_TYPE "mlir-tblgen-operator"
39using llvm::StringInit;
42 : dialect(def.getValueAsDef(
"opDialect")), def(def) {
48 std::tie(prefix, cppClassName) = def.getName().split(
'_');
51 cppClassName = def.getName();
52 }
else if (cppClassName.empty()) {
54 cppClassName = prefix;
57 cppNamespace = def.getValueAsString(
"cppNamespace");
59 populateOpStructure();
64 auto prefix = dialect.getName();
65 auto opName = def.getValueAsString(
"opName");
67 return std::string(opName);
68 return std::string(llvm::formatv(
"{0}.{1}", prefix, opName));
76 return std::string(llvm::formatv(
"{0}GenericAdaptor",
getCppClassName()));
81 std::string accessorName =
82 convertToCamelFromSnakeCase(name,
true);
92 auto nameOverlapsWithOpAPI = [&](StringRef newName) {
93 if (newName ==
"AttributeNames" || newName ==
"Attributes" ||
94 newName ==
"Operation")
96 if (newName ==
"Operands")
98 if (newName ==
"Regions")
100 if (newName ==
"Type")
104 if (nameOverlapsWithOpAPI(accessorName)) {
108 PrintFatalError(op.
getLoc(),
"generated accessor for `" + name +
109 "` overlaps with a default one; please "
110 "rename to avoid overlap");
117 auto checkName = [&](StringRef name, StringRef entity) {
120 auto insertion = existingNames.insert({name, entity});
121 if (insertion.second) {
126 if (entity == insertion.first->second)
127 PrintFatalError(
getLoc(),
"op has a conflict with two " + entity +
128 " having the same name '" + name +
"'");
129 PrintFatalError(
getLoc(),
"op has a conflict with " +
130 insertion.first->second +
" and " + entity +
131 " both having an entry with the name '" +
157 if (cppNamespace.empty())
158 return std::string(cppClassName);
159 return std::string(llvm::formatv(
"{0}::{1}", cppNamespace, cppClassName));
165 const DagInit *results = def.getValueAsDag(
"results");
166 return results->getNumArgs();
170 constexpr auto attr =
"extraClassDeclaration";
171 if (def.isValueUnset(attr))
173 return def.getValueAsString(attr);
177 constexpr auto attr =
"extraClassDefinition";
178 if (def.isValueUnset(attr))
180 return def.getValueAsString(attr);
186 return def.getValueAsBit(
"skipDefaultBuilders");
190 return def.getValueAsBit(
"hasCustomPropertiesPrinter");
194 return results.begin();
198 return results.end();
206 const DagInit *results = def.getValueAsDag(
"results");
211 const DagInit *results = def.getValueAsDag(
"results");
212 return results->getArgNameStr(
index);
217 cast<DefInit>(def.getValueAsDag(
"results")->getArg(
index))->getDef();
218 if (!
result->isSubClassOf(
"OpVariable"))
220 return *
result->getValueAsListInit(
"decorators");
249 const DagInit *argumentValues = def.getValueAsDag(
"arguments");
250 return argumentValues->getArgNameStr(
index);
255 cast<DefInit>(def.getValueAsDag(
"arguments")->getArg(
index))->getDef();
256 if (!arg->isSubClassOf(
"OpVariable"))
258 return *arg->getValueAsListInit(
"decorators");
262 for (
const auto &t : traits) {
263 if (
const auto *traitDef = dyn_cast<NativeTrait>(&t)) {
264 if (traitDef->getFullyQualifiedTraitName() == trait)
266 }
else if (
const auto *traitDef = dyn_cast<InternalTrait>(&t)) {
267 if (traitDef->getFullyQualifiedTraitName() == trait)
269 }
else if (
const auto *traitDef = dyn_cast<InterfaceTrait>(&t)) {
270 if (traitDef->getFullyQualifiedTraitName() == trait)
278 if (!properties.empty())
280 if (
getTrait(
"::mlir::OpTrait::AttrSizedOperandSegments") ||
281 getTrait(
"::mlir::OpTrait::AttrSizedResultSegments"))
291 if (!attr.attr.isDerivedAttr())
292 names.push_back(attr.name);
294 names.push_back(property.name);
295 if (
getTrait(
"::mlir::OpTrait::AttrSizedOperandSegments")) {
299 if (
getTrait(
"::mlir::OpTrait::AttrSizedResultSegments")) {
307 return regions.begin();
310 return regions.end();
320 return regions[
index];
324 return llvm::count_if(regions,
329 return successors.begin();
332 return successors.end();
342 return successors[
index];
346 return llvm::count_if(successors,
351 return traits.begin();
361 return attributes.begin();
364 return attributes.end();
371 return attributes.begin();
374 return attributes.end();
381 return operands.begin();
384 return operands.end();
393 return any_of(llvm::concat<const NamedTypeConstraint>(operands, results),
397void Operator::populateTypeInferenceInfo(
398 const llvm::StringMap<int> &argumentsAndResultsIndex) {
401 auto &recordKeeper = def.getRecords();
403 allResultsHaveKnownTypes =
false;
418 if (
getTrait(
"::mlir::OpTrait::SameOperandsAndResultType")) {
420 auto *operandI = llvm::find_if(arguments, [](
const Argument &arg) {
422 llvm::dyn_cast_if_present<NamedTypeConstraint *>(arg);
425 if (operandI == arguments.end())
429 int operandIdx = operandI - arguments.begin();
431 resultTypeMapping.emplace_back(operandIdx,
"$_self");
433 allResultsHaveKnownTypes =
true;
443 struct ResultTypeInference {
447 bool inferred =
false;
453 llvm::for_overwrite);
457 for (
auto [idx, infer] : llvm::enumerate(inference)) {
458 if (
getResult(idx).constraint.getBuilderCall()) {
461 infer.inferred =
true;
467 for (
const Trait &trait : traits) {
468 const Record &def = trait.getDef();
474 if (def.isSubClassOf(
477 if (
const auto *traitDef = dyn_cast<InterfaceTrait>(&trait))
478 if (&traitDef->getDef() == inferTrait)
483 if (def.isSubClassOf(
"TypesMatchWith")) {
484 int target = argumentsAndResultsIndex.lookup(def.getValueAsString(
"rhs"));
489 ResultTypeInference &infer = inference[resultIndex];
494 argumentsAndResultsIndex.lookup(def.getValueAsString(
"lhs"));
495 infer.sources.emplace_back(sourceIndex,
496 def.getValueAsString(
"transformer").str());
507 if (def.isSubClassOf(
"ShapedTypeMatchesElementCountAndTypes")) {
508 StringRef shapedArg = def.getValueAsString(
"shaped");
509 StringRef elementsArg = def.getValueAsString(
"elements");
511 int shapedIndex = argumentsAndResultsIndex.lookup(shapedArg);
512 int elementsIndex = argumentsAndResultsIndex.lookup(elementsArg);
518 ResultTypeInference &infer = inference[resultIndex];
519 if (!infer.inferred) {
520 infer.sources.emplace_back(
522 "::llvm::SmallVector<::mlir::Type>(::llvm::cast<::mlir::"
523 "ShapedType>($_self).getNumElements(), "
524 "::llvm::cast<::mlir::ShapedType>($_self).getElementType())");
525 infer.inferred =
true;
535 if (!def.isSubClassOf(
"AllTypesMatch"))
538 auto values = def.getValueAsListOfStrings(
"values");
544 std::optional<int> fullyInferredIndex;
545 SmallVector<int> resultIndices;
546 for (StringRef name : values) {
547 int index = argumentsAndResultsIndex.lookup(name);
552 fullyInferredIndex = index;
554 if (fullyInferredIndex) {
557 for (
int resultIndex : resultIndices) {
558 ResultTypeInference &infer = inference[resultIndex];
559 if (!infer.inferred) {
560 infer.sources.assign(1, {*fullyInferredIndex,
"$_self"});
561 infer.inferred =
true;
566 for (
int resultIndex : resultIndices) {
567 for (
int otherResultIndex : resultIndices) {
568 if (resultIndex == otherResultIndex)
570 inference[resultIndex].sources.emplace_back(
578 std::vector<ResultTypeInference *> worklist;
579 for (ResultTypeInference &infer : inference)
581 worklist.push_back(&infer);
585 for (
auto cur = worklist.begin(); cur != worklist.end();) {
586 ResultTypeInference &infer = **cur;
588 InferredResultType *iter =
589 llvm::find_if(infer.sources, [&](
const InferredResultType &source) {
590 assert(InferredResultType::isResultIndex(source.getIndex()));
591 return inference[InferredResultType::unmapResultIndex(
595 if (iter == infer.sources.end()) {
601 infer.inferred =
true;
603 infer.sources.assign(1, *iter);
604 cur = worklist.erase(cur);
608 allResultsHaveKnownTypes = worklist.empty();
611 if (allResultsHaveKnownTypes) {
613 for (
const ResultTypeInference &infer : inference)
614 resultTypeMapping.push_back(infer.sources.front());
618void Operator::populateOpStructure() {
619 auto &recordKeeper = def.getRecords();
620 auto *typeConstraintClass = recordKeeper.getClass(
"TypeConstraint");
621 auto *attrClass = recordKeeper.getClass(
"Attr");
622 auto *propertyClass = recordKeeper.getClass(
"Property");
623 auto *derivedAttrClass = recordKeeper.getClass(
"DerivedAttr");
624 auto *opVarClass = recordKeeper.getClass(
"OpVariable");
625 numNativeAttributes = 0;
627 const DagInit *argumentValues = def.getValueAsDag(
"arguments");
628 unsigned numArgs = argumentValues->getNumArgs();
632 llvm::StringMap<int> argumentsAndResultsIndex;
635 for (
unsigned i = 0; i != numArgs; ++i) {
636 auto *arg = argumentValues->getArg(i);
637 auto givenName = argumentValues->getArgNameStr(i);
638 auto *argDefInit = dyn_cast<DefInit>(arg);
640 PrintFatalError(def.getLoc(),
641 Twine(
"undefined type for argument #") + Twine(i));
642 const Record *argDef = argDefInit->getDef();
643 if (argDef->isSubClassOf(opVarClass))
644 argDef = argDef->getValueAsDef(
"constraint");
646 if (argDef->isSubClassOf(typeConstraintClass)) {
648 NamedTypeConstraint{givenName, TypeConstraint(argDef)});
649 }
else if (argDef->isSubClassOf(attrClass)) {
650 if (givenName.empty())
651 PrintFatalError(argDef->getLoc(),
"attributes must be named");
652 if (argDef->isSubClassOf(derivedAttrClass))
653 PrintFatalError(argDef->getLoc(),
654 "derived attributes not allowed in argument list");
655 attributes.push_back({givenName, Attribute(argDef)});
656 ++numNativeAttributes;
657 }
else if (argDef->isSubClassOf(propertyClass)) {
658 if (givenName.empty())
659 PrintFatalError(argDef->getLoc(),
"properties must be named");
660 properties.push_back({givenName, Property(argDef)});
662 PrintFatalError(def.getLoc(),
663 "unexpected def type; only defs deriving "
664 "from TypeConstraint or Attr or Property are allowed");
666 if (!givenName.empty())
667 argumentsAndResultsIndex[givenName] = i;
671 for (
const auto &val : def.getValues()) {
672 if (
auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) {
673 if (!record->isSubClassOf(attrClass))
675 if (!record->isSubClassOf(derivedAttrClass))
676 PrintFatalError(def.getLoc(),
677 "unexpected Attr where only DerivedAttr is allowed");
679 if (record->getClasses().size() != 1) {
682 "unsupported attribute modelling, only single class expected");
684 attributes.push_back({cast<StringInit>(val.getNameInit())->getValue(),
685 Attribute(cast<DefInit>(val.getValue()))});
693 int operandIndex = 0, attrIndex = 0, propIndex = 0;
694 for (
unsigned i = 0; i != numArgs; ++i) {
695 const Record *argDef =
696 dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
697 if (argDef->isSubClassOf(opVarClass))
698 argDef = argDef->getValueAsDef(
"constraint");
700 if (argDef->isSubClassOf(typeConstraintClass)) {
701 attrPropOrOperandMapping.push_back(
703 arguments.emplace_back(&operands[operandIndex++]);
704 }
else if (argDef->isSubClassOf(attrClass)) {
705 attrPropOrOperandMapping.push_back(
707 arguments.emplace_back(&attributes[attrIndex++]);
709 assert(argDef->isSubClassOf(propertyClass));
710 attrPropOrOperandMapping.push_back(
712 arguments.emplace_back(&properties[propIndex++]);
716 auto *resultsDag = def.getValueAsDag(
"results");
717 auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator());
718 if (!outsOp || outsOp->getDef()->getName() !=
"outs") {
719 PrintFatalError(def.getLoc(),
"'results' must have 'outs' directive");
723 for (
unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) {
724 auto name = resultsDag->getArgNameStr(i);
725 auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i));
727 PrintFatalError(def.getLoc(),
728 Twine(
"undefined type for result #") + Twine(i));
730 auto *resultDef = resultInit->getDef();
731 if (resultDef->isSubClassOf(opVarClass))
732 resultDef = resultDef->getValueAsDef(
"constraint");
733 results.push_back({name, TypeConstraint(resultDef)});
738 if (results.back().constraint.isVariadicOfVariadic()) {
741 "'VariadicOfVariadic' results are currently not supported");
746 auto *successorsDag = def.getValueAsDag(
"successors");
747 auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator());
748 if (!successorsOp || successorsOp->getDef()->getName() !=
"successor") {
749 PrintFatalError(def.getLoc(),
750 "'successors' must have 'successor' directive");
753 for (
unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) {
754 auto name = successorsDag->getArgNameStr(i);
755 auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i));
756 if (!successorInit) {
757 PrintFatalError(def.getLoc(),
758 Twine(
"undefined kind for successor #") + Twine(i));
760 Successor successor(successorInit->getDef());
763 if (i != e - 1 && successor.isVariadic())
764 PrintFatalError(def.getLoc(),
"only the last successor can be variadic");
765 successors.push_back({name, successor});
770 if (
auto *traitList = def.getValueAsListInit(
"traits")) {
772 SmallPtrSet<const Init *, 32> traitSet;
773 traits.reserve(traitSet.size());
780 auto verifyTraitValidity = [&](
const Record *trait) {
781 auto *dependentTraits = trait->getValueAsListInit(
"dependentTraits");
782 for (
auto *traitInit : *dependentTraits)
783 if (!traitSet.contains(traitInit))
786 trait->getValueAsString(
"trait") +
" requires " +
787 cast<DefInit>(traitInit)->getDef()->getValueAsString(
789 " to precede it in traits list");
792 std::function<void(
const ListInit *)> insert;
793 insert = [&](
const ListInit *traitList) {
794 for (
auto *traitInit : *traitList) {
795 auto *def = cast<DefInit>(traitInit)->getDef();
796 if (def->isSubClassOf(
"TraitList")) {
797 insert(def->getValueAsListInit(
"traits"));
802 if (!traitSet.insert(traitInit).second)
807 if (def->isSubClassOf(
"Interface"))
808 insert(def->getValueAsListInit(
"baseInterfaces"));
812 verifyTraitValidity(def);
819 populateTypeInferenceInfo(argumentsAndResultsIndex);
822 auto *regionsDag = def.getValueAsDag(
"regions");
823 auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator());
824 if (!regionsOp || regionsOp->getDef()->getName() !=
"region") {
825 PrintFatalError(def.getLoc(),
"'regions' must have 'region' directive");
828 for (
unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) {
829 auto name = regionsDag->getArgNameStr(i);
830 auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i));
832 PrintFatalError(def.getLoc(),
833 Twine(
"undefined kind for region #") + Twine(i));
835 Region region(regionInit->getDef());
836 if (region.isVariadic()) {
839 PrintFatalError(def.getLoc(),
"only the last region can be variadic");
841 PrintFatalError(def.getLoc(),
"variadic regions must be named");
844 regions.push_back({name, region});
848 auto *builderList = dyn_cast_or_null<ListInit>(def.getValueInit(
"builders"));
849 if (builderList && !builderList->empty()) {
850 for (
const Init *init : builderList->getElements())
851 builders.emplace_back(cast<DefInit>(init)->
getDef(), def.getLoc());
855 "default builders are skipped and no custom builders provided");
858 LLVM_DEBUG(
print(llvm::dbgs()));
863 return resultTypeMapping[
index];
873 return def.getValueAsString(
"description");
879 return def.getValueAsString(
"summary");
883 auto *valueInit = def.getValueInit(
"assemblyFormat");
884 return isa<StringInit>(valueInit);
889 .Case([&](
const StringInit *init) {
return init->getValue(); });
895 if (
auto *attr = llvm::dyn_cast_if_present<NamedAttribute *>(arg))
896 os <<
"[attribute] " << attr->name <<
'\n';
898 os <<
"[operand] " << cast<NamedTypeConstraint *>(arg)->name <<
'\n';
908 return attrPropOrOperandMapping[
index];
912 return "get" + convertToCamelFromSnakeCase(name,
true);
916 return "set" + convertToCamelFromSnakeCase(name,
true);
920 return "remove" + convertToCamelFromSnakeCase(name,
true);
926 return def.getValueAsBit(
"useCustomPropertiesEncoding");
static void assertAccessorInvariants(const Operator &op, StringRef name)
Assert the invariants of accessors generated for the given name.
bool isDerivedAttr() const
This class represents an inferred result type.
static int mapResultIndex(int i)
static int unmapResultIndex(int i)
static bool isResultIndex(int i)
static bool isArgIndex(int i)
Wrapper class that contains a MLIR op's information (e.g., operands, attributes) defined in TableGen ...
std::string getQualCppClassName() const
Returns this op's C++ class name prefixed with namespaces.
unsigned getNumSuccessors() const
Returns the number of successors.
const NamedRegion & getRegion(unsigned index) const
Returns the index-th region.
TypeConstraint getResultTypeConstraint(int index) const
Returns the index-th result's type constraint.
ArrayRef< SMLoc > getLoc() const
Operator(const llvm::Record &def)
const NamedTypeConstraint * const_value_iterator
llvm::iterator_range< const_region_iterator > getRegions() const
StringRef getCppNamespace() const
Returns this op's C++ namespace.
const_attribute_iterator attribute_begin() const
std::string getGetterName(StringRef name) const
Returns the getter name for the accessor of name.
const_successor_iterator successor_end() const
int getNumOperands() const
StringRef getDescription() const
const_value_range getResults() const
arg_range getArgs() const
const NamedAttribute * const_attribute_iterator
Op attribute iterators.
const_value_range getOperands() const
const_region_iterator region_begin() const
bool useCustomPropertiesEncoding() const
Whether to generate the readProperty/writeProperty methods for bytecode emission.
const NamedRegion * const_region_iterator
Regions.
NamedTypeConstraint & getOperand(int index)
StringRef getResultName(int index) const
Returns the index-th result's name.
var_decorator_range getArgDecorators(int index) const
const Argument * arg_iterator
unsigned getNumVariableLengthOperands() const
Returns the number of variadic operands in this operation.
OperandAttrOrProp getArgToOperandAttrOrProp(int index) const
Returns the OperandAttrOrProp corresponding to the index.
var_decorator_range getResultDecorators(int index) const
Returns the index-th result's decorators.
std::string getGenericAdaptorName() const
Returns the name of op's generic adaptor C++ class.
StringRef getExtraClassDefinition() const
Returns this op's extra class definition code.
const_value_iterator result_begin() const
Op result iterators.
const Trait * const_trait_iterator
Trait.
const_attribute_iterator attribute_end() const
const_trait_iterator trait_end() const
llvm::iterator_range< VariableDecoratorIterator > var_decorator_range
std::string getAdaptorName() const
Returns the name of op's adaptor C++ class.
bool hasNonEmptyProperties() const
Returns whether this operation has any non-empty properties.
int getNumResults() const
Returns the number of results this op produces.
llvm::iterator_range< const_attribute_iterator > getAttributes() const
llvm::iterator_range< const_value_iterator > const_value_range
const_value_iterator operand_end() const
arg_iterator arg_end() const
int getNumArgs() const
Returns the total number of arguments.
NamedTypeConstraint & getResult(int index)
Returns the op result at the given index.
llvm::iterator_range< arg_iterator > arg_range
const_value_iterator operand_begin() const
Op operand iterators.
void assertInvariants() const
Check invariants (like no duplicated or conflicted names) and abort the process if any invariant is b...
StringRef getArgName(int index) const
StringRef getDialectName() const
Returns this op's dialect name.
const_region_iterator region_end() const
unsigned getNumVariableLengthResults() const
Returns the number of variable length results in this operation.
bool hasSingleVariadicArg() const
Returns true of the operation has a single variadic arg.
const NamedSuccessor * const_successor_iterator
Successors.
unsigned getNumVariadicSuccessors() const
Returns the number of variadic successors in this operation.
StringRef getSummary() const
bool isVariadic() const
Returns true if this op has variable length operands or results.
llvm::iterator_range< const_trait_iterator > getTraits() const
bool hasCustomPropertiesPrinter() const
Returns true if the operation provides a custom properties printer.
const Trait * getTrait(llvm::StringRef trait) const
Returns the trait wrapper for the given MLIR C++ trait.
SmallVector< StringRef > getInherentAttrNames() const
Returns all accepted attribute spellings for this operation's inherent attributes and properties,...
llvm::iterator_range< const_successor_iterator > getSuccessors() const
const_successor_iterator successor_begin() const
void print(llvm::raw_ostream &os) const
Prints the contents in this operator to the given os.
unsigned getNumRegions() const
Returns the number of regions.
const_trait_iterator trait_begin() const
NamedAttribute * attribute_iterator
StringRef getExtraClassDeclaration() const
Returns this op's extra class declaration code.
StringRef getAssemblyFormat() const
std::string getSetterName(StringRef name) const
Returns the setter name for the accessor of name.
std::string getOperationName() const
Returns the operation name.
const NamedSuccessor & getSuccessor(unsigned index) const
Returns the index-th successor.
StringRef getCppClassName() const
Returns this op's C++ class name.
bool allResultTypesKnown() const
Return whether all the result types are known.
bool hasAssemblyFormat() const
Query functions for the assembly format of the operator.
unsigned getNumVariadicRegions() const
Returns the number of variadic regions in this operation.
bool skipDefaultBuilders() const
Returns true if default builders should not be generated.
arg_iterator arg_begin() const
Op argument (attribute or operand) iterators.
const InferredResultType & getInferredResultType(int index) const
Return all arguments or type constraints with same type as result[index].
const llvm::Record & getDef() const
Returns the Tablegen definition this operator was constructed from.
const_value_iterator result_end() const
std::string getRemoverName(StringRef name) const
Returns the remove name for the accessor of name.
Argument getArg(int index) const
Op argument (attribute or operand) accessors.
bool hasDescription() const
Query functions for the documentation of the operator.
static Trait create(const llvm::Init *init)
bool isVariableLength() const
The OpAsmOpInterface, see OpAsmInterface.td for more details.
constexpr StringLiteral legacyResultSegmentAttrName
const char * inferTypeOpInterface
constexpr StringLiteral legacyOperandSegmentAttrName
constexpr StringLiteral operandSegmentAttrName
The canonical and legacy names of the implicit segment-size properties.
llvm::PointerUnion< NamedAttribute *, NamedProperty *, NamedTypeConstraint * > Argument
constexpr StringLiteral resultSegmentAttrName
Include the generated interface declarations.
llvm::TypeSwitch< T, ResultT > TypeSwitch
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
bool isVariableLength() const
TypeConstraint constraint
Pair consisting kind of argument and index into operands, attributes, or properties.
static VariableDecorator unwrap(const llvm::Init *init)
A class used to represent the decorators of an operator variable, i.e.