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/IndentedOstream.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/FunctionExtras.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringSet.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/FormatAdapters.h"
27 #include "llvm/Support/PrettyStackTrace.h"
28 #include "llvm/Support/Signals.h"
29 #include "llvm/TableGen/Error.h"
30 #include "llvm/TableGen/Main.h"
31 #include "llvm/TableGen/Record.h"
32 #include "llvm/TableGen/TableGenBackend.h"
33 
34 using namespace mlir;
35 using namespace mlir::tblgen;
36 
37 using llvm::formatv;
38 using llvm::Record;
39 using llvm::RecordKeeper;
40 
41 #define DEBUG_TYPE "mlir-tblgen-rewritergen"
42 
43 namespace llvm {
44 template <>
45 struct format_provider<mlir::tblgen::Pattern::IdentifierLine> {
46   static void format(const mlir::tblgen::Pattern::IdentifierLine &v,
47                      raw_ostream &os, StringRef style) {
48     os << v.first << ":" << v.second;
49   }
50 };
51 } // end namespace llvm
52 
53 // Escape a string for use inside a C++ literal.
54 // E.g. foo"bar -> foo\x22bar.
55 static std::string escapeString(StringRef value) {
56   std::string ret;
57   llvm::raw_string_ostream os(ret);
58   os.write_escaped(value, /*use_hex_escapes=*/true);
59   return os.str();
60 }
61 
62 //===----------------------------------------------------------------------===//
63 // PatternEmitter
64 //===----------------------------------------------------------------------===//
65 
66 namespace {
67 
68 class StaticMatcherHelper;
69 
70 class PatternEmitter {
71 public:
72   PatternEmitter(Record *pat, RecordOperatorMap *mapper, raw_ostream &os,
73                  StaticMatcherHelper &helper);
74 
75   // Emits the mlir::RewritePattern struct named `rewriteName`.
76   void emit(StringRef rewriteName);
77 
78   // Emits the static function of DAG matcher.
79   void emitStaticMatcher(DagNode tree, std::string funcName);
80 
81 private:
82   // Emits the code for matching ops.
83   void emitMatchLogic(DagNode tree, StringRef opName);
84 
85   // Emits the code for rewriting ops.
86   void emitRewriteLogic();
87 
88   //===--------------------------------------------------------------------===//
89   // Match utilities
90   //===--------------------------------------------------------------------===//
91 
92   // Emits C++ statements for matching the DAG structure.
93   void emitMatch(DagNode tree, StringRef name, int depth);
94 
95   // Emit C++ function call to static DAG matcher.
96   void emitStaticMatchCall(DagNode tree, StringRef name);
97 
98   // Emits C++ statements for matching using a native code call.
99   void emitNativeCodeMatch(DagNode tree, StringRef name, int depth);
100 
101   // Emits C++ statements for matching the op constrained by the given DAG
102   // `tree` returning the op's variable name.
103   void emitOpMatch(DagNode tree, StringRef opName, int depth);
104 
105   // Emits C++ statements for matching the `argIndex`-th argument of the given
106   // DAG `tree` as an operand. operandIndex is the index in the DAG excluding
107   // the preceding attributes.
108   void emitOperandMatch(DagNode tree, StringRef opName, int argIndex,
109                         int operandIndex, int depth);
110 
111   // Emits C++ statements for matching the `argIndex`-th argument of the given
112   // DAG `tree` as an attribute.
113   void emitAttributeMatch(DagNode tree, StringRef opName, int argIndex,
114                           int depth);
115 
116   // Emits C++ for checking a match with a corresponding match failure
117   // diagnostic.
118   void emitMatchCheck(StringRef opName, const FmtObjectBase &matchFmt,
119                       const llvm::formatv_object_base &failureFmt);
120 
121   // Emits C++ for checking a match with a corresponding match failure
122   // diagnostics.
123   void emitMatchCheck(StringRef opName, const std::string &matchStr,
124                       const std::string &failureStr);
125 
126   //===--------------------------------------------------------------------===//
127   // Rewrite utilities
128   //===--------------------------------------------------------------------===//
129 
130   // The entry point for handling a result pattern rooted at `resultTree`. This
131   // method dispatches to concrete handlers according to `resultTree`'s kind and
132   // returns a symbol representing the whole value pack. Callers are expected to
133   // further resolve the symbol according to the specific use case.
134   //
135   // `depth` is the nesting level of `resultTree`; 0 means top-level result
136   // pattern. For top-level result pattern, `resultIndex` indicates which result
137   // of the matched root op this pattern is intended to replace, which can be
138   // used to deduce the result type of the op generated from this result
139   // pattern.
140   std::string handleResultPattern(DagNode resultTree, int resultIndex,
141                                   int depth);
142 
143   // Emits the C++ statement to replace the matched DAG with a value built via
144   // calling native C++ code.
145   std::string handleReplaceWithNativeCodeCall(DagNode resultTree, int depth);
146 
147   // Returns the symbol of the old value serving as the replacement.
148   StringRef handleReplaceWithValue(DagNode tree);
149 
150   // Trailing directives are used at the end of DAG node argument lists to
151   // specify additional behaviour for op matchers and creators, etc.
152   struct TrailingDirectives {
153     // DAG node containing the `location` directive. Null if there is none.
154     DagNode location;
155 
156     // DAG node containing the `returnType` directive. Null if there is none.
157     DagNode returnType;
158 
159     // Number of found trailing directives.
160     int numDirectives;
161   };
162 
163   // Collect any trailing directives.
164   TrailingDirectives getTrailingDirectives(DagNode tree);
165 
166   // Returns the location value to use.
167   std::string getLocation(TrailingDirectives &tail);
168 
169   // Returns the location value to use.
170   std::string handleLocationDirective(DagNode tree);
171 
172   // Emit return type argument.
173   std::string handleReturnTypeArg(DagNode returnType, int i, int depth);
174 
175   // Emits the C++ statement to build a new op out of the given DAG `tree` and
176   // returns the variable name that this op is assigned to. If the root op in
177   // DAG `tree` has a specified name, the created op will be assigned to a
178   // variable of the given name. Otherwise, a unique name will be used as the
179   // result value name.
180   std::string handleOpCreation(DagNode tree, int resultIndex, int depth);
181 
182   using ChildNodeIndexNameMap = DenseMap<unsigned, std::string>;
183 
184   // Emits a local variable for each value and attribute to be used for creating
185   // an op.
186   void createSeparateLocalVarsForOpArgs(DagNode node,
187                                         ChildNodeIndexNameMap &childNodeNames);
188 
189   // Emits the concrete arguments used to call an op's builder.
190   void supplyValuesForOpArgs(DagNode node,
191                              const ChildNodeIndexNameMap &childNodeNames,
192                              int depth);
193 
194   // Emits the local variables for holding all values as a whole and all named
195   // attributes as a whole to be used for creating an op.
196   void createAggregateLocalVarsForOpArgs(
197       DagNode node, const ChildNodeIndexNameMap &childNodeNames, int depth);
198 
199   // Returns the C++ expression to construct a constant attribute of the given
200   // `value` for the given attribute kind `attr`.
201   std::string handleConstantAttr(Attribute attr, const Twine &value);
202 
203   // Returns the C++ expression to build an argument from the given DAG `leaf`.
204   // `patArgName` is used to bound the argument to the source pattern.
205   std::string handleOpArgument(DagLeaf leaf, StringRef patArgName);
206 
207   //===--------------------------------------------------------------------===//
208   // General utilities
209   //===--------------------------------------------------------------------===//
210 
211   // Collects all of the operations within the given dag tree.
212   void collectOps(DagNode tree, llvm::SmallPtrSetImpl<const Operator *> &ops);
213 
214   // Returns a unique symbol for a local variable of the given `op`.
215   std::string getUniqueSymbol(const Operator *op);
216 
217   //===--------------------------------------------------------------------===//
218   // Symbol utilities
219   //===--------------------------------------------------------------------===//
220 
221   // Returns how many static values the given DAG `node` correspond to.
222   int getNodeValueCount(DagNode node);
223 
224 private:
225   // Pattern instantiation location followed by the location of multiclass
226   // prototypes used. This is intended to be used as a whole to
227   // PrintFatalError() on errors.
228   ArrayRef<llvm::SMLoc> loc;
229 
230   // Op's TableGen Record to wrapper object.
231   RecordOperatorMap *opMap;
232 
233   // Handy wrapper for pattern being emitted.
234   Pattern pattern;
235 
236   // Map for all bound symbols' info.
237   SymbolInfoMap symbolInfoMap;
238 
239   StaticMatcherHelper &staticMatcherHelper;
240 
241   // The next unused ID for newly created values.
242   unsigned nextValueId;
243 
244   raw_indented_ostream os;
245 
246   // Format contexts containing placeholder substitutions.
247   FmtContext fmtCtx;
248 };
249 
250 // Tracks DagNode's reference multiple times across patterns. Enables generating
251 // static matcher functions for DagNode's referenced multiple times rather than
252 // inlining them.
253 class StaticMatcherHelper {
254 public:
255   StaticMatcherHelper(RecordOperatorMap &mapper);
256 
257   // Determine if we should inline the match logic or delegate to a static
258   // function.
259   bool useStaticMatcher(DagNode node) {
260     return refStats[node] > kStaticMatcherThreshold;
261   }
262 
263   // Get the name of the static DAG matcher function corresponding to the node.
264   std::string getMatcherName(DagNode node) {
265     assert(useStaticMatcher(node));
266     return matcherNames[node];
267   }
268 
269   // Collect the `Record`s, i.e., the DRR, so that we can get the information of
270   // the duplicated DAGs.
271   void addPattern(Record *record);
272 
273   // Emit all static functions of DAG Matcher.
274   void populateStaticMatchers(raw_ostream &os);
275 
276 private:
277   static constexpr unsigned kStaticMatcherThreshold = 1;
278 
279   // Consider two patterns as down below,
280   //   DagNode_Root_A    DagNode_Root_B
281   //       \                 \
282   //     DagNode_C         DagNode_C
283   //         \                 \
284   //       DagNode_D         DagNode_D
285   //
286   // DagNode_Root_A and DagNode_Root_B share the same subtree which consists of
287   // DagNode_C and DagNode_D. Both DagNode_C and DagNode_D are referenced
288   // multiple times so we'll have static matchers for both of them. When we're
289   // emitting the match logic for DagNode_C, we will check if DagNode_D has the
290   // static matcher generated. If so, then we'll generate a call to the
291   // function, inline otherwise. In this case, inlining is not what we want. As
292   // a result, generate the static matcher in topological order to ensure all
293   // the dependent static matchers are generated and we can avoid accidentally
294   // inlining.
295   //
296   // The topological order of all the DagNodes among all patterns.
297   SmallVector<std::pair<DagNode, Record *>> topologicalOrder;
298 
299   RecordOperatorMap &opMap;
300 
301   // Records of the static function name of each DagNode
302   DenseMap<DagNode, std::string> matcherNames;
303 
304   // After collecting all the DagNode in each pattern, `refStats` records the
305   // number of users for each DagNode. We will generate the static matcher for a
306   // DagNode while the number of users exceeds a certain threshold.
307   DenseMap<DagNode, unsigned> refStats;
308 
309   // Number of static matcher generated. This is used to generate a unique name
310   // for each DagNode.
311   int staticMatcherCounter = 0;
312 };
313 
314 } // end anonymous namespace
315 
316 PatternEmitter::PatternEmitter(Record *pat, RecordOperatorMap *mapper,
317                                raw_ostream &os, StaticMatcherHelper &helper)
318     : loc(pat->getLoc()), opMap(mapper), pattern(pat, mapper),
319       symbolInfoMap(pat->getLoc()), staticMatcherHelper(helper), nextValueId(0),
320       os(os) {
321   fmtCtx.withBuilder("rewriter");
322 }
323 
324 std::string PatternEmitter::handleConstantAttr(Attribute attr,
325                                                const Twine &value) {
326   if (!attr.isConstBuildable())
327     PrintFatalError(loc, "Attribute " + attr.getAttrDefName() +
328                              " does not have the 'constBuilderCall' field");
329 
330   // TODO: Verify the constants here
331   return std::string(tgfmt(attr.getConstBuilderTemplate(), &fmtCtx, value));
332 }
333 
334 void PatternEmitter::emitStaticMatcher(DagNode tree, std::string funcName) {
335   os << formatv(
336       "static ::mlir::LogicalResult {0}(::mlir::PatternRewriter &rewriter, "
337       "::mlir::Operation *op0, ::llvm::SmallVector<::mlir::Operation "
338       "*, 4> &tblgen_ops",
339       funcName);
340 
341   // We pass the reference of the variables that need to be captured. Hence we
342   // need to collect all the symbols in the tree first.
343   pattern.collectBoundSymbols(tree, symbolInfoMap, /*isSrcPattern=*/true);
344   symbolInfoMap.assignUniqueAlternativeNames();
345   for (const auto &info : symbolInfoMap)
346     os << formatv(", {0}", info.second.getArgDecl(info.first));
347 
348   os << ") {\n";
349   os.indent();
350   os << "(void)tblgen_ops;\n";
351 
352   // Note that a static matcher is considered at least one step from the match
353   // entry.
354   emitMatch(tree, "op0", /*depth=*/1);
355 
356   os << "return ::mlir::success();\n";
357   os.unindent();
358   os << "}\n\n";
359 }
360 
361 // Helper function to match patterns.
362 void PatternEmitter::emitMatch(DagNode tree, StringRef name, int depth) {
363   if (tree.isNativeCodeCall()) {
364     emitNativeCodeMatch(tree, name, depth);
365     return;
366   }
367 
368   if (tree.isOperation()) {
369     emitOpMatch(tree, name, depth);
370     return;
371   }
372 
373   PrintFatalError(loc, "encountered non-op, non-NativeCodeCall match.");
374 }
375 
376 void PatternEmitter::emitStaticMatchCall(DagNode tree, StringRef opName) {
377   std::string funcName = staticMatcherHelper.getMatcherName(tree);
378   os << formatv("if(failed({0}(rewriter, {1}, tblgen_ops", funcName, opName);
379 
380   // TODO(chiahungduan): Add a lookupBoundSymbols() to do the subtree lookup in
381   // one pass.
382 
383   // In general, bound symbol should have the unique name in the pattern but
384   // for the operand, binding same symbol to multiple operands imply a
385   // constraint at the same time. In this case, we will rename those operands
386   // with different names. As a result, we need to collect all the symbolInfos
387   // from the DagNode then get the updated name of the local variables from the
388   // global symbolInfoMap.
389 
390   // Collect all the bound symbols in the Dag
391   SymbolInfoMap localSymbolMap(loc);
392   pattern.collectBoundSymbols(tree, localSymbolMap, /*isSrcPattern=*/true);
393 
394   for (const auto &info : localSymbolMap) {
395     auto name = info.first;
396     auto symboInfo = info.second;
397     auto ret = symbolInfoMap.findBoundSymbol(name, symboInfo);
398     os << formatv(", {0}", ret->second.getVarName(name));
399   }
400 
401   os << "))) {\n";
402   os.scope().os << "return ::mlir::failure();\n";
403   os << "}\n";
404 }
405 
406 // Helper function to match patterns.
407 void PatternEmitter::emitNativeCodeMatch(DagNode tree, StringRef opName,
408                                          int depth) {
409   LLVM_DEBUG(llvm::dbgs() << "handle NativeCodeCall matcher pattern: ");
410   LLVM_DEBUG(tree.print(llvm::dbgs()));
411   LLVM_DEBUG(llvm::dbgs() << '\n');
412 
413   // The order of generating static matcher follows the topological order so
414   // that for every dependent DagNode already have their static matcher
415   // generated if needed. The reason we check if `getMatcherName(tree).empty()`
416   // is when we are generating the static matcher for a DagNode itself. In this
417   // case, we need to emit the function body rather than a function call.
418   if (staticMatcherHelper.useStaticMatcher(tree) &&
419       !staticMatcherHelper.getMatcherName(tree).empty()) {
420     emitStaticMatchCall(tree, opName);
421 
422     // NativeCodeCall will never be at depth 0 so that we don't need to catch
423     // the root operation as emitOpMatch();
424 
425     return;
426   }
427 
428   // TODO(suderman): iterate through arguments, determine their types, output
429   // names.
430   SmallVector<std::string, 8> capture;
431 
432   raw_indented_ostream::DelimitedScope scope(os);
433 
434   for (int i = 0, e = tree.getNumArgs(); i != e; ++i) {
435     std::string argName = formatv("arg{0}_{1}", depth, i);
436     if (DagNode argTree = tree.getArgAsNestedDag(i)) {
437       os << "Value " << argName << ";\n";
438     } else {
439       auto leaf = tree.getArgAsLeaf(i);
440       if (leaf.isAttrMatcher() || leaf.isConstantAttr()) {
441         os << "Attribute " << argName << ";\n";
442       } else {
443         os << "Value " << argName << ";\n";
444       }
445     }
446 
447     capture.push_back(std::move(argName));
448   }
449 
450   auto tail = getTrailingDirectives(tree);
451   if (tail.returnType)
452     PrintFatalError(loc, "`NativeCodeCall` cannot have return type specifier");
453   auto locToUse = getLocation(tail);
454 
455   auto fmt = tree.getNativeCodeTemplate();
456   if (fmt.count("$_self") != 1)
457     PrintFatalError(loc, "NativeCodeCall must have $_self as argument for "
458                          "passing the defining Operation");
459 
460   auto nativeCodeCall = std::string(
461       tgfmt(fmt, &fmtCtx.addSubst("_loc", locToUse).withSelf(opName.str()),
462             static_cast<ArrayRef<std::string>>(capture)));
463 
464   emitMatchCheck(opName, formatv("!failed({0})", nativeCodeCall),
465                  formatv("\"{0} return failure\"", nativeCodeCall));
466 
467   for (int i = 0, e = tree.getNumArgs() - tail.numDirectives; i != e; ++i) {
468     auto name = tree.getArgName(i);
469     if (!name.empty() && name != "_") {
470       os << formatv("{0} = {1};\n", name, capture[i]);
471     }
472   }
473 
474   for (int i = 0, e = tree.getNumArgs() - tail.numDirectives; i != e; ++i) {
475     std::string argName = capture[i];
476 
477     // Handle nested DAG construct first
478     if (DagNode argTree = tree.getArgAsNestedDag(i)) {
479       PrintFatalError(
480           loc, formatv("Matching nested tree in NativeCodecall not support for "
481                        "{0} as arg {1}",
482                        argName, i));
483     }
484 
485     DagLeaf leaf = tree.getArgAsLeaf(i);
486 
487     // The parameter for native function doesn't bind any constraints.
488     if (leaf.isUnspecified())
489       continue;
490 
491     auto constraint = leaf.getAsConstraint();
492 
493     std::string self;
494     if (leaf.isAttrMatcher() || leaf.isConstantAttr())
495       self = argName;
496     else
497       self = formatv("{0}.getType()", argName);
498     emitMatchCheck(
499         opName,
500         tgfmt(constraint.getConditionTemplate(), &fmtCtx.withSelf(self)),
501         formatv("\"operand {0} of native code call '{1}' failed to satisfy "
502                 "constraint: "
503                 "'{2}'\"",
504                 i, tree.getNativeCodeTemplate(),
505                 escapeString(constraint.getSummary())));
506   }
507 
508   LLVM_DEBUG(llvm::dbgs() << "done emitting match for native code call\n");
509 }
510 
511 // Helper function to match patterns.
512 void PatternEmitter::emitOpMatch(DagNode tree, StringRef opName, int depth) {
513   Operator &op = tree.getDialectOp(opMap);
514   LLVM_DEBUG(llvm::dbgs() << "start emitting match for op '"
515                           << op.getOperationName() << "' at depth " << depth
516                           << '\n');
517 
518   auto getCastedName = [depth]() -> std::string {
519     return formatv("castedOp{0}", depth);
520   };
521 
522   // The order of generating static matcher follows the topological order so
523   // that for every dependent DagNode already have their static matcher
524   // generated if needed. The reason we check if `getMatcherName(tree).empty()`
525   // is when we are generating the static matcher for a DagNode itself. In this
526   // case, we need to emit the function body rather than a function call.
527   if (staticMatcherHelper.useStaticMatcher(tree) &&
528       !staticMatcherHelper.getMatcherName(tree).empty()) {
529     emitStaticMatchCall(tree, opName);
530     // In the codegen of rewriter, we suppose that castedOp0 will capture the
531     // root operation. Manually add it if the root DagNode is a static matcher.
532     if (depth == 0)
533       os << formatv("auto {2} = ::llvm::dyn_cast_or_null<{1}>({0}); "
534                     "(void){2};\n",
535                     opName, op.getQualCppClassName(), getCastedName());
536     return;
537   }
538 
539   std::string castedName = getCastedName();
540   os << formatv("auto {0} = ::llvm::dyn_cast<{2}>({1}); "
541                 "(void){0};\n",
542                 castedName, opName, op.getQualCppClassName());
543 
544   // Skip the operand matching at depth 0 as the pattern rewriter already does.
545   if (depth != 0)
546     emitMatchCheck(opName, /*matchStr=*/castedName,
547                    formatv("\"{0} is not {1} type\"", castedName,
548                            op.getQualCppClassName()));
549 
550   if (tree.getNumArgs() != op.getNumArgs())
551     PrintFatalError(loc, formatv("op '{0}' argument number mismatch: {1} in "
552                                  "pattern vs. {2} in definition",
553                                  op.getOperationName(), tree.getNumArgs(),
554                                  op.getNumArgs()));
555 
556   // If the operand's name is set, set to that variable.
557   auto name = tree.getSymbol();
558   if (!name.empty())
559     os << formatv("{0} = {1};\n", name, castedName);
560 
561   for (int i = 0, e = tree.getNumArgs(), nextOperand = 0; i != e; ++i) {
562     auto opArg = op.getArg(i);
563     std::string argName = formatv("op{0}", depth + 1);
564 
565     // Handle nested DAG construct first
566     if (DagNode argTree = tree.getArgAsNestedDag(i)) {
567       if (auto *operand = opArg.dyn_cast<NamedTypeConstraint *>()) {
568         if (operand->isVariableLength()) {
569           auto error = formatv("use nested DAG construct to match op {0}'s "
570                                "variadic operand #{1} unsupported now",
571                                op.getOperationName(), i);
572           PrintFatalError(loc, error);
573         }
574       }
575       os << "{\n";
576 
577       // Attributes don't count for getODSOperands.
578       // TODO: Operand is a Value, check if we should remove `getDefiningOp()`.
579       os.indent() << formatv(
580           "auto *{0} = "
581           "(*{1}.getODSOperands({2}).begin()).getDefiningOp();\n",
582           argName, castedName, nextOperand);
583       // Null check of operand's definingOp
584       emitMatchCheck(castedName, /*matchStr=*/argName,
585                      formatv("\"Operand {0} of {1} has null definingOp\"",
586                              nextOperand++, castedName));
587       emitMatch(argTree, argName, depth + 1);
588       os << formatv("tblgen_ops.push_back({0});\n", argName);
589       os.unindent() << "}\n";
590       continue;
591     }
592 
593     // Next handle DAG leaf: operand or attribute
594     if (opArg.is<NamedTypeConstraint *>()) {
595       // emitOperandMatch's argument indexing counts attributes.
596       emitOperandMatch(tree, castedName, i, nextOperand, depth);
597       ++nextOperand;
598     } else if (opArg.is<NamedAttribute *>()) {
599       emitAttributeMatch(tree, opName, i, depth);
600     } else {
601       PrintFatalError(loc, "unhandled case when matching op");
602     }
603   }
604   LLVM_DEBUG(llvm::dbgs() << "done emitting match for op '"
605                           << op.getOperationName() << "' at depth " << depth
606                           << '\n');
607 }
608 
609 void PatternEmitter::emitOperandMatch(DagNode tree, StringRef opName,
610                                       int argIndex, int operandIndex,
611                                       int depth) {
612   Operator &op = tree.getDialectOp(opMap);
613   auto *operand = op.getArg(argIndex).get<NamedTypeConstraint *>();
614   auto matcher = tree.getArgAsLeaf(argIndex);
615 
616   // If a constraint is specified, we need to generate C++ statements to
617   // check the constraint.
618   if (!matcher.isUnspecified()) {
619     if (!matcher.isOperandMatcher()) {
620       PrintFatalError(
621           loc, formatv("the {1}-th argument of op '{0}' should be an operand",
622                        op.getOperationName(), argIndex + 1));
623     }
624 
625     // Only need to verify if the matcher's type is different from the one
626     // of op definition.
627     Constraint constraint = matcher.getAsConstraint();
628     if (operand->constraint != constraint) {
629       if (operand->isVariableLength()) {
630         auto error = formatv(
631             "further constrain op {0}'s variadic operand #{1} unsupported now",
632             op.getOperationName(), argIndex);
633         PrintFatalError(loc, error);
634       }
635       auto self = formatv("(*{0}.getODSOperands({1}).begin()).getType()",
636                           opName, operandIndex);
637       emitMatchCheck(
638           opName,
639           tgfmt(constraint.getConditionTemplate(), &fmtCtx.withSelf(self)),
640           formatv("\"operand {0} of op '{1}' failed to satisfy constraint: "
641                   "'{2}'\"",
642                   operand - op.operand_begin(), op.getOperationName(),
643                   escapeString(constraint.getSummary())));
644     }
645   }
646 
647   // Capture the value
648   auto name = tree.getArgName(argIndex);
649   // `$_` is a special symbol to ignore op argument matching.
650   if (!name.empty() && name != "_") {
651     // We need to subtract the number of attributes before this operand to get
652     // the index in the operand list.
653     auto numPrevAttrs = std::count_if(
654         op.arg_begin(), op.arg_begin() + argIndex,
655         [](const Argument &arg) { return arg.is<NamedAttribute *>(); });
656 
657     auto res = symbolInfoMap.findBoundSymbol(name, tree, op, argIndex);
658     os << formatv("{0} = {1}.getODSOperands({2});\n",
659                   res->second.getVarName(name), opName,
660                   argIndex - numPrevAttrs);
661   }
662 }
663 
664 void PatternEmitter::emitAttributeMatch(DagNode tree, StringRef opName,
665                                         int argIndex, int depth) {
666   Operator &op = tree.getDialectOp(opMap);
667   auto *namedAttr = op.getArg(argIndex).get<NamedAttribute *>();
668   const auto &attr = namedAttr->attr;
669 
670   os << "{\n";
671   os.indent() << formatv("auto tblgen_attr = {0}->getAttrOfType<{1}>(\"{2}\");"
672                          "(void)tblgen_attr;\n",
673                          opName, attr.getStorageType(), namedAttr->name);
674 
675   // TODO: This should use getter method to avoid duplication.
676   if (attr.hasDefaultValue()) {
677     os << "if (!tblgen_attr) tblgen_attr = "
678        << std::string(tgfmt(attr.getConstBuilderTemplate(), &fmtCtx,
679                             attr.getDefaultValue()))
680        << ";\n";
681   } else if (attr.isOptional()) {
682     // For a missing attribute that is optional according to definition, we
683     // should just capture a mlir::Attribute() to signal the missing state.
684     // That is precisely what getAttr() returns on missing attributes.
685   } else {
686     emitMatchCheck(opName, tgfmt("tblgen_attr", &fmtCtx),
687                    formatv("\"expected op '{0}' to have attribute '{1}' "
688                            "of type '{2}'\"",
689                            op.getOperationName(), namedAttr->name,
690                            attr.getStorageType()));
691   }
692 
693   auto matcher = tree.getArgAsLeaf(argIndex);
694   if (!matcher.isUnspecified()) {
695     if (!matcher.isAttrMatcher()) {
696       PrintFatalError(
697           loc, formatv("the {1}-th argument of op '{0}' should be an attribute",
698                        op.getOperationName(), argIndex + 1));
699     }
700 
701     // If a constraint is specified, we need to generate C++ statements to
702     // check the constraint.
703     emitMatchCheck(
704         opName,
705         tgfmt(matcher.getConditionTemplate(), &fmtCtx.withSelf("tblgen_attr")),
706         formatv("\"op '{0}' attribute '{1}' failed to satisfy constraint: "
707                 "'{2}'\"",
708                 op.getOperationName(), namedAttr->name,
709                 escapeString(matcher.getAsConstraint().getSummary())));
710   }
711 
712   // Capture the value
713   auto name = tree.getArgName(argIndex);
714   // `$_` is a special symbol to ignore op argument matching.
715   if (!name.empty() && name != "_") {
716     os << formatv("{0} = tblgen_attr;\n", name);
717   }
718 
719   os.unindent() << "}\n";
720 }
721 
722 void PatternEmitter::emitMatchCheck(
723     StringRef opName, const FmtObjectBase &matchFmt,
724     const llvm::formatv_object_base &failureFmt) {
725   emitMatchCheck(opName, matchFmt.str(), failureFmt.str());
726 }
727 
728 void PatternEmitter::emitMatchCheck(StringRef opName,
729                                     const std::string &matchStr,
730                                     const std::string &failureStr) {
731 
732   os << "if (!(" << matchStr << "))";
733   os.scope("{\n", "\n}\n").os << "return rewriter.notifyMatchFailure(" << opName
734                               << ", [&](::mlir::Diagnostic &diag) {\n  diag << "
735                               << failureStr << ";\n});";
736 }
737 
738 void PatternEmitter::emitMatchLogic(DagNode tree, StringRef opName) {
739   LLVM_DEBUG(llvm::dbgs() << "--- start emitting match logic ---\n");
740   int depth = 0;
741   emitMatch(tree, opName, depth);
742 
743   for (auto &appliedConstraint : pattern.getConstraints()) {
744     auto &constraint = appliedConstraint.constraint;
745     auto &entities = appliedConstraint.entities;
746 
747     auto condition = constraint.getConditionTemplate();
748     if (isa<TypeConstraint>(constraint)) {
749       auto self = formatv("({0}.getType())",
750                           symbolInfoMap.getValueAndRangeUse(entities.front()));
751       emitMatchCheck(
752           opName, tgfmt(condition, &fmtCtx.withSelf(self.str())),
753           formatv("\"value entity '{0}' failed to satisfy constraint: '{1}'\"",
754                   entities.front(), escapeString(constraint.getSummary())));
755 
756     } else if (isa<AttrConstraint>(constraint)) {
757       PrintFatalError(
758           loc, "cannot use AttrConstraint in Pattern multi-entity constraints");
759     } else {
760       // TODO: replace formatv arguments with the exact specified
761       // args.
762       if (entities.size() > 4) {
763         PrintFatalError(loc, "only support up to 4-entity constraints now");
764       }
765       SmallVector<std::string, 4> names;
766       int i = 0;
767       for (int e = entities.size(); i < e; ++i)
768         names.push_back(symbolInfoMap.getValueAndRangeUse(entities[i]));
769       std::string self = appliedConstraint.self;
770       if (!self.empty())
771         self = symbolInfoMap.getValueAndRangeUse(self);
772       for (; i < 4; ++i)
773         names.push_back("<unused>");
774       emitMatchCheck(opName,
775                      tgfmt(condition, &fmtCtx.withSelf(self), names[0],
776                            names[1], names[2], names[3]),
777                      formatv("\"entities '{0}' failed to satisfy constraint: "
778                              "'{1}'\"",
779                              llvm::join(entities, ", "),
780                              escapeString(constraint.getSummary())));
781     }
782   }
783 
784   // Some of the operands could be bound to the same symbol name, we need
785   // to enforce equality constraint on those.
786   // TODO: we should be able to emit equality checks early
787   // and short circuit unnecessary work if vars are not equal.
788   for (auto symbolInfoIt = symbolInfoMap.begin();
789        symbolInfoIt != symbolInfoMap.end();) {
790     auto range = symbolInfoMap.getRangeOfEqualElements(symbolInfoIt->first);
791     auto startRange = range.first;
792     auto endRange = range.second;
793 
794     auto firstOperand = symbolInfoIt->second.getVarName(symbolInfoIt->first);
795     for (++startRange; startRange != endRange; ++startRange) {
796       auto secondOperand = startRange->second.getVarName(symbolInfoIt->first);
797       emitMatchCheck(
798           opName,
799           formatv("*{0}.begin() == *{1}.begin()", firstOperand, secondOperand),
800           formatv("\"Operands '{0}' and '{1}' must be equal\"", firstOperand,
801                   secondOperand));
802     }
803 
804     symbolInfoIt = endRange;
805   }
806 
807   LLVM_DEBUG(llvm::dbgs() << "--- done emitting match logic ---\n");
808 }
809 
810 void PatternEmitter::collectOps(DagNode tree,
811                                 llvm::SmallPtrSetImpl<const Operator *> &ops) {
812   // Check if this tree is an operation.
813   if (tree.isOperation()) {
814     const Operator &op = tree.getDialectOp(opMap);
815     LLVM_DEBUG(llvm::dbgs()
816                << "found operation " << op.getOperationName() << '\n');
817     ops.insert(&op);
818   }
819 
820   // Recurse the arguments of the tree.
821   for (unsigned i = 0, e = tree.getNumArgs(); i != e; ++i)
822     if (auto child = tree.getArgAsNestedDag(i))
823       collectOps(child, ops);
824 }
825 
826 void PatternEmitter::emit(StringRef rewriteName) {
827   // Get the DAG tree for the source pattern.
828   DagNode sourceTree = pattern.getSourcePattern();
829 
830   const Operator &rootOp = pattern.getSourceRootOp();
831   auto rootName = rootOp.getOperationName();
832 
833   // Collect the set of result operations.
834   llvm::SmallPtrSet<const Operator *, 4> resultOps;
835   LLVM_DEBUG(llvm::dbgs() << "start collecting ops used in result patterns\n");
836   for (unsigned i = 0, e = pattern.getNumResultPatterns(); i != e; ++i) {
837     collectOps(pattern.getResultPattern(i), resultOps);
838   }
839   LLVM_DEBUG(llvm::dbgs() << "done collecting ops used in result patterns\n");
840 
841   // Emit RewritePattern for Pattern.
842   auto locs = pattern.getLocation();
843   os << formatv("/* Generated from:\n    {0:$[ instantiating\n    ]}\n*/\n",
844                 make_range(locs.rbegin(), locs.rend()));
845   os << formatv(R"(struct {0} : public ::mlir::RewritePattern {
846   {0}(::mlir::MLIRContext *context)
847       : ::mlir::RewritePattern("{1}", {2}, context, {{)",
848                 rewriteName, rootName, pattern.getBenefit());
849   // Sort result operators by name.
850   llvm::SmallVector<const Operator *, 4> sortedResultOps(resultOps.begin(),
851                                                          resultOps.end());
852   llvm::sort(sortedResultOps, [&](const Operator *lhs, const Operator *rhs) {
853     return lhs->getOperationName() < rhs->getOperationName();
854   });
855   llvm::interleaveComma(sortedResultOps, os, [&](const Operator *op) {
856     os << '"' << op->getOperationName() << '"';
857   });
858   os << "}) {}\n";
859 
860   // Emit matchAndRewrite() function.
861   {
862     auto classScope = os.scope();
863     os.reindent(R"(
864     ::mlir::LogicalResult matchAndRewrite(::mlir::Operation *op0,
865         ::mlir::PatternRewriter &rewriter) const override {)")
866         << '\n';
867     {
868       auto functionScope = os.scope();
869 
870       // Register all symbols bound in the source pattern.
871       pattern.collectSourcePatternBoundSymbols(symbolInfoMap);
872 
873       LLVM_DEBUG(llvm::dbgs()
874                  << "start creating local variables for capturing matches\n");
875       os << "// Variables for capturing values and attributes used while "
876             "creating ops\n";
877       // Create local variables for storing the arguments and results bound
878       // to symbols.
879       for (const auto &symbolInfoPair : symbolInfoMap) {
880         const auto &symbol = symbolInfoPair.first;
881         const auto &info = symbolInfoPair.second;
882 
883         os << info.getVarDecl(symbol);
884       }
885       // TODO: capture ops with consistent numbering so that it can be
886       // reused for fused loc.
887       os << "::llvm::SmallVector<::mlir::Operation *, 4> tblgen_ops;\n\n";
888       LLVM_DEBUG(llvm::dbgs()
889                  << "done creating local variables for capturing matches\n");
890 
891       os << "// Match\n";
892       os << "tblgen_ops.push_back(op0);\n";
893       emitMatchLogic(sourceTree, "op0");
894 
895       os << "\n// Rewrite\n";
896       emitRewriteLogic();
897 
898       os << "return ::mlir::success();\n";
899     }
900     os << "};\n";
901   }
902   os << "};\n\n";
903 }
904 
905 void PatternEmitter::emitRewriteLogic() {
906   LLVM_DEBUG(llvm::dbgs() << "--- start emitting rewrite logic ---\n");
907   const Operator &rootOp = pattern.getSourceRootOp();
908   int numExpectedResults = rootOp.getNumResults();
909   int numResultPatterns = pattern.getNumResultPatterns();
910 
911   // First register all symbols bound to ops generated in result patterns.
912   pattern.collectResultPatternBoundSymbols(symbolInfoMap);
913 
914   // Only the last N static values generated are used to replace the matched
915   // root N-result op. We need to calculate the starting index (of the results
916   // of the matched op) each result pattern is to replace.
917   SmallVector<int, 4> offsets(numResultPatterns + 1, numExpectedResults);
918   // If we don't need to replace any value at all, set the replacement starting
919   // index as the number of result patterns so we skip all of them when trying
920   // to replace the matched op's results.
921   int replStartIndex = numExpectedResults == 0 ? numResultPatterns : -1;
922   for (int i = numResultPatterns - 1; i >= 0; --i) {
923     auto numValues = getNodeValueCount(pattern.getResultPattern(i));
924     offsets[i] = offsets[i + 1] - numValues;
925     if (offsets[i] == 0) {
926       if (replStartIndex == -1)
927         replStartIndex = i;
928     } else if (offsets[i] < 0 && offsets[i + 1] > 0) {
929       auto error = formatv(
930           "cannot use the same multi-result op '{0}' to generate both "
931           "auxiliary values and values to be used for replacing the matched op",
932           pattern.getResultPattern(i).getSymbol());
933       PrintFatalError(loc, error);
934     }
935   }
936 
937   if (offsets.front() > 0) {
938     const char error[] = "no enough values generated to replace the matched op";
939     PrintFatalError(loc, error);
940   }
941 
942   os << "auto odsLoc = rewriter.getFusedLoc({";
943   for (int i = 0, e = pattern.getSourcePattern().getNumOps(); i != e; ++i) {
944     os << (i ? ", " : "") << "tblgen_ops[" << i << "]->getLoc()";
945   }
946   os << "}); (void)odsLoc;\n";
947 
948   // Process auxiliary result patterns.
949   for (int i = 0; i < replStartIndex; ++i) {
950     DagNode resultTree = pattern.getResultPattern(i);
951     auto val = handleResultPattern(resultTree, offsets[i], 0);
952     // Normal op creation will be streamed to `os` by the above call; but
953     // NativeCodeCall will only be materialized to `os` if it is used. Here
954     // we are handling auxiliary patterns so we want the side effect even if
955     // NativeCodeCall is not replacing matched root op's results.
956     if (resultTree.isNativeCodeCall() &&
957         resultTree.getNumReturnsOfNativeCode() == 0)
958       os << val << ";\n";
959   }
960 
961   if (numExpectedResults == 0) {
962     assert(replStartIndex >= numResultPatterns &&
963            "invalid auxiliary vs. replacement pattern division!");
964     // No result to replace. Just erase the op.
965     os << "rewriter.eraseOp(op0);\n";
966   } else {
967     // Process replacement result patterns.
968     os << "::llvm::SmallVector<::mlir::Value, 4> tblgen_repl_values;\n";
969     for (int i = replStartIndex; i < numResultPatterns; ++i) {
970       DagNode resultTree = pattern.getResultPattern(i);
971       auto val = handleResultPattern(resultTree, offsets[i], 0);
972       os << "\n";
973       // Resolve each symbol for all range use so that we can loop over them.
974       // We need an explicit cast to `SmallVector` to capture the cases where
975       // `{0}` resolves to an `Operation::result_range` as well as cases that
976       // are not iterable (e.g. vector that gets wrapped in additional braces by
977       // RewriterGen).
978       // TODO: Revisit the need for materializing a vector.
979       os << symbolInfoMap.getAllRangeUse(
980           val,
981           "for (auto v: ::llvm::SmallVector<::mlir::Value, 4>{ {0} }) {{\n"
982           "  tblgen_repl_values.push_back(v);\n}\n",
983           "\n");
984     }
985     os << "\nrewriter.replaceOp(op0, tblgen_repl_values);\n";
986   }
987 
988   LLVM_DEBUG(llvm::dbgs() << "--- done emitting rewrite logic ---\n");
989 }
990 
991 std::string PatternEmitter::getUniqueSymbol(const Operator *op) {
992   return std::string(
993       formatv("tblgen_{0}_{1}", op->getCppClassName(), nextValueId++));
994 }
995 
996 std::string PatternEmitter::handleResultPattern(DagNode resultTree,
997                                                 int resultIndex, int depth) {
998   LLVM_DEBUG(llvm::dbgs() << "handle result pattern: ");
999   LLVM_DEBUG(resultTree.print(llvm::dbgs()));
1000   LLVM_DEBUG(llvm::dbgs() << '\n');
1001 
1002   if (resultTree.isLocationDirective()) {
1003     PrintFatalError(loc,
1004                     "location directive can only be used with op creation");
1005   }
1006 
1007   if (resultTree.isNativeCodeCall())
1008     return handleReplaceWithNativeCodeCall(resultTree, depth);
1009 
1010   if (resultTree.isReplaceWithValue())
1011     return handleReplaceWithValue(resultTree).str();
1012 
1013   // Normal op creation.
1014   auto symbol = handleOpCreation(resultTree, resultIndex, depth);
1015   if (resultTree.getSymbol().empty()) {
1016     // This is an op not explicitly bound to a symbol in the rewrite rule.
1017     // Register the auto-generated symbol for it.
1018     symbolInfoMap.bindOpResult(symbol, pattern.getDialectOp(resultTree));
1019   }
1020   return symbol;
1021 }
1022 
1023 StringRef PatternEmitter::handleReplaceWithValue(DagNode tree) {
1024   assert(tree.isReplaceWithValue());
1025 
1026   if (tree.getNumArgs() != 1) {
1027     PrintFatalError(
1028         loc, "replaceWithValue directive must take exactly one argument");
1029   }
1030 
1031   if (!tree.getSymbol().empty()) {
1032     PrintFatalError(loc, "cannot bind symbol to replaceWithValue");
1033   }
1034 
1035   return tree.getArgName(0);
1036 }
1037 
1038 std::string PatternEmitter::handleLocationDirective(DagNode tree) {
1039   assert(tree.isLocationDirective());
1040   auto lookUpArgLoc = [this, &tree](int idx) {
1041     const auto *const lookupFmt = "(*{0}.begin()).getLoc()";
1042     return symbolInfoMap.getAllRangeUse(tree.getArgName(idx), lookupFmt);
1043   };
1044 
1045   if (tree.getNumArgs() == 0)
1046     llvm::PrintFatalError(
1047         "At least one argument to location directive required");
1048 
1049   if (!tree.getSymbol().empty())
1050     PrintFatalError(loc, "cannot bind symbol to location");
1051 
1052   if (tree.getNumArgs() == 1) {
1053     DagLeaf leaf = tree.getArgAsLeaf(0);
1054     if (leaf.isStringAttr())
1055       return formatv("::mlir::NameLoc::get(rewriter.getIdentifier(\"{0}\"))",
1056                      leaf.getStringAttr())
1057           .str();
1058     return lookUpArgLoc(0);
1059   }
1060 
1061   std::string ret;
1062   llvm::raw_string_ostream os(ret);
1063   std::string strAttr;
1064   os << "rewriter.getFusedLoc({";
1065   bool first = true;
1066   for (int i = 0, e = tree.getNumArgs(); i != e; ++i) {
1067     DagLeaf leaf = tree.getArgAsLeaf(i);
1068     // Handle the optional string value.
1069     if (leaf.isStringAttr()) {
1070       if (!strAttr.empty())
1071         llvm::PrintFatalError("Only one string attribute may be specified");
1072       strAttr = leaf.getStringAttr();
1073       continue;
1074     }
1075     os << (first ? "" : ", ") << lookUpArgLoc(i);
1076     first = false;
1077   }
1078   os << "}";
1079   if (!strAttr.empty()) {
1080     os << ", rewriter.getStringAttr(\"" << strAttr << "\")";
1081   }
1082   os << ")";
1083   return os.str();
1084 }
1085 
1086 std::string PatternEmitter::handleReturnTypeArg(DagNode returnType, int i,
1087                                                 int depth) {
1088   // Nested NativeCodeCall.
1089   if (auto dagNode = returnType.getArgAsNestedDag(i)) {
1090     if (!dagNode.isNativeCodeCall())
1091       PrintFatalError(loc, "nested DAG in `returnType` must be a native code "
1092                            "call");
1093     return handleReplaceWithNativeCodeCall(dagNode, depth);
1094   }
1095   // String literal.
1096   auto dagLeaf = returnType.getArgAsLeaf(i);
1097   if (dagLeaf.isStringAttr())
1098     return tgfmt(dagLeaf.getStringAttr(), &fmtCtx);
1099   return tgfmt(
1100       "$0.getType()", &fmtCtx,
1101       handleOpArgument(returnType.getArgAsLeaf(i), returnType.getArgName(i)));
1102 }
1103 
1104 std::string PatternEmitter::handleOpArgument(DagLeaf leaf,
1105                                              StringRef patArgName) {
1106   if (leaf.isStringAttr())
1107     PrintFatalError(loc, "raw string not supported as argument");
1108   if (leaf.isConstantAttr()) {
1109     auto constAttr = leaf.getAsConstantAttr();
1110     return handleConstantAttr(constAttr.getAttribute(),
1111                               constAttr.getConstantValue());
1112   }
1113   if (leaf.isEnumAttrCase()) {
1114     auto enumCase = leaf.getAsEnumAttrCase();
1115     if (enumCase.isStrCase())
1116       return handleConstantAttr(enumCase, "\"" + enumCase.getSymbol() + "\"");
1117     // This is an enum case backed by an IntegerAttr. We need to get its value
1118     // to build the constant.
1119     std::string val = std::to_string(enumCase.getValue());
1120     return handleConstantAttr(enumCase, val);
1121   }
1122 
1123   LLVM_DEBUG(llvm::dbgs() << "handle argument '" << patArgName << "'\n");
1124   auto argName = symbolInfoMap.getValueAndRangeUse(patArgName);
1125   if (leaf.isUnspecified() || leaf.isOperandMatcher()) {
1126     LLVM_DEBUG(llvm::dbgs() << "replace " << patArgName << " with '" << argName
1127                             << "' (via symbol ref)\n");
1128     return argName;
1129   }
1130   if (leaf.isNativeCodeCall()) {
1131     auto repl = tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(argName));
1132     LLVM_DEBUG(llvm::dbgs() << "replace " << patArgName << " with '" << repl
1133                             << "' (via NativeCodeCall)\n");
1134     return std::string(repl);
1135   }
1136   PrintFatalError(loc, "unhandled case when rewriting op");
1137 }
1138 
1139 std::string PatternEmitter::handleReplaceWithNativeCodeCall(DagNode tree,
1140                                                             int depth) {
1141   LLVM_DEBUG(llvm::dbgs() << "handle NativeCodeCall pattern: ");
1142   LLVM_DEBUG(tree.print(llvm::dbgs()));
1143   LLVM_DEBUG(llvm::dbgs() << '\n');
1144 
1145   auto fmt = tree.getNativeCodeTemplate();
1146 
1147   SmallVector<std::string, 16> attrs;
1148 
1149   auto tail = getTrailingDirectives(tree);
1150   if (tail.returnType)
1151     PrintFatalError(loc, "`NativeCodeCall` cannot have return type specifier");
1152   auto locToUse = getLocation(tail);
1153 
1154   for (int i = 0, e = tree.getNumArgs() - tail.numDirectives; i != e; ++i) {
1155     if (tree.isNestedDagArg(i)) {
1156       attrs.push_back(
1157           handleResultPattern(tree.getArgAsNestedDag(i), i, depth + 1));
1158     } else {
1159       attrs.push_back(
1160           handleOpArgument(tree.getArgAsLeaf(i), tree.getArgName(i)));
1161     }
1162     LLVM_DEBUG(llvm::dbgs() << "NativeCodeCall argument #" << i
1163                             << " replacement: " << attrs[i] << "\n");
1164   }
1165 
1166   std::string symbol = tgfmt(fmt, &fmtCtx.addSubst("_loc", locToUse),
1167                              static_cast<ArrayRef<std::string>>(attrs));
1168 
1169   // In general, NativeCodeCall without naming binding don't need this. To
1170   // ensure void helper function has been correctly labeled, i.e., use
1171   // NativeCodeCallVoid, we cache the result to a local variable so that we will
1172   // get a compilation error in the auto-generated file.
1173   // Example.
1174   //   // In the td file
1175   //   Pat<(...), (NativeCodeCall<Foo> ...)>
1176   //
1177   //   ---
1178   //
1179   //   // In the auto-generated .cpp
1180   //   ...
1181   //   // Causes compilation error if Foo() returns void.
1182   //   auto nativeVar = Foo();
1183   //   ...
1184   if (tree.getNumReturnsOfNativeCode() != 0) {
1185     // Determine the local variable name for return value.
1186     std::string varName =
1187         SymbolInfoMap::getValuePackName(tree.getSymbol()).str();
1188     if (varName.empty()) {
1189       varName = formatv("nativeVar_{0}", nextValueId++);
1190       // Register the local variable for later uses.
1191       symbolInfoMap.bindValues(varName, tree.getNumReturnsOfNativeCode());
1192     }
1193 
1194     // Catch the return value of helper function.
1195     os << formatv("auto {0} = {1}; (void){0};\n", varName, symbol);
1196 
1197     if (!tree.getSymbol().empty())
1198       symbol = tree.getSymbol().str();
1199     else
1200       symbol = varName;
1201   }
1202 
1203   return symbol;
1204 }
1205 
1206 int PatternEmitter::getNodeValueCount(DagNode node) {
1207   if (node.isOperation()) {
1208     // If the op is bound to a symbol in the rewrite rule, query its result
1209     // count from the symbol info map.
1210     auto symbol = node.getSymbol();
1211     if (!symbol.empty()) {
1212       return symbolInfoMap.getStaticValueCount(symbol);
1213     }
1214     // Otherwise this is an unbound op; we will use all its results.
1215     return pattern.getDialectOp(node).getNumResults();
1216   }
1217 
1218   if (node.isNativeCodeCall())
1219     return node.getNumReturnsOfNativeCode();
1220 
1221   return 1;
1222 }
1223 
1224 PatternEmitter::TrailingDirectives
1225 PatternEmitter::getTrailingDirectives(DagNode tree) {
1226   TrailingDirectives tail = {DagNode(nullptr), DagNode(nullptr), 0};
1227 
1228   // Look backwards through the arguments.
1229   auto numPatArgs = tree.getNumArgs();
1230   for (int i = numPatArgs - 1; i >= 0; --i) {
1231     auto dagArg = tree.getArgAsNestedDag(i);
1232     // A leaf is not a directive. Stop looking.
1233     if (!dagArg)
1234       break;
1235 
1236     auto isLocation = dagArg.isLocationDirective();
1237     auto isReturnType = dagArg.isReturnTypeDirective();
1238     // If encountered a DAG node that isn't a trailing directive, stop looking.
1239     if (!(isLocation || isReturnType))
1240       break;
1241     // Save the directive, but error if one of the same type was already
1242     // found.
1243     ++tail.numDirectives;
1244     if (isLocation) {
1245       if (tail.location)
1246         PrintFatalError(loc, "`location` directive can only be specified "
1247                              "once");
1248       tail.location = dagArg;
1249     } else if (isReturnType) {
1250       if (tail.returnType)
1251         PrintFatalError(loc, "`returnType` directive can only be specified "
1252                              "once");
1253       tail.returnType = dagArg;
1254     }
1255   }
1256 
1257   return tail;
1258 }
1259 
1260 std::string
1261 PatternEmitter::getLocation(PatternEmitter::TrailingDirectives &tail) {
1262   if (tail.location)
1263     return handleLocationDirective(tail.location);
1264 
1265   // If no explicit location is given, use the default, all fused, location.
1266   return "odsLoc";
1267 }
1268 
1269 std::string PatternEmitter::handleOpCreation(DagNode tree, int resultIndex,
1270                                              int depth) {
1271   LLVM_DEBUG(llvm::dbgs() << "create op for pattern: ");
1272   LLVM_DEBUG(tree.print(llvm::dbgs()));
1273   LLVM_DEBUG(llvm::dbgs() << '\n');
1274 
1275   Operator &resultOp = tree.getDialectOp(opMap);
1276   auto numOpArgs = resultOp.getNumArgs();
1277   auto numPatArgs = tree.getNumArgs();
1278 
1279   auto tail = getTrailingDirectives(tree);
1280   auto locToUse = getLocation(tail);
1281 
1282   auto inPattern = numPatArgs - tail.numDirectives;
1283   if (numOpArgs != inPattern) {
1284     PrintFatalError(loc,
1285                     formatv("resultant op '{0}' argument number mismatch: "
1286                             "{1} in pattern vs. {2} in definition",
1287                             resultOp.getOperationName(), inPattern, numOpArgs));
1288   }
1289 
1290   // A map to collect all nested DAG child nodes' names, with operand index as
1291   // the key. This includes both bound and unbound child nodes.
1292   ChildNodeIndexNameMap childNodeNames;
1293 
1294   // First go through all the child nodes who are nested DAG constructs to
1295   // create ops for them and remember the symbol names for them, so that we can
1296   // use the results in the current node. This happens in a recursive manner.
1297   for (int i = 0, e = tree.getNumArgs() - tail.numDirectives; i != e; ++i) {
1298     if (auto child = tree.getArgAsNestedDag(i))
1299       childNodeNames[i] = handleResultPattern(child, i, depth + 1);
1300   }
1301 
1302   // The name of the local variable holding this op.
1303   std::string valuePackName;
1304   // The symbol for holding the result of this pattern. Note that the result of
1305   // this pattern is not necessarily the same as the variable created by this
1306   // pattern because we can use `__N` suffix to refer only a specific result if
1307   // the generated op is a multi-result op.
1308   std::string resultValue;
1309   if (tree.getSymbol().empty()) {
1310     // No symbol is explicitly bound to this op in the pattern. Generate a
1311     // unique name.
1312     valuePackName = resultValue = getUniqueSymbol(&resultOp);
1313   } else {
1314     resultValue = std::string(tree.getSymbol());
1315     // Strip the index to get the name for the value pack and use it to name the
1316     // local variable for the op.
1317     valuePackName = std::string(SymbolInfoMap::getValuePackName(resultValue));
1318   }
1319 
1320   // Create the local variable for this op.
1321   os << formatv("{0} {1};\n{{\n", resultOp.getQualCppClassName(),
1322                 valuePackName);
1323 
1324   // Right now ODS don't have general type inference support. Except a few
1325   // special cases listed below, DRR needs to supply types for all results
1326   // when building an op.
1327   bool isSameOperandsAndResultType =
1328       resultOp.getTrait("::mlir::OpTrait::SameOperandsAndResultType");
1329   bool useFirstAttr =
1330       resultOp.getTrait("::mlir::OpTrait::FirstAttrDerivedResultType");
1331 
1332   if (!tail.returnType && (isSameOperandsAndResultType || useFirstAttr)) {
1333     // We know how to deduce the result type for ops with these traits and we've
1334     // generated builders taking aggregate parameters. Use those builders to
1335     // create the ops.
1336 
1337     // First prepare local variables for op arguments used in builder call.
1338     createAggregateLocalVarsForOpArgs(tree, childNodeNames, depth);
1339 
1340     // Then create the op.
1341     os.scope("", "\n}\n").os << formatv(
1342         "{0} = rewriter.create<{1}>({2}, tblgen_values, tblgen_attrs);",
1343         valuePackName, resultOp.getQualCppClassName(), locToUse);
1344     return resultValue;
1345   }
1346 
1347   bool usePartialResults = valuePackName != resultValue;
1348 
1349   if (!tail.returnType && (usePartialResults || depth > 0 || resultIndex < 0)) {
1350     // For these cases (broadcastable ops, op results used both as auxiliary
1351     // values and replacement values, ops in nested patterns, auxiliary ops), we
1352     // still need to supply the result types when building the op. But because
1353     // we don't generate a builder automatically with ODS for them, it's the
1354     // developer's responsibility to make sure such a builder (with result type
1355     // deduction ability) exists. We go through the separate-parameter builder
1356     // here given that it's easier for developers to write compared to
1357     // aggregate-parameter builders.
1358     createSeparateLocalVarsForOpArgs(tree, childNodeNames);
1359 
1360     os.scope().os << formatv("{0} = rewriter.create<{1}>({2}", valuePackName,
1361                              resultOp.getQualCppClassName(), locToUse);
1362     supplyValuesForOpArgs(tree, childNodeNames, depth);
1363     os << "\n  );\n}\n";
1364     return resultValue;
1365   }
1366 
1367   // If we are provided explicit return types, use them to build the op.
1368   // However, if depth == 0 and resultIndex >= 0, it means we are replacing
1369   // the values generated from the source pattern root op. Then we must use the
1370   // source pattern's value types to determine the value type of the generated
1371   // op here.
1372   if (depth == 0 && resultIndex >= 0 && tail.returnType)
1373     PrintFatalError(loc, "Cannot specify explicit return types in an op whose "
1374                          "return values replace the source pattern's root op");
1375 
1376   // First prepare local variables for op arguments used in builder call.
1377   createAggregateLocalVarsForOpArgs(tree, childNodeNames, depth);
1378 
1379   // Then prepare the result types. We need to specify the types for all
1380   // results.
1381   os.indent() << formatv("::mlir::SmallVector<::mlir::Type, 4> tblgen_types; "
1382                          "(void)tblgen_types;\n");
1383   int numResults = resultOp.getNumResults();
1384   if (tail.returnType) {
1385     auto numRetTys = tail.returnType.getNumArgs();
1386     for (int i = 0; i < numRetTys; ++i) {
1387       auto varName = handleReturnTypeArg(tail.returnType, i, depth + 1);
1388       os << "tblgen_types.push_back(" << varName << ");\n";
1389     }
1390   } else {
1391     if (numResults != 0) {
1392       // Copy the result types from the source pattern.
1393       for (int i = 0; i < numResults; ++i)
1394         os << formatv("for (auto v: castedOp0.getODSResults({0})) {{\n"
1395                       "  tblgen_types.push_back(v.getType());\n}\n",
1396                       resultIndex + i);
1397     }
1398   }
1399   os << formatv("{0} = rewriter.create<{1}>({2}, tblgen_types, "
1400                 "tblgen_values, tblgen_attrs);\n",
1401                 valuePackName, resultOp.getQualCppClassName(), locToUse);
1402   os.unindent() << "}\n";
1403   return resultValue;
1404 }
1405 
1406 void PatternEmitter::createSeparateLocalVarsForOpArgs(
1407     DagNode node, ChildNodeIndexNameMap &childNodeNames) {
1408   Operator &resultOp = node.getDialectOp(opMap);
1409 
1410   // Now prepare operands used for building this op:
1411   // * If the operand is non-variadic, we create a `Value` local variable.
1412   // * If the operand is variadic, we create a `SmallVector<Value>` local
1413   //   variable.
1414 
1415   int valueIndex = 0; // An index for uniquing local variable names.
1416   for (int argIndex = 0, e = resultOp.getNumArgs(); argIndex < e; ++argIndex) {
1417     const auto *operand =
1418         resultOp.getArg(argIndex).dyn_cast<NamedTypeConstraint *>();
1419     // We do not need special handling for attributes.
1420     if (!operand)
1421       continue;
1422 
1423     raw_indented_ostream::DelimitedScope scope(os);
1424     std::string varName;
1425     if (operand->isVariadic()) {
1426       varName = std::string(formatv("tblgen_values_{0}", valueIndex++));
1427       os << formatv("::mlir::SmallVector<::mlir::Value, 4> {0};\n", varName);
1428       std::string range;
1429       if (node.isNestedDagArg(argIndex)) {
1430         range = childNodeNames[argIndex];
1431       } else {
1432         range = std::string(node.getArgName(argIndex));
1433       }
1434       // Resolve the symbol for all range use so that we have a uniform way of
1435       // capturing the values.
1436       range = symbolInfoMap.getValueAndRangeUse(range);
1437       os << formatv("for (auto v: {0}) {{\n  {1}.push_back(v);\n}\n", range,
1438                     varName);
1439     } else {
1440       varName = std::string(formatv("tblgen_value_{0}", valueIndex++));
1441       os << formatv("::mlir::Value {0} = ", varName);
1442       if (node.isNestedDagArg(argIndex)) {
1443         os << symbolInfoMap.getValueAndRangeUse(childNodeNames[argIndex]);
1444       } else {
1445         DagLeaf leaf = node.getArgAsLeaf(argIndex);
1446         auto symbol =
1447             symbolInfoMap.getValueAndRangeUse(node.getArgName(argIndex));
1448         if (leaf.isNativeCodeCall()) {
1449           os << std::string(
1450               tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(symbol)));
1451         } else {
1452           os << symbol;
1453         }
1454       }
1455       os << ";\n";
1456     }
1457 
1458     // Update to use the newly created local variable for building the op later.
1459     childNodeNames[argIndex] = varName;
1460   }
1461 }
1462 
1463 void PatternEmitter::supplyValuesForOpArgs(
1464     DagNode node, const ChildNodeIndexNameMap &childNodeNames, int depth) {
1465   Operator &resultOp = node.getDialectOp(opMap);
1466   for (int argIndex = 0, numOpArgs = resultOp.getNumArgs();
1467        argIndex != numOpArgs; ++argIndex) {
1468     // Start each argument on its own line.
1469     os << ",\n    ";
1470 
1471     Argument opArg = resultOp.getArg(argIndex);
1472     // Handle the case of operand first.
1473     if (auto *operand = opArg.dyn_cast<NamedTypeConstraint *>()) {
1474       if (!operand->name.empty())
1475         os << "/*" << operand->name << "=*/";
1476       os << childNodeNames.lookup(argIndex);
1477       continue;
1478     }
1479 
1480     // The argument in the op definition.
1481     auto opArgName = resultOp.getArgName(argIndex);
1482     if (auto subTree = node.getArgAsNestedDag(argIndex)) {
1483       if (!subTree.isNativeCodeCall())
1484         PrintFatalError(loc, "only NativeCodeCall allowed in nested dag node "
1485                              "for creating attribute");
1486       os << formatv("/*{0}=*/{1}", opArgName, childNodeNames.lookup(argIndex));
1487     } else {
1488       auto leaf = node.getArgAsLeaf(argIndex);
1489       // The argument in the result DAG pattern.
1490       auto patArgName = node.getArgName(argIndex);
1491       if (leaf.isConstantAttr() || leaf.isEnumAttrCase()) {
1492         // TODO: Refactor out into map to avoid recomputing these.
1493         if (!opArg.is<NamedAttribute *>())
1494           PrintFatalError(loc, Twine("expected attribute ") + Twine(argIndex));
1495         if (!patArgName.empty())
1496           os << "/*" << patArgName << "=*/";
1497       } else {
1498         os << "/*" << opArgName << "=*/";
1499       }
1500       os << handleOpArgument(leaf, patArgName);
1501     }
1502   }
1503 }
1504 
1505 void PatternEmitter::createAggregateLocalVarsForOpArgs(
1506     DagNode node, const ChildNodeIndexNameMap &childNodeNames, int depth) {
1507   Operator &resultOp = node.getDialectOp(opMap);
1508 
1509   auto scope = os.scope();
1510   os << formatv("::mlir::SmallVector<::mlir::Value, 4> "
1511                 "tblgen_values; (void)tblgen_values;\n");
1512   os << formatv("::mlir::SmallVector<::mlir::NamedAttribute, 4> "
1513                 "tblgen_attrs; (void)tblgen_attrs;\n");
1514 
1515   const char *addAttrCmd =
1516       "if (auto tmpAttr = {1}) {\n"
1517       "  tblgen_attrs.emplace_back(rewriter.getIdentifier(\"{0}\"), "
1518       "tmpAttr);\n}\n";
1519   for (int argIndex = 0, e = resultOp.getNumArgs(); argIndex < e; ++argIndex) {
1520     if (resultOp.getArg(argIndex).is<NamedAttribute *>()) {
1521       // The argument in the op definition.
1522       auto opArgName = resultOp.getArgName(argIndex);
1523       if (auto subTree = node.getArgAsNestedDag(argIndex)) {
1524         if (!subTree.isNativeCodeCall())
1525           PrintFatalError(loc, "only NativeCodeCall allowed in nested dag node "
1526                                "for creating attribute");
1527         os << formatv(addAttrCmd, opArgName, childNodeNames.lookup(argIndex));
1528       } else {
1529         auto leaf = node.getArgAsLeaf(argIndex);
1530         // The argument in the result DAG pattern.
1531         auto patArgName = node.getArgName(argIndex);
1532         os << formatv(addAttrCmd, opArgName,
1533                       handleOpArgument(leaf, patArgName));
1534       }
1535       continue;
1536     }
1537 
1538     const auto *operand =
1539         resultOp.getArg(argIndex).get<NamedTypeConstraint *>();
1540     std::string varName;
1541     if (operand->isVariadic()) {
1542       std::string range;
1543       if (node.isNestedDagArg(argIndex)) {
1544         range = childNodeNames.lookup(argIndex);
1545       } else {
1546         range = std::string(node.getArgName(argIndex));
1547       }
1548       // Resolve the symbol for all range use so that we have a uniform way of
1549       // capturing the values.
1550       range = symbolInfoMap.getValueAndRangeUse(range);
1551       os << formatv("for (auto v: {0}) {{\n  tblgen_values.push_back(v);\n}\n",
1552                     range);
1553     } else {
1554       os << formatv("tblgen_values.push_back(");
1555       if (node.isNestedDagArg(argIndex)) {
1556         os << symbolInfoMap.getValueAndRangeUse(
1557             childNodeNames.lookup(argIndex));
1558       } else {
1559         DagLeaf leaf = node.getArgAsLeaf(argIndex);
1560         if (leaf.isConstantAttr())
1561           // TODO: Use better location
1562           PrintFatalError(
1563               loc,
1564               "attribute found where value was expected, if attempting to use "
1565               "constant value, construct a constant op with given attribute "
1566               "instead");
1567 
1568         auto symbol =
1569             symbolInfoMap.getValueAndRangeUse(node.getArgName(argIndex));
1570         if (leaf.isNativeCodeCall()) {
1571           os << std::string(
1572               tgfmt(leaf.getNativeCodeTemplate(), &fmtCtx.withSelf(symbol)));
1573         } else {
1574           os << symbol;
1575         }
1576       }
1577       os << ");\n";
1578     }
1579   }
1580 }
1581 
1582 StaticMatcherHelper::StaticMatcherHelper(RecordOperatorMap &mapper)
1583     : opMap(mapper) {}
1584 
1585 void StaticMatcherHelper::populateStaticMatchers(raw_ostream &os) {
1586   // PatternEmitter will use the static matcher if there's one generated. To
1587   // ensure that all the dependent static matchers are generated before emitting
1588   // the matching logic of the DagNode, we use topological order to achieve it.
1589   for (auto &dagInfo : topologicalOrder) {
1590     DagNode node = dagInfo.first;
1591     if (!useStaticMatcher(node))
1592       continue;
1593 
1594     std::string funcName =
1595         formatv("static_dag_matcher_{0}", staticMatcherCounter++);
1596     assert(matcherNames.find(node) == matcherNames.end());
1597     PatternEmitter(dagInfo.second, &opMap, os, *this)
1598         .emitStaticMatcher(node, funcName);
1599     matcherNames[node] = funcName;
1600   }
1601 }
1602 
1603 void StaticMatcherHelper::addPattern(Record *record) {
1604   Pattern pat(record, &opMap);
1605 
1606   // While generating the function body of the DAG matcher, it may depends on
1607   // other DAG matchers. To ensure the dependent matchers are ready, we compute
1608   // the topological order for all the DAGs and emit the DAG matchers in this
1609   // order.
1610   llvm::unique_function<void(DagNode)> dfs = [&](DagNode node) {
1611     ++refStats[node];
1612 
1613     if (refStats[node] != 1)
1614       return;
1615 
1616     for (unsigned i = 0, e = node.getNumArgs(); i < e; ++i)
1617       if (DagNode sibling = node.getArgAsNestedDag(i))
1618         dfs(sibling);
1619 
1620     topologicalOrder.push_back(std::make_pair(node, record));
1621   };
1622 
1623   dfs(pat.getSourcePattern());
1624 }
1625 
1626 static void emitRewriters(const RecordKeeper &recordKeeper, raw_ostream &os) {
1627   emitSourceFileHeader("Rewriters", os);
1628 
1629   const auto &patterns = recordKeeper.getAllDerivedDefinitions("Pattern");
1630 
1631   // We put the map here because it can be shared among multiple patterns.
1632   RecordOperatorMap recordOpMap;
1633 
1634   // Exam all the patterns and generate static matcher for the duplicated
1635   // DagNode.
1636   StaticMatcherHelper staticMatcher(recordOpMap);
1637   for (Record *p : patterns)
1638     staticMatcher.addPattern(p);
1639   staticMatcher.populateStaticMatchers(os);
1640 
1641   std::vector<std::string> rewriterNames;
1642   rewriterNames.reserve(patterns.size());
1643 
1644   std::string baseRewriterName = "GeneratedConvert";
1645   int rewriterIndex = 0;
1646 
1647   for (Record *p : patterns) {
1648     std::string name;
1649     if (p->isAnonymous()) {
1650       // If no name is provided, ensure unique rewriter names simply by
1651       // appending unique suffix.
1652       name = baseRewriterName + llvm::utostr(rewriterIndex++);
1653     } else {
1654       name = std::string(p->getName());
1655     }
1656     LLVM_DEBUG(llvm::dbgs()
1657                << "=== start generating pattern '" << name << "' ===\n");
1658     PatternEmitter(p, &recordOpMap, os, staticMatcher).emit(name);
1659     LLVM_DEBUG(llvm::dbgs()
1660                << "=== done generating pattern '" << name << "' ===\n");
1661     rewriterNames.push_back(std::move(name));
1662   }
1663 
1664   // Emit function to add the generated matchers to the pattern list.
1665   os << "void LLVM_ATTRIBUTE_UNUSED populateWithGenerated("
1666         "::mlir::RewritePatternSet &patterns) {\n";
1667   for (const auto &name : rewriterNames) {
1668     os << "  patterns.add<" << name << ">(patterns.getContext());\n";
1669   }
1670   os << "}\n";
1671 }
1672 
1673 static mlir::GenRegistration
1674     genRewriters("gen-rewriters", "Generate pattern rewriters",
1675                  [](const RecordKeeper &records, raw_ostream &os) {
1676                    emitRewriters(records, os);
1677                    return false;
1678                  });
1679