1 //===- RewriterGen.cpp - MLIR pattern rewriter 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 // RewriterGen uses pattern rewrite definitions to generate rewriter matchers.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Support/STLExtras.h"
14 #include "mlir/TableGen/Attribute.h"
15 #include "mlir/TableGen/Format.h"
16 #include "mlir/TableGen/GenInfo.h"
17 #include "mlir/TableGen/Operator.h"
18 #include "mlir/TableGen/Pattern.h"
19 #include "mlir/TableGen/Predicate.h"
20 #include "mlir/TableGen/Type.h"
21 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/ADT/StringSet.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/FormatAdapters.h"
26 #include "llvm/Support/PrettyStackTrace.h"
27 #include "llvm/Support/Signals.h"
28 #include "llvm/TableGen/Error.h"
29 #include "llvm/TableGen/Main.h"
30 #include "llvm/TableGen/Record.h"
31 #include "llvm/TableGen/TableGenBackend.h"
32 
33 using namespace mlir;
34 using namespace mlir::tblgen;
35 
36 using llvm::formatv;
37 using llvm::Record;
38 using llvm::RecordKeeper;
39 
40 #define DEBUG_TYPE "mlir-tblgen-rewritergen"
41 
42 namespace llvm {
43 template <> struct format_provider<mlir::tblgen::Pattern::IdentifierLine> {
44   static void format(const mlir::tblgen::Pattern::IdentifierLine &v,
45                      raw_ostream &os, StringRef style) {
46     os << v.first << ":" << v.second;
47   }
48 };
49 } // end namespace llvm
50 
51 //===----------------------------------------------------------------------===//
52 // PatternEmitter
53 //===----------------------------------------------------------------------===//
54 
55 namespace {
56 class PatternEmitter {
57 public:
58   PatternEmitter(Record *pat, RecordOperatorMap *mapper, raw_ostream &os);
59 
60   // Emits the mlir::RewritePattern struct named `rewriteName`.
61   void emit(StringRef rewriteName);
62 
63 private:
64   // Emits the code for matching ops.
65   void emitMatchLogic(DagNode tree);
66 
67   // Emits the code for rewriting ops.
68   void emitRewriteLogic();
69 
70   //===--------------------------------------------------------------------===//
71   // Match utilities
72   //===--------------------------------------------------------------------===//
73 
74   // Emits C++ statements for matching the op constrained by the given DAG
75   // `tree`.
76   void emitOpMatch(DagNode tree, int depth);
77 
78   // Emits C++ statements for matching the `argIndex`-th argument of the given
79   // DAG `tree` as an operand.
80   void emitOperandMatch(DagNode tree, int argIndex, int depth, int indent);
81 
82   // Emits C++ statements for matching the `argIndex`-th argument of the given
83   // DAG `tree` as an attribute.
84   void emitAttributeMatch(DagNode tree, int argIndex, int depth, int indent);
85 
86   // Emits C++ for checking a match with a corresponding match failure
87   // diagnostic.
88   void emitMatchCheck(int depth, const FmtObjectBase &matchFmt,
89                       const llvm::formatv_object_base &failureFmt);
90 
91   //===--------------------------------------------------------------------===//
92   // Rewrite utilities
93   //===--------------------------------------------------------------------===//
94 
95   // The entry point for handling a result pattern rooted at `resultTree`. This
96   // method dispatches to concrete handlers according to `resultTree`'s kind and
97   // returns a symbol representing the whole value pack. Callers are expected to
98   // further resolve the symbol according to the specific use case.
99   //
100   // `depth` is the nesting level of `resultTree`; 0 means top-level result
101   // pattern. For top-level result pattern, `resultIndex` indicates which result
102   // of the matched root op this pattern is intended to replace, which can be
103   // used to deduce the result type of the op generated from this result
104   // pattern.
105   std::string handleResultPattern(DagNode resultTree, int resultIndex,
106                                   int depth);
107 
108   // Emits the C++ statement to replace the matched DAG with a value built via
109   // calling native C++ code.
110   std::string handleReplaceWithNativeCodeCall(DagNode resultTree);
111 
112   // Returns the C++ expression referencing the old value serving as the
113   // replacement.
114   std::string handleReplaceWithValue(DagNode tree);
115 
116   // Emits the C++ statement to build a new op out of the given DAG `tree` and
117   // returns the variable name that this op is assigned to. If the root op in
118   // DAG `tree` has a specified name, the created op will be assigned to a
119   // variable of the given name. Otherwise, a unique name will be used as the
120   // result value name.
121   std::string handleOpCreation(DagNode tree, int resultIndex, int depth);
122 
123   using ChildNodeIndexNameMap = DenseMap<unsigned, std::string>;
124 
125   // Emits a local variable for each value and attribute to be used for creating
126   // an op.
127   void createSeparateLocalVarsForOpArgs(DagNode node,
128                                         ChildNodeIndexNameMap &childNodeNames);
129 
130   // Emits the concrete arguments used to call an op's builder.
131   void supplyValuesForOpArgs(DagNode node,
132                              const ChildNodeIndexNameMap &childNodeNames);
133 
134   // Emits the local variables for holding all values as a whole and all named
135   // attributes as a whole to be used for creating an op.
136   void createAggregateLocalVarsForOpArgs(
137       DagNode node, const ChildNodeIndexNameMap &childNodeNames);
138 
139   // Returns the C++ expression to construct a constant attribute of the given
140   // `value` for the given attribute kind `attr`.
141   std::string handleConstantAttr(Attribute attr, StringRef value);
142 
143   // Returns the C++ expression to build an argument from the given DAG `leaf`.
144   // `patArgName` is used to bound the argument to the source pattern.
145   std::string handleOpArgument(DagLeaf leaf, StringRef patArgName);
146 
147   //===--------------------------------------------------------------------===//
148   // General utilities
149   //===--------------------------------------------------------------------===//
150 
151   // Collects all of the operations within the given dag tree.
152   void collectOps(DagNode tree, llvm::SmallPtrSetImpl<const Operator *> &ops);
153 
154   // Returns a unique symbol for a local variable of the given `op`.
155   std::string getUniqueSymbol(const Operator *op);
156 
157   //===--------------------------------------------------------------------===//
158   // Symbol utilities
159   //===--------------------------------------------------------------------===//
160 
161   // Returns how many static values the given DAG `node` correspond to.
162   int getNodeValueCount(DagNode node);
163 
164 private:
165   // Pattern instantiation location followed by the location of multiclass
166   // prototypes used. This is intended to be used as a whole to
167   // PrintFatalError() on errors.
168   ArrayRef<llvm::SMLoc> loc;
169 
170   // Op's TableGen Record to wrapper object.
171   RecordOperatorMap *opMap;
172 
173   // Handy wrapper for pattern being emitted.
174   Pattern pattern;
175 
176   // Map for all bound symbols' info.
177   SymbolInfoMap symbolInfoMap;
178 
179   // The next unused ID for newly created values.
180   unsigned nextValueId;
181 
182   raw_ostream &os;
183 
184   // Format contexts containing placeholder substitutions.
185   FmtContext fmtCtx;
186 
187   // Number of op processed.
188   int opCounter = 0;
189 };
190 } // end anonymous namespace
191 
192 PatternEmitter::PatternEmitter(Record *pat, RecordOperatorMap *mapper,
193                                raw_ostream &os)
194     : loc(pat->getLoc()), opMap(mapper), pattern(pat, mapper),
195       symbolInfoMap(pat->getLoc()), nextValueId(0), os(os) {
196   fmtCtx.withBuilder("rewriter");
197 }
198 
199 std::string PatternEmitter::handleConstantAttr(Attribute attr,
200                                                StringRef value) {
201   if (!attr.isConstBuildable())
202     PrintFatalError(loc, "Attribute " + attr.getAttrDefName() +
203                              " does not have the 'constBuilderCall' field");
204 
205   // TODO(jpienaar): Verify the constants here
206   return std::string(tgfmt(attr.getConstBuilderTemplate(), &fmtCtx, value));
207 }
208 
209 // Helper function to match patterns.
210 void PatternEmitter::emitOpMatch(DagNode tree, int depth) {
211   Operator &op = tree.getDialectOp(opMap);
212   LLVM_DEBUG(llvm::dbgs() << "start emitting match for op '"
213                           << op.getOperationName() << "' at depth " << depth
214                           << '\n');
215 
216   int indent = 4 + 2 * depth;
217   os.indent(indent) << formatv(
218       "auto castedOp{0} = dyn_cast_or_null<{1}>(op{0}); (void)castedOp{0};\n",
219       depth, op.getQualCppClassName());
220   // Skip the operand matching at depth 0 as the pattern rewriter already does.
221   if (depth != 0) {
222     // Skip if there is no defining operation (e.g., arguments to function).
223     os.indent(indent) << formatv("if (!castedOp{0}) return failure();\n",
224                                  depth);
225   }
226   if (tree.getNumArgs() != op.getNumArgs()) {
227     PrintFatalError(loc, formatv("op '{0}' argument number mismatch: {1} in "
228                                  "pattern vs. {2} in definition",
229                                  op.getOperationName(), tree.getNumArgs(),
230                                  op.getNumArgs()));
231   }
232 
233   // If the operand's name is set, set to that variable.
234   auto name = tree.getSymbol();
235   if (!name.empty())
236     os.indent(indent) << formatv("{0} = castedOp{1};\n", name, depth);
237 
238   for (int i = 0, e = tree.getNumArgs(); i != e; ++i) {
239     auto opArg = op.getArg(i);
240 
241     // Handle nested DAG construct first
242     if (DagNode argTree = tree.getArgAsNestedDag(i)) {
243       if (auto *operand = opArg.dyn_cast<NamedTypeConstraint *>()) {
244         if (operand->isVariadic()) {
245           auto error = formatv("use nested DAG construct to match op {0}'s "
246                                "variadic operand #{1} unsupported now",
247                                op.getOperationName(), i);
248           PrintFatalError(loc, error);
249         }
250       }
251       os.indent(indent) << "{\n";
252 
253       os.indent(indent + 2) << formatv(
254           "auto *op{0} = "
255           "(*castedOp{1}.getODSOperands({2}).begin()).getDefiningOp();\n",
256           depth + 1, depth, i);
257       emitOpMatch(argTree, depth + 1);
258       os.indent(indent + 2)
259           << formatv("tblgen_ops[{0}] = op{1};\n", ++opCounter, depth + 1);
260       os.indent(indent) << "}\n";
261       continue;
262     }
263 
264     // Next handle DAG leaf: operand or attribute
265     if (opArg.is<NamedTypeConstraint *>()) {
266       emitOperandMatch(tree, i, depth, indent);
267     } else if (opArg.is<NamedAttribute *>()) {
268       emitAttributeMatch(tree, i, depth, indent);
269     } else {
270       PrintFatalError(loc, "unhandled case when matching op");
271     }
272   }
273   LLVM_DEBUG(llvm::dbgs() << "done emitting match for op '"
274                           << op.getOperationName() << "' at depth " << depth
275                           << '\n');
276 }
277 
278 void PatternEmitter::emitOperandMatch(DagNode tree, int argIndex, int depth,
279                                       int indent) {
280   Operator &op = tree.getDialectOp(opMap);
281   auto *operand = op.getArg(argIndex).get<NamedTypeConstraint *>();
282   auto matcher = tree.getArgAsLeaf(argIndex);
283 
284   // If a constraint is specified, we need to generate C++ statements to
285   // check the constraint.
286   if (!matcher.isUnspecified()) {
287     if (!matcher.isOperandMatcher()) {
288       PrintFatalError(
289           loc, formatv("the {1}-th argument of op '{0}' should be an operand",
290                        op.getOperationName(), argIndex + 1));
291     }
292 
293     // Only need to verify if the matcher's type is different from the one
294     // of op definition.
295     Constraint constraint = matcher.getAsConstraint();
296     if (operand->constraint != constraint) {
297       if (operand->isVariadic()) {
298         auto error = formatv(
299             "further constrain op {0}'s variadic operand #{1} unsupported now",
300             op.getOperationName(), argIndex);
301         PrintFatalError(loc, error);
302       }
303       auto self =
304           formatv("(*castedOp{0}.getODSOperands({1}).begin()).getType()", depth,
305                   argIndex);
306       emitMatchCheck(
307           depth,
308           tgfmt(constraint.getConditionTemplate(), &fmtCtx.withSelf(self)),
309           formatv("\"operand {0} of op '{1}' failed to satisfy constraint: "
310                   "'{2}'\"",
311                   operand - op.operand_begin(), op.getOperationName(),
312                   constraint.getDescription()));
313     }
314   }
315 
316   // Capture the value
317   auto name = tree.getArgName(argIndex);
318   // `$_` is a special symbol to ignore op argument matching.
319   if (!name.empty() && name != "_") {
320     // We need to subtract the number of attributes before this operand to get
321     // the index in the operand list.
322     auto numPrevAttrs = std::count_if(
323         op.arg_begin(), op.arg_begin() + argIndex,
324         [](const Argument &arg) { return arg.is<NamedAttribute *>(); });
325 
326     os.indent(indent) << formatv("{0} = castedOp{1}.getODSOperands({2});\n",
327                                  name, depth, argIndex - numPrevAttrs);
328   }
329 }
330 
331 void PatternEmitter::emitAttributeMatch(DagNode tree, int argIndex, int depth,
332                                         int indent) {
333   Operator &op = tree.getDialectOp(opMap);
334   auto *namedAttr = op.getArg(argIndex).get<NamedAttribute *>();
335   const auto &attr = namedAttr->attr;
336 
337   os.indent(indent) << "{\n";
338   indent += 2;
339   os.indent(indent) << formatv(
340       "auto tblgen_attr = op{0}->getAttrOfType<{1}>(\"{2}\");"
341       "(void)tblgen_attr;\n",
342       depth, attr.getStorageType(), namedAttr->name);
343 
344   // TODO(antiagainst): This should use getter method to avoid duplication.
345   if (attr.hasDefaultValue()) {
346     os.indent(indent) << "if (!tblgen_attr) tblgen_attr = "
347                       << std::string(tgfmt(attr.getConstBuilderTemplate(),
348                                            &fmtCtx, attr.getDefaultValue()))
349                       << ";\n";
350   } else if (attr.isOptional()) {
351     // For a missing attribute that is optional according to definition, we
352     // should just capture a mlir::Attribute() to signal the missing state.
353     // That is precisely what getAttr() returns on missing attributes.
354   } else {
355     emitMatchCheck(depth, tgfmt("tblgen_attr", &fmtCtx),
356                    formatv("\"expected op '{0}' to have attribute '{1}' "
357                            "of type '{2}'\"",
358                            op.getOperationName(), namedAttr->name,
359                            attr.getStorageType()));
360   }
361 
362   auto matcher = tree.getArgAsLeaf(argIndex);
363   if (!matcher.isUnspecified()) {
364     if (!matcher.isAttrMatcher()) {
365       PrintFatalError(
366           loc, formatv("the {1}-th argument of op '{0}' should be an attribute",
367                        op.getOperationName(), argIndex + 1));
368     }
369 
370     // If a constraint is specified, we need to generate C++ statements to
371     // check the constraint.
372     emitMatchCheck(
373         depth,
374         tgfmt(matcher.getConditionTemplate(), &fmtCtx.withSelf("tblgen_attr")),
375         formatv("\"op '{0}' attribute '{1}' failed to satisfy constraint: "
376                 "{2}\"",
377                 op.getOperationName(), namedAttr->name,
378                 matcher.getAsConstraint().getDescription()));
379   }
380 
381   // Capture the value
382   auto name = tree.getArgName(argIndex);
383   // `$_` is a special symbol to ignore op argument matching.
384   if (!name.empty() && name != "_") {
385     os.indent(indent) << formatv("{0} = tblgen_attr;\n", name);
386   }
387 
388   indent -= 2;
389   os.indent(indent) << "}\n";
390 }
391 
392 void PatternEmitter::emitMatchCheck(
393     int depth, const FmtObjectBase &matchFmt,
394     const llvm::formatv_object_base &failureFmt) {
395   // {0} The match depth (used to get the operation that failed to match).
396   // {1} The format for the match string.
397   // {2} The format for the failure string.
398   const char *matchStr = R"(
399     if (!({1})) {
400       return rewriter.notifyMatchFailure(op{0}, [&](::mlir::Diagnostic &diag) {
401         diag << {2};
402       });
403     })";
404   os << llvm::formatv(matchStr, depth, matchFmt.str(), failureFmt.str())
405      << "\n";
406 }
407 
408 void PatternEmitter::emitMatchLogic(DagNode tree) {
409   LLVM_DEBUG(llvm::dbgs() << "--- start emitting match logic ---\n");
410   int depth = 0;
411   emitOpMatch(tree, depth);
412 
413   for (auto &appliedConstraint : pattern.getConstraints()) {
414     auto &constraint = appliedConstraint.constraint;
415     auto &entities = appliedConstraint.entities;
416 
417     auto condition = constraint.getConditionTemplate();
418     if (isa<TypeConstraint>(constraint)) {
419       auto self = formatv("({0}.getType())",
420                           symbolInfoMap.getValueAndRangeUse(entities.front()));
421       emitMatchCheck(
422           depth, tgfmt(condition, &fmtCtx.withSelf(self.str())),
423           formatv("\"value entity '{0}' failed to satisfy constraint: {1}\"",
424                   entities.front(), constraint.getDescription()));
425 
426     } else if (isa<AttrConstraint>(constraint)) {
427       PrintFatalError(
428           loc, "cannot use AttrConstraint in Pattern multi-entity constraints");
429     } else {
430       // TODO(b/138794486): replace formatv arguments with the exact specified
431       // args.
432       if (entities.size() > 4) {
433         PrintFatalError(loc, "only support up to 4-entity constraints now");
434       }
435       SmallVector<std::string, 4> names;
436       int i = 0;
437       for (int e = entities.size(); i < e; ++i)
438         names.push_back(symbolInfoMap.getValueAndRangeUse(entities[i]));
439       std::string self = appliedConstraint.self;
440       if (!self.empty())
441         self = symbolInfoMap.getValueAndRangeUse(self);
442       for (; i < 4; ++i)
443         names.push_back("<unused>");
444       emitMatchCheck(depth,
445                      tgfmt(condition, &fmtCtx.withSelf(self), names[0],
446                            names[1], names[2], names[3]),
447                      formatv("\"entities '{0}' failed to satisfy constraint: "
448                              "{1}\"",
449                              llvm::join(entities, ", "),
450                              constraint.getDescription()));
451     }
452   }
453   LLVM_DEBUG(llvm::dbgs() << "--- done emitting match logic ---\n");
454 }
455 
456 void PatternEmitter::collectOps(DagNode tree,
457                                 llvm::SmallPtrSetImpl<const Operator *> &ops) {
458   // Check if this tree is an operation.
459   if (tree.isOperation()) {
460     const Operator &op = tree.getDialectOp(opMap);
461     LLVM_DEBUG(llvm::dbgs()
462                << "found operation " << op.getOperationName() << '\n');
463     ops.insert(&op);
464   }
465 
466   // Recurse the arguments of the tree.
467   for (unsigned i = 0, e = tree.getNumArgs(); i != e; ++i)
468     if (auto child = tree.getArgAsNestedDag(i))
469       collectOps(child, ops);
470 }
471 
472 void PatternEmitter::emit(StringRef rewriteName) {
473   // Get the DAG tree for the source pattern.
474   DagNode sourceTree = pattern.getSourcePattern();
475 
476   const Operator &rootOp = pattern.getSourceRootOp();
477   auto rootName = rootOp.getOperationName();
478 
479   // Collect the set of result operations.
480   llvm::SmallPtrSet<const Operator *, 4> resultOps;
481   LLVM_DEBUG(llvm::dbgs() << "start collecting ops used in result patterns\n");
482   for (unsigned i = 0, e = pattern.getNumResultPatterns(); i != e; ++i) {
483     collectOps(pattern.getResultPattern(i), resultOps);
484   }
485   LLVM_DEBUG(llvm::dbgs() << "done collecting ops used in result patterns\n");
486 
487   // Emit RewritePattern for Pattern.
488   auto locs = pattern.getLocation();
489   os << formatv("/* Generated from:\n\t{0:$[ instantiating\n\t]}\n*/\n",
490                 make_range(locs.rbegin(), locs.rend()));
491   os << formatv(R"(struct {0} : public RewritePattern {
492   {0}(MLIRContext *context)
493       : RewritePattern("{1}", {{)",
494                 rewriteName, rootName);
495   // Sort result operators by name.
496   llvm::SmallVector<const Operator *, 4> sortedResultOps(resultOps.begin(),
497                                                          resultOps.end());
498   llvm::sort(sortedResultOps, [&](const Operator *lhs, const Operator *rhs) {
499     return lhs->getOperationName() < rhs->getOperationName();
500   });
501   interleaveComma(sortedResultOps, os, [&](const Operator *op) {
502     os << '"' << op->getOperationName() << '"';
503   });
504   os << formatv(R"(}, {0}, context) {{})", pattern.getBenefit()) << "\n";
505 
506   // Emit matchAndRewrite() function.
507   os << R"(
508   LogicalResult matchAndRewrite(Operation *op0,
509                                      PatternRewriter &rewriter) const override {
510 )";
511 
512   // Register all symbols bound in the source pattern.
513   pattern.collectSourcePatternBoundSymbols(symbolInfoMap);
514 
515   LLVM_DEBUG(
516       llvm::dbgs() << "start creating local variables for capturing matches\n");
517   os.indent(4) << "// Variables for capturing values and attributes used for "
518                   "creating ops\n";
519   // Create local variables for storing the arguments and results bound
520   // to symbols.
521   for (const auto &symbolInfoPair : symbolInfoMap) {
522     StringRef symbol = symbolInfoPair.getKey();
523     auto &info = symbolInfoPair.getValue();
524     os.indent(4) << info.getVarDecl(symbol);
525   }
526   // TODO(jpienaar): capture ops with consistent numbering so that it can be
527   // reused for fused loc.
528   os.indent(4) << formatv("Operation *tblgen_ops[{0}];\n\n",
529                           pattern.getSourcePattern().getNumOps());
530   LLVM_DEBUG(
531       llvm::dbgs() << "done creating local variables for capturing matches\n");
532 
533   os.indent(4) << "// Match\n";
534   os.indent(4) << "tblgen_ops[0] = op0;\n";
535   emitMatchLogic(sourceTree);
536   os << "\n";
537 
538   os.indent(4) << "// Rewrite\n";
539   emitRewriteLogic();
540 
541   os.indent(4) << "return success();\n";
542   os << "  };\n";
543   os << "};\n";
544 }
545 
546 void PatternEmitter::emitRewriteLogic() {
547   LLVM_DEBUG(llvm::dbgs() << "--- start emitting rewrite logic ---\n");
548   const Operator &rootOp = pattern.getSourceRootOp();
549   int numExpectedResults = rootOp.getNumResults();
550   int numResultPatterns = pattern.getNumResultPatterns();
551 
552   // First register all symbols bound to ops generated in result patterns.
553   pattern.collectResultPatternBoundSymbols(symbolInfoMap);
554 
555   // Only the last N static values generated are used to replace the matched
556   // root N-result op. We need to calculate the starting index (of the results
557   // of the matched op) each result pattern is to replace.
558   SmallVector<int, 4> offsets(numResultPatterns + 1, numExpectedResults);
559   // If we don't need to replace any value at all, set the replacement starting
560   // index as the number of result patterns so we skip all of them when trying
561   // to replace the matched op's results.
562   int replStartIndex = numExpectedResults == 0 ? numResultPatterns : -1;
563   for (int i = numResultPatterns - 1; i >= 0; --i) {
564     auto numValues = getNodeValueCount(pattern.getResultPattern(i));
565     offsets[i] = offsets[i + 1] - numValues;
566     if (offsets[i] == 0) {
567       if (replStartIndex == -1)
568         replStartIndex = i;
569     } else if (offsets[i] < 0 && offsets[i + 1] > 0) {
570       auto error = formatv(
571           "cannot use the same multi-result op '{0}' to generate both "
572           "auxiliary values and values to be used for replacing the matched op",
573           pattern.getResultPattern(i).getSymbol());
574       PrintFatalError(loc, error);
575     }
576   }
577 
578   if (offsets.front() > 0) {
579     const char error[] = "no enough values generated to replace the matched op";
580     PrintFatalError(loc, error);
581   }
582 
583   os.indent(4) << "auto loc = rewriter.getFusedLoc({";
584   for (int i = 0, e = pattern.getSourcePattern().getNumOps(); i != e; ++i) {
585     os << (i ? ", " : "") << "tblgen_ops[" << i << "]->getLoc()";
586   }
587   os << "}); (void)loc;\n";
588 
589   // Process auxiliary result patterns.
590   for (int i = 0; i < replStartIndex; ++i) {
591     DagNode resultTree = pattern.getResultPattern(i);
592     auto val = handleResultPattern(resultTree, offsets[i], 0);
593     // Normal op creation will be streamed to `os` by the above call; but
594     // NativeCodeCall will only be materialized to `os` if it is used. Here
595     // we are handling auxiliary patterns so we want the side effect even if
596     // NativeCodeCall is not replacing matched root op's results.
597     if (resultTree.isNativeCodeCall())
598       os.indent(4) << val << ";\n";
599   }
600 
601   if (numExpectedResults == 0) {
602     assert(replStartIndex >= numResultPatterns &&
603            "invalid auxiliary vs. replacement pattern division!");
604     // No result to replace. Just erase the op.
605     os.indent(4) << "rewriter.eraseOp(op0);\n";
606   } else {
607     // Process replacement result patterns.
608     os.indent(4) << "SmallVector<Value, 4> tblgen_repl_values;\n";
609     for (int i = replStartIndex; i < numResultPatterns; ++i) {
610       DagNode resultTree = pattern.getResultPattern(i);
611       auto val = handleResultPattern(resultTree, offsets[i], 0);
612       os.indent(4) << "\n";
613       // Resolve each symbol for all range use so that we can loop over them.
614       // We need an explicit cast to `SmallVector` to capture the cases where
615       // `{0}` resolves to an `Operation::result_range` as well as cases that
616       // are not iterable (e.g. vector that gets wrapped in additional braces by
617       // RewriterGen).
618       // TODO(b/147096809): Revisit the need for materializing a vector.
619       os << symbolInfoMap.getAllRangeUse(
620           val,
621           "    for (auto v : SmallVector<Value, 4>{ {0} }) {{ "
622           "tblgen_repl_values.push_back(v); }",
623           "\n");
624     }
625     os.indent(4) << "\n";
626     os.indent(4) << "rewriter.replaceOp(op0, tblgen_repl_values);\n";
627   }
628 
629   LLVM_DEBUG(llvm::dbgs() << "--- done emitting rewrite logic ---\n");
630 }
631 
632 std::string PatternEmitter::getUniqueSymbol(const Operator *op) {
633   return std::string(
634       formatv("tblgen_{0}_{1}", op->getCppClassName(), nextValueId++));
635 }
636 
637 std::string PatternEmitter::handleResultPattern(DagNode resultTree,
638                                                 int resultIndex, int depth) {
639   LLVM_DEBUG(llvm::dbgs() << "handle result pattern: ");
640   LLVM_DEBUG(resultTree.print(llvm::dbgs()));
641   LLVM_DEBUG(llvm::dbgs() << '\n');
642 
643   if (resultTree.isNativeCodeCall()) {
644     auto symbol = handleReplaceWithNativeCodeCall(resultTree);
645     symbolInfoMap.bindValue(symbol);
646     return symbol;
647   }
648 
649   if (resultTree.isReplaceWithValue()) {
650     return handleReplaceWithValue(resultTree);
651   }
652 
653   // Normal op creation.
654   auto symbol = handleOpCreation(resultTree, resultIndex, depth);
655   if (resultTree.getSymbol().empty()) {
656     // This is an op not explicitly bound to a symbol in the rewrite rule.
657     // Register the auto-generated symbol for it.
658     symbolInfoMap.bindOpResult(symbol, pattern.getDialectOp(resultTree));
659   }
660   return symbol;
661 }
662 
663 std::string PatternEmitter::handleReplaceWithValue(DagNode tree) {
664   assert(tree.isReplaceWithValue());
665 
666   if (tree.getNumArgs() != 1) {
667     PrintFatalError(
668         loc, "replaceWithValue directive must take exactly one argument");
669   }
670 
671   if (!tree.getSymbol().empty()) {
672     PrintFatalError(loc, "cannot bind symbol to replaceWithValue");
673   }
674 
675   return std::string(tree.getArgName(0));
676 }
677 
678 std::string PatternEmitter::handleOpArgument(DagLeaf leaf,
679                                              StringRef patArgName) {
680   if (leaf.isConstantAttr()) {
681     auto constAttr = leaf.getAsConstantAttr();
682     return handleConstantAttr(constAttr.getAttribute(),
683                               constAttr.getConstantValue());
684   }
685   if (leaf.isEnumAttrCase()) {
686     auto enumCase = leaf.getAsEnumAttrCase();
687     if (enumCase.isStrCase())
688       return handleConstantAttr(enumCase, enumCase.getSymbol());
689     // This is an enum case backed by an IntegerAttr. We need to get its value
690     // to build the constant.
691     std::string val = std::to_string(enumCase.getValue());
692     return handleConstantAttr(enumCase, val);
693   }
694 
695   LLVM_DEBUG(llvm::dbgs() << "handle argument '" << patArgName << "'\n");
696   auto argName = symbolInfoMap.getValueAndRangeUse(patArgName);
697   if (leaf.isUnspecified() || leaf.isOperandMatcher()) {
698     LLVM_DEBUG(llvm::dbgs() << "replace " << patArgName << " with '" << argName
699                             << "' (via symbol ref)\n");
700     return argName;
701   }
702   if (leaf.isNativeCodeCall()) {
703     auto repl = tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(argName));
704     LLVM_DEBUG(llvm::dbgs() << "replace " << patArgName << " with '" << repl
705                             << "' (via NativeCodeCall)\n");
706     return std::string(repl);
707   }
708   PrintFatalError(loc, "unhandled case when rewriting op");
709 }
710 
711 std::string PatternEmitter::handleReplaceWithNativeCodeCall(DagNode tree) {
712   LLVM_DEBUG(llvm::dbgs() << "handle NativeCodeCall pattern: ");
713   LLVM_DEBUG(tree.print(llvm::dbgs()));
714   LLVM_DEBUG(llvm::dbgs() << '\n');
715 
716   auto fmt = tree.getNativeCodeTemplate();
717   // TODO(b/138794486): replace formatv arguments with the exact specified args.
718   SmallVector<std::string, 8> attrs(8);
719   if (tree.getNumArgs() > 8) {
720     PrintFatalError(loc, "unsupported NativeCodeCall argument numbers: " +
721                              Twine(tree.getNumArgs()));
722   }
723   for (int i = 0, e = tree.getNumArgs(); i != e; ++i) {
724     attrs[i] = handleOpArgument(tree.getArgAsLeaf(i), tree.getArgName(i));
725     LLVM_DEBUG(llvm::dbgs() << "NativeCodeCall argument #" << i
726                             << " replacement: " << attrs[i] << "\n");
727   }
728   return std::string(tgfmt(fmt, &fmtCtx, attrs[0], attrs[1], attrs[2], attrs[3],
729                            attrs[4], attrs[5], attrs[6], attrs[7]));
730 }
731 
732 int PatternEmitter::getNodeValueCount(DagNode node) {
733   if (node.isOperation()) {
734     // If the op is bound to a symbol in the rewrite rule, query its result
735     // count from the symbol info map.
736     auto symbol = node.getSymbol();
737     if (!symbol.empty()) {
738       return symbolInfoMap.getStaticValueCount(symbol);
739     }
740     // Otherwise this is an unbound op; we will use all its results.
741     return pattern.getDialectOp(node).getNumResults();
742   }
743   // TODO(antiagainst): This considers all NativeCodeCall as returning one
744   // value. Enhance if multi-value ones are needed.
745   return 1;
746 }
747 
748 std::string PatternEmitter::handleOpCreation(DagNode tree, int resultIndex,
749                                              int depth) {
750   LLVM_DEBUG(llvm::dbgs() << "create op for pattern: ");
751   LLVM_DEBUG(tree.print(llvm::dbgs()));
752   LLVM_DEBUG(llvm::dbgs() << '\n');
753 
754   Operator &resultOp = tree.getDialectOp(opMap);
755   auto numOpArgs = resultOp.getNumArgs();
756 
757   if (numOpArgs != tree.getNumArgs()) {
758     PrintFatalError(loc, formatv("resultant op '{0}' argument number mismatch: "
759                                  "{1} in pattern vs. {2} in definition",
760                                  resultOp.getOperationName(), tree.getNumArgs(),
761                                  numOpArgs));
762   }
763 
764   // A map to collect all nested DAG child nodes' names, with operand index as
765   // the key. This includes both bound and unbound child nodes.
766   ChildNodeIndexNameMap childNodeNames;
767 
768   // First go through all the child nodes who are nested DAG constructs to
769   // create ops for them and remember the symbol names for them, so that we can
770   // use the results in the current node. This happens in a recursive manner.
771   for (int i = 0, e = resultOp.getNumOperands(); i != e; ++i) {
772     if (auto child = tree.getArgAsNestedDag(i)) {
773       childNodeNames[i] = handleResultPattern(child, i, depth + 1);
774     }
775   }
776 
777   // The name of the local variable holding this op.
778   std::string valuePackName;
779   // The symbol for holding the result of this pattern. Note that the result of
780   // this pattern is not necessarily the same as the variable created by this
781   // pattern because we can use `__N` suffix to refer only a specific result if
782   // the generated op is a multi-result op.
783   std::string resultValue;
784   if (tree.getSymbol().empty()) {
785     // No symbol is explicitly bound to this op in the pattern. Generate a
786     // unique name.
787     valuePackName = resultValue = getUniqueSymbol(&resultOp);
788   } else {
789     resultValue = std::string(tree.getSymbol());
790     // Strip the index to get the name for the value pack and use it to name the
791     // local variable for the op.
792     valuePackName = std::string(SymbolInfoMap::getValuePackName(resultValue));
793   }
794 
795   // Create the local variable for this op.
796   os.indent(4) << formatv("{0} {1};\n", resultOp.getQualCppClassName(),
797                           valuePackName);
798   os.indent(4) << "{\n";
799 
800   // Right now ODS don't have general type inference support. Except a few
801   // special cases listed below, DRR needs to supply types for all results
802   // when building an op.
803   bool isSameOperandsAndResultType =
804       resultOp.getTrait("OpTrait::SameOperandsAndResultType");
805   bool useFirstAttr = resultOp.getTrait("OpTrait::FirstAttrDerivedResultType");
806 
807   if (isSameOperandsAndResultType || useFirstAttr) {
808     // We know how to deduce the result type for ops with these traits and we've
809     // generated builders taking aggregate parameters. Use those builders to
810     // create the ops.
811 
812     // First prepare local variables for op arguments used in builder call.
813     createAggregateLocalVarsForOpArgs(tree, childNodeNames);
814     // Then create the op.
815     os.indent(6) << formatv(
816         "{0} = rewriter.create<{1}>(loc, tblgen_values, tblgen_attrs);\n",
817         valuePackName, resultOp.getQualCppClassName());
818     os.indent(4) << "}\n";
819     return resultValue;
820   }
821 
822   // TODO: Remove once broadcastable has been updated. This query here is not
823   // really about broadcastable or not, it is about which build method to invoke
824   // and that requires knowledge of whether ODS generated a builder that need
825   // not take return types. That knowledge should be captured in one place
826   // rather than duplicated.
827   bool isResultsBroadcastableShape =
828       resultOp.getTrait("OpTrait::ResultsBroadcastableShape");
829   bool usePartialResults = valuePackName != resultValue;
830 
831   if (isResultsBroadcastableShape || usePartialResults || depth > 0 ||
832       resultIndex < 0) {
833     // For these cases (broadcastable ops, op results used both as auxiliary
834     // values and replacement values, ops in nested patterns, auxiliary ops), we
835     // still need to supply the result types when building the op. But because
836     // we don't generate a builder automatically with ODS for them, it's the
837     // developer's responsibility to make sure such a builder (with result type
838     // deduction ability) exists. We go through the separate-parameter builder
839     // here given that it's easier for developers to write compared to
840     // aggregate-parameter builders.
841     createSeparateLocalVarsForOpArgs(tree, childNodeNames);
842     os.indent(6) << formatv("{0} = rewriter.create<{1}>(loc", valuePackName,
843                             resultOp.getQualCppClassName());
844     supplyValuesForOpArgs(tree, childNodeNames);
845     os << "\n      );\n";
846     os.indent(4) << "}\n";
847     return resultValue;
848   }
849 
850   // If depth == 0 and resultIndex >= 0, it means we are replacing the values
851   // generated from the source pattern root op. Then we can use the source
852   // pattern's value types to determine the value type of the generated op
853   // here.
854 
855   // First prepare local variables for op arguments used in builder call.
856   createAggregateLocalVarsForOpArgs(tree, childNodeNames);
857 
858   // Then prepare the result types. We need to specify the types for all
859   // results.
860   os.indent(6) << formatv(
861       "SmallVector<Type, 4> tblgen_types; (void)tblgen_types;\n");
862   int numResults = resultOp.getNumResults();
863   if (numResults != 0) {
864     for (int i = 0; i < numResults; ++i)
865       os.indent(6) << formatv("for (auto v : castedOp0.getODSResults({0})) {{"
866                               "tblgen_types.push_back(v.getType()); }\n",
867                               resultIndex + i);
868   }
869   os.indent(6) << formatv("{0} = rewriter.create<{1}>(loc, tblgen_types, "
870                           "tblgen_values, tblgen_attrs);\n",
871                           valuePackName, resultOp.getQualCppClassName());
872   os.indent(4) << "}\n";
873   return resultValue;
874 }
875 
876 void PatternEmitter::createSeparateLocalVarsForOpArgs(
877     DagNode node, ChildNodeIndexNameMap &childNodeNames) {
878   Operator &resultOp = node.getDialectOp(opMap);
879 
880   // Now prepare operands used for building this op:
881   // * If the operand is non-variadic, we create a `Value` local variable.
882   // * If the operand is variadic, we create a `SmallVector<Value>` local
883   //   variable.
884 
885   int valueIndex = 0; // An index for uniquing local variable names.
886   for (int argIndex = 0, e = resultOp.getNumArgs(); argIndex < e; ++argIndex) {
887     const auto *operand =
888         resultOp.getArg(argIndex).dyn_cast<NamedTypeConstraint *>();
889     if (!operand) {
890       // We do not need special handling for attributes.
891       continue;
892     }
893 
894     std::string varName;
895     if (operand->isVariadic()) {
896       varName = std::string(formatv("tblgen_values_{0}", valueIndex++));
897       os.indent(6) << formatv("SmallVector<Value, 4> {0};\n", varName);
898       std::string range;
899       if (node.isNestedDagArg(argIndex)) {
900         range = childNodeNames[argIndex];
901       } else {
902         range = std::string(node.getArgName(argIndex));
903       }
904       // Resolve the symbol for all range use so that we have a uniform way of
905       // capturing the values.
906       range = symbolInfoMap.getValueAndRangeUse(range);
907       os.indent(6) << formatv("for (auto v : {0}) {1}.push_back(v);\n", range,
908                               varName);
909     } else {
910       varName = std::string(formatv("tblgen_value_{0}", valueIndex++));
911       os.indent(6) << formatv("Value {0} = ", varName);
912       if (node.isNestedDagArg(argIndex)) {
913         os << symbolInfoMap.getValueAndRangeUse(childNodeNames[argIndex]);
914       } else {
915         DagLeaf leaf = node.getArgAsLeaf(argIndex);
916         auto symbol =
917             symbolInfoMap.getValueAndRangeUse(node.getArgName(argIndex));
918         if (leaf.isNativeCodeCall()) {
919           os << std::string(
920               tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(symbol)));
921         } else {
922           os << symbol;
923         }
924       }
925       os << ";\n";
926     }
927 
928     // Update to use the newly created local variable for building the op later.
929     childNodeNames[argIndex] = varName;
930   }
931 }
932 
933 void PatternEmitter::supplyValuesForOpArgs(
934     DagNode node, const ChildNodeIndexNameMap &childNodeNames) {
935   Operator &resultOp = node.getDialectOp(opMap);
936   for (int argIndex = 0, numOpArgs = resultOp.getNumArgs();
937        argIndex != numOpArgs; ++argIndex) {
938     // Start each argument on its own line.
939     (os << ",\n").indent(8);
940 
941     Argument opArg = resultOp.getArg(argIndex);
942     // Handle the case of operand first.
943     if (auto *operand = opArg.dyn_cast<NamedTypeConstraint *>()) {
944       if (!operand->name.empty())
945         os << "/*" << operand->name << "=*/";
946       os << childNodeNames.lookup(argIndex);
947       continue;
948     }
949 
950     // The argument in the op definition.
951     auto opArgName = resultOp.getArgName(argIndex);
952     if (auto subTree = node.getArgAsNestedDag(argIndex)) {
953       if (!subTree.isNativeCodeCall())
954         PrintFatalError(loc, "only NativeCodeCall allowed in nested dag node "
955                              "for creating attribute");
956       os << formatv("/*{0}=*/{1}", opArgName,
957                     handleReplaceWithNativeCodeCall(subTree));
958     } else {
959       auto leaf = node.getArgAsLeaf(argIndex);
960       // The argument in the result DAG pattern.
961       auto patArgName = node.getArgName(argIndex);
962       if (leaf.isConstantAttr() || leaf.isEnumAttrCase()) {
963         // TODO(jpienaar): Refactor out into map to avoid recomputing these.
964         if (!opArg.is<NamedAttribute *>())
965           PrintFatalError(loc, Twine("expected attribute ") + Twine(argIndex));
966         if (!patArgName.empty())
967           os << "/*" << patArgName << "=*/";
968       } else {
969         os << "/*" << opArgName << "=*/";
970       }
971       os << handleOpArgument(leaf, patArgName);
972     }
973   }
974 }
975 
976 void PatternEmitter::createAggregateLocalVarsForOpArgs(
977     DagNode node, const ChildNodeIndexNameMap &childNodeNames) {
978   Operator &resultOp = node.getDialectOp(opMap);
979 
980   os.indent(6) << formatv(
981       "SmallVector<Value, 4> tblgen_values; (void)tblgen_values;\n");
982   os.indent(6) << formatv(
983       "SmallVector<NamedAttribute, 4> tblgen_attrs; (void)tblgen_attrs;\n");
984 
985   for (int argIndex = 0, e = resultOp.getNumArgs(); argIndex < e; ++argIndex) {
986     if (resultOp.getArg(argIndex).is<NamedAttribute *>()) {
987       const char *addAttrCmd = "if ({1}) {{"
988                                "  tblgen_attrs.emplace_back(rewriter."
989                                "getIdentifier(\"{0}\"), {1}); }\n";
990       // The argument in the op definition.
991       auto opArgName = resultOp.getArgName(argIndex);
992       if (auto subTree = node.getArgAsNestedDag(argIndex)) {
993         if (!subTree.isNativeCodeCall())
994           PrintFatalError(loc, "only NativeCodeCall allowed in nested dag node "
995                                "for creating attribute");
996         os.indent(6) << formatv(addAttrCmd, opArgName,
997                                 handleReplaceWithNativeCodeCall(subTree));
998       } else {
999         auto leaf = node.getArgAsLeaf(argIndex);
1000         // The argument in the result DAG pattern.
1001         auto patArgName = node.getArgName(argIndex);
1002         os.indent(6) << formatv(addAttrCmd, opArgName,
1003                                 handleOpArgument(leaf, patArgName));
1004       }
1005       continue;
1006     }
1007 
1008     const auto *operand =
1009         resultOp.getArg(argIndex).get<NamedTypeConstraint *>();
1010     std::string varName;
1011     if (operand->isVariadic()) {
1012       std::string range;
1013       if (node.isNestedDagArg(argIndex)) {
1014         range = childNodeNames.lookup(argIndex);
1015       } else {
1016         range = std::string(node.getArgName(argIndex));
1017       }
1018       // Resolve the symbol for all range use so that we have a uniform way of
1019       // capturing the values.
1020       range = symbolInfoMap.getValueAndRangeUse(range);
1021       os.indent(6) << formatv(
1022           "for (auto v : {0}) tblgen_values.push_back(v);\n", range);
1023     } else {
1024       os.indent(6) << formatv("tblgen_values.push_back(", varName);
1025       if (node.isNestedDagArg(argIndex)) {
1026         os << symbolInfoMap.getValueAndRangeUse(
1027             childNodeNames.lookup(argIndex));
1028       } else {
1029         DagLeaf leaf = node.getArgAsLeaf(argIndex);
1030         auto symbol =
1031             symbolInfoMap.getValueAndRangeUse(node.getArgName(argIndex));
1032         if (leaf.isNativeCodeCall()) {
1033           os << std::string(
1034               tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(symbol)));
1035         } else {
1036           os << symbol;
1037         }
1038       }
1039       os << ");\n";
1040     }
1041   }
1042 }
1043 
1044 static void emitRewriters(const RecordKeeper &recordKeeper, raw_ostream &os) {
1045   emitSourceFileHeader("Rewriters", os);
1046 
1047   const auto &patterns = recordKeeper.getAllDerivedDefinitions("Pattern");
1048   auto numPatterns = patterns.size();
1049 
1050   // We put the map here because it can be shared among multiple patterns.
1051   RecordOperatorMap recordOpMap;
1052 
1053   std::vector<std::string> rewriterNames;
1054   rewriterNames.reserve(numPatterns);
1055 
1056   std::string baseRewriterName = "GeneratedConvert";
1057   int rewriterIndex = 0;
1058 
1059   for (Record *p : patterns) {
1060     std::string name;
1061     if (p->isAnonymous()) {
1062       // If no name is provided, ensure unique rewriter names simply by
1063       // appending unique suffix.
1064       name = baseRewriterName + llvm::utostr(rewriterIndex++);
1065     } else {
1066       name = std::string(p->getName());
1067     }
1068     LLVM_DEBUG(llvm::dbgs()
1069                << "=== start generating pattern '" << name << "' ===\n");
1070     PatternEmitter(p, &recordOpMap, os).emit(name);
1071     LLVM_DEBUG(llvm::dbgs()
1072                << "=== done generating pattern '" << name << "' ===\n");
1073     rewriterNames.push_back(std::move(name));
1074   }
1075 
1076   // Emit function to add the generated matchers to the pattern list.
1077   os << "void LLVM_ATTRIBUTE_UNUSED populateWithGenerated(MLIRContext "
1078         "*context, OwningRewritePatternList *patterns) {\n";
1079   for (const auto &name : rewriterNames) {
1080     os << "  patterns->insert<" << name << ">(context);\n";
1081   }
1082   os << "}\n";
1083 }
1084 
1085 static mlir::GenRegistration
1086     genRewriters("gen-rewriters", "Generate pattern rewriters",
1087                  [](const RecordKeeper &records, raw_ostream &os) {
1088                    emitRewriters(records, os);
1089                    return false;
1090                  });
1091