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