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 "mlir/TableGen/Format.h"
16 #include "mlir/TableGen/GenInfo.h"
17 #include "mlir/TableGen/OpClass.h"
18 #include "mlir/TableGen/OpInterfaces.h"
19 #include "mlir/TableGen/OpTrait.h"
20 #include "mlir/TableGen/Operator.h"
21 #include "mlir/TableGen/SideEffects.h"
22 #include "llvm/ADT/Sequence.h"
23 #include "llvm/ADT/StringExtras.h"
24 #include "llvm/Support/Signals.h"
25 #include "llvm/TableGen/Error.h"
26 #include "llvm/TableGen/Record.h"
27 #include "llvm/TableGen/TableGenBackend.h"
28 
29 #define DEBUG_TYPE "mlir-tblgen-opdefgen"
30 
31 using namespace llvm;
32 using namespace mlir;
33 using namespace mlir::tblgen;
34 
35 static const char *const tblgenNamePrefix = "tblgen_";
36 static const char *const generatedArgName = "odsArg";
37 static const char *const builderOpState = "odsState";
38 
39 // The logic to calculate the actual value range for a declared operand/result
40 // of an op with variadic operands/results. Note that this logic is not for
41 // general use; it assumes all variadic operands/results must have the same
42 // number of values.
43 //
44 // {0}: The list of whether each declared operand/result is variadic.
45 // {1}: The total number of non-variadic operands/results.
46 // {2}: The total number of variadic operands/results.
47 // {3}: The total number of actual values.
48 // {4}: The begin iterator of the actual values.
49 // {5}: "operand" or "result".
50 const char *sameVariadicSizeValueRangeCalcCode = R"(
51   bool isVariadic[] = {{{0}};
52   int prevVariadicCount = 0;
53   for (unsigned i = 0; i < index; ++i)
54     if (isVariadic[i]) ++prevVariadicCount;
55 
56   // Calculate how many dynamic values a static variadic {5} corresponds to.
57   // This assumes all static variadic {5}s have the same dynamic value count.
58   int variadicSize = ({3} - {1}) / {2};
59   // `index` passed in as the parameter is the static index which counts each
60   // {5} (variadic or not) as size 1. So here for each previous static variadic
61   // {5}, we need to offset by (variadicSize - 1) to get where the dynamic
62   // value pack for this static {5} starts.
63   int offset = index + (variadicSize - 1) * prevVariadicCount;
64   int size = isVariadic[index] ? variadicSize : 1;
65 
66   return {{std::next({4}, offset), std::next({4}, offset + size)};
67 )";
68 
69 // The logic to calculate the actual value range for a declared operand/result
70 // of an op with variadic operands/results. Note that this logic is assumes
71 // the op has an attribute specifying the size of each operand/result segment
72 // (variadic or not).
73 //
74 // {0}: The name of the attribute specifying the segment sizes.
75 // {1}: The begin iterator of the actual values.
76 const char *attrSizedSegmentValueRangeCalcCode = R"(
77   auto sizeAttr = getAttrOfType<DenseIntElementsAttr>("{0}");
78   unsigned start = 0;
79   for (unsigned i = 0; i < index; ++i)
80     start += (*(sizeAttr.begin() + i)).getZExtValue();
81   unsigned end = start + (*(sizeAttr.begin() + index)).getZExtValue();
82   return {{std::next({1}, start), std::next({1}, end)};
83 )";
84 
85 static const char *const opCommentHeader = R"(
86 //===----------------------------------------------------------------------===//
87 // {0} {1}
88 //===----------------------------------------------------------------------===//
89 
90 )";
91 
92 //===----------------------------------------------------------------------===//
93 // Utility structs and functions
94 //===----------------------------------------------------------------------===//
95 
96 // Replaces all occurrences of `match` in `str` with `substitute`.
97 static std::string replaceAllSubstrs(std::string str, const std::string &match,
98                                      const std::string &substitute) {
99   std::string::size_type scanLoc = 0, matchLoc = std::string::npos;
100   while ((matchLoc = str.find(match, scanLoc)) != std::string::npos) {
101     str = str.replace(matchLoc, match.size(), substitute);
102     scanLoc = matchLoc + substitute.size();
103   }
104   return str;
105 }
106 
107 // Returns whether the record has a value of the given name that can be returned
108 // via getValueAsString.
109 static inline bool hasStringAttribute(const Record &record,
110                                       StringRef fieldName) {
111   auto valueInit = record.getValueInit(fieldName);
112   return isa<CodeInit>(valueInit) || isa<StringInit>(valueInit);
113 }
114 
115 static std::string getArgumentName(const Operator &op, int index) {
116   const auto &operand = op.getOperand(index);
117   if (!operand.name.empty())
118     return std::string(operand.name);
119   else
120     return std::string(formatv("{0}_{1}", generatedArgName, index));
121 }
122 
123 // Returns true if we can use unwrapped value for the given `attr` in builders.
124 static bool canUseUnwrappedRawValue(const tblgen::Attribute &attr) {
125   return attr.getReturnType() != attr.getStorageType() &&
126          // We need to wrap the raw value into an attribute in the builder impl
127          // so we need to make sure that the attribute specifies how to do that.
128          !attr.getConstBuilderTemplate().empty();
129 }
130 
131 //===----------------------------------------------------------------------===//
132 // Op emitter
133 //===----------------------------------------------------------------------===//
134 
135 namespace {
136 // Simple RAII helper for defining ifdef-undef-endif scopes.
137 class IfDefScope {
138 public:
139   IfDefScope(StringRef name, raw_ostream &os) : name(name), os(os) {
140     os << "#ifdef " << name << "\n"
141        << "#undef " << name << "\n\n";
142   }
143 
144   ~IfDefScope() { os << "\n#endif  // " << name << "\n\n"; }
145 
146 private:
147   StringRef name;
148   raw_ostream &os;
149 };
150 } // end anonymous namespace
151 
152 namespace {
153 // Helper class to emit a record into the given output stream.
154 class OpEmitter {
155 public:
156   static void emitDecl(const Operator &op, raw_ostream &os);
157   static void emitDef(const Operator &op, raw_ostream &os);
158 
159 private:
160   OpEmitter(const Operator &op);
161 
162   void emitDecl(raw_ostream &os);
163   void emitDef(raw_ostream &os);
164 
165   // Generates the OpAsmOpInterface for this operation if possible.
166   void genOpAsmInterface();
167 
168   // Generates the `getOperationName` method for this op.
169   void genOpNameGetter();
170 
171   // Generates getters for the attributes.
172   void genAttrGetters();
173 
174   // Generates setter for the attributes.
175   void genAttrSetters();
176 
177   // Generates getters for named operands.
178   void genNamedOperandGetters();
179 
180   // Generates getters for named results.
181   void genNamedResultGetters();
182 
183   // Generates getters for named regions.
184   void genNamedRegionGetters();
185 
186   // Generates getters for named successors.
187   void genNamedSuccessorGetters();
188 
189   // Generates builder methods for the operation.
190   void genBuilder();
191 
192   // Generates the build() method that takes each operand/attribute
193   // as a stand-alone parameter.
194   void genSeparateArgParamBuilder();
195 
196   // Generates the build() method that takes each operand/attribute as a
197   // stand-alone parameter. The generated build() method uses first operand's
198   // type as all results' types.
199   void genUseOperandAsResultTypeSeparateParamBuilder();
200 
201   // Generates the build() method that takes all operands/attributes
202   // collectively as one parameter. The generated build() method uses first
203   // operand's type as all results' types.
204   void genUseOperandAsResultTypeCollectiveParamBuilder();
205 
206   // Generates the build() method that takes aggregate operands/attributes
207   // parameters. This build() method uses inferred types as result types.
208   // Requires: The type needs to be inferable via InferTypeOpInterface.
209   void genInferredTypeCollectiveParamBuilder();
210 
211   // Generates the build() method that takes each operand/attribute as a
212   // stand-alone parameter. The generated build() method uses first attribute's
213   // type as all result's types.
214   void genUseAttrAsResultTypeBuilder();
215 
216   // Generates the build() method that takes all result types collectively as
217   // one parameter. Similarly for operands and attributes.
218   void genCollectiveParamBuilder();
219 
220   // The kind of parameter to generate for result types in builders.
221   enum class TypeParamKind {
222     None,       // No result type in parameter list.
223     Separate,   // A separate parameter for each result type.
224     Collective, // An ArrayRef<Type> for all result types.
225   };
226 
227   // The kind of parameter to generate for attributes in builders.
228   enum class AttrParamKind {
229     WrappedAttr,    // A wrapped MLIR Attribute instance.
230     UnwrappedValue, // A raw value without MLIR Attribute wrapper.
231   };
232 
233   // Builds the parameter list for build() method of this op. This method writes
234   // to `paramList` the comma-separated parameter list and updates
235   // `resultTypeNames` with the names for parameters for specifying result
236   // types. The given `typeParamKind` and `attrParamKind` controls how result
237   // types and attributes are placed in the parameter list.
238   void buildParamList(std::string &paramList,
239                       SmallVectorImpl<std::string> &resultTypeNames,
240                       TypeParamKind typeParamKind,
241                       AttrParamKind attrParamKind = AttrParamKind::WrappedAttr);
242 
243   // Adds op arguments and regions into operation state for build() methods.
244   void genCodeForAddingArgAndRegionForBuilder(OpMethodBody &body,
245                                               bool isRawValueAttr = false);
246 
247   // Generates canonicalizer declaration for the operation.
248   void genCanonicalizerDecls();
249 
250   // Generates the folder declaration for the operation.
251   void genFolderDecls();
252 
253   // Generates the parser for the operation.
254   void genParser();
255 
256   // Generates the printer for the operation.
257   void genPrinter();
258 
259   // Generates verify method for the operation.
260   void genVerifier();
261 
262   // Generates verify statements for operands and results in the operation.
263   // The generated code will be attached to `body`.
264   void genOperandResultVerifier(OpMethodBody &body,
265                                 Operator::value_range values,
266                                 StringRef valueKind);
267 
268   // Generates verify statements for regions in the operation.
269   // The generated code will be attached to `body`.
270   void genRegionVerifier(OpMethodBody &body);
271 
272   // Generates verify statements for successors in the operation.
273   // The generated code will be attached to `body`.
274   void genSuccessorVerifier(OpMethodBody &body);
275 
276   // Generates the traits used by the object.
277   void genTraits();
278 
279   // Generate the OpInterface methods.
280   void genOpInterfaceMethods();
281 
282   // Generate the side effect interface methods.
283   void genSideEffectInterfaceMethods();
284 
285 private:
286   // The TableGen record for this op.
287   // TODO(antiagainst,zinenko): OpEmitter should not have a Record directly,
288   // it should rather go through the Operator for better abstraction.
289   const Record &def;
290 
291   // The wrapper operator class for querying information from this op.
292   Operator op;
293 
294   // The C++ code builder for this op
295   OpClass opClass;
296 
297   // The format context for verification code generation.
298   FmtContext verifyCtx;
299 };
300 } // end anonymous namespace
301 
302 OpEmitter::OpEmitter(const Operator &op)
303     : def(op.getDef()), op(op),
304       opClass(op.getCppClassName(), op.getExtraClassDeclaration()) {
305   verifyCtx.withOp("(*this->getOperation())");
306 
307   genTraits();
308   // Generate C++ code for various op methods. The order here determines the
309   // methods in the generated file.
310   genOpAsmInterface();
311   genOpNameGetter();
312   genNamedOperandGetters();
313   genNamedResultGetters();
314   genNamedRegionGetters();
315   genNamedSuccessorGetters();
316   genAttrGetters();
317   genAttrSetters();
318   genBuilder();
319   genParser();
320   genPrinter();
321   genVerifier();
322   genCanonicalizerDecls();
323   genFolderDecls();
324   genOpInterfaceMethods();
325   generateOpFormat(op, opClass);
326   genSideEffectInterfaceMethods();
327 }
328 
329 void OpEmitter::emitDecl(const Operator &op, raw_ostream &os) {
330   OpEmitter(op).emitDecl(os);
331 }
332 
333 void OpEmitter::emitDef(const Operator &op, raw_ostream &os) {
334   OpEmitter(op).emitDef(os);
335 }
336 
337 void OpEmitter::emitDecl(raw_ostream &os) { opClass.writeDeclTo(os); }
338 
339 void OpEmitter::emitDef(raw_ostream &os) { opClass.writeDefTo(os); }
340 
341 void OpEmitter::genAttrGetters() {
342   FmtContext fctx;
343   fctx.withBuilder("mlir::Builder(this->getContext())");
344 
345   // Emit the derived attribute body.
346   auto emitDerivedAttr = [&](StringRef name, Attribute attr) {
347     auto &method = opClass.newMethod(attr.getReturnType(), name);
348     auto &body = method.body();
349     body << "  " << attr.getDerivedCodeBody() << "\n";
350   };
351 
352   // Emit with return type specified.
353   auto emitAttrWithReturnType = [&](StringRef name, Attribute attr) {
354     auto &method = opClass.newMethod(attr.getReturnType(), name);
355     auto &body = method.body();
356     body << "  auto attr = " << name << "Attr();\n";
357     if (attr.hasDefaultValue()) {
358       // Returns the default value if not set.
359       // TODO: this is inefficient, we are recreating the attribute for every
360       // call. This should be set instead.
361       std::string defaultValue = std::string(
362           tgfmt(attr.getConstBuilderTemplate(), &fctx, attr.getDefaultValue()));
363       body << "    if (!attr)\n      return "
364            << tgfmt(attr.getConvertFromStorageCall(),
365                     &fctx.withSelf(defaultValue))
366            << ";\n";
367     }
368     body << "  return "
369          << tgfmt(attr.getConvertFromStorageCall(), &fctx.withSelf("attr"))
370          << ";\n";
371   };
372 
373   // Generate raw named accessor type. This is a wrapper class that allows
374   // referring to the attributes via accessors instead of having to use
375   // the string interface for better compile time verification.
376   auto emitAttrWithStorageType = [&](StringRef name, Attribute attr) {
377     auto &method =
378         opClass.newMethod(attr.getStorageType(), (name + "Attr").str());
379     auto &body = method.body();
380     body << "  return this->getAttr(\"" << name << "\").";
381     if (attr.isOptional() || attr.hasDefaultValue())
382       body << "dyn_cast_or_null<";
383     else
384       body << "cast<";
385     body << attr.getStorageType() << ">();";
386   };
387 
388   for (auto &namedAttr : op.getAttributes()) {
389     const auto &name = namedAttr.name;
390     const auto &attr = namedAttr.attr;
391     if (attr.isDerivedAttr()) {
392       emitDerivedAttr(name, attr);
393     } else {
394       emitAttrWithStorageType(name, attr);
395       emitAttrWithReturnType(name, attr);
396     }
397   }
398 
399   // Generate helper method to query whether a named attribute is a derived
400   // attribute. This enables, for example, avoiding adding an attribute that
401   // overlaps with a derived attribute.
402   auto derivedAttr = make_filter_range(op.getAttributes(),
403                                        [](const NamedAttribute &namedAttr) {
404                                          return namedAttr.attr.isDerivedAttr();
405                                        });
406   if (!derivedAttr.empty()) {
407     opClass.addTrait("DerivedAttributeOpInterface::Trait");
408     auto &method = opClass.newMethod("bool", "isDerivedAttribute",
409                                      "StringRef name", OpMethod::MP_Static);
410     auto &body = method.body();
411     for (auto namedAttr : derivedAttr)
412       body << "    if (name == \"" << namedAttr.name << "\") return true;\n";
413     body << " return false;";
414   }
415 }
416 
417 void OpEmitter::genAttrSetters() {
418   // Generate raw named setter type. This is a wrapper class that allows setting
419   // to the attributes via setters instead of having to use the string interface
420   // for better compile time verification.
421   auto emitAttrWithStorageType = [&](StringRef name, Attribute attr) {
422     auto &method = opClass.newMethod("void", (name + "Attr").str(),
423                                      (attr.getStorageType() + " attr").str());
424     auto &body = method.body();
425     body << "  this->getOperation()->setAttr(\"" << name << "\", attr);";
426   };
427 
428   for (auto &namedAttr : op.getAttributes()) {
429     const auto &name = namedAttr.name;
430     const auto &attr = namedAttr.attr;
431     if (!attr.isDerivedAttr())
432       emitAttrWithStorageType(name, attr);
433   }
434 }
435 
436 // Generates the named operand getter methods for the given Operator `op` and
437 // puts them in `opClass`.  Uses `rangeType` as the return type of getters that
438 // return a range of operands (individual operands are `Value ` and each
439 // element in the range must also be `Value `); use `rangeBeginCall` to get
440 // an iterator to the beginning of the operand range; use `rangeSizeCall` to
441 // obtain the number of operands. `getOperandCallPattern` contains the code
442 // necessary to obtain a single operand whose position will be substituted
443 // instead of
444 // "{0}" marker in the pattern.  Note that the pattern should work for any kind
445 // of ops, in particular for one-operand ops that may not have the
446 // `getOperand(unsigned)` method.
447 static void generateNamedOperandGetters(const Operator &op, Class &opClass,
448                                         StringRef rangeType,
449                                         StringRef rangeBeginCall,
450                                         StringRef rangeSizeCall,
451                                         StringRef getOperandCallPattern) {
452   const int numOperands = op.getNumOperands();
453   const int numVariadicOperands = op.getNumVariableLengthOperands();
454   const int numNormalOperands = numOperands - numVariadicOperands;
455 
456   const auto *sameVariadicSize =
457       op.getTrait("OpTrait::SameVariadicOperandSize");
458   const auto *attrSizedOperands =
459       op.getTrait("OpTrait::AttrSizedOperandSegments");
460 
461   if (numVariadicOperands > 1 && !sameVariadicSize && !attrSizedOperands) {
462     PrintFatalError(op.getLoc(), "op has multiple variadic operands but no "
463                                  "specification over their sizes");
464   }
465 
466   if (numVariadicOperands < 2 && attrSizedOperands) {
467     PrintFatalError(op.getLoc(), "op must have at least two variadic operands "
468                                  "to use 'AttrSizedOperandSegments' trait");
469   }
470 
471   if (attrSizedOperands && sameVariadicSize) {
472     PrintFatalError(op.getLoc(),
473                     "op cannot have both 'AttrSizedOperandSegments' and "
474                     "'SameVariadicOperandSize' traits");
475   }
476 
477   // First emit a "sink" getter method upon which we layer all nicer named
478   // getter methods.
479   auto &m = opClass.newMethod(rangeType, "getODSOperands", "unsigned index");
480 
481   if (numVariadicOperands == 0) {
482     // We still need to match the return type, which is a range.
483     m.body() << "  return {std::next(" << rangeBeginCall
484              << ", index), std::next(" << rangeBeginCall << ", index + 1)};";
485   } else if (attrSizedOperands) {
486     m.body() << formatv(attrSizedSegmentValueRangeCalcCode,
487                         "operand_segment_sizes", rangeBeginCall);
488   } else {
489     // Because the op can have arbitrarily interleaved variadic and non-variadic
490     // operands, we need to embed a list in the "sink" getter method for
491     // calculation at run-time.
492     llvm::SmallVector<StringRef, 4> isVariadic;
493     isVariadic.reserve(numOperands);
494     for (int i = 0; i < numOperands; ++i)
495       isVariadic.push_back(op.getOperand(i).isVariableLength() ? "true"
496                                                                : "false");
497     std::string isVariadicList = llvm::join(isVariadic, ", ");
498 
499     m.body() << formatv(sameVariadicSizeValueRangeCalcCode, isVariadicList,
500                         numNormalOperands, numVariadicOperands, rangeSizeCall,
501                         rangeBeginCall, "operand");
502   }
503 
504   // Then we emit nicer named getter methods by redirecting to the "sink" getter
505   // method.
506 
507   for (int i = 0; i != numOperands; ++i) {
508     const auto &operand = op.getOperand(i);
509     if (operand.name.empty())
510       continue;
511 
512     if (operand.isOptional()) {
513       auto &m = opClass.newMethod("Value", operand.name);
514       m.body() << "  auto operands = getODSOperands(" << i << ");\n"
515                << "  return operands.empty() ? Value() : *operands.begin();";
516     } else if (operand.isVariadic()) {
517       auto &m = opClass.newMethod(rangeType, operand.name);
518       m.body() << "  return getODSOperands(" << i << ");";
519     } else {
520       auto &m = opClass.newMethod("Value", operand.name);
521       m.body() << "  return *getODSOperands(" << i << ").begin();";
522     }
523   }
524 }
525 
526 void OpEmitter::genNamedOperandGetters() {
527   if (op.getTrait("OpTrait::AttrSizedOperandSegments"))
528     opClass.setHasOperandAdaptorClass(false);
529 
530   generateNamedOperandGetters(
531       op, opClass, /*rangeType=*/"Operation::operand_range",
532       /*rangeBeginCall=*/"getOperation()->operand_begin()",
533       /*rangeSizeCall=*/"getOperation()->getNumOperands()",
534       /*getOperandCallPattern=*/"getOperation()->getOperand({0})");
535 }
536 
537 void OpEmitter::genNamedResultGetters() {
538   const int numResults = op.getNumResults();
539   const int numVariadicResults = op.getNumVariableLengthResults();
540   const int numNormalResults = numResults - numVariadicResults;
541 
542   // If we have more than one variadic results, we need more complicated logic
543   // to calculate the value range for each result.
544 
545   const auto *sameVariadicSize = op.getTrait("OpTrait::SameVariadicResultSize");
546   const auto *attrSizedResults =
547       op.getTrait("OpTrait::AttrSizedResultSegments");
548 
549   if (numVariadicResults > 1 && !sameVariadicSize && !attrSizedResults) {
550     PrintFatalError(op.getLoc(), "op has multiple variadic results but no "
551                                  "specification over their sizes");
552   }
553 
554   if (numVariadicResults < 2 && attrSizedResults) {
555     PrintFatalError(op.getLoc(), "op must have at least two variadic results "
556                                  "to use 'AttrSizedResultSegments' trait");
557   }
558 
559   if (attrSizedResults && sameVariadicSize) {
560     PrintFatalError(op.getLoc(),
561                     "op cannot have both 'AttrSizedResultSegments' and "
562                     "'SameVariadicResultSize' traits");
563   }
564 
565   auto &m = opClass.newMethod("Operation::result_range", "getODSResults",
566                               "unsigned index");
567 
568   if (numVariadicResults == 0) {
569     m.body() << "  return {std::next(getOperation()->result_begin(), index), "
570                 "std::next(getOperation()->result_begin(), index + 1)};";
571   } else if (attrSizedResults) {
572     m.body() << formatv(attrSizedSegmentValueRangeCalcCode,
573                         "result_segment_sizes",
574                         "getOperation()->result_begin()");
575   } else {
576     llvm::SmallVector<StringRef, 4> isVariadic;
577     isVariadic.reserve(numResults);
578     for (int i = 0; i < numResults; ++i)
579       isVariadic.push_back(op.getResult(i).isVariableLength() ? "true"
580                                                               : "false");
581     std::string isVariadicList = llvm::join(isVariadic, ", ");
582 
583     m.body() << formatv(sameVariadicSizeValueRangeCalcCode, isVariadicList,
584                         numNormalResults, numVariadicResults,
585                         "getOperation()->getNumResults()",
586                         "getOperation()->result_begin()", "result");
587   }
588 
589   for (int i = 0; i != numResults; ++i) {
590     const auto &result = op.getResult(i);
591     if (result.name.empty())
592       continue;
593 
594     if (result.isOptional()) {
595       auto &m = opClass.newMethod("Value", result.name);
596       m.body() << "  auto results = getODSResults(" << i << ");\n"
597                << "  return results.empty() ? Value() : *results.begin();";
598     } else if (result.isVariadic()) {
599       auto &m = opClass.newMethod("Operation::result_range", result.name);
600       m.body() << "  return getODSResults(" << i << ");";
601     } else {
602       auto &m = opClass.newMethod("Value", result.name);
603       m.body() << "  return *getODSResults(" << i << ").begin();";
604     }
605   }
606 }
607 
608 void OpEmitter::genNamedRegionGetters() {
609   unsigned numRegions = op.getNumRegions();
610   for (unsigned i = 0; i < numRegions; ++i) {
611     const auto &region = op.getRegion(i);
612     if (region.name.empty())
613       continue;
614 
615     // Generate the accessors for a varidiadic region.
616     if (region.isVariadic()) {
617       auto &m = opClass.newMethod("MutableArrayRef<Region>", region.name);
618       m.body() << formatv(
619           "  return this->getOperation()->getRegions().drop_front({0});", i);
620       continue;
621     }
622 
623     auto &m = opClass.newMethod("Region &", region.name);
624     m.body() << formatv("  return this->getOperation()->getRegion({0});", i);
625   }
626 }
627 
628 void OpEmitter::genNamedSuccessorGetters() {
629   unsigned numSuccessors = op.getNumSuccessors();
630   for (unsigned i = 0; i < numSuccessors; ++i) {
631     const NamedSuccessor &successor = op.getSuccessor(i);
632     if (successor.name.empty())
633       continue;
634 
635     // Generate the accessors for a variadic successor list.
636     if (successor.isVariadic()) {
637       auto &m = opClass.newMethod("SuccessorRange", successor.name);
638       m.body() << formatv(
639           "  return {std::next(this->getOperation()->successor_begin(), {0}), "
640           "this->getOperation()->successor_end()};",
641           i);
642       continue;
643     }
644 
645     auto &m = opClass.newMethod("Block *", successor.name);
646     m.body() << formatv("  return this->getOperation()->getSuccessor({0});", i);
647   }
648 }
649 
650 static bool canGenerateUnwrappedBuilder(Operator &op) {
651   // If this op does not have native attributes at all, return directly to avoid
652   // redefining builders.
653   if (op.getNumNativeAttributes() == 0)
654     return false;
655 
656   bool canGenerate = false;
657   // We are generating builders that take raw values for attributes. We need to
658   // make sure the native attributes have a meaningful "unwrapped" value type
659   // different from the wrapped mlir::Attribute type to avoid redefining
660   // builders. This checks for the op has at least one such native attribute.
661   for (int i = 0, e = op.getNumNativeAttributes(); i < e; ++i) {
662     NamedAttribute &namedAttr = op.getAttribute(i);
663     if (canUseUnwrappedRawValue(namedAttr.attr)) {
664       canGenerate = true;
665       break;
666     }
667   }
668   return canGenerate;
669 }
670 
671 void OpEmitter::genSeparateArgParamBuilder() {
672   SmallVector<AttrParamKind, 2> attrBuilderType;
673   attrBuilderType.push_back(AttrParamKind::WrappedAttr);
674   if (canGenerateUnwrappedBuilder(op))
675     attrBuilderType.push_back(AttrParamKind::UnwrappedValue);
676 
677   // Emit with separate builders with or without unwrapped attributes and/or
678   // inferring result type.
679   auto emit = [&](AttrParamKind attrType, TypeParamKind paramKind,
680                   bool inferType) {
681     std::string paramList;
682     llvm::SmallVector<std::string, 4> resultNames;
683     buildParamList(paramList, resultNames, paramKind, attrType);
684 
685     auto &m =
686         opClass.newMethod("void", "build", paramList, OpMethod::MP_Static);
687     auto &body = m.body();
688 
689     genCodeForAddingArgAndRegionForBuilder(
690         body, /*isRawValueAttr=*/attrType == AttrParamKind::UnwrappedValue);
691 
692     // Push all result types to the operation state
693 
694     if (inferType) {
695       // Generate builder that infers type too.
696       // TODO(jpienaar): Subsume this with general checking if type can be
697       // inferred automatically.
698       // TODO(jpienaar): Expand to handle regions.
699       body << formatv(R"(
700         SmallVector<Type, 2> inferredReturnTypes;
701         if (succeeded({0}::inferReturnTypes(odsBuilder->getContext(),
702                       {1}.location, {1}.operands, {1}.attributes,
703                       /*regions=*/{{}, inferredReturnTypes)))
704           {1}.addTypes(inferredReturnTypes);
705         else
706           llvm::report_fatal_error("Failed to infer result type(s).");)",
707                       opClass.getClassName(), builderOpState);
708       return;
709     }
710 
711     switch (paramKind) {
712     case TypeParamKind::None:
713       return;
714     case TypeParamKind::Separate:
715       for (int i = 0, e = op.getNumResults(); i < e; ++i) {
716         if (op.getResult(i).isOptional())
717           body << "  if (" << resultNames[i] << ")\n  ";
718         body << "  " << builderOpState << ".addTypes(" << resultNames[i]
719              << ");\n";
720       }
721       return;
722     case TypeParamKind::Collective:
723       body << "  "
724            << "assert(resultTypes.size() "
725            << (op.getNumVariableLengthResults() == 0 ? "==" : ">=") << " "
726            << (op.getNumResults() - op.getNumVariableLengthResults())
727            << "u && \"mismatched number of results\");\n";
728       body << "  " << builderOpState << ".addTypes(resultTypes);\n";
729       return;
730     }
731     llvm_unreachable("unhandled TypeParamKind");
732   };
733 
734   bool canInferType =
735       op.getTrait("InferTypeOpInterface::Trait") && op.getNumRegions() == 0;
736   for (auto attrType : attrBuilderType) {
737     emit(attrType, TypeParamKind::Separate, /*inferType=*/false);
738     if (canInferType)
739       emit(attrType, TypeParamKind::None, /*inferType=*/true);
740     // Emit separate arg build with collective type, unless there is only one
741     // variadic result, in which case the above would have already generated
742     // the same build method.
743     if (!(op.getNumResults() == 1 && op.getResult(0).isVariableLength()))
744       emit(attrType, TypeParamKind::Collective, /*inferType=*/false);
745   }
746 }
747 
748 void OpEmitter::genUseOperandAsResultTypeCollectiveParamBuilder() {
749   // If this op has a variadic result, we cannot generate this builder because
750   // we don't know how many results to create.
751   if (op.getNumVariableLengthResults() != 0)
752     return;
753 
754   int numResults = op.getNumResults();
755 
756   // Signature
757   std::string params =
758       std::string("Builder *odsBuilder, OperationState &") + builderOpState +
759       ", ValueRange operands, ArrayRef<NamedAttribute> attributes";
760   if (op.getNumVariadicRegions())
761     params += ", unsigned numRegions";
762   auto &m = opClass.newMethod("void", "build", params, OpMethod::MP_Static);
763   auto &body = m.body();
764 
765   // Operands
766   body << "  " << builderOpState << ".addOperands(operands);\n";
767   if (op.hasResizableOperandList())
768     body << formatv("  {0}.setOperandListToResizable();\n\n", builderOpState);
769 
770   // Attributes
771   body << "  " << builderOpState << ".addAttributes(attributes);\n";
772 
773   // Create the correct number of regions
774   if (int numRegions = op.getNumRegions()) {
775     body << llvm::formatv(
776         "  for (unsigned i = 0; i != {0}; ++i)\n",
777         (op.getNumVariadicRegions() ? "numRegions" : Twine(numRegions)));
778     body << "    (void)" << builderOpState << ".addRegion();\n";
779   }
780 
781   // Result types
782   SmallVector<std::string, 2> resultTypes(numResults, "operands[0].getType()");
783   body << "  " << builderOpState << ".addTypes({"
784        << llvm::join(resultTypes, ", ") << "});\n\n";
785 }
786 
787 void OpEmitter::genInferredTypeCollectiveParamBuilder() {
788   // TODO(jpienaar): Expand to support regions.
789   const char *params =
790       "Builder *odsBuilder, OperationState &{0}, "
791       "ValueRange operands, ArrayRef<NamedAttribute> attributes";
792   auto &m =
793       opClass.newMethod("void", "build", formatv(params, builderOpState).str(),
794                         OpMethod::MP_Static);
795   auto &body = m.body();
796   body << formatv(R"(
797     SmallVector<Type, 2> inferredReturnTypes;
798     if (succeeded({0}::inferReturnTypes(odsBuilder->getContext(),
799                   {1}.location, operands, attributes,
800                   /*regions=*/{{}, inferredReturnTypes)))
801       build(odsBuilder, odsState, inferredReturnTypes, operands, attributes);
802     else
803       llvm::report_fatal_error("Failed to infer result type(s).");)",
804                   opClass.getClassName(), builderOpState);
805 }
806 
807 void OpEmitter::genUseOperandAsResultTypeSeparateParamBuilder() {
808   std::string paramList;
809   llvm::SmallVector<std::string, 4> resultNames;
810   buildParamList(paramList, resultNames, TypeParamKind::None);
811 
812   auto &m = opClass.newMethod("void", "build", paramList, OpMethod::MP_Static);
813   genCodeForAddingArgAndRegionForBuilder(m.body());
814 
815   auto numResults = op.getNumResults();
816   if (numResults == 0)
817     return;
818 
819   // Push all result types to the operation state
820   const char *index = op.getOperand(0).isVariadic() ? ".front()" : "";
821   std::string resultType =
822       formatv("{0}{1}.getType()", getArgumentName(op, 0), index).str();
823   m.body() << "  " << builderOpState << ".addTypes({" << resultType;
824   for (int i = 1; i != numResults; ++i)
825     m.body() << ", " << resultType;
826   m.body() << "});\n\n";
827 }
828 
829 void OpEmitter::genUseAttrAsResultTypeBuilder() {
830   std::string params =
831       std::string("Builder *odsBuilder, OperationState &") + builderOpState +
832       ", ValueRange operands, ArrayRef<NamedAttribute> attributes";
833   auto &m = opClass.newMethod("void", "build", params, OpMethod::MP_Static);
834   auto &body = m.body();
835 
836   // Push all result types to the operation state
837   std::string resultType;
838   const auto &namedAttr = op.getAttribute(0);
839 
840   body << "  for (auto attr : attributes) {\n";
841   body << "    if (attr.first != \"" << namedAttr.name << "\") continue;\n";
842   if (namedAttr.attr.isTypeAttr()) {
843     resultType = "attr.second.cast<TypeAttr>().getValue()";
844   } else {
845     resultType = "attr.second.getType()";
846   }
847 
848   // Operands
849   body << "  " << builderOpState << ".addOperands(operands);\n";
850   if (op.hasResizableOperandList())
851     body << formatv("  {0}.setOperandListToResizable();\n\n", builderOpState);
852 
853   // Attributes
854   body << "  " << builderOpState << ".addAttributes(attributes);\n";
855 
856   // Result types
857   SmallVector<std::string, 2> resultTypes(op.getNumResults(), resultType);
858   body << "    " << builderOpState << ".addTypes({"
859        << llvm::join(resultTypes, ", ") << "});\n";
860   body << "  }\n";
861 }
862 
863 void OpEmitter::genBuilder() {
864   // Handle custom builders if provided.
865   // TODO(antiagainst): Create wrapper class for OpBuilder to hide the native
866   // TableGen API calls here.
867   {
868     auto *listInit = dyn_cast_or_null<ListInit>(def.getValueInit("builders"));
869     if (listInit) {
870       for (Init *init : listInit->getValues()) {
871         Record *builderDef = cast<DefInit>(init)->getDef();
872         StringRef params = builderDef->getValueAsString("params");
873         StringRef body = builderDef->getValueAsString("body");
874         bool hasBody = !body.empty();
875 
876         auto &method =
877             opClass.newMethod("void", "build", params, OpMethod::MP_Static,
878                               /*declOnly=*/!hasBody);
879         if (hasBody)
880           method.body() << body;
881       }
882     }
883     if (op.skipDefaultBuilders()) {
884       if (!listInit || listInit->empty())
885         PrintFatalError(
886             op.getLoc(),
887             "default builders are skipped and no custom builders provided");
888       return;
889     }
890   }
891 
892   // Generate default builders that requires all result type, operands, and
893   // attributes as parameters.
894 
895   // We generate three classes of builders here:
896   // 1. one having a stand-alone parameter for each operand / attribute, and
897   genSeparateArgParamBuilder();
898   // 2. one having an aggregated parameter for all result types / operands /
899   //    attributes, and
900   genCollectiveParamBuilder();
901   // 3. one having a stand-alone parameter for each operand and attribute,
902   //    use the first operand or attribute's type as all result types
903   //    to facilitate different call patterns.
904   if (op.getNumVariableLengthResults() == 0) {
905     if (op.getTrait("OpTrait::SameOperandsAndResultType")) {
906       genUseOperandAsResultTypeSeparateParamBuilder();
907       genUseOperandAsResultTypeCollectiveParamBuilder();
908     }
909     if (op.getTrait("OpTrait::FirstAttrDerivedResultType"))
910       genUseAttrAsResultTypeBuilder();
911   }
912 }
913 
914 void OpEmitter::genCollectiveParamBuilder() {
915   int numResults = op.getNumResults();
916   int numVariadicResults = op.getNumVariableLengthResults();
917   int numNonVariadicResults = numResults - numVariadicResults;
918 
919   int numOperands = op.getNumOperands();
920   int numVariadicOperands = op.getNumVariableLengthOperands();
921   int numNonVariadicOperands = numOperands - numVariadicOperands;
922   // Signature
923   std::string params = std::string("Builder *, OperationState &") +
924                        builderOpState +
925                        ", ArrayRef<Type> resultTypes, ValueRange operands, "
926                        "ArrayRef<NamedAttribute> attributes";
927   if (op.getNumVariadicRegions())
928     params += ", unsigned numRegions";
929   auto &m = opClass.newMethod("void", "build", params, OpMethod::MP_Static);
930   auto &body = m.body();
931 
932   // Operands
933   if (numVariadicOperands == 0 || numNonVariadicOperands != 0)
934     body << "  assert(operands.size()"
935          << (numVariadicOperands != 0 ? " >= " : " == ")
936          << numNonVariadicOperands
937          << "u && \"mismatched number of parameters\");\n";
938   body << "  " << builderOpState << ".addOperands(operands);\n";
939   if (op.hasResizableOperandList())
940     body << formatv("  {0}.setOperandListToResizable();\n\n", builderOpState);
941 
942   // Attributes
943   body << "  " << builderOpState << ".addAttributes(attributes);\n";
944 
945   // Create the correct number of regions
946   if (int numRegions = op.getNumRegions()) {
947     body << llvm::formatv(
948         "  for (unsigned i = 0; i != {0}; ++i)\n",
949         (op.getNumVariadicRegions() ? "numRegions" : Twine(numRegions)));
950     body << "    (void)" << builderOpState << ".addRegion();\n";
951   }
952 
953   // Result types
954   if (numVariadicResults == 0 || numNonVariadicResults != 0)
955     body << "  assert(resultTypes.size()"
956          << (numVariadicResults != 0 ? " >= " : " == ") << numNonVariadicResults
957          << "u && \"mismatched number of return types\");\n";
958   body << "  " << builderOpState << ".addTypes(resultTypes);\n";
959 
960   // Generate builder that infers type too.
961   // TODO(jpienaar): Subsume this with general checking if type can be inferred
962   // automatically.
963   // TODO(jpienaar): Expand to handle regions and successors.
964   if (op.getTrait("InferTypeOpInterface::Trait") && op.getNumRegions() == 0 &&
965       op.getNumSuccessors() == 0)
966     genInferredTypeCollectiveParamBuilder();
967 }
968 
969 void OpEmitter::buildParamList(std::string &paramList,
970                                SmallVectorImpl<std::string> &resultTypeNames,
971                                TypeParamKind typeParamKind,
972                                AttrParamKind attrParamKind) {
973   resultTypeNames.clear();
974   auto numResults = op.getNumResults();
975   resultTypeNames.reserve(numResults);
976 
977   paramList = "Builder *odsBuilder, OperationState &";
978   paramList.append(builderOpState);
979 
980   switch (typeParamKind) {
981   case TypeParamKind::None:
982     break;
983   case TypeParamKind::Separate: {
984     // Add parameters for all return types
985     for (int i = 0; i < numResults; ++i) {
986       const auto &result = op.getResult(i);
987       std::string resultName = std::string(result.name);
988       if (resultName.empty())
989         resultName = std::string(formatv("resultType{0}", i));
990 
991       if (result.isOptional())
992         paramList.append(", /*optional*/Type ");
993       else if (result.isVariadic())
994         paramList.append(", ArrayRef<Type> ");
995       else
996         paramList.append(", Type ");
997       paramList.append(resultName);
998 
999       resultTypeNames.emplace_back(std::move(resultName));
1000     }
1001   } break;
1002   case TypeParamKind::Collective: {
1003     paramList.append(", ArrayRef<Type> resultTypes");
1004     resultTypeNames.push_back("resultTypes");
1005   } break;
1006   }
1007 
1008   // Add parameters for all arguments (operands and attributes).
1009 
1010   int numOperands = 0;
1011   int numAttrs = 0;
1012 
1013   int defaultValuedAttrStartIndex = op.getNumArgs();
1014   if (attrParamKind == AttrParamKind::UnwrappedValue) {
1015     // Calculate the start index from which we can attach default values in the
1016     // builder declaration.
1017     for (int i = op.getNumArgs() - 1; i >= 0; --i) {
1018       auto *namedAttr = op.getArg(i).dyn_cast<tblgen::NamedAttribute *>();
1019       if (!namedAttr || !namedAttr->attr.hasDefaultValue())
1020         break;
1021 
1022       if (!canUseUnwrappedRawValue(namedAttr->attr))
1023         break;
1024 
1025       // Creating an APInt requires us to provide bitwidth, value, and
1026       // signedness, which is complicated compared to others. Similarly
1027       // for APFloat.
1028       // TODO(b/144412160) Adjust the 'returnType' field of such attributes
1029       // to support them.
1030       StringRef retType = namedAttr->attr.getReturnType();
1031       if (retType == "APInt" || retType == "APFloat")
1032         break;
1033 
1034       defaultValuedAttrStartIndex = i;
1035     }
1036   }
1037 
1038   for (int i = 0, e = op.getNumArgs(); i < e; ++i) {
1039     auto argument = op.getArg(i);
1040     if (argument.is<tblgen::NamedTypeConstraint *>()) {
1041       const auto &operand = op.getOperand(numOperands);
1042       if (operand.isOptional())
1043         paramList.append(", /*optional*/Value ");
1044       else if (operand.isVariadic())
1045         paramList.append(", ValueRange ");
1046       else
1047         paramList.append(", Value ");
1048       paramList.append(getArgumentName(op, numOperands));
1049       ++numOperands;
1050     } else {
1051       const auto &namedAttr = op.getAttribute(numAttrs);
1052       const auto &attr = namedAttr.attr;
1053       paramList.append(", ");
1054 
1055       if (attr.isOptional())
1056         paramList.append("/*optional*/");
1057 
1058       switch (attrParamKind) {
1059       case AttrParamKind::WrappedAttr:
1060         paramList.append(std::string(attr.getStorageType()));
1061         break;
1062       case AttrParamKind::UnwrappedValue:
1063         if (canUseUnwrappedRawValue(attr)) {
1064           paramList.append(std::string(attr.getReturnType()));
1065         } else {
1066           paramList.append(std::string(attr.getStorageType()));
1067         }
1068         break;
1069       }
1070       paramList.append(" ");
1071       paramList.append(std::string(namedAttr.name));
1072 
1073       // Attach default value if requested and possible.
1074       if (attrParamKind == AttrParamKind::UnwrappedValue &&
1075           i >= defaultValuedAttrStartIndex) {
1076         bool isString = attr.getReturnType() == "StringRef";
1077         paramList.append(" = ");
1078         if (isString)
1079           paramList.append("\"");
1080         paramList.append(std::string(attr.getDefaultValue()));
1081         if (isString)
1082           paramList.append("\"");
1083       }
1084       ++numAttrs;
1085     }
1086   }
1087 
1088   /// Insert parameters for each successor.
1089   for (const NamedSuccessor &succ : op.getSuccessors()) {
1090     paramList += (succ.isVariadic() ? ", ArrayRef<Block *> " : ", Block *");
1091     paramList += succ.name;
1092   }
1093 
1094   /// Insert parameters for variadic regions.
1095   for (const NamedRegion &region : op.getRegions()) {
1096     if (region.isVariadic())
1097       paramList += llvm::formatv(", unsigned {0}Count", region.name).str();
1098   }
1099 }
1100 
1101 void OpEmitter::genCodeForAddingArgAndRegionForBuilder(OpMethodBody &body,
1102                                                        bool isRawValueAttr) {
1103   // Push all operands to the result.
1104   for (int i = 0, e = op.getNumOperands(); i < e; ++i) {
1105     std::string argName = getArgumentName(op, i);
1106     if (op.getOperand(i).isOptional())
1107       body << "  if (" << argName << ")\n  ";
1108     body << "  " << builderOpState << ".addOperands(" << argName << ");\n";
1109   }
1110   if (op.hasResizableOperandList())
1111     body << formatv("  {0}.setOperandListToResizable();\n", builderOpState);
1112 
1113   // If the operation has the operand segment size attribute, add it here.
1114   if (op.getTrait("OpTrait::AttrSizedOperandSegments")) {
1115     body << "  " << builderOpState
1116          << ".addAttribute(\"operand_segment_sizes\", "
1117             "odsBuilder->getI32VectorAttr({";
1118     llvm::interleaveComma(
1119         llvm::seq<int>(0, op.getNumOperands()), body, [&](int i) {
1120           if (op.getOperand(i).isOptional())
1121             body << "(" << getArgumentName(op, i) << " ? 1 : 0)";
1122           else if (op.getOperand(i).isVariadic())
1123             body << "static_cast<int32_t>(" << getArgumentName(op, i)
1124                  << ".size())";
1125           else
1126             body << "1";
1127         });
1128     body << "}));\n";
1129   }
1130 
1131   // Push all attributes to the result.
1132   for (const auto &namedAttr : op.getAttributes()) {
1133     auto &attr = namedAttr.attr;
1134     if (!attr.isDerivedAttr()) {
1135       bool emitNotNullCheck = attr.isOptional();
1136       if (emitNotNullCheck) {
1137         body << formatv("  if ({0}) ", namedAttr.name) << "{\n";
1138       }
1139       if (isRawValueAttr && canUseUnwrappedRawValue(attr)) {
1140         // If this is a raw value, then we need to wrap it in an Attribute
1141         // instance.
1142         FmtContext fctx;
1143         fctx.withBuilder("(*odsBuilder)");
1144 
1145         std::string builderTemplate =
1146             std::string(attr.getConstBuilderTemplate());
1147 
1148         // For StringAttr, its constant builder call will wrap the input in
1149         // quotes, which is correct for normal string literals, but incorrect
1150         // here given we use function arguments. So we need to strip the
1151         // wrapping quotes.
1152         if (StringRef(builderTemplate).contains("\"$0\""))
1153           builderTemplate = replaceAllSubstrs(builderTemplate, "\"$0\"", "$0");
1154 
1155         std::string value =
1156             std::string(tgfmt(builderTemplate, &fctx, namedAttr.name));
1157         body << formatv("  {0}.addAttribute(\"{1}\", {2});\n", builderOpState,
1158                         namedAttr.name, value);
1159       } else {
1160         body << formatv("  {0}.addAttribute(\"{1}\", {1});\n", builderOpState,
1161                         namedAttr.name);
1162       }
1163       if (emitNotNullCheck) {
1164         body << "  }\n";
1165       }
1166     }
1167   }
1168 
1169   // Create the correct number of regions.
1170   for (const NamedRegion &region : op.getRegions()) {
1171     if (region.isVariadic())
1172       body << formatv("  for (unsigned i = 0; i < {0}Count; ++i)\n  ",
1173                       region.name);
1174 
1175     body << "  (void)" << builderOpState << ".addRegion();\n";
1176   }
1177 
1178   // Push all successors to the result.
1179   for (const NamedSuccessor &namedSuccessor : op.getSuccessors()) {
1180     body << formatv("  {0}.addSuccessors({1});\n", builderOpState,
1181                     namedSuccessor.name);
1182   }
1183 }
1184 
1185 void OpEmitter::genCanonicalizerDecls() {
1186   if (!def.getValueAsBit("hasCanonicalizer"))
1187     return;
1188 
1189   const char *const params =
1190       "OwningRewritePatternList &results, MLIRContext *context";
1191   opClass.newMethod("void", "getCanonicalizationPatterns", params,
1192                     OpMethod::MP_Static, /*declOnly=*/true);
1193 }
1194 
1195 void OpEmitter::genFolderDecls() {
1196   bool hasSingleResult =
1197       op.getNumResults() == 1 && op.getNumVariableLengthResults() == 0;
1198 
1199   if (def.getValueAsBit("hasFolder")) {
1200     if (hasSingleResult) {
1201       const char *const params = "ArrayRef<Attribute> operands";
1202       opClass.newMethod("OpFoldResult", "fold", params, OpMethod::MP_None,
1203                         /*declOnly=*/true);
1204     } else {
1205       const char *const params = "ArrayRef<Attribute> operands, "
1206                                  "SmallVectorImpl<OpFoldResult> &results";
1207       opClass.newMethod("LogicalResult", "fold", params, OpMethod::MP_None,
1208                         /*declOnly=*/true);
1209     }
1210   }
1211 }
1212 
1213 void OpEmitter::genOpInterfaceMethods() {
1214   for (const auto &trait : op.getTraits()) {
1215     auto opTrait = dyn_cast<tblgen::InterfaceOpTrait>(&trait);
1216     if (!opTrait || !opTrait->shouldDeclareMethods())
1217       continue;
1218     auto interface = opTrait->getOpInterface();
1219     for (auto method : interface.getMethods()) {
1220       // Don't declare if the method has a body or a default implementation.
1221       if (method.getBody() || method.getDefaultImplementation())
1222         continue;
1223       std::string args;
1224       llvm::raw_string_ostream os(args);
1225       llvm::interleaveComma(method.getArguments(), os,
1226                             [&](const OpInterfaceMethod::Argument &arg) {
1227                               os << arg.type << " " << arg.name;
1228                             });
1229       opClass.newMethod(method.getReturnType(), method.getName(), os.str(),
1230                         method.isStatic() ? OpMethod::MP_Static
1231                                           : OpMethod::MP_None,
1232                         /*declOnly=*/true);
1233     }
1234   }
1235 }
1236 
1237 void OpEmitter::genSideEffectInterfaceMethods() {
1238   enum EffectKind { Operand, Result, Static };
1239   struct EffectLocation {
1240     /// The effect applied.
1241     SideEffect effect;
1242 
1243     /// The index if the kind is either operand or result.
1244     unsigned index : 30;
1245 
1246     /// The kind of the location.
1247     unsigned kind : 2;
1248   };
1249 
1250   StringMap<SmallVector<EffectLocation, 1>> interfaceEffects;
1251   auto resolveDecorators = [&](Operator::var_decorator_range decorators,
1252                                unsigned index, unsigned kind) {
1253     for (auto decorator : decorators)
1254       if (SideEffect *effect = dyn_cast<SideEffect>(&decorator))
1255         interfaceEffects[effect->getBaseEffectName()].push_back(
1256             EffectLocation{*effect, index, kind});
1257   };
1258 
1259   // Collect effects that were specified via:
1260   /// Traits.
1261   for (const auto &trait : op.getTraits()) {
1262     const auto *opTrait = dyn_cast<tblgen::SideEffectTrait>(&trait);
1263     if (!opTrait)
1264       continue;
1265     auto &effects = interfaceEffects[opTrait->getBaseEffectName()];
1266     for (auto decorator : opTrait->getEffects())
1267       effects.push_back(EffectLocation{cast<SideEffect>(decorator),
1268                                        /*index=*/0, EffectKind::Static});
1269   }
1270   /// Operands.
1271   for (unsigned i = 0, operandIt = 0, e = op.getNumArgs(); i != e; ++i) {
1272     if (op.getArg(i).is<NamedTypeConstraint *>()) {
1273       resolveDecorators(op.getArgDecorators(i), operandIt, EffectKind::Operand);
1274       ++operandIt;
1275     }
1276   }
1277   /// Results.
1278   for (unsigned i = 0, e = op.getNumResults(); i != e; ++i)
1279     resolveDecorators(op.getResultDecorators(i), i, EffectKind::Result);
1280 
1281   for (auto &it : interfaceEffects) {
1282     auto effectsParam =
1283         llvm::formatv(
1284             "SmallVectorImpl<SideEffects::EffectInstance<{0}>> &effects",
1285             it.first())
1286             .str();
1287 
1288     // Generate the 'getEffects' method.
1289     auto &getEffects = opClass.newMethod("void", "getEffects", effectsParam);
1290     auto &body = getEffects.body();
1291 
1292     // Add effect instances for each of the locations marked on the operation.
1293     for (auto &location : it.second) {
1294       if (location.kind != EffectKind::Static) {
1295         body << "  for (Value value : getODS"
1296              << (location.kind == EffectKind::Operand ? "Operands" : "Results")
1297              << "(" << location.index << "))\n  ";
1298       }
1299 
1300       body << "  effects.emplace_back(" << location.effect.getName()
1301            << "::get()";
1302 
1303       // If the effect isn't static, it has a specific value attached to it.
1304       if (location.kind != EffectKind::Static)
1305         body << ", value";
1306       body << ", " << location.effect.getResource() << "::get());\n";
1307     }
1308   }
1309 }
1310 
1311 void OpEmitter::genParser() {
1312   if (!hasStringAttribute(def, "parser") ||
1313       hasStringAttribute(def, "assemblyFormat"))
1314     return;
1315 
1316   auto &method = opClass.newMethod(
1317       "ParseResult", "parse", "OpAsmParser &parser, OperationState &result",
1318       OpMethod::MP_Static);
1319   FmtContext fctx;
1320   fctx.addSubst("cppClass", opClass.getClassName());
1321   auto parser = def.getValueAsString("parser").ltrim().rtrim(" \t\v\f\r");
1322   method.body() << "  " << tgfmt(parser, &fctx);
1323 }
1324 
1325 void OpEmitter::genPrinter() {
1326   if (hasStringAttribute(def, "assemblyFormat"))
1327     return;
1328 
1329   auto valueInit = def.getValueInit("printer");
1330   CodeInit *codeInit = dyn_cast<CodeInit>(valueInit);
1331   if (!codeInit)
1332     return;
1333 
1334   auto &method = opClass.newMethod("void", "print", "OpAsmPrinter &p");
1335   FmtContext fctx;
1336   fctx.addSubst("cppClass", opClass.getClassName());
1337   auto printer = codeInit->getValue().ltrim().rtrim(" \t\v\f\r");
1338   method.body() << "  " << tgfmt(printer, &fctx);
1339 }
1340 
1341 void OpEmitter::genVerifier() {
1342   auto valueInit = def.getValueInit("verifier");
1343   CodeInit *codeInit = dyn_cast<CodeInit>(valueInit);
1344   bool hasCustomVerify = codeInit && !codeInit->getValue().empty();
1345 
1346   auto &method = opClass.newMethod("LogicalResult", "verify", /*params=*/"");
1347   auto &body = method.body();
1348 
1349   const char *checkAttrSizedValueSegmentsCode = R"(
1350   auto sizeAttr = getAttrOfType<DenseIntElementsAttr>("{0}");
1351   auto numElements = sizeAttr.getType().cast<ShapedType>().getNumElements();
1352   if (numElements != {1}) {{
1353     return emitOpError("'{0}' attribute for specifying {2} segments "
1354                        "must have {1} elements");
1355   }
1356   )";
1357 
1358   // Verify a few traits first so that we can use
1359   // getODSOperands()/getODSResults() in the rest of the verifier.
1360   for (auto &trait : op.getTraits()) {
1361     if (auto *t = dyn_cast<tblgen::NativeOpTrait>(&trait)) {
1362       if (t->getTrait() == "OpTrait::AttrSizedOperandSegments") {
1363         body << formatv(checkAttrSizedValueSegmentsCode,
1364                         "operand_segment_sizes", op.getNumOperands(),
1365                         "operand");
1366       } else if (t->getTrait() == "OpTrait::AttrSizedResultSegments") {
1367         body << formatv(checkAttrSizedValueSegmentsCode, "result_segment_sizes",
1368                         op.getNumResults(), "result");
1369       }
1370     }
1371   }
1372 
1373   // Populate substitutions for attributes and named operands and results.
1374   for (const auto &namedAttr : op.getAttributes())
1375     verifyCtx.addSubst(namedAttr.name,
1376                        formatv("this->getAttr(\"{0}\")", namedAttr.name));
1377   for (int i = 0, e = op.getNumOperands(); i < e; ++i) {
1378     auto &value = op.getOperand(i);
1379     if (value.name.empty())
1380       continue;
1381 
1382     if (value.isVariadic())
1383       verifyCtx.addSubst(value.name, formatv("this->getODSOperands({0})", i));
1384     else
1385       verifyCtx.addSubst(value.name,
1386                          formatv("(*this->getODSOperands({0}).begin())", i));
1387   }
1388   for (int i = 0, e = op.getNumResults(); i < e; ++i) {
1389     auto &value = op.getResult(i);
1390     if (value.name.empty())
1391       continue;
1392 
1393     if (value.isVariadic())
1394       verifyCtx.addSubst(value.name, formatv("this->getODSResults({0})", i));
1395     else
1396       verifyCtx.addSubst(value.name,
1397                          formatv("(*this->getODSResults({0}).begin())", i));
1398   }
1399 
1400   // Verify the attributes have the correct type.
1401   for (const auto &namedAttr : op.getAttributes()) {
1402     const auto &attr = namedAttr.attr;
1403     if (attr.isDerivedAttr())
1404       continue;
1405 
1406     auto attrName = namedAttr.name;
1407     // Prefix with `tblgen_` to avoid hiding the attribute accessor.
1408     auto varName = tblgenNamePrefix + attrName;
1409     body << formatv("  auto {0} = this->getAttr(\"{1}\");\n", varName,
1410                     attrName);
1411 
1412     bool allowMissingAttr = attr.hasDefaultValue() || attr.isOptional();
1413     if (allowMissingAttr) {
1414       // If the attribute has a default value, then only verify the predicate if
1415       // set. This does effectively assume that the default value is valid.
1416       // TODO: verify the debug value is valid (perhaps in debug mode only).
1417       body << "  if (" << varName << ") {\n";
1418     } else {
1419       body << "  if (!" << varName
1420            << ") return emitOpError(\"requires attribute '" << attrName
1421            << "'\");\n  {\n";
1422     }
1423 
1424     auto attrPred = attr.getPredicate();
1425     if (!attrPred.isNull()) {
1426       body << tgfmt(
1427           "    if (!($0)) return emitOpError(\"attribute '$1' "
1428           "failed to satisfy constraint: $2\");\n",
1429           /*ctx=*/nullptr,
1430           tgfmt(attrPred.getCondition(), &verifyCtx.withSelf(varName)),
1431           attrName, attr.getDescription());
1432     }
1433 
1434     body << "  }\n";
1435   }
1436 
1437   genOperandResultVerifier(body, op.getOperands(), "operand");
1438   genOperandResultVerifier(body, op.getResults(), "result");
1439 
1440   for (auto &trait : op.getTraits()) {
1441     if (auto *t = dyn_cast<tblgen::PredOpTrait>(&trait)) {
1442       body << tgfmt("  if (!($0)) {\n    "
1443                     "return emitOpError(\"failed to verify that $1\");\n  }\n",
1444                     &verifyCtx, tgfmt(t->getPredTemplate(), &verifyCtx),
1445                     t->getDescription());
1446     }
1447   }
1448 
1449   genRegionVerifier(body);
1450   genSuccessorVerifier(body);
1451 
1452   if (hasCustomVerify) {
1453     FmtContext fctx;
1454     fctx.addSubst("cppClass", opClass.getClassName());
1455     auto printer = codeInit->getValue().ltrim().rtrim(" \t\v\f\r");
1456     body << "  " << tgfmt(printer, &fctx);
1457   } else {
1458     body << "  return mlir::success();\n";
1459   }
1460 }
1461 
1462 void OpEmitter::genOperandResultVerifier(OpMethodBody &body,
1463                                          Operator::value_range values,
1464                                          StringRef valueKind) {
1465   FmtContext fctx;
1466 
1467   body << "  {\n";
1468   body << "    unsigned index = 0; (void)index;\n";
1469 
1470   for (auto staticValue : llvm::enumerate(values)) {
1471     bool hasPredicate = staticValue.value().hasPredicate();
1472     bool isOptional = staticValue.value().isOptional();
1473     if (!hasPredicate && !isOptional)
1474       continue;
1475     body << formatv("    auto valueGroup{2} = getODS{0}{1}s({2});\n",
1476                     // Capitalize the first letter to match the function name
1477                     valueKind.substr(0, 1).upper(), valueKind.substr(1),
1478                     staticValue.index());
1479 
1480     // If the constraint is optional check that the value group has at most 1
1481     // value.
1482     if (isOptional) {
1483       body << formatv("    if (valueGroup{0}.size() > 1)\n"
1484                       "      return emitOpError(\"{1} group starting at #\") "
1485                       "<< index << \" requires 0 or 1 element, but found \" << "
1486                       "valueGroup{0}.size();\n",
1487                       staticValue.index(), valueKind);
1488     }
1489 
1490     // Otherwise, if there is no predicate there is nothing left to do.
1491     if (!hasPredicate)
1492       continue;
1493 
1494     // Emit a loop to check all the dynamic values in the pack.
1495     body << "    for (Value v : valueGroup" << staticValue.index() << ") {\n";
1496 
1497     auto constraint = staticValue.value().constraint;
1498     body << "      (void)v;\n"
1499          << "      if (!("
1500          << tgfmt(constraint.getConditionTemplate(),
1501                   &fctx.withSelf("v.getType()"))
1502          << ")) {\n"
1503          << formatv("        return emitOpError(\"{0} #\") << index "
1504                     "<< \" must be {1}, but got \" << v.getType();\n",
1505                     valueKind, constraint.getDescription())
1506          << "      }\n" // if
1507          << "      ++index;\n"
1508          << "    }\n"; // for
1509   }
1510 
1511   body << "  }\n";
1512 }
1513 
1514 void OpEmitter::genRegionVerifier(OpMethodBody &body) {
1515   // If we have no regions, there is nothing more to do.
1516   unsigned numRegions = op.getNumRegions();
1517   if (numRegions == 0)
1518     return;
1519 
1520   body << "{\n";
1521   body << "    unsigned index = 0; (void)index;\n";
1522 
1523   for (unsigned i = 0; i < numRegions; ++i) {
1524     const auto &region = op.getRegion(i);
1525     if (region.constraint.getPredicate().isNull())
1526       continue;
1527 
1528     body << "    for (Region &region : ";
1529     body << formatv(
1530         region.isVariadic()
1531             ? "{0}()"
1532             : "MutableArrayRef<Region>(this->getOperation()->getRegion({1}))",
1533         region.name, i);
1534     body << ") {\n";
1535     auto constraint = tgfmt(region.constraint.getConditionTemplate(),
1536                             &verifyCtx.withSelf("region"))
1537                           .str();
1538 
1539     body << formatv("      (void)region;\n"
1540                     "      if (!({0})) {\n        "
1541                     "return emitOpError(\"region #\") << index << \" {1}"
1542                     "failed to "
1543                     "verify constraint: {2}\";\n      }\n",
1544                     constraint,
1545                     region.name.empty() ? "" : "('" + region.name + "') ",
1546                     region.constraint.getDescription())
1547          << "      ++index;\n"
1548          << "    }\n";
1549   }
1550   body << "  }\n";
1551 }
1552 
1553 void OpEmitter::genSuccessorVerifier(OpMethodBody &body) {
1554   // If we have no successors, there is nothing more to do.
1555   unsigned numSuccessors = op.getNumSuccessors();
1556   if (numSuccessors == 0)
1557     return;
1558 
1559   body << "{\n";
1560   body << "    unsigned index = 0; (void)index;\n";
1561 
1562   for (unsigned i = 0; i < numSuccessors; ++i) {
1563     const auto &successor = op.getSuccessor(i);
1564     if (successor.constraint.getPredicate().isNull())
1565       continue;
1566 
1567     body << "    for (Block *successor : ";
1568     body << formatv(successor.isVariadic() ? "{0}()"
1569                                            : "ArrayRef<Block *>({0}())",
1570                     successor.name);
1571     body << ") {\n";
1572     auto constraint = tgfmt(successor.constraint.getConditionTemplate(),
1573                             &verifyCtx.withSelf("successor"))
1574                           .str();
1575 
1576     body << formatv("      (void)successor;\n"
1577                     "      if (!({0})) {\n        "
1578                     "return emitOpError(\"successor #\") << index << \"('{1}') "
1579                     "failed to "
1580                     "verify constraint: {2}\";\n      }\n",
1581                     constraint, successor.name,
1582                     successor.constraint.getDescription())
1583          << "      ++index;\n"
1584          << "    }\n";
1585   }
1586   body << "  }\n";
1587 }
1588 
1589 /// Add a size count trait to the given operation class.
1590 static void addSizeCountTrait(OpClass &opClass, StringRef traitKind,
1591                               int numTotal, int numVariadic) {
1592   if (numVariadic != 0) {
1593     if (numTotal == numVariadic)
1594       opClass.addTrait("OpTrait::Variadic" + traitKind + "s");
1595     else
1596       opClass.addTrait("OpTrait::AtLeastN" + traitKind + "s<" +
1597                        Twine(numTotal - numVariadic) + ">::Impl");
1598     return;
1599   }
1600   switch (numTotal) {
1601   case 0:
1602     opClass.addTrait("OpTrait::Zero" + traitKind);
1603     break;
1604   case 1:
1605     opClass.addTrait("OpTrait::One" + traitKind);
1606     break;
1607   default:
1608     opClass.addTrait("OpTrait::N" + traitKind + "s<" + Twine(numTotal) +
1609                      ">::Impl");
1610     break;
1611   }
1612 }
1613 
1614 void OpEmitter::genTraits() {
1615   // Add region size trait.
1616   unsigned numRegions = op.getNumRegions();
1617   unsigned numVariadicRegions = op.getNumVariadicRegions();
1618   addSizeCountTrait(opClass, "Region", numRegions, numVariadicRegions);
1619 
1620   // Add result size trait.
1621   int numResults = op.getNumResults();
1622   int numVariadicResults = op.getNumVariableLengthResults();
1623   addSizeCountTrait(opClass, "Result", numResults, numVariadicResults);
1624 
1625   // Add successor size trait.
1626   unsigned numSuccessors = op.getNumSuccessors();
1627   unsigned numVariadicSuccessors = op.getNumVariadicSuccessors();
1628   addSizeCountTrait(opClass, "Successor", numSuccessors, numVariadicSuccessors);
1629 
1630   // Add variadic size trait and normal op traits.
1631   int numOperands = op.getNumOperands();
1632   int numVariadicOperands = op.getNumVariableLengthOperands();
1633 
1634   // Add operand size trait.
1635   if (numVariadicOperands != 0) {
1636     if (numOperands == numVariadicOperands)
1637       opClass.addTrait("OpTrait::VariadicOperands");
1638     else
1639       opClass.addTrait("OpTrait::AtLeastNOperands<" +
1640                        Twine(numOperands - numVariadicOperands) + ">::Impl");
1641   } else {
1642     switch (numOperands) {
1643     case 0:
1644       opClass.addTrait("OpTrait::ZeroOperands");
1645       break;
1646     case 1:
1647       opClass.addTrait("OpTrait::OneOperand");
1648       break;
1649     default:
1650       opClass.addTrait("OpTrait::NOperands<" + Twine(numOperands) + ">::Impl");
1651       break;
1652     }
1653   }
1654 
1655   // Add the native and interface traits.
1656   for (const auto &trait : op.getTraits()) {
1657     if (auto opTrait = dyn_cast<tblgen::NativeOpTrait>(&trait))
1658       opClass.addTrait(opTrait->getTrait());
1659     else if (auto opTrait = dyn_cast<tblgen::InterfaceOpTrait>(&trait))
1660       opClass.addTrait(opTrait->getTrait());
1661   }
1662 }
1663 
1664 void OpEmitter::genOpNameGetter() {
1665   auto &method = opClass.newMethod("StringRef", "getOperationName",
1666                                    /*params=*/"", OpMethod::MP_Static);
1667   method.body() << "  return \"" << op.getOperationName() << "\";\n";
1668 }
1669 
1670 void OpEmitter::genOpAsmInterface() {
1671   // If the user only has one results or specifically added the Asm trait,
1672   // then don't generate it for them. We specifically only handle multi result
1673   // operations, because the name of a single result in the common case is not
1674   // interesting(generally 'result'/'output'/etc.).
1675   // TODO: We could also add a flag to allow operations to opt in to this
1676   // generation, even if they only have a single operation.
1677   int numResults = op.getNumResults();
1678   if (numResults <= 1 || op.getTrait("OpAsmOpInterface::Trait"))
1679     return;
1680 
1681   SmallVector<StringRef, 4> resultNames(numResults);
1682   for (int i = 0; i != numResults; ++i)
1683     resultNames[i] = op.getResultName(i);
1684 
1685   // Don't add the trait if none of the results have a valid name.
1686   if (llvm::all_of(resultNames, [](StringRef name) { return name.empty(); }))
1687     return;
1688   opClass.addTrait("OpAsmOpInterface::Trait");
1689 
1690   // Generate the right accessor for the number of results.
1691   auto &method = opClass.newMethod("void", "getAsmResultNames",
1692                                    "OpAsmSetValueNameFn setNameFn");
1693   auto &body = method.body();
1694   for (int i = 0; i != numResults; ++i) {
1695     body << "  auto resultGroup" << i << " = getODSResults(" << i << ");\n"
1696          << "  if (!llvm::empty(resultGroup" << i << "))\n"
1697          << "    setNameFn(*resultGroup" << i << ".begin(), \""
1698          << resultNames[i] << "\");\n";
1699   }
1700 }
1701 
1702 //===----------------------------------------------------------------------===//
1703 // OpOperandAdaptor emitter
1704 //===----------------------------------------------------------------------===//
1705 
1706 namespace {
1707 // Helper class to emit Op operand adaptors to an output stream.  Operand
1708 // adaptors are wrappers around ArrayRef<Value> that provide named operand
1709 // getters identical to those defined in the Op.
1710 class OpOperandAdaptorEmitter {
1711 public:
1712   static void emitDecl(const Operator &op, raw_ostream &os);
1713   static void emitDef(const Operator &op, raw_ostream &os);
1714 
1715 private:
1716   explicit OpOperandAdaptorEmitter(const Operator &op);
1717 
1718   Class adapterClass;
1719 };
1720 } // end namespace
1721 
1722 OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(const Operator &op)
1723     : adapterClass(op.getCppClassName().str() + "OperandAdaptor") {
1724   adapterClass.newField("ArrayRef<Value>", "tblgen_operands");
1725   auto &constructor = adapterClass.newConstructor("ArrayRef<Value> values");
1726   constructor.body() << "  tblgen_operands = values;\n";
1727 
1728   generateNamedOperandGetters(op, adapterClass,
1729                               /*rangeType=*/"ArrayRef<Value>",
1730                               /*rangeBeginCall=*/"tblgen_operands.begin()",
1731                               /*rangeSizeCall=*/"tblgen_operands.size()",
1732                               /*getOperandCallPattern=*/"tblgen_operands[{0}]");
1733 }
1734 
1735 void OpOperandAdaptorEmitter::emitDecl(const Operator &op, raw_ostream &os) {
1736   OpOperandAdaptorEmitter(op).adapterClass.writeDeclTo(os);
1737 }
1738 
1739 void OpOperandAdaptorEmitter::emitDef(const Operator &op, raw_ostream &os) {
1740   OpOperandAdaptorEmitter(op).adapterClass.writeDefTo(os);
1741 }
1742 
1743 // Emits the opcode enum and op classes.
1744 static void emitOpClasses(const std::vector<Record *> &defs, raw_ostream &os,
1745                           bool emitDecl) {
1746   IfDefScope scope("GET_OP_CLASSES", os);
1747   // First emit forward declaration for each class, this allows them to refer
1748   // to each others in traits for example.
1749   if (emitDecl) {
1750     for (auto *def : defs) {
1751       Operator op(*def);
1752       os << "class " << op.getCppClassName() << ";\n";
1753     }
1754   }
1755   for (auto *def : defs) {
1756     Operator op(*def);
1757     const auto *attrSizedOperands =
1758         op.getTrait("OpTrait::AttrSizedOperandSegments");
1759     if (emitDecl) {
1760       os << formatv(opCommentHeader, op.getQualCppClassName(), "declarations");
1761       // We cannot generate the operand adaptor class if operand getters depend
1762       // on an attribute.
1763       if (!attrSizedOperands)
1764         OpOperandAdaptorEmitter::emitDecl(op, os);
1765       OpEmitter::emitDecl(op, os);
1766     } else {
1767       os << formatv(opCommentHeader, op.getQualCppClassName(), "definitions");
1768       if (!attrSizedOperands)
1769         OpOperandAdaptorEmitter::emitDef(op, os);
1770       OpEmitter::emitDef(op, os);
1771     }
1772   }
1773 }
1774 
1775 // Emits a comma-separated list of the ops.
1776 static void emitOpList(const std::vector<Record *> &defs, raw_ostream &os) {
1777   IfDefScope scope("GET_OP_LIST", os);
1778 
1779   llvm::interleave(
1780       // TODO: We are constructing the Operator wrapper instance just for
1781       // getting it's qualified class name here. Reduce the overhead by having a
1782       // lightweight version of Operator class just for that purpose.
1783       defs, [&os](Record *def) { os << Operator(def).getQualCppClassName(); },
1784       [&os]() { os << ",\n"; });
1785 }
1786 
1787 static bool emitOpDecls(const RecordKeeper &recordKeeper, raw_ostream &os) {
1788   emitSourceFileHeader("Op Declarations", os);
1789 
1790   const auto &defs = recordKeeper.getAllDerivedDefinitions("Op");
1791   emitOpClasses(defs, os, /*emitDecl=*/true);
1792 
1793   return false;
1794 }
1795 
1796 static bool emitOpDefs(const RecordKeeper &recordKeeper, raw_ostream &os) {
1797   emitSourceFileHeader("Op Definitions", os);
1798 
1799   const auto &defs = recordKeeper.getAllDerivedDefinitions("Op");
1800   emitOpList(defs, os);
1801   emitOpClasses(defs, os, /*emitDecl=*/false);
1802 
1803   return false;
1804 }
1805 
1806 static mlir::GenRegistration
1807     genOpDecls("gen-op-decls", "Generate op declarations",
1808                [](const RecordKeeper &records, raw_ostream &os) {
1809                  return emitOpDecls(records, os);
1810                });
1811 
1812 static mlir::GenRegistration genOpDefs("gen-op-defs", "Generate op definitions",
1813                                        [](const RecordKeeper &records,
1814                                           raw_ostream &os) {
1815                                          return emitOpDefs(records, os);
1816                                        });
1817