15#include "mlir/Config/mlir-config.h"
27#include "llvm/ADT/BitVector.h"
28#include "llvm/ADT/DenseMap.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/Support/DebugLog.h"
31#include "llvm/Support/ScopedPrinter.h"
32#include "llvm/Support/raw_ostream.h"
34#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
40#define DEBUG_TYPE "greedy-rewriter"
48#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
63 void computeFingerPrints(
Operation *topLevel) {
64 this->topLevel = topLevel;
65 this->topLevelFingerPrint.emplace(topLevel);
67 fingerprints.try_emplace(op, op,
false);
74 topLevelFingerPrint.reset();
78 void notifyRewriteSuccess() {
83 if (failed(
verify(topLevel)))
84 llvm::report_fatal_error(
"IR failed to verify after pattern application");
88 if (*topLevelFingerPrint == afterFingerPrint) {
90 llvm::report_fatal_error(
91 "pattern returned success but IR did not change");
93 for (
const auto &it : fingerprints) {
95 if (it.first == topLevel)
106 llvm::report_fatal_error(
"operation finger print changed");
111 void notifyRewriteFailure() {
117 if (*topLevelFingerPrint != afterFingerPrint) {
119 llvm::report_fatal_error(
"pattern returned failure but IR did change");
123 void notifyFoldingSuccess() {
128 if (failed(
verify(topLevel)))
129 llvm::report_fatal_error(
"IR failed to verify after folding");
134 void invalidateFingerPrint(
Operation *op) { fingerprints.erase(op); }
155 invalidateFingerPrint(op);
160 op->
walk([
this](
Operation *op) { invalidateFingerPrint(op); });
172 std::optional<OperationFingerPrint> topLevelFingerPrint;
184static void logSuccessfulFolding(
Operation *op) {
185 LDBG() <<
"// *** IR Dump After Successful Folding ***\n"
226 std::vector<Operation *> list;
232Worklist::Worklist() { list.reserve(64); }
234void Worklist::clear() {
239bool Worklist::empty()
const {
241 return !llvm::any_of(list,
242 [](
Operation *op) {
return static_cast<bool>(op); });
246 assert(op &&
"cannot push nullptr to worklist");
248 if (!map.insert({op, list.size()}).second)
254 assert(!empty() &&
"cannot pop from empty worklist");
262 while (!list.empty() && !list.back())
268 assert(op &&
"cannot remove nullptr from worklist");
269 auto it = map.find(op);
270 if (it != map.end()) {
271 assert(list[it->second] == op &&
"malformed worklist data structure");
272 list[it->second] =
nullptr;
277void Worklist::reverse() {
278 std::reverse(list.begin(), list.end());
279 for (
size_t i = 0, e = list.size(); i != e; ++i)
283#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
288class RandomizedWorklist :
public Worklist {
290 RandomizedWorklist() : Worklist() {
291 generator.seed(MLIR_GREEDY_REWRITE_RANDOMIZER_SEED);
298 assert(!list.empty() &&
"cannot pop from empty worklist");
301 list.
erase(list.begin() + pos);
302 for (
int64_t i = pos, e = list.size(); i < e; ++i)
326 explicit GreedyPatternRewriteDriver(
MLIRContext *ctx,
331 void addSingleOpToWorklist(
Operation *op);
338 void notifyOperationModified(
Operation *op)
override;
343 void notifyOperationInserted(
Operation *op,
349 void notifyOperationErased(
Operation *op)
override;
357 bool processWorklist();
365#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
366 RandomizedWorklist worklist;
378 llvm::SmallDenseSet<Operation *, 4> strictModeFilteredOps;
385 void addOperandsToWorklist(
Operation *op);
388 void notifyBlockInserted(
Block *block,
Region *previous,
392 void notifyBlockErased(
Block *block)
override;
402 llvm::impl::raw_ldbg_ostream os{(Twine(
"[") +
DEBUG_TYPE +
":1] ").str(),
405 llvm::ScopedPrinter logger{os};
411#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
412 ExpensiveChecks expensiveChecks;
417GreedyPatternRewriteDriver::GreedyPatternRewriteDriver(
418 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
419 const GreedyRewriteConfig &config)
420 : rewriter(ctx), config(config), matcher(patterns)
421#
if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
425 config.getScope() ? config.getScope()->getParentOp()
431 matcher.applyDefaultCostModel();
434#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
443bool GreedyPatternRewriteDriver::processWorklist() {
445 const char *logLineComment =
446 "//===-------------------------------------------===//\n";
449 auto logResult = [&](StringRef
result,
const llvm::Twine &msg = {}) {
451 logger.startLine() <<
"} -> " <<
result;
452 if (!msg.isTriviallyEmpty())
453 logger.getOStream() <<
" : " << msg;
454 logger.getOStream() <<
"\n";
456 auto logResultWithLine = [&](StringRef
result,
const llvm::Twine &msg = {}) {
458 logger.startLine() << logLineComment;
462 bool changed =
false;
463 int64_t numRewrites = 0;
464 while (!worklist.empty() &&
467 auto *op = worklist.pop();
470 logger.getOStream() <<
"\n";
471 logger.startLine() << logLineComment;
472 logger.startLine() <<
"Processing operation : '" << op->getName() <<
"'("
477 if (op->getNumRegions() == 0) {
480 OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs());
481 logger.getOStream() <<
"\n\n";
490 LLVM_DEBUG(logResultWithLine(
"success",
"operation is trivially dead"));
499 SmallVector<OpFoldResult> foldResults;
500 if (succeeded(op->fold(foldResults))) {
501 LLVM_DEBUG(logResultWithLine(
"success",
"operation was folded"));
505 if (foldResults.empty()) {
507 notifyOperationModified(op);
509 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
510#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
511 expensiveChecks.notifyFoldingSuccess();
517 assert(foldResults.size() == op->getNumResults() &&
518 "folder produced incorrect number of results");
519 OpBuilder::InsertionGuard g(rewriter);
521 SmallVector<Value> replacements;
522 bool materializationSucceeded =
true;
523 for (
auto [ofr, resultType] :
524 llvm::zip_equal(foldResults, op->getResultTypes())) {
525 if (
auto value = dyn_cast<Value>(ofr)) {
526 assert(value.getType() == resultType &&
527 "folder produced value of incorrect type");
528 replacements.push_back(value);
532 Operation *constOp = op->getDialect()->materializeConstant(
533 rewriter, cast<Attribute>(ofr), resultType, op->getLoc());
538 llvm::SmallDenseSet<Operation *> replacementOps;
541 "folder reused existing op for one result but constant "
542 "materialization failed for another result");
543 replacementOps.insert(
replacement.getDefiningOp());
545 for (Operation *op : replacementOps) {
549 materializationSucceeded =
false;
553 assert(constOp->
hasTrait<OpTrait::ConstantLike>() &&
554 "materializeConstant produced op that is not a ConstantLike");
556 "materializeConstant produced incorrect result type");
557 replacements.push_back(constOp->
getResult(0));
560 if (materializationSucceeded) {
563 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
564#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
565 expensiveChecks.notifyFoldingSuccess();
575 auto canApplyCallback = [&](
const Pattern &pattern) {
577 logger.getOStream() <<
"\n";
578 logger.startLine() <<
"* Pattern " << pattern.getDebugName() <<
" : '"
579 << op->getName() <<
" -> (";
580 llvm::interleaveComma(pattern.getGeneratedOps(), logger.getOStream());
581 logger.getOStream() <<
")' {\n";
584 if (RewriterBase::Listener *listener = config.
getListener())
585 listener->notifyPatternBegin(pattern, op);
588 function_ref<bool(
const Pattern &)> canApply = canApplyCallback;
589 auto onFailureCallback = [&](
const Pattern &pattern) {
590 LLVM_DEBUG(logResult(
"failure",
"pattern failed to match"));
591 if (RewriterBase::Listener *listener = config.
getListener())
592 listener->notifyPatternEnd(pattern, failure());
594 function_ref<void(
const Pattern &)> onFailure = onFailureCallback;
595 auto onSuccessCallback = [&](
const Pattern &pattern) {
596 LLVM_DEBUG(logResult(
"success",
"pattern applied successfully"));
597 if (RewriterBase::Listener *listener = config.
getListener())
598 listener->notifyPatternEnd(pattern,
success());
601 function_ref<LogicalResult(
const Pattern &)> onSuccess = onSuccessCallback;
613#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
617 llvm::scope_exit clearFingerprints([&]() { expensiveChecks.clear(); });
620 LogicalResult matchResult =
623 if (succeeded(matchResult)) {
624 LLVM_DEBUG(logResultWithLine(
"success",
"at least one pattern matched"));
625#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
626 expensiveChecks.notifyRewriteSuccess();
631 LLVM_DEBUG(logResultWithLine(
"failure",
"all patterns failed to match"));
632#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
633 expensiveChecks.notifyRewriteFailure();
641void GreedyPatternRewriteDriver::addToWorklist(Operation *op) {
642 assert(op &&
"expected valid op");
644 SmallVector<Operation *, 8> ancestors;
645 Region *region =
nullptr;
647 ancestors.push_back(op);
651 for (Operation *op : ancestors)
652 addSingleOpToWorklist(op);
655 if (region ==
nullptr)
660void GreedyPatternRewriteDriver::addSingleOpToWorklist(Operation *op) {
661 if (config.
getStrictness() == GreedyRewriteStrictness::AnyOp ||
662 strictModeFilteredOps.contains(op))
666void GreedyPatternRewriteDriver::notifyBlockInserted(
668 if (RewriterBase::Listener *listener = config.
getListener())
669 listener->notifyBlockInserted(block, previous, previousIt);
672void GreedyPatternRewriteDriver::notifyBlockErased(
Block *block) {
673 if (RewriterBase::Listener *listener = config.
getListener())
674 listener->notifyBlockErased(block);
677void GreedyPatternRewriteDriver::notifyOperationInserted(
678 Operation *op, OpBuilder::InsertPoint previous) {
680 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
683 if (RewriterBase::Listener *listener = config.
getListener())
684 listener->notifyOperationInserted(op, previous);
685 if (config.
getStrictness() == GreedyRewriteStrictness::ExistingAndNewOps)
686 strictModeFilteredOps.insert(op);
690void GreedyPatternRewriteDriver::notifyOperationModified(Operation *op) {
692 logger.startLine() <<
"** Modified: '" << op->
getName() <<
"'(" << op
695 if (RewriterBase::Listener *listener = config.
getListener())
696 listener->notifyOperationModified(op);
700void GreedyPatternRewriteDriver::addOperandsToWorklist(Operation *op) {
710 auto *defOp = operand.getDefiningOp();
714 Operation *otherUser =
nullptr;
715 bool hasMoreThanTwoUses =
false;
716 for (
auto *user : operand.getUsers()) {
717 if (user == op || user == otherUser)
723 hasMoreThanTwoUses =
true;
726 if (hasMoreThanTwoUses)
729 addToWorklist(defOp);
733void GreedyPatternRewriteDriver::notifyOperationErased(Operation *op) {
735 logger.startLine() <<
"** Erase : '" << op->
getName() <<
"'(" << op
747 "scope region must not be erased during greedy pattern rewrite");
750 if (RewriterBase::Listener *listener = config.
getListener())
751 listener->notifyOperationErased(op);
753 addOperandsToWorklist(op);
756 if (config.
getStrictness() != GreedyRewriteStrictness::AnyOp)
757 strictModeFilteredOps.erase(op);
760void GreedyPatternRewriteDriver::notifyOperationReplaced(
763 logger.startLine() <<
"** Replace : '" << op->
getName() <<
"'(" << op
766 if (RewriterBase::Listener *listener = config.
getListener())
767 listener->notifyOperationReplaced(op,
replacement);
770void GreedyPatternRewriteDriver::notifyMatchFailure(
771 Location loc,
function_ref<
void(Diagnostic &)> reasonCallback) {
773 Diagnostic
diag(loc, DiagnosticSeverity::Remark);
774 reasonCallback(
diag);
775 logger.startLine() <<
"** Match Failure : " <<
diag.str() <<
"\n";
777 if (RewriterBase::Listener *listener = config.
getListener())
778 listener->notifyMatchFailure(loc, reasonCallback);
788class RegionPatternRewriteDriver :
public GreedyPatternRewriteDriver {
790 explicit RegionPatternRewriteDriver(MLIRContext *ctx,
791 const FrozenRewritePatternSet &patterns,
792 const GreedyRewriteConfig &config,
797 LogicalResult simplify(
bool *changed) &&;
805RegionPatternRewriteDriver::RegionPatternRewriteDriver(
806 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
807 const GreedyRewriteConfig &config, Region ®ion)
808 : GreedyPatternRewriteDriver(ctx, patterns, config), region(region) {
811 region.walk([&](Operation *op) { strictModeFilteredOps.insert(op); });
817 while (r && r != scope)
818 r = r->getParentRegion();
819 assert(r &&
"provided region is not within the config scope");
825class GreedyPatternRewriteIteration
829 GreedyPatternRewriteIteration(ArrayRef<IRUnit> units, int64_t iteration)
830 : tracing::ActionImpl<GreedyPatternRewriteIteration>(units),
831 iteration(iteration) {}
832 static constexpr StringLiteral tag =
"GreedyPatternRewriteIteration";
833 void print(raw_ostream &os)
const override {
834 os <<
"GreedyPatternRewriteIteration(" << iteration <<
")";
838 int64_t iteration = 0;
842LogicalResult RegionPatternRewriteDriver::simplify(
bool *changed) && {
843 bool continueRewrites =
false;
858 auto insertKnownConstant = [&](
Operation *op) {
863 if (!folder.insertKnownConstant(op, constValue))
890 continueRewrites =
false;
901 continueRewrites |= processWorklist();
917 bool cseChanged =
false;
920 continueRewrites |= cseChanged;
923 {®ion}, iteration);
924 }
while (continueRewrites);
927 *changed = iteration > 1;
930 return success(!continueRewrites);
941 "patterns can only be applied to operations IsolatedFromAbove");
947#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
949 llvm::report_fatal_error(
950 "greedy pattern rewriter input IR failed to verify");
954 RegionPatternRewriteDriver driver(region.
getContext(), patterns, config,
956 LogicalResult converged = std::move(driver).simplify(changed);
957 if (failed(converged))
958 LDBG() <<
"The pattern rewrite did not converge after scanning "
969class MultiOpPatternRewriteDriver :
public GreedyPatternRewriteDriver {
971 explicit MultiOpPatternRewriteDriver(
974 llvm::SmallDenseSet<Operation *, 4> *survivingOps =
nullptr);
980 void notifyOperationErased(
Operation *op)
override {
981 GreedyPatternRewriteDriver::notifyOperationErased(op);
983 survivingOps->erase(op);
989 llvm::SmallDenseSet<Operation *, 4> *
const survivingOps =
nullptr;
993MultiOpPatternRewriteDriver::MultiOpPatternRewriteDriver(
996 llvm::SmallDenseSet<Operation *, 4> *survivingOps)
997 : GreedyPatternRewriteDriver(ctx, patterns, config),
998 survivingOps(survivingOps) {
1000 strictModeFilteredOps.insert_range(ops);
1003 survivingOps->clear();
1004 survivingOps->insert_range(ops);
1012 addSingleOpToWorklist(op);
1015 bool result = processWorklist();
1019 return success(worklist.empty());
1027 assert(!ops.empty() &&
"expected at least one op");
1029 if (ops.size() == 1)
1030 return ops.front()->getParentRegion();
1032 Region *region = ops.front()->getParentRegion();
1033 ops = ops.drop_front();
1034 int sz = ops.size();
1035 llvm::BitVector remainingOps(sz,
true);
1039 while ((pos = remainingOps.find_first_in(pos + 1, sz)) != -1) {
1042 remainingOps.reset(pos);
1044 if (remainingOps.none())
1070 bool allOpsInScope = llvm::all_of(ops, [&](
Operation *op) {
1073 assert(allOpsInScope &&
"ops must be within the specified scope");
1077#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1079 llvm::report_fatal_error(
1080 "greedy pattern rewriter input IR failed to verify");
1084 llvm::SmallDenseSet<Operation *, 4> surviving;
1085 MultiOpPatternRewriteDriver driver(ops.front()->getContext(), patterns,
1087 allErased ? &surviving :
nullptr);
1088 LogicalResult converged = std::move(driver).simplify(ops, changed);
1090 *allErased = surviving.empty();
1091 if (failed(converged))
1092 LDBG() <<
"The pattern rewrite did not converge after "
static Region * findCommonAncestor(ArrayRef< Operation * > ops)
Find the region that is the closest common ancestor of all given ops.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static const mlir::GenInfo * generator
static std::string diag(const llvm::Value &value)
static Operation * getDumpRootOp(Operation *op)
Log IR after pattern application.
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
A class for computing basic dominance information.
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.
static constexpr int64_t kNoLimit
bool isFoldingEnabled() const
Whether this should fold while greedily rewriting.
RewriterBase::Listener * getListener() const
An optional listener that should be notified about IR modifications.
bool isConstantCSEEnabled() const
If set to "true", constants are CSE'd (even across multiple regions that are in a parent-ancestor rel...
Region * getScope() const
Only ops within the scope are added to the worklist.
GreedyRewriteStrictness getStrictness() const
Strict mode can restrict the ops that are added to the worklist during the rewrite.
bool isCSEBetweenIterationsEnabled() const
If set to "true", full common-subexpression elimination is run on the scoped region between each patt...
bool getUseTopDownTraversal() const
This specifies the order of initial traversal that populates the rewriters worklist.
GreedyRewriteConfig & setScope(Region *scope)
GreedyRewriteConfig & setListener(RewriterBase::Listener *listener)
int64_t getMaxNumRewrites() const
This specifies the maximum number of rewrites within an iteration.
int64_t getMaxIterations() const
This specifies the maximum number of times the rewriter will iterate between applying patterns and si...
GreedySimplifyRegionLevel getRegionSimplificationLevel() const
Perform control flow optimizations to the region tree after applying all patterns.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
void executeAction(function_ref< void()> actionFn, const tracing::Action &action)
Dispatch the provided action to the handler if any, or just execute it.
This class represents a saved insertion point.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Set of flags used to control the behavior of the various IR print methods (e.g.
This class provides the API for ops that are known to be isolated from above.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
A unique fingerprint for a specific operation, and all of it's internal operations (if includeNested ...
A utility class for folding operations, and unifying duplicated constants generated along the way.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
OperationName getName()
The name of an operation is the key identifier for it.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
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),...
Region * getParentRegion()
Returns the region to which the instruction belongs.
void erase()
Remove this operation from its parent block and delete it.
This class manages the application of a group of rewrite patterns, with a user-provided cost model.
LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter, function_ref< bool(const Pattern &)> canApply={}, function_ref< void(const Pattern &)> onFailure={}, function_ref< LogicalResult(const Pattern &)> onSuccess={})
Attempt to match and rewrite the given op with any pattern, allowing a predicate to decide if a patte...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
Operation * findAncestorOpInRegion(Operation &op)
Returns 'op' if 'op' lies in this region, or otherwise finds the ancestor of 'op' that lies in this r...
Operation * getParentOp()
Return the parent operation this region is attached to.
MLIRContext * getContext()
Return the context this region is inserted in.
BlockListType::iterator iterator
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
This class provides an abstraction over the different types of ranges over Values.
static WalkResult advance()
CRTP Implementation of an action.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void eliminateCommonSubExpressions(RewriterBase &rewriter, DominanceInfo &domInfo, Operation *op, bool *changed=nullptr, int64_t *numCSE=nullptr, int64_t *numDCE=nullptr)
Eliminate common subexpressions within the given operation.
@ Aggressive
Run extra simplificiations (e.g.
@ Disabled
Disable region control-flow simplification.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
LogicalResult applyOpPatternsGreedily(ArrayRef< Operation * > ops, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr, bool *allErased=nullptr)
Rewrite the specified ops by repeatedly applying the highest benefit patterns in a greedy worklist dr...
LogicalResult eraseUnreachableBlocks(RewriterBase &rewriter, MutableArrayRef< Region > regions)
Erase the unreachable blocks within the provided regions.
bool isOpTriviallyDead(Operation *op)
Return true if the given operation is unused, and has no side effects on memory that prevent erasing.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
@ AnyOp
No restrictions wrt. which ops are processed.
LogicalResult simplifyRegions(RewriterBase &rewriter, MutableArrayRef< Region > regions, bool mergeBlocks=true)
Run a set of structural simplifications over the given regions.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
llvm::function_ref< Fn > function_ref
A listener that forwards all notifications to another listener.
void notifyOperationInserted(Operation *op, InsertPoint previous) override
Notify the listener that the specified operation was inserted.
void notifyOperationModified(Operation *op) override
Notify the listener that the specified operation was modified in-place.
void notifyOperationErased(Operation *op) override
Notify the listener that the specified operation is about to be erased.
void notifyBlockErased(Block *block) override
Notify the listener that the specified block is about to be erased.