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