MLIR  16.0.0git
GreedyPatternRewriteDriver.cpp
Go to the documentation of this file.
1 //===- GreedyPatternRewriteDriver.cpp - A greedy rewriter -----------------===//
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 // This file implements mlir::applyPatternsAndFoldGreedily.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "mlir/IR/Matchers.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/ScopedPrinter.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace mlir;
26 
27 #define DEBUG_TYPE "greedy-rewriter"
28 
29 //===----------------------------------------------------------------------===//
30 // GreedyPatternRewriteDriver
31 //===----------------------------------------------------------------------===//
32 
33 namespace {
34 /// This is a worklist-driven driver for the PatternMatcher, which repeatedly
35 /// applies the locally optimal patterns in a roughly "bottom up" way.
36 class GreedyPatternRewriteDriver : public PatternRewriter {
37 public:
38  explicit GreedyPatternRewriteDriver(MLIRContext *ctx,
39  const FrozenRewritePatternSet &patterns,
40  const GreedyRewriteConfig &config);
41 
42  /// Simplify the operations within the given regions.
43  bool simplify(MutableArrayRef<Region> regions);
44 
45  /// Add the given operation to the worklist.
46  virtual void addToWorklist(Operation *op);
47 
48  /// Pop the next operation from the worklist.
49  Operation *popFromWorklist();
50 
51  /// If the specified operation is in the worklist, remove it.
52  void removeFromWorklist(Operation *op);
53 
54  /// Notifies the driver that the specified operation may have been modified
55  /// in-place.
56  void finalizeRootUpdate(Operation *op) override;
57 
58 protected:
59  // Implement the hook for inserting operations, and make sure that newly
60  // inserted ops are added to the worklist for processing.
61  void notifyOperationInserted(Operation *op) override;
62 
63  // Look over the provided operands for any defining operations that should
64  // be re-added to the worklist. This function should be called when an
65  // operation is modified or removed, as it may trigger further
66  // simplifications.
67  void addOperandsToWorklist(ValueRange operands);
68 
69  // If an operation is about to be removed, make sure it is not in our
70  // worklist anymore because we'd get dangling references to it.
71  void notifyOperationRemoved(Operation *op) override;
72 
73  // When the root of a pattern is about to be replaced, it can trigger
74  // simplifications to its users - make sure to add them to the worklist
75  // before the root is changed.
76  void notifyRootReplaced(Operation *op, ValueRange replacement) override;
77 
78  /// PatternRewriter hook for erasing a dead operation.
79  void eraseOp(Operation *op) override;
80 
81  /// PatternRewriter hook for notifying match failure reasons.
83  notifyMatchFailure(Location loc,
84  function_ref<void(Diagnostic &)> reasonCallback) override;
85 
86  /// The low-level pattern applicator.
87  PatternApplicator matcher;
88 
89  /// The worklist for this transformation keeps track of the operations that
90  /// need to be revisited, plus their index in the worklist. This allows us to
91  /// efficiently remove operations from the worklist when they are erased, even
92  /// if they aren't the root of a pattern.
93  std::vector<Operation *> worklist;
95 
96  /// Non-pattern based folder for operations.
97  OperationFolder folder;
98 
99 private:
100  /// Configuration information for how to simplify.
101  GreedyRewriteConfig config;
102 
103 #ifndef NDEBUG
104  /// A logger used to emit information during the application process.
105  llvm::ScopedPrinter logger{llvm::dbgs()};
106 #endif
107 };
108 } // namespace
109 
110 GreedyPatternRewriteDriver::GreedyPatternRewriteDriver(
111  MLIRContext *ctx, const FrozenRewritePatternSet &patterns,
112  const GreedyRewriteConfig &config)
113  : PatternRewriter(ctx), matcher(patterns), folder(ctx), config(config) {
114  worklist.reserve(64);
115 
116  // Apply a simple cost model based solely on pattern benefit.
117  matcher.applyDefaultCostModel();
118 }
119 
120 bool GreedyPatternRewriteDriver::simplify(MutableArrayRef<Region> regions) {
121 #ifndef NDEBUG
122  const char *logLineComment =
123  "//===-------------------------------------------===//\n";
124 
125  /// A utility function to log a process result for the given reason.
126  auto logResult = [&](StringRef result, const llvm::Twine &msg = {}) {
127  logger.unindent();
128  logger.startLine() << "} -> " << result;
129  if (!msg.isTriviallyEmpty())
130  logger.getOStream() << " : " << msg;
131  logger.getOStream() << "\n";
132  };
133  auto logResultWithLine = [&](StringRef result, const llvm::Twine &msg = {}) {
134  logResult(result, msg);
135  logger.startLine() << logLineComment;
136  };
137 #endif
138 
139  auto insertKnownConstant = [&](Operation *op) {
140  // Check for existing constants when populating the worklist. This avoids
141  // accidentally reversing the constant order during processing.
142  Attribute constValue;
143  if (matchPattern(op, m_Constant(&constValue)))
144  if (!folder.insertKnownConstant(op, constValue))
145  return true;
146  return false;
147  };
148 
149  bool changed = false;
150  unsigned iteration = 0;
151  do {
152  worklist.clear();
153  worklistMap.clear();
154 
155  if (!config.useTopDownTraversal) {
156  // Add operations to the worklist in postorder.
157  for (auto &region : regions) {
158  region.walk([&](Operation *op) {
159  if (!insertKnownConstant(op))
160  addToWorklist(op);
161  });
162  }
163  } else {
164  // Add all nested operations to the worklist in preorder.
165  for (auto &region : regions) {
166  region.walk<WalkOrder::PreOrder>([&](Operation *op) {
167  if (!insertKnownConstant(op)) {
168  worklist.push_back(op);
169  return WalkResult::advance();
170  }
171  return WalkResult::skip();
172  });
173  }
174 
175  // Reverse the list so our pop-back loop processes them in-order.
176  std::reverse(worklist.begin(), worklist.end());
177  // Remember the reverse index.
178  for (size_t i = 0, e = worklist.size(); i != e; ++i)
179  worklistMap[worklist[i]] = i;
180  }
181 
182  // These are scratch vectors used in the folding loop below.
183  SmallVector<Value, 8> originalOperands, resultValues;
184 
185  changed = false;
186  while (!worklist.empty()) {
187  auto *op = popFromWorklist();
188 
189  // Nulls get added to the worklist when operations are removed, ignore
190  // them.
191  if (op == nullptr)
192  continue;
193 
194  LLVM_DEBUG({
195  logger.getOStream() << "\n";
196  logger.startLine() << logLineComment;
197  logger.startLine() << "Processing operation : '" << op->getName()
198  << "'(" << op << ") {\n";
199  logger.indent();
200 
201  // If the operation has no regions, just print it here.
202  if (op->getNumRegions() == 0) {
203  op->print(
204  logger.startLine(),
205  OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs());
206  logger.getOStream() << "\n\n";
207  }
208  });
209 
210  // If the operation is trivially dead - remove it.
211  if (isOpTriviallyDead(op)) {
212  notifyOperationRemoved(op);
213  op->erase();
214  changed = true;
215 
216  LLVM_DEBUG(logResultWithLine("success", "operation is trivially dead"));
217  continue;
218  }
219 
220  // Collects all the operands and result uses of the given `op` into work
221  // list. Also remove `op` and nested ops from worklist.
222  originalOperands.assign(op->operand_begin(), op->operand_end());
223  auto preReplaceAction = [&](Operation *op) {
224  // Add the operands to the worklist for visitation.
225  addOperandsToWorklist(originalOperands);
226 
227  // Add all the users of the result to the worklist so we make sure
228  // to revisit them.
229  for (auto result : op->getResults())
230  for (auto *userOp : result.getUsers())
231  addToWorklist(userOp);
232 
233  notifyOperationRemoved(op);
234  };
235 
236  // Add the given operation to the worklist.
237  auto collectOps = [this](Operation *op) { addToWorklist(op); };
238 
239  // Try to fold this op.
240  bool inPlaceUpdate;
241  if ((succeeded(folder.tryToFold(op, collectOps, preReplaceAction,
242  &inPlaceUpdate)))) {
243  LLVM_DEBUG(logResultWithLine("success", "operation was folded"));
244 
245  changed = true;
246  if (!inPlaceUpdate)
247  continue;
248  }
249 
250  // Try to match one of the patterns. The rewriter is automatically
251  // notified of any necessary changes, so there is nothing else to do
252  // here.
253 #ifndef NDEBUG
254  auto canApply = [&](const Pattern &pattern) {
255  LLVM_DEBUG({
256  logger.getOStream() << "\n";
257  logger.startLine() << "* Pattern " << pattern.getDebugName() << " : '"
258  << op->getName() << " -> (";
259  llvm::interleaveComma(pattern.getGeneratedOps(), logger.getOStream());
260  logger.getOStream() << ")' {\n";
261  logger.indent();
262  });
263  return true;
264  };
265  auto onFailure = [&](const Pattern &pattern) {
266  LLVM_DEBUG(logResult("failure", "pattern failed to match"));
267  };
268  auto onSuccess = [&](const Pattern &pattern) {
269  LLVM_DEBUG(logResult("success", "pattern applied successfully"));
270  return success();
271  };
272 
273  LogicalResult matchResult =
274  matcher.matchAndRewrite(op, *this, canApply, onFailure, onSuccess);
275  if (succeeded(matchResult))
276  LLVM_DEBUG(logResultWithLine("success", "pattern matched"));
277  else
278  LLVM_DEBUG(logResultWithLine("failure", "pattern failed to match"));
279 #else
280  LogicalResult matchResult = matcher.matchAndRewrite(op, *this);
281 #endif
282  changed |= succeeded(matchResult);
283  }
284 
285  // After applying patterns, make sure that the CFG of each of the regions
286  // is kept up to date.
287  if (config.enableRegionSimplification)
288  changed |= succeeded(simplifyRegions(*this, regions));
289  } while (changed &&
290  (iteration++ < config.maxIterations ||
291  config.maxIterations == GreedyRewriteConfig::kNoIterationLimit));
292 
293  // Whether the rewrite converges, i.e. wasn't changed in the last iteration.
294  return !changed;
295 }
296 
297 void GreedyPatternRewriteDriver::addToWorklist(Operation *op) {
298  // Check to see if the worklist already contains this op.
299  if (worklistMap.count(op))
300  return;
301 
302  worklistMap[op] = worklist.size();
303  worklist.push_back(op);
304 }
305 
306 Operation *GreedyPatternRewriteDriver::popFromWorklist() {
307  auto *op = worklist.back();
308  worklist.pop_back();
309 
310  // This operation is no longer in the worklist, keep worklistMap up to date.
311  if (op)
312  worklistMap.erase(op);
313  return op;
314 }
315 
316 void GreedyPatternRewriteDriver::removeFromWorklist(Operation *op) {
317  auto it = worklistMap.find(op);
318  if (it != worklistMap.end()) {
319  assert(worklist[it->second] == op && "malformed worklist data structure");
320  worklist[it->second] = nullptr;
321  worklistMap.erase(it);
322  }
323 }
324 
325 void GreedyPatternRewriteDriver::notifyOperationInserted(Operation *op) {
326  LLVM_DEBUG({
327  logger.startLine() << "** Insert : '" << op->getName() << "'(" << op
328  << ")\n";
329  });
330  addToWorklist(op);
331 }
332 
333 void GreedyPatternRewriteDriver::finalizeRootUpdate(Operation *op) {
334  LLVM_DEBUG({
335  logger.startLine() << "** Modified: '" << op->getName() << "'(" << op
336  << ")\n";
337  });
338  addToWorklist(op);
339 }
340 
341 void GreedyPatternRewriteDriver::addOperandsToWorklist(ValueRange operands) {
342  for (Value operand : operands) {
343  // If the use count of this operand is now < 2, we re-add the defining
344  // operation to the worklist.
345  // TODO: This is based on the fact that zero use operations
346  // may be deleted, and that single use values often have more
347  // canonicalization opportunities.
348  if (!operand || (!operand.use_empty() && !operand.hasOneUse()))
349  continue;
350  if (auto *defOp = operand.getDefiningOp())
351  addToWorklist(defOp);
352  }
353 }
354 
355 void GreedyPatternRewriteDriver::notifyOperationRemoved(Operation *op) {
356  addOperandsToWorklist(op->getOperands());
357  op->walk([this](Operation *operation) {
358  removeFromWorklist(operation);
359  folder.notifyRemoval(operation);
360  });
361 }
362 
363 void GreedyPatternRewriteDriver::notifyRootReplaced(Operation *op,
364  ValueRange replacement) {
365  LLVM_DEBUG({
366  logger.startLine() << "** Replace : '" << op->getName() << "'(" << op
367  << ")\n";
368  });
369  for (auto result : op->getResults())
370  for (auto *user : result.getUsers())
371  addToWorklist(user);
372 }
373 
374 void GreedyPatternRewriteDriver::eraseOp(Operation *op) {
375  LLVM_DEBUG({
376  logger.startLine() << "** Erase : '" << op->getName() << "'(" << op
377  << ")\n";
378  });
379  PatternRewriter::eraseOp(op);
380 }
381 
382 LogicalResult GreedyPatternRewriteDriver::notifyMatchFailure(
383  Location loc, function_ref<void(Diagnostic &)> reasonCallback) {
384  LLVM_DEBUG({
385  Diagnostic diag(loc, DiagnosticSeverity::Remark);
386  reasonCallback(diag);
387  logger.startLine() << "** Failure : " << diag.str() << "\n";
388  });
389  return failure();
390 }
391 
392 /// Rewrite the regions of the specified operation, which must be isolated from
393 /// above, by repeatedly applying the highest benefit patterns in a greedy
394 /// work-list driven manner. Return success if no more patterns can be matched
395 /// in the result operation regions. Note: This does not apply patterns to the
396 /// top-level operation itself.
397 ///
400  const FrozenRewritePatternSet &patterns,
401  GreedyRewriteConfig config) {
402  if (regions.empty())
403  return success();
404 
405  // The top-level operation must be known to be isolated from above to
406  // prevent performing canonicalizations on operations defined at or above
407  // the region containing 'op'.
408  auto regionIsIsolated = [](Region &region) {
409  return region.getParentOp()->hasTrait<OpTrait::IsIsolatedFromAbove>();
410  };
411  (void)regionIsIsolated;
412  assert(llvm::all_of(regions, regionIsIsolated) &&
413  "patterns can only be applied to operations IsolatedFromAbove");
414 
415  // Start the pattern driver.
416  GreedyPatternRewriteDriver driver(regions[0].getContext(), patterns, config);
417  bool converged = driver.simplify(regions);
418  LLVM_DEBUG(if (!converged) {
419  llvm::dbgs() << "The pattern rewrite doesn't converge after scanning "
420  << config.maxIterations << " times\n";
421  });
422  return success(converged);
423 }
424 
425 //===----------------------------------------------------------------------===//
426 // OpPatternRewriteDriver
427 //===----------------------------------------------------------------------===//
428 
429 namespace {
430 /// This is a simple driver for the PatternMatcher to apply patterns and perform
431 /// folding on a single op. It repeatedly applies locally optimal patterns.
432 class OpPatternRewriteDriver : public PatternRewriter {
433 public:
434  explicit OpPatternRewriteDriver(MLIRContext *ctx,
435  const FrozenRewritePatternSet &patterns)
436  : PatternRewriter(ctx), matcher(patterns), folder(ctx) {
437  // Apply a simple cost model based solely on pattern benefit.
438  matcher.applyDefaultCostModel();
439  }
440 
441  LogicalResult simplifyLocally(Operation *op, int maxIterations, bool &erased);
442 
443  // These are hooks implemented for PatternRewriter.
444 protected:
445  /// If an operation is about to be removed, mark it so that we can let clients
446  /// know.
447  void notifyOperationRemoved(Operation *op) override {
448  opErasedViaPatternRewrites = true;
449  }
450 
451  // When a root is going to be replaced, its removal will be notified as well.
452  // So there is nothing to do here.
453  void notifyRootReplaced(Operation *op, ValueRange replacement) override {}
454 
455 private:
456  /// The low-level pattern applicator.
457  PatternApplicator matcher;
458 
459  /// Non-pattern based folder for operations.
460  OperationFolder folder;
461 
462  /// Set to true if the operation has been erased via pattern rewrites.
463  bool opErasedViaPatternRewrites = false;
464 };
465 
466 } // namespace
467 
468 /// Performs the rewrites and folding only on `op`. The simplification
469 /// converges if the op is erased as a result of being folded, replaced, or
470 /// becoming dead, or no more changes happen in an iteration. Returns success if
471 /// the rewrite converges in `maxIterations`. `erased` is set to true if `op`
472 /// gets erased.
473 LogicalResult OpPatternRewriteDriver::simplifyLocally(Operation *op,
474  int maxIterations,
475  bool &erased) {
476  bool changed = false;
477  erased = false;
478  opErasedViaPatternRewrites = false;
479  int iterations = 0;
480  // Iterate until convergence or until maxIterations. Deletion of the op as
481  // a result of being dead or folded is convergence.
482  do {
483  changed = false;
484 
485  // If the operation is trivially dead - remove it.
486  if (isOpTriviallyDead(op)) {
487  op->erase();
488  erased = true;
489  return success();
490  }
491 
492  // Try to fold this op.
493  bool inPlaceUpdate;
494  if (succeeded(folder.tryToFold(op, /*processGeneratedConstants=*/nullptr,
495  /*preReplaceAction=*/nullptr,
496  &inPlaceUpdate))) {
497  changed = true;
498  if (!inPlaceUpdate) {
499  erased = true;
500  return success();
501  }
502  }
503 
504  // Try to match one of the patterns. The rewriter is automatically
505  // notified of any necessary changes, so there is nothing else to do here.
506  changed |= succeeded(matcher.matchAndRewrite(op, *this));
507  if ((erased = opErasedViaPatternRewrites))
508  return success();
509  } while (changed &&
510  (++iterations < maxIterations ||
511  maxIterations == GreedyRewriteConfig::kNoIterationLimit));
512 
513  // Whether the rewrite converges, i.e. wasn't changed in the last iteration.
514  return failure(changed);
515 }
516 
517 //===----------------------------------------------------------------------===//
518 // MultiOpPatternRewriteDriver
519 //===----------------------------------------------------------------------===//
520 
521 namespace {
522 
523 /// This is a specialized GreedyPatternRewriteDriver to apply patterns and
524 /// perform folding for a supplied set of ops. It repeatedly simplifies while
525 /// restricting the rewrites to only the provided set of ops or optionally
526 /// to those directly affected by it (result users or operand providers).
527 class MultiOpPatternRewriteDriver : public GreedyPatternRewriteDriver {
528 public:
529  explicit MultiOpPatternRewriteDriver(MLIRContext *ctx,
530  const FrozenRewritePatternSet &patterns,
531  bool strict)
532  : GreedyPatternRewriteDriver(ctx, patterns, GreedyRewriteConfig()),
533  strictMode(strict) {}
534 
535  bool simplifyLocally(ArrayRef<Operation *> op);
536 
537  void addToWorklist(Operation *op) override {
538  if (!strictMode || strictModeFilteredOps.contains(op))
539  GreedyPatternRewriteDriver::addToWorklist(op);
540  }
541 
542 private:
543  void notifyOperationInserted(Operation *op) override {
544  GreedyPatternRewriteDriver::notifyOperationInserted(op);
545  if (strictMode)
546  strictModeFilteredOps.insert(op);
547  }
548 
549  void notifyOperationRemoved(Operation *op) override {
550  GreedyPatternRewriteDriver::notifyOperationRemoved(op);
551  if (strictMode)
552  strictModeFilteredOps.erase(op);
553  }
554 
555  /// If `strictMode` is true, any pre-existing ops outside of
556  /// `strictModeFilteredOps` remain completely untouched by the rewrite driver.
557  /// If `strictMode` is false, operations that use results of (or supply
558  /// operands to) any rewritten ops stemming from the simplification of the
559  /// provided ops are in turn simplified; any other ops still remain untouched
560  /// (i.e., regardless of `strictMode`).
561  bool strictMode = false;
562 
563  /// The list of ops we are restricting our rewrites to if `strictMode` is on.
564  /// These include the supplied set of ops as well as new ops created while
565  /// rewriting those ops. This set is not maintained when strictMode is off.
566  llvm::SmallDenseSet<Operation *, 4> strictModeFilteredOps;
567 };
568 
569 } // namespace
570 
571 /// Performs the specified rewrites on `ops` while also trying to fold these ops
572 /// as well as any other ops that were in turn created due to these rewrite
573 /// patterns. Any pre-existing ops outside of `ops` remain completely
574 /// unmodified if `strictMode` is true. If `strictMode` is false, other
575 /// operations that use results of rewritten ops or supply operands to such ops
576 /// are in turn simplified; any other ops still remain unmodified (i.e.,
577 /// regardless of `strictMode`). Note that ops in `ops` could be erased as a
578 /// result of folding, becoming dead, or via pattern rewrites. Returns true if
579 /// at all any changes happened.
580 // Unlike `OpPatternRewriteDriver::simplifyLocally` which works on a single op
581 // or GreedyPatternRewriteDriver::simplify, this method just iterates until
582 // the worklist is empty. As our objective is to keep simplification "local",
583 // there is no strong rationale to re-add all operations into the worklist and
584 // rerun until an iteration changes nothing. If more widereaching simplification
585 // is desired, GreedyPatternRewriteDriver should be used.
586 bool MultiOpPatternRewriteDriver::simplifyLocally(ArrayRef<Operation *> ops) {
587  if (strictMode) {
588  strictModeFilteredOps.clear();
589  strictModeFilteredOps.insert(ops.begin(), ops.end());
590  }
591 
592  bool changed = false;
593  worklist.clear();
594  worklistMap.clear();
595  for (Operation *op : ops)
596  addToWorklist(op);
597 
598  // These are scratch vectors used in the folding loop below.
599  SmallVector<Value, 8> originalOperands, resultValues;
600  while (!worklist.empty()) {
601  Operation *op = popFromWorklist();
602 
603  // Nulls get added to the worklist when operations are removed, ignore
604  // them.
605  if (op == nullptr)
606  continue;
607 
608  assert((!strictMode || strictModeFilteredOps.contains(op)) &&
609  "unexpected op was inserted under strict mode");
610 
611  // If the operation is trivially dead - remove it.
612  if (isOpTriviallyDead(op)) {
613  notifyOperationRemoved(op);
614  op->erase();
615  changed = true;
616  continue;
617  }
618 
619  // Collects all the operands and result uses of the given `op` into work
620  // list. Also remove `op` and nested ops from worklist.
621  originalOperands.assign(op->operand_begin(), op->operand_end());
622  auto preReplaceAction = [&](Operation *op) {
623  // Add the operands to the worklist for visitation.
624  addOperandsToWorklist(originalOperands);
625 
626  // Add all the users of the result to the worklist so we make sure
627  // to revisit them.
628  for (Value result : op->getResults()) {
629  for (Operation *userOp : result.getUsers())
630  addToWorklist(userOp);
631  }
632 
633  notifyOperationRemoved(op);
634  };
635 
636  // Add the given operation generated by the folder to the worklist.
637  auto processGeneratedConstants = [this](Operation *op) {
638  notifyOperationInserted(op);
639  };
640 
641  // Try to fold this op.
642  bool inPlaceUpdate;
643  if (succeeded(folder.tryToFold(op, processGeneratedConstants,
644  preReplaceAction, &inPlaceUpdate))) {
645  changed = true;
646  if (!inPlaceUpdate) {
647  // Op has been erased.
648  continue;
649  }
650  }
651 
652  // Try to match one of the patterns. The rewriter is automatically
653  // notified of any necessary changes, so there is nothing else to do
654  // here.
655  changed |= succeeded(matcher.matchAndRewrite(op, *this));
656  }
657 
658  return changed;
659 }
660 
661 /// Rewrites only `op` using the supplied canonicalization patterns and
662 /// folding. `erased` is set to true if the op is erased as a result of being
663 /// folded, replaced, or dead.
665  Operation *op, const FrozenRewritePatternSet &patterns, bool *erased) {
666  // Start the pattern driver.
667  GreedyRewriteConfig config;
668  OpPatternRewriteDriver driver(op->getContext(), patterns);
669  bool opErased;
670  LogicalResult converged =
671  driver.simplifyLocally(op, config.maxIterations, opErased);
672  if (erased)
673  *erased = opErased;
674  LLVM_DEBUG(if (failed(converged)) {
675  llvm::dbgs() << "The pattern rewrite doesn't converge after scanning "
676  << config.maxIterations << " times";
677  });
678  return converged;
679 }
680 
682  const FrozenRewritePatternSet &patterns,
683  bool strict) {
684  if (ops.empty())
685  return false;
686 
687  // Start the pattern driver.
688  MultiOpPatternRewriteDriver driver(ops.front()->getContext(), patterns,
689  strict);
690  return driver.simplifyLocally(ops);
691 }
static std::string diag(llvm::Value &value)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Definition: Diagnostics.h:155
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This class allows control over how the GreedyPatternRewriteDriver works.
int64_t maxIterations
This specifies the maximum number of times the rewriter will iterate between applying patterns and si...
bool useTopDownTraversal
This specifies the order of initial traversal that populates the rewriters worklist.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:64
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:56
This class provides the API for ops that are known to be isolated from above.
A utility class for folding operations, and unifying duplicated constants generated along the way.
Definition: FoldUtils.h:32
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
operand_iterator operand_begin()
Definition: Operation.h:291
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:147
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition: Operation.h:477
operand_iterator operand_end()
Definition: Operation.h:292
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:50
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:295
user_range getUsers()
Returns a range of all users.
Definition: Operation.h:654
result_range getResults()
Definition: Operation.h:332
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Definition: Operation.h:578
void erase()
Remove this operation from its parent block and delete it.
Definition: Operation.cpp:418
This class manages the application of a group of rewrite patterns, with a user-provided cost model.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:610
This class contains all of the data related to a pattern, but does not contain any methods or logic f...
Definition: PatternMatch.h:71
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
virtual void notifyRootReplaced(Operation *op, ValueRange replacement)
These are the callback methods that subclasses can choose to implement if they would like to be notif...
Definition: PatternMatch.h:561
virtual void notifyOperationRemoved(Operation *op)
This is called on an operation that a rewrite is removing, right before the operation is deleted.
Definition: PatternMatch.h:565
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:349
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition: Matchers.h:329
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult simplifyRegions(RewriterBase &rewriter, MutableArrayRef< Region > regions)
Run a set of structural simplifications over the given regions.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
LogicalResult applyPatternsAndFoldGreedily(MutableArrayRef< Region > regions, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig())
Rewrite the regions of the specified operation, which must be isolated from above,...
bool isOpTriviallyDead(Operation *op)
Return true if the given operation is unused, and has no side effects on memory that prevent erasing.
LogicalResult applyOpPatternsAndFold(Operation *op, const FrozenRewritePatternSet &patterns, bool *erased=nullptr)
Applies the specified patterns on op alone while also trying to fold it, by selecting the highest ben...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Definition: Matchers.h:255
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26