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/ADT/SetVector.h"
31#include "llvm/ADT/SmallPtrSet.h"
32#include "llvm/Support/DebugLog.h"
33#include "llvm/Support/ScopedPrinter.h"
34#include "llvm/Support/raw_ostream.h"
36#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
42#define DEBUG_TYPE "greedy-rewriter"
50#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
65 void computeFingerPrints(
Operation *topLevel) {
66 this->topLevel = topLevel;
67 this->topLevelFingerPrint.emplace(topLevel);
69 fingerprints.try_emplace(op, op,
false);
76 topLevelFingerPrint.reset();
80 void notifyRewriteSuccess() {
85 if (failed(
verify(topLevel)))
86 llvm::report_fatal_error(
"IR failed to verify after pattern application");
90 if (*topLevelFingerPrint == afterFingerPrint) {
92 llvm::report_fatal_error(
93 "pattern returned success but IR did not change");
95 for (
const auto &it : fingerprints) {
97 if (it.first == topLevel)
108 llvm::report_fatal_error(
"operation finger print changed");
113 void notifyRewriteFailure() {
119 if (*topLevelFingerPrint != afterFingerPrint) {
121 llvm::report_fatal_error(
"pattern returned failure but IR did change");
125 void notifyFoldingSuccess() {
130 if (failed(
verify(topLevel)))
131 llvm::report_fatal_error(
"IR failed to verify after folding");
136 void invalidateFingerPrint(
Operation *op) { fingerprints.erase(op); }
169 invalidateFingerPrint(op);
174 op->
walk([
this](
Operation *op) { invalidateFingerPrint(op); });
186 std::optional<OperationFingerPrint> topLevelFingerPrint;
198static void logSuccessfulFolding(
Operation *op) {
199 LDBG() <<
"// *** IR Dump After Successful Folding ***\n"
240 std::vector<Operation *> list;
246Worklist::Worklist() { list.reserve(64); }
248void Worklist::clear() {
253bool Worklist::empty()
const {
255 return !llvm::any_of(list,
256 [](
Operation *op) {
return static_cast<bool>(op); });
260 assert(op &&
"cannot push nullptr to worklist");
262 if (!map.insert({op, list.size()}).second)
268 assert(!empty() &&
"cannot pop from empty worklist");
276 while (!list.empty() && !list.back())
282 assert(op &&
"cannot remove nullptr from worklist");
283 auto it = map.find(op);
284 if (it != map.end()) {
285 assert(list[it->second] == op &&
"malformed worklist data structure");
286 list[it->second] =
nullptr;
291void Worklist::reverse() {
292 std::reverse(list.begin(), list.end());
293 for (
size_t i = 0, e = list.size(); i != e; ++i)
297#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
302class RandomizedWorklist :
public Worklist {
304 RandomizedWorklist() : Worklist() {
305 generator.seed(MLIR_GREEDY_REWRITE_RANDOMIZER_SEED);
312 assert(!list.empty() &&
"cannot pop from empty worklist");
315 list.
erase(list.begin() + pos);
316 for (
int64_t i = pos, e = list.size(); i < e; ++i)
350 void clear() { regionStates.clear(); }
352 void notifyBlockInserted(
Block *block,
Region *previous,
354 void notifyBlockErased(
Block *block)
override;
355 void notifyOperationInserted(
Operation *op,
357 void notifyOperationModified(
Operation *op)
override;
358 void notifyOperationErased(
Operation *op)
override;
365 Block *entry =
nullptr;
377 llvm::SmallDenseSet<Block *, 4> uncertain;
380 llvm::SmallSetVector<Block *, 4> changedBlocks;
383 llvm::SmallDenseSet<Block *, 4> removedBlocks;
386 void traverse(
Region *region);
391 void markUncertain(
Block *block);
394 LogicalResult applyChanges();
399 void markChanged(
Block *block) {
402 auto it = regionStates.find(block->
getParent());
403 if (it != regionStates.end())
404 it->second.changedBlocks.insert(block);
408 auto it = regionStates.find(region);
409 if (it != regionStates.end())
410 it->second.removedBlocks.insert(block);
412 bool isBlockReachable(
Block *block);
429 explicit GreedyPatternRewriteDriver(
MLIRContext *ctx,
434 void addSingleOpToWorklist(
Operation *op);
441 void notifyOperationModified(
Operation *op)
override;
446 void notifyOperationInserted(
Operation *op,
452 void notifyOperationErased(
Operation *op)
override;
461 bool processWorklist();
469#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
470 RandomizedWorklist worklist;
482 llvm::SmallDenseSet<Operation *, 4> strictModeFilteredOps;
486 ReachabilityListener reachabilityListener;
493 void addOperandsToWorklist(
Operation *op);
496 void notifyBlockInserted(
Block *block,
Region *previous,
500 void notifyBlockErased(
Block *block)
override;
510 llvm::impl::raw_ldbg_ostream os{(Twine(
"[") +
DEBUG_TYPE +
":1] ").str(),
513 llvm::ScopedPrinter logger{os};
519#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
520 ExpensiveChecks expensiveChecks;
537 if (successor->getParent() == block->
getParent())
538 successors.insert(successor);
542void ReachabilityListener::RegionState::traverse(Region *region) {
547 changedBlocks.clear();
548 removedBlocks.clear();
549 entry = ®ion->
front();
550 addReachable({entry},
false);
553void ReachabilityListener::RegionState::addReachable(SmallVector<Block *> roots,
555 while (!roots.empty()) {
556 auto [it,
inserted] = reachable.try_emplace(roots.pop_back_val());
560 it->second.append(successors.begin(), successors.end());
562 uncertain.insert(it->first);
563 roots.append(it->second);
567void ReachabilityListener::RegionState::markUncertain(
Block *block) {
568 SmallVector<Block *> worklist{block};
569 while (!worklist.empty()) {
570 Block *current = worklist.pop_back_val();
571 auto it = reachable.find(current);
572 if (it == reachable.end() || !uncertain.insert(current).second)
574 worklist.append(it->second);
578LogicalResult ReachabilityListener::RegionState::applyChanges() {
579 if (changedBlocks.empty() && removedBlocks.empty())
583 SmallVector<Block *> unreachable;
584 for (
Block *changed : changedBlocks) {
587 if (removedBlocks.contains(changed))
589 auto it = reachable.find(changed);
590 if (it == reachable.end())
595 if (changed != entry && changed->hasNoPredecessors())
596 markUncertain(changed);
599 const auto &old = it->second;
601 for (
Block *lost : old) {
602 if (current.contains(lost))
607 auto lostIt = reachable.find(lost);
608 if (lostIt == reachable.end())
617 bool isGone = removedBlocks.contains(lost) || lost->hasNoPredecessors();
618 if (isGone && llvm::all_of(lostIt->second, [&](
Block *successor) {
619 return current.contains(successor);
621 unreachable.push_back(lost);
628 SmallVector<Block *> roots;
629 for (
Block *successor : current)
630 if (!reachable.contains(successor))
631 roots.push_back(successor);
633 it->second.assign(current.begin(), current.end());
634 addReachable(std::move(roots), uncertain.contains(changed));
638 unreachable.append(removedBlocks.begin(), removedBlocks.end());
639 for (
Block *block : unreachable) {
640 reachable.erase(block);
641 uncertain.erase(block);
643 changedBlocks.clear();
644 removedBlocks.clear();
648bool ReachabilityListener::isBlockReachable(
Block *block) {
651 if (!region || block == ®ion->
front())
655 auto [it,
inserted] = regionStates.try_emplace(region);
656 RegionState &state = it->second;
658 if (isStale ||
failed(state.applyChanges()) ||
659 state.uncertain.contains(block))
660 state.traverse(region);
661 bool result = state.reachable.contains(block);
662#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
664 "reachability cache disagrees with a traversal");
669bool ReachabilityListener::isReachable(Operation *op) {
673 if (!isBlockReachable(block))
676 if (!region || region == scope)
683void ReachabilityListener::notifyBlockInserted(
Block *block, Region *previous,
690 if (previous != region) {
692 markRemoved(previous, block);
693 auto it = regionStates.find(region);
694 if (it != regionStates.end() && (it->second.removedBlocks.contains(block) ||
695 it->second.reachable.contains(block)))
696 regionStates.erase(it);
702void ReachabilityListener::notifyBlockErased(
Block *block) {
707void ReachabilityListener::notifyOperationInserted(
708 Operation *op, OpBuilder::InsertPoint previous) {
711 if (previous.
isSet())
717void ReachabilityListener::notifyOperationModified(Operation *op) {
723void ReachabilityListener::notifyOperationErased(Operation *op) {
728 regionStates.erase(®ion);
732GreedyPatternRewriteDriver::GreedyPatternRewriteDriver(
733 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
734 const GreedyRewriteConfig &config)
735 : rewriter(ctx), config(config),
736 reachabilityListener(this, config.getScope()), matcher(patterns)
737#
if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
740 &reachabilityListener,
741 config.getScope() ? config.getScope()->getParentOp()
747 matcher.applyDefaultCostModel();
750#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
759bool GreedyPatternRewriteDriver::processWorklist() {
763 llvm::scope_exit clearReachability([&] { reachabilityListener.clear(); });
766 const char *logLineComment =
767 "//===-------------------------------------------===//\n";
770 auto logResult = [&](StringRef
result,
const llvm::Twine &msg = {}) {
772 logger.startLine() <<
"} -> " <<
result;
773 if (!msg.isTriviallyEmpty())
774 logger.getOStream() <<
" : " << msg;
775 logger.getOStream() <<
"\n";
777 auto logResultWithLine = [&](StringRef
result,
const llvm::Twine &msg = {}) {
779 logger.startLine() << logLineComment;
783 bool changed =
false;
784 int64_t numRewrites = 0;
785 while (!worklist.empty() &&
788 auto *op = worklist.pop();
789 if (!reachabilityListener.isReachable(op)) {
790 LLVM_DEBUG(logger.startLine() <<
"Skipping unreachable operation : '"
791 << op->
getName() <<
"'(" << op <<
")\n");
796 logger.getOStream() <<
"\n";
797 logger.startLine() << logLineComment;
798 logger.startLine() <<
"Processing operation : '" << op->
getName() <<
"'("
806 OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs());
807 logger.getOStream() <<
"\n\n";
816 LLVM_DEBUG(logResultWithLine(
"success",
"operation is trivially dead"));
825 SmallVector<OpFoldResult> foldResults;
826 if (succeeded(op->
fold(foldResults))) {
827 LLVM_DEBUG(logResultWithLine(
"success",
"operation was folded"));
831 if (foldResults.empty()) {
835 reachabilityListener.notifyOperationModified(op);
837 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
838#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
839 expensiveChecks.notifyFoldingSuccess();
846 "folder produced incorrect number of results");
847 OpBuilder::InsertionGuard g(rewriter);
849 SmallVector<Value> replacements;
850 bool materializationSucceeded =
true;
851 for (
auto [ofr, resultType] :
853 if (
auto value = dyn_cast<Value>(ofr)) {
854 assert(value.getType() == resultType &&
855 "folder produced value of incorrect type");
856 replacements.push_back(value);
861 rewriter, cast<Attribute>(ofr), resultType, op->
getLoc());
866 llvm::SmallDenseSet<Operation *> replacementOps;
869 "folder reused existing op for one result but constant "
870 "materialization failed for another result");
871 replacementOps.insert(
replacement.getDefiningOp());
873 for (Operation *op : replacementOps) {
877 materializationSucceeded =
false;
881 assert(constOp->
hasTrait<OpTrait::ConstantLike>() &&
882 "materializeConstant produced op that is not a ConstantLike");
884 "materializeConstant produced incorrect result type");
885 replacements.push_back(constOp->
getResult(0));
888 if (materializationSucceeded) {
891 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
892#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
893 expensiveChecks.notifyFoldingSuccess();
903 auto canApplyCallback = [&](
const Pattern &pattern) {
905 logger.getOStream() <<
"\n";
906 logger.startLine() <<
"* Pattern " << pattern.getDebugName() <<
" : '"
908 llvm::interleaveComma(pattern.getGeneratedOps(), logger.getOStream());
909 logger.getOStream() <<
")' {\n";
912 if (RewriterBase::Listener *listener = config.
getListener())
913 listener->notifyPatternBegin(pattern, op);
916 function_ref<bool(
const Pattern &)> canApply = canApplyCallback;
917 auto onFailureCallback = [&](
const Pattern &pattern) {
918 LLVM_DEBUG(logResult(
"failure",
"pattern failed to match"));
919 if (RewriterBase::Listener *listener = config.
getListener())
920 listener->notifyPatternEnd(pattern, failure());
922 function_ref<void(
const Pattern &)> onFailure = onFailureCallback;
923 auto onSuccessCallback = [&](
const Pattern &pattern) {
924 LLVM_DEBUG(logResult(
"success",
"pattern applied successfully"));
925 if (RewriterBase::Listener *listener = config.
getListener())
926 listener->notifyPatternEnd(pattern,
success());
929 function_ref<LogicalResult(
const Pattern &)> onSuccess = onSuccessCallback;
941#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
945 llvm::scope_exit clearFingerprints([&]() { expensiveChecks.clear(); });
948 LogicalResult matchResult =
951 if (succeeded(matchResult)) {
952 LLVM_DEBUG(logResultWithLine(
"success",
"at least one pattern matched"));
953#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
954 expensiveChecks.notifyRewriteSuccess();
959 LLVM_DEBUG(logResultWithLine(
"failure",
"all patterns failed to match"));
960#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
961 expensiveChecks.notifyRewriteFailure();
969void GreedyPatternRewriteDriver::addToWorklist(Operation *op) {
970 assert(op &&
"expected valid op");
972 SmallVector<Operation *, 8> ancestors;
973 Region *region =
nullptr;
975 ancestors.push_back(op);
979 for (Operation *op : ancestors)
980 addSingleOpToWorklist(op);
983 if (region ==
nullptr)
988void GreedyPatternRewriteDriver::addSingleOpToWorklist(Operation *op) {
989 if (config.
getStrictness() == GreedyRewriteStrictness::AnyOp ||
990 strictModeFilteredOps.contains(op))
994void GreedyPatternRewriteDriver::notifyBlockInserted(
996 if (RewriterBase::Listener *listener = config.
getListener())
997 listener->notifyBlockInserted(block, previous, previousIt);
1000void GreedyPatternRewriteDriver::notifyBlockErased(
Block *block) {
1001 if (RewriterBase::Listener *listener = config.
getListener())
1002 listener->notifyBlockErased(block);
1005void GreedyPatternRewriteDriver::notifyOperationInserted(
1006 Operation *op, OpBuilder::InsertPoint previous) {
1008 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
1011 if (RewriterBase::Listener *listener = config.
getListener())
1012 listener->notifyOperationInserted(op, previous);
1013 if (config.
getStrictness() == GreedyRewriteStrictness::ExistingAndNewOps)
1014 strictModeFilteredOps.insert(op);
1018void GreedyPatternRewriteDriver::notifyOperationModified(Operation *op) {
1020 logger.startLine() <<
"** Modified: '" << op->
getName() <<
"'(" << op
1023 if (RewriterBase::Listener *listener = config.
getListener())
1024 listener->notifyOperationModified(op);
1028void GreedyPatternRewriteDriver::addOperandsToWorklist(Operation *op) {
1038 auto *defOp = operand.getDefiningOp();
1042 Operation *otherUser =
nullptr;
1043 bool hasMoreThanTwoUses =
false;
1044 for (
auto *user : operand.getUsers()) {
1045 if (user == op || user == otherUser)
1051 hasMoreThanTwoUses =
true;
1054 if (hasMoreThanTwoUses)
1057 addToWorklist(defOp);
1061void GreedyPatternRewriteDriver::notifyOperationErased(Operation *op) {
1063 logger.startLine() <<
"** Erase : '" << op->
getName() <<
"'(" << op
1075 "scope region must not be erased during greedy pattern rewrite");
1078 if (RewriterBase::Listener *listener = config.
getListener())
1079 listener->notifyOperationErased(op);
1081 addOperandsToWorklist(op);
1082 worklist.remove(op);
1084 if (config.
getStrictness() != GreedyRewriteStrictness::AnyOp)
1085 strictModeFilteredOps.erase(op);
1088void GreedyPatternRewriteDriver::notifyOperationReplaced(
1091 logger.startLine() <<
"** Replace : '" << op->
getName() <<
"'(" << op
1094 if (RewriterBase::Listener *listener = config.
getListener())
1095 listener->notifyOperationReplaced(op,
replacement);
1098void GreedyPatternRewriteDriver::notifyMatchFailure(
1099 Location loc,
function_ref<
void(Diagnostic &)> reasonCallback) {
1101 Diagnostic diag(loc, DiagnosticSeverity::Remark);
1102 reasonCallback(diag);
1103 logger.startLine() <<
"** Match Failure : " << diag.str() <<
"\n";
1105 if (RewriterBase::Listener *listener = config.
getListener())
1106 listener->notifyMatchFailure(loc, reasonCallback);
1116class RegionPatternRewriteDriver :
public GreedyPatternRewriteDriver {
1118 explicit RegionPatternRewriteDriver(MLIRContext *ctx,
1119 const FrozenRewritePatternSet &patterns,
1120 const GreedyRewriteConfig &config,
1125 LogicalResult simplify(
bool *changed) &&;
1133RegionPatternRewriteDriver::RegionPatternRewriteDriver(
1134 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
1135 const GreedyRewriteConfig &config, Region ®ion)
1136 : GreedyPatternRewriteDriver(ctx, patterns, config), region(region) {
1139 region.walk([&](Operation *op) { strictModeFilteredOps.insert(op); });
1144 Region *r = ®ion;
1145 while (r && r != scope)
1146 r = r->getParentRegion();
1147 assert(r &&
"provided region is not within the config scope");
1153class GreedyPatternRewriteIteration
1157 GreedyPatternRewriteIteration(ArrayRef<IRUnit> units, int64_t iteration)
1158 : tracing::ActionImpl<GreedyPatternRewriteIteration>(units),
1159 iteration(iteration) {}
1160 static constexpr StringLiteral tag =
"GreedyPatternRewriteIteration";
1161 void print(raw_ostream &os)
const override {
1162 os <<
"GreedyPatternRewriteIteration(" << iteration <<
")";
1166 int64_t iteration = 0;
1170LogicalResult RegionPatternRewriteDriver::simplify(
bool *changed) && {
1171 bool continueRewrites =
false;
1172 bool anyChanged =
false;
1189 auto insertKnownConstant = [&](
Operation *op) {
1195 auto result = folder.insertKnownConstant(op, constValue);
1223 continueRewrites =
false;
1237 continueRewrites |= processWorklist();
1253 bool cseChanged =
false;
1256 continueRewrites |= cseChanged;
1259 {®ion}, iteration);
1260 anyChanged |= continueRewrites;
1261 }
while (continueRewrites);
1264 *changed = anyChanged;
1267 return success(!continueRewrites);
1278 "patterns can only be applied to operations IsolatedFromAbove");
1284#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1286 llvm::report_fatal_error(
1287 "greedy pattern rewriter input IR failed to verify");
1290#ifdef EXPENSIVE_CHECKS
1293 bool rewriteChanged =
false;
1296 RegionPatternRewriteDriver driver(region.
getContext(), patterns, config,
1298 LogicalResult converged = std::move(driver).simplify(&rewriteChanged);
1299#ifdef EXPENSIVE_CHECKS
1300 if (rewriteChanged !=
1302 llvm::report_fatal_error(
1303 "greedy pattern rewriter changed flag does not match the IR");
1306 *changed = rewriteChanged;
1307 if (failed(converged))
1308 LDBG() <<
"The pattern rewrite did not converge after scanning "
1319class MultiOpPatternRewriteDriver :
public GreedyPatternRewriteDriver {
1321 explicit MultiOpPatternRewriteDriver(
1324 llvm::SmallDenseSet<Operation *, 4> *survivingOps =
nullptr);
1330 void notifyOperationErased(
Operation *op)
override {
1331 GreedyPatternRewriteDriver::notifyOperationErased(op);
1333 survivingOps->erase(op);
1339 llvm::SmallDenseSet<Operation *, 4> *
const survivingOps =
nullptr;
1343MultiOpPatternRewriteDriver::MultiOpPatternRewriteDriver(
1346 llvm::SmallDenseSet<Operation *, 4> *survivingOps)
1347 : GreedyPatternRewriteDriver(ctx, patterns, config),
1348 survivingOps(survivingOps) {
1350 strictModeFilteredOps.insert_range(ops);
1353 survivingOps->clear();
1354 survivingOps->insert_range(ops);
1362 addSingleOpToWorklist(op);
1365 bool result = processWorklist();
1369 return success(worklist.empty());
1377 assert(!ops.empty() &&
"expected at least one op");
1379 if (ops.size() == 1)
1380 return ops.front()->getParentRegion();
1382 Region *region = ops.front()->getParentRegion();
1383 ops = ops.drop_front();
1384 int sz = ops.size();
1385 llvm::BitVector remainingOps(sz,
true);
1389 while ((pos = remainingOps.find_first_in(pos + 1, sz)) != -1) {
1392 remainingOps.reset(pos);
1394 if (remainingOps.none())
1420 bool allOpsInScope = llvm::all_of(ops, [&](
Operation *op) {
1423 assert(allOpsInScope &&
"ops must be within the specified scope");
1427#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1429 llvm::report_fatal_error(
1430 "greedy pattern rewriter input IR failed to verify");
1433#ifdef EXPENSIVE_CHECKS
1434 std::optional<OperationFingerPrint> before;
1438 bool rewriteChanged =
false;
1441 llvm::SmallDenseSet<Operation *, 4> surviving;
1442 MultiOpPatternRewriteDriver driver(ops.front()->getContext(), patterns,
1444 allErased ? &surviving :
nullptr);
1445 LogicalResult converged = std::move(driver).simplify(ops, &rewriteChanged);
1446#ifdef EXPENSIVE_CHECKS
1450 llvm::report_fatal_error(
1451 "greedy pattern rewriter changed flag does not match the IR");
1454 *changed = rewriteChanged;
1456 *allErased = surviving.empty();
1457 if (failed(converged))
1458 LDBG() <<
"The pattern rewrite did not converge after "
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
static bool mayDefineSuccessors(Operation *op)
Return whether op may define successors of its block.
static Region * findCommonAncestor(ArrayRef< Operation * > ops)
Find the region that is the closest common ancestor of all given ops.
static SmallPtrSet< Block *, 2 > getRegionSuccessors(Block *block)
Collect the distinct successors of block that are in the same region.
*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 inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
*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 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.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
SuccessorRange getSuccessors()
bool isReachable(Block *other, SmallPtrSet< Block *, 16 > &&except={})
Return "true" if there is a path from this block to the given block (according to the successors rela...
bool hasNoPredecessors()
Return true if this block has no predecessors.
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.
virtual Operation * materializeConstant(OpBuilder &builder, Attribute value, Type type, Location loc)
Registered hook to materialize a single constant operation from a given attribute value with the desi...
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.
bool isSet() const
Returns true if this insert point is set.
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.
This class provides the API for ops that are known to be terminators.
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.
@ Unchanged
The operation was retained without modifying the IR.
@ Replaced
The operation was replaced with an existing constant and erased.
Operation is the basic unit of execution within MLIR.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
LogicalResult fold(ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results)
Attempt to fold this operation with the specified constant operand values.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
unsigned getNumSuccessors()
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
Block * getBlock()
Returns the operation block that contains this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
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.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
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.
unsigned getNumResults()
Return the number of results held by this operation.
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.
LogicalResult eraseUnreachableBlocks(RewriterBase &rewriter, MutableArrayRef< Region > regions, bool recurse=true)
Erase the unreachable blocks within the provided regions.
@ 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...
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.
void notifyBlockInserted(Block *block, Region *previous, Region::iterator previousIt) override
Notify the listener that the specified block was inserted.