1fd407e1fSAlex Zinenko //===- OpPythonBindingGen.cpp - Generator of Python API for MLIR Ops ------===// 2fd407e1fSAlex Zinenko // 3fd407e1fSAlex Zinenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fd407e1fSAlex Zinenko // See https://llvm.org/LICENSE.txt for license information. 5fd407e1fSAlex Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fd407e1fSAlex Zinenko // 7fd407e1fSAlex Zinenko //===----------------------------------------------------------------------===// 8fd407e1fSAlex Zinenko // 9fd407e1fSAlex Zinenko // OpPythonBindingGen uses ODS specification of MLIR ops to generate Python 10fd407e1fSAlex Zinenko // binding classes wrapping a generic operation API. 11fd407e1fSAlex Zinenko // 12fd407e1fSAlex Zinenko //===----------------------------------------------------------------------===// 13fd407e1fSAlex Zinenko 1492233062Smax #include "OpGenHelpers.h" 1592233062Smax 16fd407e1fSAlex Zinenko #include "mlir/TableGen/GenInfo.h" 17fd407e1fSAlex Zinenko #include "mlir/TableGen/Operator.h" 18fd407e1fSAlex Zinenko #include "llvm/ADT/StringSet.h" 19fd407e1fSAlex Zinenko #include "llvm/Support/CommandLine.h" 20fd407e1fSAlex Zinenko #include "llvm/Support/FormatVariadic.h" 21fd407e1fSAlex Zinenko #include "llvm/TableGen/Error.h" 22fd407e1fSAlex Zinenko #include "llvm/TableGen/Record.h" 23fd407e1fSAlex Zinenko 24fd407e1fSAlex Zinenko using namespace mlir; 25fd407e1fSAlex Zinenko using namespace mlir::tblgen; 26bccd37f6SRahul Joshi using llvm::formatv; 27bccd37f6SRahul Joshi using llvm::Record; 28bccd37f6SRahul Joshi using llvm::RecordKeeper; 29fd407e1fSAlex Zinenko 30fd407e1fSAlex Zinenko /// File header and includes. 31894d88a7SStella Laurenzo /// {0} is the dialect namespace. 32fd407e1fSAlex Zinenko constexpr const char *fileHeader = R"Py( 33fd407e1fSAlex Zinenko # Autogenerated by mlir-tblgen; don't manually edit. 34fd407e1fSAlex Zinenko 35e31c77b1SStella Laurenzo from ._ods_common import _cext as _ods_cext 367c850867SMaksim Levental from ._ods_common import ( 377c850867SMaksim Levental equally_sized_accessor as _ods_equally_sized_accessor, 387c850867SMaksim Levental get_default_loc_context as _ods_get_default_loc_context, 397c850867SMaksim Levental get_op_result_or_op_results as _get_op_result_or_op_results, 407c850867SMaksim Levental get_op_results_or_values as _get_op_results_or_values, 417c850867SMaksim Levental segmented_accessor as _ods_segmented_accessor, 427c850867SMaksim Levental ) 438a1f1a10SStella Laurenzo _ods_ir = _ods_cext.ir 44894d88a7SStella Laurenzo 45b4c93eceSJohn Demme import builtins 4627c6d55cSMaksim Levental from typing import Sequence as _Sequence, Union as _Union 47b4c93eceSJohn Demme 48fd407e1fSAlex Zinenko )Py"; 49fd407e1fSAlex Zinenko 50fd407e1fSAlex Zinenko /// Template for dialect class: 51fd407e1fSAlex Zinenko /// {0} is the dialect namespace. 52fd407e1fSAlex Zinenko constexpr const char *dialectClassTemplate = R"Py( 538a1f1a10SStella Laurenzo @_ods_cext.register_dialect 548a1f1a10SStella Laurenzo class _Dialect(_ods_ir.Dialect): 55fd407e1fSAlex Zinenko DIALECT_NAMESPACE = "{0}" 56fd407e1fSAlex Zinenko )Py"; 57fd407e1fSAlex Zinenko 583f71765aSAlex Zinenko constexpr const char *dialectExtensionTemplate = R"Py( 593f71765aSAlex Zinenko from ._{0}_ops_gen import _Dialect 603f71765aSAlex Zinenko )Py"; 613f71765aSAlex Zinenko 62fd407e1fSAlex Zinenko /// Template for operation class: 63fd407e1fSAlex Zinenko /// {0} is the Python class name; 64fd407e1fSAlex Zinenko /// {1} is the operation name. 65fd407e1fSAlex Zinenko constexpr const char *opClassTemplate = R"Py( 668a1f1a10SStella Laurenzo @_ods_cext.register_operation(_Dialect) 678a1f1a10SStella Laurenzo class {0}(_ods_ir.OpView): 68fd407e1fSAlex Zinenko OPERATION_NAME = "{1}" 69fd407e1fSAlex Zinenko )Py"; 70fd407e1fSAlex Zinenko 7171b6b010SStella Laurenzo /// Template for class level declarations of operand and result 7271b6b010SStella Laurenzo /// segment specs. 7371b6b010SStella Laurenzo /// {0} is either "OPERAND" or "RESULT" 7471b6b010SStella Laurenzo /// {1} is the segment spec 7571b6b010SStella Laurenzo /// Each segment spec is either None (default) or an array of integers 7671b6b010SStella Laurenzo /// where: 7771b6b010SStella Laurenzo /// 1 = single element (expect non sequence operand/result) 78192d9dd7SKazu Hirata /// 0 = optional element (expect a value or std::nullopt) 7971b6b010SStella Laurenzo /// -1 = operand/result is a sequence corresponding to a variadic 8071b6b010SStella Laurenzo constexpr const char *opClassSizedSegmentsTemplate = R"Py( 8171b6b010SStella Laurenzo _ODS_{0}_SEGMENTS = {1} 8271b6b010SStella Laurenzo )Py"; 8371b6b010SStella Laurenzo 8471b6b010SStella Laurenzo /// Template for class level declarations of the _ODS_REGIONS spec: 8571b6b010SStella Laurenzo /// {0} is the minimum number of regions 8671b6b010SStella Laurenzo /// {1} is the Python bool literal for hasNoVariadicRegions 8771b6b010SStella Laurenzo constexpr const char *opClassRegionSpecTemplate = R"Py( 8871b6b010SStella Laurenzo _ODS_REGIONS = ({0}, {1}) 8971b6b010SStella Laurenzo )Py"; 9071b6b010SStella Laurenzo 91fd407e1fSAlex Zinenko /// Template for single-element accessor: 92fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 93fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 94fd407e1fSAlex Zinenko /// {2} is the position in the element list. 95fd407e1fSAlex Zinenko constexpr const char *opSingleTemplate = R"Py( 96b4c93eceSJohn Demme @builtins.property 97fd407e1fSAlex Zinenko def {0}(self): 98fd407e1fSAlex Zinenko return self.operation.{1}s[{2}] 99fd407e1fSAlex Zinenko )Py"; 100fd407e1fSAlex Zinenko 101fd407e1fSAlex Zinenko /// Template for single-element accessor after a variable-length group: 102fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 103fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 104fd407e1fSAlex Zinenko /// {2} is the total number of element groups; 105fd407e1fSAlex Zinenko /// {3} is the position of the current group in the group list. 106fd407e1fSAlex Zinenko /// This works for both a single variadic group (non-negative length) and an 107fd407e1fSAlex Zinenko /// single optional element (zero length if the element is absent). 108fd407e1fSAlex Zinenko constexpr const char *opSingleAfterVariableTemplate = R"Py( 109b4c93eceSJohn Demme @builtins.property 110fd407e1fSAlex Zinenko def {0}(self): 1118a1f1a10SStella Laurenzo _ods_variadic_group_length = len(self.operation.{1}s) - {2} + 1 1128a1f1a10SStella Laurenzo return self.operation.{1}s[{3} + _ods_variadic_group_length - 1] 113fd407e1fSAlex Zinenko )Py"; 114fd407e1fSAlex Zinenko 115fd407e1fSAlex Zinenko /// Template for an optional element accessor: 116fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 117fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 118fd407e1fSAlex Zinenko /// {2} is the total number of element groups; 119fd407e1fSAlex Zinenko /// {3} is the position of the current group in the group list. 12054c99842SMichal Terepeta /// This works if we have only one variable-length group (and it's the optional 12154c99842SMichal Terepeta /// operand/result): we can deduce it's absent if the `len(operation.{1}s)` is 12254c99842SMichal Terepeta /// smaller than the total number of groups. 123fd407e1fSAlex Zinenko constexpr const char *opOneOptionalTemplate = R"Py( 124b4c93eceSJohn Demme @builtins.property 125fd226c9bSStella Laurenzo def {0}(self): 12654c99842SMichal Terepeta return None if len(self.operation.{1}s) < {2} else self.operation.{1}s[{3}] 127fd407e1fSAlex Zinenko )Py"; 128fd407e1fSAlex Zinenko 129fd407e1fSAlex Zinenko /// Template for the variadic group accessor in the single variadic group case: 130fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 131fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 132fd407e1fSAlex Zinenko /// {2} is the total number of element groups; 133fd407e1fSAlex Zinenko /// {3} is the position of the current group in the group list. 134fd407e1fSAlex Zinenko constexpr const char *opOneVariadicTemplate = R"Py( 135b4c93eceSJohn Demme @builtins.property 136fd407e1fSAlex Zinenko def {0}(self): 1378a1f1a10SStella Laurenzo _ods_variadic_group_length = len(self.operation.{1}s) - {2} + 1 1388a1f1a10SStella Laurenzo return self.operation.{1}s[{3}:{3} + _ods_variadic_group_length] 139fd407e1fSAlex Zinenko )Py"; 140fd407e1fSAlex Zinenko 141fd407e1fSAlex Zinenko /// First part of the template for equally-sized variadic group accessor: 142fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 143fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 1443766ba44SKasper Nielsen /// {2} is the total number of non-variadic groups; 1453766ba44SKasper Nielsen /// {3} is the total number of variadic groups; 1463766ba44SKasper Nielsen /// {4} is the number of non-variadic groups preceding the current group; 1473766ba44SKasper Nielsen /// {5} is the number of variadic groups preceding the current group. 148fd407e1fSAlex Zinenko constexpr const char *opVariadicEqualPrefixTemplate = R"Py( 149b4c93eceSJohn Demme @builtins.property 150fd407e1fSAlex Zinenko def {0}(self): 1513766ba44SKasper Nielsen start, elements_per_group = _ods_equally_sized_accessor(self.operation.{1}s, {2}, {3}, {4}, {5}))Py"; 152fd407e1fSAlex Zinenko 153fd407e1fSAlex Zinenko /// Second part of the template for equally-sized case, accessing a single 154fd407e1fSAlex Zinenko /// element: 155fd407e1fSAlex Zinenko /// {0} is either 'operand' or 'result'. 156fd407e1fSAlex Zinenko constexpr const char *opVariadicEqualSimpleTemplate = R"Py( 157fd407e1fSAlex Zinenko return self.operation.{0}s[start] 158fd407e1fSAlex Zinenko )Py"; 159fd407e1fSAlex Zinenko 160fd407e1fSAlex Zinenko /// Second part of the template for equally-sized case, accessing a variadic 161fd407e1fSAlex Zinenko /// group: 162fd407e1fSAlex Zinenko /// {0} is either 'operand' or 'result'. 163fd407e1fSAlex Zinenko constexpr const char *opVariadicEqualVariadicTemplate = R"Py( 1643766ba44SKasper Nielsen return self.operation.{0}s[start:start + elements_per_group] 165fd407e1fSAlex Zinenko )Py"; 166fd407e1fSAlex Zinenko 167fd407e1fSAlex Zinenko /// Template for an attribute-sized group accessor: 168fd407e1fSAlex Zinenko /// {0} is the name of the accessor; 169fd407e1fSAlex Zinenko /// {1} is either 'operand' or 'result'; 170fd407e1fSAlex Zinenko /// {2} is the position of the group in the group list; 171fd407e1fSAlex Zinenko /// {3} is a return suffix (expected [0] for single-element, empty for 172fd407e1fSAlex Zinenko /// variadic, and opVariadicSegmentOptionalTrailingTemplate for optional). 173fd407e1fSAlex Zinenko constexpr const char *opVariadicSegmentTemplate = R"Py( 174b4c93eceSJohn Demme @builtins.property 175fd407e1fSAlex Zinenko def {0}(self): 1768a1f1a10SStella Laurenzo {1}_range = _ods_segmented_accessor( 177fd407e1fSAlex Zinenko self.operation.{1}s, 178363b6559SMehdi Amini self.operation.attributes["{1}SegmentSizes"], {2}) 179fd407e1fSAlex Zinenko return {1}_range{3} 180fd407e1fSAlex Zinenko )Py"; 181fd407e1fSAlex Zinenko 182fd407e1fSAlex Zinenko /// Template for a suffix when accessing an optional element in the 183fd407e1fSAlex Zinenko /// attribute-sized case: 184fd407e1fSAlex Zinenko /// {0} is either 'operand' or 'result'; 185fd407e1fSAlex Zinenko constexpr const char *opVariadicSegmentOptionalTrailingTemplate = 186fd407e1fSAlex Zinenko R"Py([0] if len({0}_range) > 0 else None)Py"; 187fd407e1fSAlex Zinenko 188c5a6712fSAlex Zinenko /// Template for an operation attribute getter: 189c5a6712fSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 19067a910bbSRahul Kayaith /// {1} is the original name of the attribute. 191c5a6712fSAlex Zinenko constexpr const char *attributeGetterTemplate = R"Py( 192b4c93eceSJohn Demme @builtins.property 193c5a6712fSAlex Zinenko def {0}(self): 19467a910bbSRahul Kayaith return self.operation.attributes["{1}"] 195c5a6712fSAlex Zinenko )Py"; 196c5a6712fSAlex Zinenko 197c5a6712fSAlex Zinenko /// Template for an optional operation attribute getter: 198c5a6712fSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 19967a910bbSRahul Kayaith /// {1} is the original name of the attribute. 200c5a6712fSAlex Zinenko constexpr const char *optionalAttributeGetterTemplate = R"Py( 201b4c93eceSJohn Demme @builtins.property 202c5a6712fSAlex Zinenko def {0}(self): 20367a910bbSRahul Kayaith if "{1}" not in self.operation.attributes: 204c5a6712fSAlex Zinenko return None 20567a910bbSRahul Kayaith return self.operation.attributes["{1}"] 206c5a6712fSAlex Zinenko )Py"; 207c5a6712fSAlex Zinenko 208029e199dSAlex Zinenko /// Template for a getter of a unit operation attribute, returns True of the 209c5a6712fSAlex Zinenko /// unit attribute is present, False otherwise (unit attributes have meaning 210c5a6712fSAlex Zinenko /// by mere presence): 211c5a6712fSAlex Zinenko /// {0} is the name of the attribute sanitized for Python, 212c5a6712fSAlex Zinenko /// {1} is the original name of the attribute. 213c5a6712fSAlex Zinenko constexpr const char *unitAttributeGetterTemplate = R"Py( 214b4c93eceSJohn Demme @builtins.property 215c5a6712fSAlex Zinenko def {0}(self): 216c5a6712fSAlex Zinenko return "{1}" in self.operation.attributes 217c5a6712fSAlex Zinenko )Py"; 218c5a6712fSAlex Zinenko 219029e199dSAlex Zinenko /// Template for an operation attribute setter: 220029e199dSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 221029e199dSAlex Zinenko /// {1} is the original name of the attribute. 222029e199dSAlex Zinenko constexpr const char *attributeSetterTemplate = R"Py( 223029e199dSAlex Zinenko @{0}.setter 224029e199dSAlex Zinenko def {0}(self, value): 225029e199dSAlex Zinenko if value is None: 226029e199dSAlex Zinenko raise ValueError("'None' not allowed as value for mandatory attributes") 227029e199dSAlex Zinenko self.operation.attributes["{1}"] = value 228029e199dSAlex Zinenko )Py"; 229029e199dSAlex Zinenko 230029e199dSAlex Zinenko /// Template for a setter of an optional operation attribute, setting to None 231029e199dSAlex Zinenko /// removes the attribute: 232029e199dSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 233029e199dSAlex Zinenko /// {1} is the original name of the attribute. 234029e199dSAlex Zinenko constexpr const char *optionalAttributeSetterTemplate = R"Py( 235029e199dSAlex Zinenko @{0}.setter 236029e199dSAlex Zinenko def {0}(self, value): 237029e199dSAlex Zinenko if value is not None: 238029e199dSAlex Zinenko self.operation.attributes["{1}"] = value 239029e199dSAlex Zinenko elif "{1}" in self.operation.attributes: 240029e199dSAlex Zinenko del self.operation.attributes["{1}"] 241029e199dSAlex Zinenko )Py"; 242029e199dSAlex Zinenko 243029e199dSAlex Zinenko /// Template for a setter of a unit operation attribute, setting to None or 244029e199dSAlex Zinenko /// False removes the attribute: 245029e199dSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 246029e199dSAlex Zinenko /// {1} is the original name of the attribute. 247029e199dSAlex Zinenko constexpr const char *unitAttributeSetterTemplate = R"Py( 248029e199dSAlex Zinenko @{0}.setter 249029e199dSAlex Zinenko def {0}(self, value): 250029e199dSAlex Zinenko if bool(value): 2518a1f1a10SStella Laurenzo self.operation.attributes["{1}"] = _ods_ir.UnitAttr.get() 252029e199dSAlex Zinenko elif "{1}" in self.operation.attributes: 253029e199dSAlex Zinenko del self.operation.attributes["{1}"] 254029e199dSAlex Zinenko )Py"; 255029e199dSAlex Zinenko 256029e199dSAlex Zinenko /// Template for a deleter of an optional or a unit operation attribute, removes 257029e199dSAlex Zinenko /// the attribute from the operation: 258029e199dSAlex Zinenko /// {0} is the name of the attribute sanitized for Python; 259029e199dSAlex Zinenko /// {1} is the original name of the attribute. 260029e199dSAlex Zinenko constexpr const char *attributeDeleterTemplate = R"Py( 261029e199dSAlex Zinenko @{0}.deleter 262029e199dSAlex Zinenko def {0}(self): 263029e199dSAlex Zinenko del self.operation.attributes["{1}"] 264029e199dSAlex Zinenko )Py"; 265029e199dSAlex Zinenko 26627c6d55cSMaksim Levental constexpr const char *regionAccessorTemplate = R"Py( 26718fbd5feSAlex Zinenko @builtins.property 268310736e0SAlex Zinenko def {0}(self): 26918fbd5feSAlex Zinenko return self.regions[{1}] 27027c6d55cSMaksim Levental )Py"; 27127c6d55cSMaksim Levental 27227c6d55cSMaksim Levental constexpr const char *valueBuilderTemplate = R"Py( 27327c6d55cSMaksim Levental def {0}({2}) -> {4}: 27451a4f319SPeter Hawkins return {1}({3}){5} 27551a4f319SPeter Hawkins )Py"; 27651a4f319SPeter Hawkins 27751a4f319SPeter Hawkins constexpr const char *valueBuilderVariadicTemplate = R"Py( 27851a4f319SPeter Hawkins def {0}({2}) -> {4}: 27927c6d55cSMaksim Levental return _get_op_result_or_op_results({1}({3})) 28027c6d55cSMaksim Levental )Py"; 28118fbd5feSAlex Zinenko 282fd407e1fSAlex Zinenko static llvm::cl::OptionCategory 283fd407e1fSAlex Zinenko clOpPythonBindingCat("Options for -gen-python-op-bindings"); 284fd407e1fSAlex Zinenko 285fd407e1fSAlex Zinenko static llvm::cl::opt<std::string> 286fd407e1fSAlex Zinenko clDialectName("bind-dialect", 287fd407e1fSAlex Zinenko llvm::cl::desc("The dialect to run the generator for"), 288fd407e1fSAlex Zinenko llvm::cl::init(""), llvm::cl::cat(clOpPythonBindingCat)); 289fd407e1fSAlex Zinenko 2903f71765aSAlex Zinenko static llvm::cl::opt<std::string> clDialectExtensionName( 2913f71765aSAlex Zinenko "dialect-extension", llvm::cl::desc("The prefix of the dialect extension"), 2923f71765aSAlex Zinenko llvm::cl::init(""), llvm::cl::cat(clOpPythonBindingCat)); 2933f71765aSAlex Zinenko 294c5a6712fSAlex Zinenko using AttributeClasses = DenseMap<StringRef, StringRef>; 295c5a6712fSAlex Zinenko 2968a1f1a10SStella Laurenzo /// Checks whether `str` would shadow a generated variable or attribute 2978a1f1a10SStella Laurenzo /// part of the OpView API. 2988a1f1a10SStella Laurenzo static bool isODSReserved(StringRef str) { 2998a1f1a10SStella Laurenzo static llvm::StringSet<> reserved( 3008a1f1a10SStella Laurenzo {"attributes", "create", "context", "ip", "operands", "print", "get_asm", 301fd226c9bSStella Laurenzo "loc", "verify", "regions", "results", "self", "operation", 3028a1f1a10SStella Laurenzo "DIALECT_NAMESPACE", "OPERATION_NAME"}); 30388d319a2SKazu Hirata return str.starts_with("_ods_") || str.ends_with("_ods") || 3048a1f1a10SStella Laurenzo reserved.contains(str); 3058a1f1a10SStella Laurenzo } 3068a1f1a10SStella Laurenzo 307fd407e1fSAlex Zinenko /// Modifies the `name` in a way that it becomes suitable for Python bindings 308fd407e1fSAlex Zinenko /// (does not change the `name` if it already is suitable) and returns the 309fd407e1fSAlex Zinenko /// modified version. 310fd407e1fSAlex Zinenko static std::string sanitizeName(StringRef name) { 311a2288a89SMaksim Levental std::string processedStr = name.str(); 31244600baeSJoelWee std::replace_if( 313a2288a89SMaksim Levental processedStr.begin(), processedStr.end(), 31444600baeSJoelWee [](char c) { return !llvm::isAlnum(c); }, '_'); 3157d4cd47eSJoelWee 316a2288a89SMaksim Levental if (llvm::isDigit(*processedStr.begin())) 317a2288a89SMaksim Levental return "_" + processedStr; 3187d4cd47eSJoelWee 319a2288a89SMaksim Levental if (isPythonReserved(processedStr) || isODSReserved(processedStr)) 320a2288a89SMaksim Levental return processedStr + "_"; 321a2288a89SMaksim Levental return processedStr; 322fd407e1fSAlex Zinenko } 323fd407e1fSAlex Zinenko 324f9265de8SAlex Zinenko static std::string attrSizedTraitForKind(const char *kind) { 325bccd37f6SRahul Joshi return formatv("::mlir::OpTrait::AttrSized{0}{1}Segments", 326bccd37f6SRahul Joshi StringRef(kind).take_front().upper(), 327bccd37f6SRahul Joshi StringRef(kind).drop_front()); 328f9265de8SAlex Zinenko } 329f9265de8SAlex Zinenko 330fd407e1fSAlex Zinenko /// Emits accessors to "elements" of an Op definition. Currently, the supported 331fd407e1fSAlex Zinenko /// elements are operands and results, indicated by `kind`, which must be either 332fd407e1fSAlex Zinenko /// `operand` or `result` and is used verbatim in the emitted code. 333fd407e1fSAlex Zinenko static void emitElementAccessors( 334fd407e1fSAlex Zinenko const Operator &op, raw_ostream &os, const char *kind, 3353766ba44SKasper Nielsen unsigned numVariadicGroups, unsigned numElements, 336fd407e1fSAlex Zinenko llvm::function_ref<const NamedTypeConstraint &(const Operator &, int)> 337fd407e1fSAlex Zinenko getElement) { 338bccd37f6SRahul Joshi assert(llvm::is_contained(SmallVector<StringRef, 2>{"operand", "result"}, 339bccd37f6SRahul Joshi kind) && 340fd407e1fSAlex Zinenko "unsupported kind"); 341fd407e1fSAlex Zinenko 342fd407e1fSAlex Zinenko // Traits indicating how to process variadic elements. 343bccd37f6SRahul Joshi std::string sameSizeTrait = formatv("::mlir::OpTrait::SameVariadic{0}{1}Size", 344bccd37f6SRahul Joshi StringRef(kind).take_front().upper(), 345bccd37f6SRahul Joshi StringRef(kind).drop_front()); 346f9265de8SAlex Zinenko std::string attrSizedTrait = attrSizedTraitForKind(kind); 347fd407e1fSAlex Zinenko 34854c99842SMichal Terepeta // If there is only one variable-length element group, its size can be 34954c99842SMichal Terepeta // inferred from the total number of elements. If there are none, the 35054c99842SMichal Terepeta // generation is straightforward. 3513766ba44SKasper Nielsen if (numVariadicGroups <= 1) { 352fd407e1fSAlex Zinenko bool seenVariableLength = false; 3533766ba44SKasper Nielsen for (unsigned i = 0; i < numElements; ++i) { 354fd407e1fSAlex Zinenko const NamedTypeConstraint &element = getElement(op, i); 355fd407e1fSAlex Zinenko if (element.isVariableLength()) 356fd407e1fSAlex Zinenko seenVariableLength = true; 357fd407e1fSAlex Zinenko if (element.name.empty()) 358fd407e1fSAlex Zinenko continue; 359fd407e1fSAlex Zinenko if (element.isVariableLength()) { 360bccd37f6SRahul Joshi os << formatv(element.isOptional() ? opOneOptionalTemplate 361fd407e1fSAlex Zinenko : opOneVariadicTemplate, 3623766ba44SKasper Nielsen sanitizeName(element.name), kind, numElements, i); 363fd407e1fSAlex Zinenko } else if (seenVariableLength) { 364bccd37f6SRahul Joshi os << formatv(opSingleAfterVariableTemplate, sanitizeName(element.name), 365bccd37f6SRahul Joshi kind, numElements, i); 366fd407e1fSAlex Zinenko } else { 367bccd37f6SRahul Joshi os << formatv(opSingleTemplate, sanitizeName(element.name), kind, i); 368fd407e1fSAlex Zinenko } 369fd407e1fSAlex Zinenko } 370fd407e1fSAlex Zinenko return; 371fd407e1fSAlex Zinenko } 372fd407e1fSAlex Zinenko 373fd407e1fSAlex Zinenko // Handle the operations where variadic groups have the same size. 374fd407e1fSAlex Zinenko if (op.getTrait(sameSizeTrait)) { 3753766ba44SKasper Nielsen // Count the number of simple elements 3763766ba44SKasper Nielsen unsigned numSimpleLength = 0; 3773766ba44SKasper Nielsen for (unsigned i = 0; i < numElements; ++i) { 3783766ba44SKasper Nielsen const NamedTypeConstraint &element = getElement(op, i); 3793766ba44SKasper Nielsen if (!element.isVariableLength()) { 3803766ba44SKasper Nielsen ++numSimpleLength; 3813766ba44SKasper Nielsen } 3823766ba44SKasper Nielsen } 3833766ba44SKasper Nielsen 3843766ba44SKasper Nielsen // Generate the accessors 385fd407e1fSAlex Zinenko int numPrecedingSimple = 0; 386fd407e1fSAlex Zinenko int numPrecedingVariadic = 0; 3873766ba44SKasper Nielsen for (unsigned i = 0; i < numElements; ++i) { 388fd407e1fSAlex Zinenko const NamedTypeConstraint &element = getElement(op, i); 389fd407e1fSAlex Zinenko if (!element.name.empty()) { 390bccd37f6SRahul Joshi os << formatv(opVariadicEqualPrefixTemplate, sanitizeName(element.name), 391bccd37f6SRahul Joshi kind, numSimpleLength, numVariadicGroups, 392bccd37f6SRahul Joshi numPrecedingSimple, numPrecedingVariadic); 393bccd37f6SRahul Joshi os << formatv(element.isVariableLength() 394fd407e1fSAlex Zinenko ? opVariadicEqualVariadicTemplate 395fd407e1fSAlex Zinenko : opVariadicEqualSimpleTemplate, 396fd407e1fSAlex Zinenko kind); 397fd407e1fSAlex Zinenko } 398fd407e1fSAlex Zinenko if (element.isVariableLength()) 399fd407e1fSAlex Zinenko ++numPrecedingVariadic; 400fd407e1fSAlex Zinenko else 401fd407e1fSAlex Zinenko ++numPrecedingSimple; 402fd407e1fSAlex Zinenko } 403fd407e1fSAlex Zinenko return; 404fd407e1fSAlex Zinenko } 405fd407e1fSAlex Zinenko 406fd407e1fSAlex Zinenko // Handle the operations where the size of groups (variadic or not) is 407fd407e1fSAlex Zinenko // provided as an attribute. For non-variadic elements, make sure to return 408fd407e1fSAlex Zinenko // an element rather than a singleton container. 409fd407e1fSAlex Zinenko if (op.getTrait(attrSizedTrait)) { 4103766ba44SKasper Nielsen for (unsigned i = 0; i < numElements; ++i) { 411fd407e1fSAlex Zinenko const NamedTypeConstraint &element = getElement(op, i); 412fd407e1fSAlex Zinenko if (element.name.empty()) 413fd407e1fSAlex Zinenko continue; 414fd407e1fSAlex Zinenko std::string trailing; 415fd407e1fSAlex Zinenko if (!element.isVariableLength()) 416fd407e1fSAlex Zinenko trailing = "[0]"; 417fd407e1fSAlex Zinenko else if (element.isOptional()) 418fd407e1fSAlex Zinenko trailing = std::string( 419bccd37f6SRahul Joshi formatv(opVariadicSegmentOptionalTrailingTemplate, kind)); 420bccd37f6SRahul Joshi os << formatv(opVariadicSegmentTemplate, sanitizeName(element.name), kind, 421bccd37f6SRahul Joshi i, trailing); 422fd407e1fSAlex Zinenko } 423fd407e1fSAlex Zinenko return; 424fd407e1fSAlex Zinenko } 425fd407e1fSAlex Zinenko 426fd407e1fSAlex Zinenko llvm::PrintFatalError("unsupported " + llvm::Twine(kind) + " structure"); 427fd407e1fSAlex Zinenko } 428fd407e1fSAlex Zinenko 429f9265de8SAlex Zinenko /// Free function helpers accessing Operator components. 430f9265de8SAlex Zinenko static int getNumOperands(const Operator &op) { return op.getNumOperands(); } 431f9265de8SAlex Zinenko static const NamedTypeConstraint &getOperand(const Operator &op, int i) { 432f9265de8SAlex Zinenko return op.getOperand(i); 433f9265de8SAlex Zinenko } 434f9265de8SAlex Zinenko static int getNumResults(const Operator &op) { return op.getNumResults(); } 435f9265de8SAlex Zinenko static const NamedTypeConstraint &getResult(const Operator &op, int i) { 436f9265de8SAlex Zinenko return op.getResult(i); 437f9265de8SAlex Zinenko } 438f9265de8SAlex Zinenko 439c5a6712fSAlex Zinenko /// Emits accessors to Op operands. 440fd407e1fSAlex Zinenko static void emitOperandAccessors(const Operator &op, raw_ostream &os) { 4413766ba44SKasper Nielsen emitElementAccessors(op, os, "operand", op.getNumVariableLengthOperands(), 4423766ba44SKasper Nielsen getNumOperands(op), getOperand); 443fd407e1fSAlex Zinenko } 444fd407e1fSAlex Zinenko 445c5a6712fSAlex Zinenko /// Emits accessors Op results. 446fd407e1fSAlex Zinenko static void emitResultAccessors(const Operator &op, raw_ostream &os) { 4473766ba44SKasper Nielsen emitElementAccessors(op, os, "result", op.getNumVariableLengthResults(), 4483766ba44SKasper Nielsen getNumResults(op), getResult); 449f9265de8SAlex Zinenko } 450f9265de8SAlex Zinenko 451c5a6712fSAlex Zinenko /// Emits accessors to Op attributes. 45267a910bbSRahul Kayaith static void emitAttributeAccessors(const Operator &op, raw_ostream &os) { 453c5a6712fSAlex Zinenko for (const auto &namedAttr : op.getAttributes()) { 454c5a6712fSAlex Zinenko // Skip "derived" attributes because they are just C++ functions that we 455c5a6712fSAlex Zinenko // don't currently expose. 456c5a6712fSAlex Zinenko if (namedAttr.attr.isDerivedAttr()) 457c5a6712fSAlex Zinenko continue; 458c5a6712fSAlex Zinenko 459c5a6712fSAlex Zinenko if (namedAttr.name.empty()) 460c5a6712fSAlex Zinenko continue; 461c5a6712fSAlex Zinenko 462029e199dSAlex Zinenko std::string sanitizedName = sanitizeName(namedAttr.name); 463029e199dSAlex Zinenko 464c5a6712fSAlex Zinenko // Unit attributes are handled specially. 465dec8055aSKazu Hirata if (namedAttr.attr.getStorageType().trim() == "::mlir::UnitAttr") { 466bccd37f6SRahul Joshi os << formatv(unitAttributeGetterTemplate, sanitizedName, namedAttr.name); 467bccd37f6SRahul Joshi os << formatv(unitAttributeSetterTemplate, sanitizedName, namedAttr.name); 468bccd37f6SRahul Joshi os << formatv(attributeDeleterTemplate, sanitizedName, namedAttr.name); 469c5a6712fSAlex Zinenko continue; 470c5a6712fSAlex Zinenko } 471c5a6712fSAlex Zinenko 472029e199dSAlex Zinenko if (namedAttr.attr.isOptional()) { 473bccd37f6SRahul Joshi os << formatv(optionalAttributeGetterTemplate, sanitizedName, 47467a910bbSRahul Kayaith namedAttr.name); 475bccd37f6SRahul Joshi os << formatv(optionalAttributeSetterTemplate, sanitizedName, 476c5a6712fSAlex Zinenko namedAttr.name); 477bccd37f6SRahul Joshi os << formatv(attributeDeleterTemplate, sanitizedName, namedAttr.name); 478029e199dSAlex Zinenko } else { 479bccd37f6SRahul Joshi os << formatv(attributeGetterTemplate, sanitizedName, namedAttr.name); 480bccd37f6SRahul Joshi os << formatv(attributeSetterTemplate, sanitizedName, namedAttr.name); 481029e199dSAlex Zinenko // Non-optional attributes cannot be deleted. 482029e199dSAlex Zinenko } 483c5a6712fSAlex Zinenko } 484c5a6712fSAlex Zinenko } 485c5a6712fSAlex Zinenko 486f9265de8SAlex Zinenko /// Template for the default auto-generated builder. 48771b6b010SStella Laurenzo /// {0} is a comma-separated list of builder arguments, including the trailing 488f9265de8SAlex Zinenko /// `loc` and `ip`; 4898e6c55c9SStella Laurenzo /// {1} is the code populating `operands`, `results` and `attributes`, 4908e6c55c9SStella Laurenzo /// `successors` fields. 491f9265de8SAlex Zinenko constexpr const char *initTemplate = R"Py( 49271b6b010SStella Laurenzo def __init__(self, {0}): 493f9265de8SAlex Zinenko operands = [] 494f9265de8SAlex Zinenko results = [] 495f9265de8SAlex Zinenko attributes = {{} 49618fbd5feSAlex Zinenko regions = None 49771b6b010SStella Laurenzo {1} 498f4125e02SPeter Hawkins super().__init__({2}) 499f9265de8SAlex Zinenko )Py"; 500f9265de8SAlex Zinenko 501f9265de8SAlex Zinenko /// Template for appending a single element to the operand/result list. 502b164f23cSAlex Zinenko /// {0} is the field name. 503*acde3f72SPeter Hawkins constexpr const char *singleOperandAppendTemplate = "operands.append({0})"; 504b164f23cSAlex Zinenko constexpr const char *singleResultAppendTemplate = "results.append({0})"; 505f9265de8SAlex Zinenko 506f9265de8SAlex Zinenko /// Template for appending an optional element to the operand/result list. 507b164f23cSAlex Zinenko /// {0} is the field name. 508b164f23cSAlex Zinenko constexpr const char *optionalAppendOperandTemplate = 509*acde3f72SPeter Hawkins "if {0} is not None: operands.append({0})"; 5106981e5ecSAlex Zinenko constexpr const char *optionalAppendAttrSizedOperandsTemplate = 511*acde3f72SPeter Hawkins "operands.append({0})"; 512b164f23cSAlex Zinenko constexpr const char *optionalAppendResultTemplate = 513b164f23cSAlex Zinenko "if {0} is not None: results.append({0})"; 514f9265de8SAlex Zinenko 515b164f23cSAlex Zinenko /// Template for appending a list of elements to the operand/result list. 516b164f23cSAlex Zinenko /// {0} is the field name. 517b164f23cSAlex Zinenko constexpr const char *multiOperandAppendTemplate = 518b164f23cSAlex Zinenko "operands.extend(_get_op_results_or_values({0}))"; 519b164f23cSAlex Zinenko constexpr const char *multiOperandAppendPackTemplate = 520b164f23cSAlex Zinenko "operands.append(_get_op_results_or_values({0}))"; 521b164f23cSAlex Zinenko constexpr const char *multiResultAppendTemplate = "results.extend({0})"; 522f9265de8SAlex Zinenko 523b57acb9aSJacques Pienaar /// Template for attribute builder from raw input in the operation builder. 524b57acb9aSJacques Pienaar /// {0} is the builder argument name; 525b57acb9aSJacques Pienaar /// {1} is the attribute builder from raw; 526b57acb9aSJacques Pienaar /// {2} is the attribute builder from raw. 527b57acb9aSJacques Pienaar /// Use the value the user passed in if either it is already an Attribute or 528b57acb9aSJacques Pienaar /// there is no method registered to make it an Attribute. 529b57acb9aSJacques Pienaar constexpr const char *initAttributeWithBuilderTemplate = 530b57acb9aSJacques Pienaar R"Py(attributes["{1}"] = ({0} if ( 53135593f66SSergei Lebedev isinstance({0}, _ods_ir.Attribute) or 532b57acb9aSJacques Pienaar not _ods_ir.AttrBuilder.contains('{2}')) else 533b57acb9aSJacques Pienaar _ods_ir.AttrBuilder.get('{2}')({0}, context=_ods_context)))Py"; 534c5a6712fSAlex Zinenko 535b57acb9aSJacques Pienaar /// Template for attribute builder from raw input for optional attribute in the 536b57acb9aSJacques Pienaar /// operation builder. 537b57acb9aSJacques Pienaar /// {0} is the builder argument name; 538b57acb9aSJacques Pienaar /// {1} is the attribute builder from raw; 539b57acb9aSJacques Pienaar /// {2} is the attribute builder from raw. 540b57acb9aSJacques Pienaar /// Use the value the user passed in if either it is already an Attribute or 541b57acb9aSJacques Pienaar /// there is no method registered to make it an Attribute. 542b57acb9aSJacques Pienaar constexpr const char *initOptionalAttributeWithBuilderTemplate = 543b57acb9aSJacques Pienaar R"Py(if {0} is not None: attributes["{1}"] = ({0} if ( 54435593f66SSergei Lebedev isinstance({0}, _ods_ir.Attribute) or 545b57acb9aSJacques Pienaar not _ods_ir.AttrBuilder.contains('{2}')) else 546b57acb9aSJacques Pienaar _ods_ir.AttrBuilder.get('{2}')({0}, context=_ods_context)))Py"; 547c5a6712fSAlex Zinenko 548c5a6712fSAlex Zinenko constexpr const char *initUnitAttributeTemplate = 5498a1f1a10SStella Laurenzo R"Py(if bool({1}): attributes["{0}"] = _ods_ir.UnitAttr.get( 5508a1f1a10SStella Laurenzo _ods_get_default_loc_context(loc)))Py"; 551c5a6712fSAlex Zinenko 5528e6c55c9SStella Laurenzo /// Template to initialize the successors list in the builder if there are any 5538e6c55c9SStella Laurenzo /// successors. 5548e6c55c9SStella Laurenzo /// {0} is the value to initialize the successors list to. 5558e6c55c9SStella Laurenzo constexpr const char *initSuccessorsTemplate = R"Py(_ods_successors = {0})Py"; 5568e6c55c9SStella Laurenzo 5578e6c55c9SStella Laurenzo /// Template to append or extend the list of successors in the builder. 5588e6c55c9SStella Laurenzo /// {0} is the list method ('append' or 'extend'); 5598e6c55c9SStella Laurenzo /// {1} is the value to add. 5608e6c55c9SStella Laurenzo constexpr const char *addSuccessorTemplate = R"Py(_ods_successors.{0}({1}))Py"; 5618e6c55c9SStella Laurenzo 5622995d29bSAlex Zinenko /// Returns true if the SameArgumentAndResultTypes trait can be used to infer 5632995d29bSAlex Zinenko /// result types of the given operation. 5642995d29bSAlex Zinenko static bool hasSameArgumentAndResultTypes(const Operator &op) { 5652995d29bSAlex Zinenko return op.getTrait("::mlir::OpTrait::SameOperandsAndResultType") && 5662995d29bSAlex Zinenko op.getNumVariableLengthResults() == 0; 5672995d29bSAlex Zinenko } 5682995d29bSAlex Zinenko 5692995d29bSAlex Zinenko /// Returns true if the FirstAttrDerivedResultType trait can be used to infer 5702995d29bSAlex Zinenko /// result types of the given operation. 5712995d29bSAlex Zinenko static bool hasFirstAttrDerivedResultTypes(const Operator &op) { 5722995d29bSAlex Zinenko return op.getTrait("::mlir::OpTrait::FirstAttrDerivedResultType") && 5732995d29bSAlex Zinenko op.getNumVariableLengthResults() == 0; 5742995d29bSAlex Zinenko } 5752995d29bSAlex Zinenko 5762995d29bSAlex Zinenko /// Returns true if the InferTypeOpInterface can be used to infer result types 5772995d29bSAlex Zinenko /// of the given operation. 5782995d29bSAlex Zinenko static bool hasInferTypeInterface(const Operator &op) { 5792995d29bSAlex Zinenko return op.getTrait("::mlir::InferTypeOpInterface::Trait") && 5802995d29bSAlex Zinenko op.getNumRegions() == 0; 5812995d29bSAlex Zinenko } 5822995d29bSAlex Zinenko 5832995d29bSAlex Zinenko /// Returns true if there is a trait or interface that can be used to infer 5842995d29bSAlex Zinenko /// result types of the given operation. 5852995d29bSAlex Zinenko static bool canInferType(const Operator &op) { 5862995d29bSAlex Zinenko return hasSameArgumentAndResultTypes(op) || 5872995d29bSAlex Zinenko hasFirstAttrDerivedResultTypes(op) || hasInferTypeInterface(op); 5882995d29bSAlex Zinenko } 5892995d29bSAlex Zinenko 5902995d29bSAlex Zinenko /// Populates `builderArgs` with result names if the builder is expected to 5912995d29bSAlex Zinenko /// accept them as arguments. 592c5a6712fSAlex Zinenko static void 5932995d29bSAlex Zinenko populateBuilderArgsResults(const Operator &op, 594bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderArgs) { 5952995d29bSAlex Zinenko if (canInferType(op)) 5962995d29bSAlex Zinenko return; 5972995d29bSAlex Zinenko 598c5a6712fSAlex Zinenko for (int i = 0, e = op.getNumResults(); i < e; ++i) { 599c5a6712fSAlex Zinenko std::string name = op.getResultName(i).str(); 600fd226c9bSStella Laurenzo if (name.empty()) { 601fd226c9bSStella Laurenzo if (op.getNumResults() == 1) { 602fd226c9bSStella Laurenzo // Special case for one result, make the default name be 'result' 603fd226c9bSStella Laurenzo // to properly match the built-in result accessor. 604fd226c9bSStella Laurenzo name = "result"; 605fd226c9bSStella Laurenzo } else { 606bccd37f6SRahul Joshi name = formatv("_gen_res_{0}", i); 607fd226c9bSStella Laurenzo } 608fd226c9bSStella Laurenzo } 609c5a6712fSAlex Zinenko name = sanitizeName(name); 610c5a6712fSAlex Zinenko builderArgs.push_back(name); 611c5a6712fSAlex Zinenko } 6122995d29bSAlex Zinenko } 6132995d29bSAlex Zinenko 6142995d29bSAlex Zinenko /// Populates `builderArgs` with the Python-compatible names of builder function 6152995d29bSAlex Zinenko /// arguments using intermixed attributes and operands in the same order as they 6162995d29bSAlex Zinenko /// appear in the `arguments` field of the op definition. Additionally, 6172995d29bSAlex Zinenko /// `operandNames` is populated with names of operands in their order of 6182995d29bSAlex Zinenko /// appearance. 619bccd37f6SRahul Joshi static void populateBuilderArgs(const Operator &op, 620bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderArgs, 621bccd37f6SRahul Joshi SmallVectorImpl<std::string> &operandNames) { 622c5a6712fSAlex Zinenko for (int i = 0, e = op.getNumArgs(); i < e; ++i) { 623c5a6712fSAlex Zinenko std::string name = op.getArgName(i).str(); 624c5a6712fSAlex Zinenko if (name.empty()) 625bccd37f6SRahul Joshi name = formatv("_gen_arg_{0}", i); 626c5a6712fSAlex Zinenko name = sanitizeName(name); 627c5a6712fSAlex Zinenko builderArgs.push_back(name); 628b0746c68SKazu Hirata if (!isa<NamedAttribute *>(op.getArg(i))) 629c5a6712fSAlex Zinenko operandNames.push_back(name); 630c5a6712fSAlex Zinenko } 6319b79f50bSJeremy Furtek } 6329b79f50bSJeremy Furtek 6339b79f50bSJeremy Furtek /// Populates `builderArgs` with the Python-compatible names of builder function 6349b79f50bSJeremy Furtek /// successor arguments. Additionally, `successorArgNames` is also populated. 635bccd37f6SRahul Joshi static void 636bccd37f6SRahul Joshi populateBuilderArgsSuccessors(const Operator &op, 637bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderArgs, 638bccd37f6SRahul Joshi SmallVectorImpl<std::string> &successorArgNames) { 6398e6c55c9SStella Laurenzo 6408e6c55c9SStella Laurenzo for (int i = 0, e = op.getNumSuccessors(); i < e; ++i) { 6418e6c55c9SStella Laurenzo NamedSuccessor successor = op.getSuccessor(i); 6428e6c55c9SStella Laurenzo std::string name = std::string(successor.name); 6438e6c55c9SStella Laurenzo if (name.empty()) 644bccd37f6SRahul Joshi name = formatv("_gen_successor_{0}", i); 6458e6c55c9SStella Laurenzo name = sanitizeName(name); 6468e6c55c9SStella Laurenzo builderArgs.push_back(name); 6478e6c55c9SStella Laurenzo successorArgNames.push_back(name); 6488e6c55c9SStella Laurenzo } 649c5a6712fSAlex Zinenko } 650c5a6712fSAlex Zinenko 651c5a6712fSAlex Zinenko /// Populates `builderLines` with additional lines that are required in the 652c5a6712fSAlex Zinenko /// builder to set up operation attributes. `argNames` is expected to contain 653c5a6712fSAlex Zinenko /// the names of builder arguments that correspond to op arguments, i.e. to the 654c5a6712fSAlex Zinenko /// operands and attributes in the same order as they appear in the `arguments` 655c5a6712fSAlex Zinenko /// field. 656c5a6712fSAlex Zinenko static void 657bccd37f6SRahul Joshi populateBuilderLinesAttr(const Operator &op, ArrayRef<std::string> argNames, 658bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 659b57acb9aSJacques Pienaar builderLines.push_back("_ods_context = _ods_get_default_loc_context(loc)"); 660c5a6712fSAlex Zinenko for (int i = 0, e = op.getNumArgs(); i < e; ++i) { 661c5a6712fSAlex Zinenko Argument arg = op.getArg(i); 66268f58812STres Popp auto *attribute = llvm::dyn_cast_if_present<NamedAttribute *>(arg); 663c5a6712fSAlex Zinenko if (!attribute) 664c5a6712fSAlex Zinenko continue; 665c5a6712fSAlex Zinenko 666c5a6712fSAlex Zinenko // Unit attributes are handled specially. 667dec8055aSKazu Hirata if (attribute->attr.getStorageType().trim() == "::mlir::UnitAttr") { 668bccd37f6SRahul Joshi builderLines.push_back( 669bccd37f6SRahul Joshi formatv(initUnitAttributeTemplate, attribute->name, argNames[i])); 670c5a6712fSAlex Zinenko continue; 671c5a6712fSAlex Zinenko } 672c5a6712fSAlex Zinenko 673bccd37f6SRahul Joshi builderLines.push_back(formatv( 674b57acb9aSJacques Pienaar attribute->attr.isOptional() || attribute->attr.hasDefaultValue() 675b57acb9aSJacques Pienaar ? initOptionalAttributeWithBuilderTemplate 676b57acb9aSJacques Pienaar : initAttributeWithBuilderTemplate, 677b57acb9aSJacques Pienaar argNames[i], attribute->name, attribute->attr.getAttrDefName())); 678c5a6712fSAlex Zinenko } 679c5a6712fSAlex Zinenko } 680c5a6712fSAlex Zinenko 681c5a6712fSAlex Zinenko /// Populates `builderLines` with additional lines that are required in the 6828e6c55c9SStella Laurenzo /// builder to set up successors. successorArgNames is expected to correspond 6838e6c55c9SStella Laurenzo /// to the Python argument name for each successor on the op. 684bccd37f6SRahul Joshi static void 685bccd37f6SRahul Joshi populateBuilderLinesSuccessors(const Operator &op, 686bccd37f6SRahul Joshi ArrayRef<std::string> successorArgNames, 687bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 6888e6c55c9SStella Laurenzo if (successorArgNames.empty()) { 689bccd37f6SRahul Joshi builderLines.push_back(formatv(initSuccessorsTemplate, "None")); 6908e6c55c9SStella Laurenzo return; 6918e6c55c9SStella Laurenzo } 6928e6c55c9SStella Laurenzo 693bccd37f6SRahul Joshi builderLines.push_back(formatv(initSuccessorsTemplate, "[]")); 6948e6c55c9SStella Laurenzo for (int i = 0, e = successorArgNames.size(); i < e; ++i) { 6958e6c55c9SStella Laurenzo auto &argName = successorArgNames[i]; 6968e6c55c9SStella Laurenzo const NamedSuccessor &successor = op.getSuccessor(i); 697bccd37f6SRahul Joshi builderLines.push_back(formatv(addSuccessorTemplate, 698bccd37f6SRahul Joshi successor.isVariadic() ? "extend" : "append", 699bccd37f6SRahul Joshi argName)); 7008e6c55c9SStella Laurenzo } 7018e6c55c9SStella Laurenzo } 7028e6c55c9SStella Laurenzo 7038e6c55c9SStella Laurenzo /// Populates `builderLines` with additional lines that are required in the 704b164f23cSAlex Zinenko /// builder to set up op operands. 705b164f23cSAlex Zinenko static void 706bccd37f6SRahul Joshi populateBuilderLinesOperand(const Operator &op, ArrayRef<std::string> names, 707bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 708b164f23cSAlex Zinenko bool sizedSegments = op.getTrait(attrSizedTraitForKind("operand")) != nullptr; 709f9265de8SAlex Zinenko 710f9265de8SAlex Zinenko // For each element, find or generate a name. 711b164f23cSAlex Zinenko for (int i = 0, e = op.getNumOperands(); i < e; ++i) { 712b164f23cSAlex Zinenko const NamedTypeConstraint &element = op.getOperand(i); 713c5a6712fSAlex Zinenko std::string name = names[i]; 714f9265de8SAlex Zinenko 715f9265de8SAlex Zinenko // Choose the formatting string based on the element kind. 716bccd37f6SRahul Joshi StringRef formatString; 717f9265de8SAlex Zinenko if (!element.isVariableLength()) { 718b164f23cSAlex Zinenko formatString = singleOperandAppendTemplate; 719f9265de8SAlex Zinenko } else if (element.isOptional()) { 7206981e5ecSAlex Zinenko if (sizedSegments) { 7216981e5ecSAlex Zinenko formatString = optionalAppendAttrSizedOperandsTemplate; 7226981e5ecSAlex Zinenko } else { 723b164f23cSAlex Zinenko formatString = optionalAppendOperandTemplate; 7246981e5ecSAlex Zinenko } 725f9265de8SAlex Zinenko } else { 726f9265de8SAlex Zinenko assert(element.isVariadic() && "unhandled element group type"); 727b164f23cSAlex Zinenko // If emitting with sizedSegments, then we add the actual list-typed 728b164f23cSAlex Zinenko // element. Otherwise, we extend the actual operands. 72971b6b010SStella Laurenzo if (sizedSegments) { 730b164f23cSAlex Zinenko formatString = multiOperandAppendPackTemplate; 73171b6b010SStella Laurenzo } else { 732b164f23cSAlex Zinenko formatString = multiOperandAppendTemplate; 73371b6b010SStella Laurenzo } 734f9265de8SAlex Zinenko } 735f9265de8SAlex Zinenko 736bccd37f6SRahul Joshi builderLines.push_back(formatv(formatString.data(), name)); 737b164f23cSAlex Zinenko } 738b164f23cSAlex Zinenko } 739b164f23cSAlex Zinenko 7402995d29bSAlex Zinenko /// Python code template for deriving the operation result types from its 7412995d29bSAlex Zinenko /// attribute: 7422995d29bSAlex Zinenko /// - {0} is the name of the attribute from which to derive the types. 7432995d29bSAlex Zinenko constexpr const char *deriveTypeFromAttrTemplate = 74427c6d55cSMaksim Levental R"Py(_ods_result_type_source_attr = attributes["{0}"] 7452995d29bSAlex Zinenko _ods_derived_result_type = ( 7462995d29bSAlex Zinenko _ods_ir.TypeAttr(_ods_result_type_source_attr).value 7472995d29bSAlex Zinenko if _ods_ir.TypeAttr.isinstance(_ods_result_type_source_attr) else 74827c6d55cSMaksim Levental _ods_result_type_source_attr.type))Py"; 7492995d29bSAlex Zinenko 7502995d29bSAlex Zinenko /// Python code template appending {0} type {1} times to the results list. 7512995d29bSAlex Zinenko constexpr const char *appendSameResultsTemplate = "results.extend([{0}] * {1})"; 7522995d29bSAlex Zinenko 7532995d29bSAlex Zinenko /// Appends the given multiline string as individual strings into 7542995d29bSAlex Zinenko /// `builderLines`. 7552995d29bSAlex Zinenko static void appendLineByLine(StringRef string, 756bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 7572995d29bSAlex Zinenko 7582995d29bSAlex Zinenko std::pair<StringRef, StringRef> split = std::make_pair(string, string); 7592995d29bSAlex Zinenko do { 7602995d29bSAlex Zinenko split = split.second.split('\n'); 7612995d29bSAlex Zinenko builderLines.push_back(split.first.str()); 7622995d29bSAlex Zinenko } while (!split.second.empty()); 7632995d29bSAlex Zinenko } 7642995d29bSAlex Zinenko 765b164f23cSAlex Zinenko /// Populates `builderLines` with additional lines that are required in the 766b164f23cSAlex Zinenko /// builder to set up op results. 767b164f23cSAlex Zinenko static void 768bccd37f6SRahul Joshi populateBuilderLinesResult(const Operator &op, ArrayRef<std::string> names, 769bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 770b164f23cSAlex Zinenko bool sizedSegments = op.getTrait(attrSizedTraitForKind("result")) != nullptr; 771b164f23cSAlex Zinenko 7722995d29bSAlex Zinenko if (hasSameArgumentAndResultTypes(op)) { 773bccd37f6SRahul Joshi builderLines.push_back(formatv(appendSameResultsTemplate, 774bccd37f6SRahul Joshi "operands[0].type", op.getNumResults())); 7752995d29bSAlex Zinenko return; 7762995d29bSAlex Zinenko } 7772995d29bSAlex Zinenko 7782995d29bSAlex Zinenko if (hasFirstAttrDerivedResultTypes(op)) { 7792995d29bSAlex Zinenko const NamedAttribute &firstAttr = op.getAttribute(0); 7802995d29bSAlex Zinenko assert(!firstAttr.name.empty() && "unexpected empty name for the attribute " 7812995d29bSAlex Zinenko "from which the type is derived"); 782bccd37f6SRahul Joshi appendLineByLine(formatv(deriveTypeFromAttrTemplate, firstAttr.name).str(), 7832995d29bSAlex Zinenko builderLines); 784bccd37f6SRahul Joshi builderLines.push_back(formatv(appendSameResultsTemplate, 7852995d29bSAlex Zinenko "_ods_derived_result_type", 7862995d29bSAlex Zinenko op.getNumResults())); 7872995d29bSAlex Zinenko return; 7882995d29bSAlex Zinenko } 7892995d29bSAlex Zinenko 790f573bc24SJacques Pienaar if (hasInferTypeInterface(op)) 7912995d29bSAlex Zinenko return; 7922995d29bSAlex Zinenko 793b164f23cSAlex Zinenko // For each element, find or generate a name. 794b164f23cSAlex Zinenko for (int i = 0, e = op.getNumResults(); i < e; ++i) { 795b164f23cSAlex Zinenko const NamedTypeConstraint &element = op.getResult(i); 796b164f23cSAlex Zinenko std::string name = names[i]; 797b164f23cSAlex Zinenko 798b164f23cSAlex Zinenko // Choose the formatting string based on the element kind. 799bccd37f6SRahul Joshi StringRef formatString; 800b164f23cSAlex Zinenko if (!element.isVariableLength()) { 801b164f23cSAlex Zinenko formatString = singleResultAppendTemplate; 802b164f23cSAlex Zinenko } else if (element.isOptional()) { 803b164f23cSAlex Zinenko formatString = optionalAppendResultTemplate; 804b164f23cSAlex Zinenko } else { 805b164f23cSAlex Zinenko assert(element.isVariadic() && "unhandled element group type"); 806b164f23cSAlex Zinenko // If emitting with sizedSegments, then we add the actual list-typed 807b164f23cSAlex Zinenko // element. Otherwise, we extend the actual operands. 808b164f23cSAlex Zinenko if (sizedSegments) { 809b164f23cSAlex Zinenko formatString = singleResultAppendTemplate; 810b164f23cSAlex Zinenko } else { 811b164f23cSAlex Zinenko formatString = multiResultAppendTemplate; 812b164f23cSAlex Zinenko } 813b164f23cSAlex Zinenko } 814b164f23cSAlex Zinenko 815bccd37f6SRahul Joshi builderLines.push_back(formatv(formatString.data(), name)); 816f9265de8SAlex Zinenko } 817f9265de8SAlex Zinenko } 818f9265de8SAlex Zinenko 81918fbd5feSAlex Zinenko /// If the operation has variadic regions, adds a builder argument to specify 82018fbd5feSAlex Zinenko /// the number of those regions and builder lines to forward it to the generic 82118fbd5feSAlex Zinenko /// constructor. 822bccd37f6SRahul Joshi static void populateBuilderRegions(const Operator &op, 823bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderArgs, 824bccd37f6SRahul Joshi SmallVectorImpl<std::string> &builderLines) { 82518fbd5feSAlex Zinenko if (op.hasNoVariadicRegions()) 82618fbd5feSAlex Zinenko return; 82718fbd5feSAlex Zinenko 82818fbd5feSAlex Zinenko // This is currently enforced when Operator is constructed. 82918fbd5feSAlex Zinenko assert(op.getNumVariadicRegions() == 1 && 83018fbd5feSAlex Zinenko op.getRegion(op.getNumRegions() - 1).isVariadic() && 83118fbd5feSAlex Zinenko "expected the last region to be varidic"); 83218fbd5feSAlex Zinenko 83318fbd5feSAlex Zinenko const NamedRegion ®ion = op.getRegion(op.getNumRegions() - 1); 83418fbd5feSAlex Zinenko std::string name = 83518fbd5feSAlex Zinenko ("num_" + region.name.take_front().lower() + region.name.drop_front()) 83618fbd5feSAlex Zinenko .str(); 83718fbd5feSAlex Zinenko builderArgs.push_back(name); 83818fbd5feSAlex Zinenko builderLines.push_back( 839bccd37f6SRahul Joshi formatv("regions = {0} + {1}", op.getNumRegions() - 1, name)); 84018fbd5feSAlex Zinenko } 84118fbd5feSAlex Zinenko 842f9265de8SAlex Zinenko /// Emits a default builder constructing an operation from the list of its 84327c6d55cSMaksim Levental /// result types, followed by a list of its operands. Returns vector 84427c6d55cSMaksim Levental /// of fully built functionArgs for downstream users (to save having to 84527c6d55cSMaksim Levental /// rebuild anew). 846bccd37f6SRahul Joshi static SmallVector<std::string> emitDefaultOpBuilder(const Operator &op, 84727c6d55cSMaksim Levental raw_ostream &os) { 848bccd37f6SRahul Joshi SmallVector<std::string> builderArgs; 849bccd37f6SRahul Joshi SmallVector<std::string> builderLines; 850bccd37f6SRahul Joshi SmallVector<std::string> operandArgNames; 851bccd37f6SRahul Joshi SmallVector<std::string> successorArgNames; 852c5a6712fSAlex Zinenko builderArgs.reserve(op.getNumOperands() + op.getNumResults() + 8538e6c55c9SStella Laurenzo op.getNumNativeAttributes() + op.getNumSuccessors()); 8542995d29bSAlex Zinenko populateBuilderArgsResults(op, builderArgs); 8552995d29bSAlex Zinenko size_t numResultArgs = builderArgs.size(); 85627c6d55cSMaksim Levental populateBuilderArgs(op, builderArgs, operandArgNames); 8579b79f50bSJeremy Furtek size_t numOperandAttrArgs = builderArgs.size() - numResultArgs; 8589b79f50bSJeremy Furtek populateBuilderArgsSuccessors(op, builderArgs, successorArgNames); 8598e6c55c9SStella Laurenzo 860b164f23cSAlex Zinenko populateBuilderLinesOperand(op, operandArgNames, builderLines); 861bccd37f6SRahul Joshi populateBuilderLinesAttr(op, ArrayRef(builderArgs).drop_front(numResultArgs), 862bccd37f6SRahul Joshi builderLines); 8632995d29bSAlex Zinenko populateBuilderLinesResult( 864bccd37f6SRahul Joshi op, ArrayRef(builderArgs).take_front(numResultArgs), builderLines); 8658e6c55c9SStella Laurenzo populateBuilderLinesSuccessors(op, successorArgNames, builderLines); 86618fbd5feSAlex Zinenko populateBuilderRegions(op, builderArgs, builderLines); 867f9265de8SAlex Zinenko 8689b79f50bSJeremy Furtek // Layout of builderArgs vector elements: 8699b79f50bSJeremy Furtek // [ result_args operand_attr_args successor_args regions ] 8709b79f50bSJeremy Furtek 8719b79f50bSJeremy Furtek // Determine whether the argument corresponding to a given index into the 8729b79f50bSJeremy Furtek // builderArgs vector is a python keyword argument or not. 8739b79f50bSJeremy Furtek auto isKeywordArgFn = [&](size_t builderArgIndex) -> bool { 8749b79f50bSJeremy Furtek // All result, successor, and region arguments are positional arguments. 8759b79f50bSJeremy Furtek if ((builderArgIndex < numResultArgs) || 8769b79f50bSJeremy Furtek (builderArgIndex >= (numResultArgs + numOperandAttrArgs))) 8779b79f50bSJeremy Furtek return false; 8789b79f50bSJeremy Furtek // Keyword arguments: 8799b79f50bSJeremy Furtek // - optional named attributes (including unit attributes) 8809b79f50bSJeremy Furtek // - default-valued named attributes 8819b79f50bSJeremy Furtek // - optional operands 8829b79f50bSJeremy Furtek Argument a = op.getArg(builderArgIndex - numResultArgs); 88368f58812STres Popp if (auto *nattr = llvm::dyn_cast_if_present<NamedAttribute *>(a)) 8849b79f50bSJeremy Furtek return (nattr->attr.isOptional() || nattr->attr.hasDefaultValue()); 88568f58812STres Popp if (auto *ntype = llvm::dyn_cast_if_present<NamedTypeConstraint *>(a)) 8869b79f50bSJeremy Furtek return ntype->isOptional(); 8879b79f50bSJeremy Furtek return false; 8889b79f50bSJeremy Furtek }; 8899b79f50bSJeremy Furtek 8909b79f50bSJeremy Furtek // StringRefs in functionArgs refer to strings allocated by builderArgs. 891bccd37f6SRahul Joshi SmallVector<StringRef> functionArgs; 8929b79f50bSJeremy Furtek 8939b79f50bSJeremy Furtek // Add positional arguments. 8949b79f50bSJeremy Furtek for (size_t i = 0, cnt = builderArgs.size(); i < cnt; ++i) { 8959b79f50bSJeremy Furtek if (!isKeywordArgFn(i)) 8969b79f50bSJeremy Furtek functionArgs.push_back(builderArgs[i]); 8979b79f50bSJeremy Furtek } 8989b79f50bSJeremy Furtek 8999b79f50bSJeremy Furtek // Add a bare '*' to indicate that all following arguments must be keyword 9009b79f50bSJeremy Furtek // arguments. 9019b79f50bSJeremy Furtek functionArgs.push_back("*"); 9029b79f50bSJeremy Furtek 9039b79f50bSJeremy Furtek // Add a default 'None' value to each keyword arg string, and then add to the 9049b79f50bSJeremy Furtek // function args list. 9059b79f50bSJeremy Furtek for (size_t i = 0, cnt = builderArgs.size(); i < cnt; ++i) { 9069b79f50bSJeremy Furtek if (isKeywordArgFn(i)) { 9079b79f50bSJeremy Furtek builderArgs[i].append("=None"); 9089b79f50bSJeremy Furtek functionArgs.push_back(builderArgs[i]); 9099b79f50bSJeremy Furtek } 9109b79f50bSJeremy Furtek } 9119b79f50bSJeremy Furtek functionArgs.push_back("loc=None"); 9129b79f50bSJeremy Furtek functionArgs.push_back("ip=None"); 913f573bc24SJacques Pienaar 914f573bc24SJacques Pienaar SmallVector<std::string> initArgs; 915f4125e02SPeter Hawkins initArgs.push_back("self.OPERATION_NAME"); 916f4125e02SPeter Hawkins initArgs.push_back("self._ODS_REGIONS"); 917f4125e02SPeter Hawkins initArgs.push_back("self._ODS_OPERAND_SEGMENTS"); 918f4125e02SPeter Hawkins initArgs.push_back("self._ODS_RESULT_SEGMENTS"); 919f573bc24SJacques Pienaar initArgs.push_back("attributes=attributes"); 920f573bc24SJacques Pienaar if (!hasInferTypeInterface(op)) 921f573bc24SJacques Pienaar initArgs.push_back("results=results"); 922f573bc24SJacques Pienaar initArgs.push_back("operands=operands"); 923f573bc24SJacques Pienaar initArgs.push_back("successors=_ods_successors"); 924f573bc24SJacques Pienaar initArgs.push_back("regions=regions"); 925f573bc24SJacques Pienaar initArgs.push_back("loc=loc"); 926f573bc24SJacques Pienaar initArgs.push_back("ip=ip"); 927f573bc24SJacques Pienaar 928bccd37f6SRahul Joshi os << formatv(initTemplate, llvm::join(functionArgs, ", "), 929bccd37f6SRahul Joshi llvm::join(builderLines, "\n "), llvm::join(initArgs, ", ")); 93027c6d55cSMaksim Levental return llvm::to_vector<8>( 931bccd37f6SRahul Joshi llvm::map_range(functionArgs, [](StringRef s) { return s.str(); })); 932fd407e1fSAlex Zinenko } 933fd407e1fSAlex Zinenko 93471b6b010SStella Laurenzo static void emitSegmentSpec( 93571b6b010SStella Laurenzo const Operator &op, const char *kind, 93671b6b010SStella Laurenzo llvm::function_ref<int(const Operator &)> getNumElements, 93771b6b010SStella Laurenzo llvm::function_ref<const NamedTypeConstraint &(const Operator &, int)> 93871b6b010SStella Laurenzo getElement, 93971b6b010SStella Laurenzo raw_ostream &os) { 94071b6b010SStella Laurenzo std::string segmentSpec("["); 94171b6b010SStella Laurenzo for (int i = 0, e = getNumElements(op); i < e; ++i) { 94271b6b010SStella Laurenzo const NamedTypeConstraint &element = getElement(op, i); 9436981e5ecSAlex Zinenko if (element.isOptional()) { 94471b6b010SStella Laurenzo segmentSpec.append("0,"); 9456981e5ecSAlex Zinenko } else if (element.isVariadic()) { 9466981e5ecSAlex Zinenko segmentSpec.append("-1,"); 94771b6b010SStella Laurenzo } else { 94871b6b010SStella Laurenzo segmentSpec.append("1,"); 94971b6b010SStella Laurenzo } 95071b6b010SStella Laurenzo } 95171b6b010SStella Laurenzo segmentSpec.append("]"); 95271b6b010SStella Laurenzo 953bccd37f6SRahul Joshi os << formatv(opClassSizedSegmentsTemplate, kind, segmentSpec); 95471b6b010SStella Laurenzo } 95571b6b010SStella Laurenzo 95671b6b010SStella Laurenzo static void emitRegionAttributes(const Operator &op, raw_ostream &os) { 95771b6b010SStella Laurenzo // Emit _ODS_REGIONS = (min_region_count, has_no_variadic_regions). 95871b6b010SStella Laurenzo // Note that the base OpView class defines this as (0, True). 95971b6b010SStella Laurenzo unsigned minRegionCount = op.getNumRegions() - op.getNumVariadicRegions(); 960bccd37f6SRahul Joshi os << formatv(opClassRegionSpecTemplate, minRegionCount, 96171b6b010SStella Laurenzo op.hasNoVariadicRegions() ? "True" : "False"); 96271b6b010SStella Laurenzo } 96371b6b010SStella Laurenzo 96418fbd5feSAlex Zinenko /// Emits named accessors to regions. 96518fbd5feSAlex Zinenko static void emitRegionAccessors(const Operator &op, raw_ostream &os) { 96689de9cc8SMehdi Amini for (const auto &en : llvm::enumerate(op.getRegions())) { 96718fbd5feSAlex Zinenko const NamedRegion ®ion = en.value(); 96818fbd5feSAlex Zinenko if (region.name.empty()) 96918fbd5feSAlex Zinenko continue; 97018fbd5feSAlex Zinenko 97118fbd5feSAlex Zinenko assert((!region.isVariadic() || en.index() == op.getNumRegions() - 1) && 97218fbd5feSAlex Zinenko "expected only the last region to be variadic"); 973bccd37f6SRahul Joshi os << formatv(regionAccessorTemplate, sanitizeName(region.name), 97418fbd5feSAlex Zinenko std::to_string(en.index()) + 97518fbd5feSAlex Zinenko (region.isVariadic() ? ":" : "")); 97618fbd5feSAlex Zinenko } 97718fbd5feSAlex Zinenko } 97818fbd5feSAlex Zinenko 97927c6d55cSMaksim Levental /// Emits builder that extracts results from op 98027c6d55cSMaksim Levental static void emitValueBuilder(const Operator &op, 981bccd37f6SRahul Joshi SmallVector<std::string> functionArgs, 98227c6d55cSMaksim Levental raw_ostream &os) { 98327c6d55cSMaksim Levental // Params with (possibly) default args. 98427c6d55cSMaksim Levental auto valueBuilderParams = 98527c6d55cSMaksim Levental llvm::map_range(functionArgs, [](const std::string &argAndMaybeDefault) { 986bccd37f6SRahul Joshi SmallVector<StringRef> argMaybeDefault = 98727c6d55cSMaksim Levental llvm::to_vector<2>(llvm::split(argAndMaybeDefault, "=")); 98827c6d55cSMaksim Levental auto arg = llvm::convertToSnakeFromCamelCase(argMaybeDefault[0]); 98927c6d55cSMaksim Levental if (argMaybeDefault.size() == 2) 99027c6d55cSMaksim Levental return arg + "=" + argMaybeDefault[1].str(); 99127c6d55cSMaksim Levental return arg; 99227c6d55cSMaksim Levental }); 99327c6d55cSMaksim Levental // Actual args passed to op builder (e.g., opParam=op_param). 99427c6d55cSMaksim Levental auto opBuilderArgs = llvm::map_range( 99527c6d55cSMaksim Levental llvm::make_filter_range(functionArgs, 99627c6d55cSMaksim Levental [](const std::string &s) { return s != "*"; }), 99727c6d55cSMaksim Levental [](const std::string &arg) { 99827c6d55cSMaksim Levental auto lhs = *llvm::split(arg, "=").begin(); 99927c6d55cSMaksim Levental return (lhs + "=" + llvm::convertToSnakeFromCamelCase(lhs)).str(); 100027c6d55cSMaksim Levental }); 100151a4f319SPeter Hawkins std::string nameWithoutDialect = sanitizeName( 100251a4f319SPeter Hawkins op.getOperationName().substr(op.getOperationName().find('.') + 1)); 100351a4f319SPeter Hawkins std::string params = llvm::join(valueBuilderParams, ", "); 100451a4f319SPeter Hawkins std::string args = llvm::join(opBuilderArgs, ", "); 100551a4f319SPeter Hawkins const char *type = 100627c6d55cSMaksim Levental (op.getNumResults() > 1 10076ce51599SSergei Lebedev ? "_Sequence[_ods_ir.Value]" 100851a4f319SPeter Hawkins : (op.getNumResults() > 0 ? "_ods_ir.Value" : "_ods_ir.Operation")); 100951a4f319SPeter Hawkins if (op.getNumVariableLengthResults() > 0) { 101051a4f319SPeter Hawkins os << formatv(valueBuilderVariadicTemplate, nameWithoutDialect, 101151a4f319SPeter Hawkins op.getCppClassName(), params, args, type); 101251a4f319SPeter Hawkins } else { 101351a4f319SPeter Hawkins const char *results; 101451a4f319SPeter Hawkins if (op.getNumResults() == 0) { 101551a4f319SPeter Hawkins results = ""; 101651a4f319SPeter Hawkins } else if (op.getNumResults() == 1) { 101751a4f319SPeter Hawkins results = ".result"; 101851a4f319SPeter Hawkins } else { 101951a4f319SPeter Hawkins results = ".results"; 102051a4f319SPeter Hawkins } 102151a4f319SPeter Hawkins os << formatv(valueBuilderTemplate, nameWithoutDialect, 102251a4f319SPeter Hawkins op.getCppClassName(), params, args, type, results); 102351a4f319SPeter Hawkins } 102427c6d55cSMaksim Levental } 102527c6d55cSMaksim Levental 1026fd407e1fSAlex Zinenko /// Emits bindings for a specific Op to the given output stream. 102767a910bbSRahul Kayaith static void emitOpBindings(const Operator &op, raw_ostream &os) { 1028bccd37f6SRahul Joshi os << formatv(opClassTemplate, op.getCppClassName(), op.getOperationName()); 102971b6b010SStella Laurenzo 103071b6b010SStella Laurenzo // Sized segments. 103171b6b010SStella Laurenzo if (op.getTrait(attrSizedTraitForKind("operand")) != nullptr) { 103271b6b010SStella Laurenzo emitSegmentSpec(op, "OPERAND", getNumOperands, getOperand, os); 103371b6b010SStella Laurenzo } 103471b6b010SStella Laurenzo if (op.getTrait(attrSizedTraitForKind("result")) != nullptr) { 103571b6b010SStella Laurenzo emitSegmentSpec(op, "RESULT", getNumResults, getResult, os); 103671b6b010SStella Laurenzo } 103771b6b010SStella Laurenzo 103871b6b010SStella Laurenzo emitRegionAttributes(op, os); 1039bccd37f6SRahul Joshi SmallVector<std::string> functionArgs = emitDefaultOpBuilder(op, os); 1040fd407e1fSAlex Zinenko emitOperandAccessors(op, os); 104167a910bbSRahul Kayaith emitAttributeAccessors(op, os); 1042fd407e1fSAlex Zinenko emitResultAccessors(op, os); 104318fbd5feSAlex Zinenko emitRegionAccessors(op, os); 104427c6d55cSMaksim Levental emitValueBuilder(op, functionArgs, os); 1045fd407e1fSAlex Zinenko } 1046fd407e1fSAlex Zinenko 1047fd407e1fSAlex Zinenko /// Emits bindings for the dialect specified in the command line, including file 1048fd407e1fSAlex Zinenko /// headers and utilities. Returns `false` on success to comply with Tablegen 1049fd407e1fSAlex Zinenko /// registration requirements. 1050bccd37f6SRahul Joshi static bool emitAllOps(const RecordKeeper &records, raw_ostream &os) { 1051fd407e1fSAlex Zinenko if (clDialectName.empty()) 1052fd407e1fSAlex Zinenko llvm::PrintFatalError("dialect name not provided"); 1053fd407e1fSAlex Zinenko 1054a2288a89SMaksim Levental os << fileHeader; 1055a2288a89SMaksim Levental if (!clDialectExtensionName.empty()) 1056bccd37f6SRahul Joshi os << formatv(dialectExtensionTemplate, clDialectName.getValue()); 10573f71765aSAlex Zinenko else 1058bccd37f6SRahul Joshi os << formatv(dialectClassTemplate, clDialectName.getValue()); 1059922b26cdSMehdi Amini 1060bccd37f6SRahul Joshi for (const Record *rec : records.getAllDerivedDefinitions("Op")) { 1061fd407e1fSAlex Zinenko Operator op(rec); 1062fd407e1fSAlex Zinenko if (op.getDialectName() == clDialectName.getValue()) 106367a910bbSRahul Kayaith emitOpBindings(op, os); 1064fd407e1fSAlex Zinenko } 1065fd407e1fSAlex Zinenko return false; 1066fd407e1fSAlex Zinenko } 1067fd407e1fSAlex Zinenko 1068fd407e1fSAlex Zinenko static GenRegistration 1069fd407e1fSAlex Zinenko genPythonBindings("gen-python-op-bindings", 1070fd407e1fSAlex Zinenko "Generate Python bindings for MLIR Ops", &emitAllOps); 1071