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