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