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);
432 void notifyBlockInserted(
Block *block,
Region *previous,
442 ForwardingListener::notifyBlockInserted(block, previous, previousIt);
445 void notifyBlockErased(
Block *block)
override {
448 ForwardingListener::notifyBlockErased(block);
451 void notifyOperationInserted(
Operation *op,
456 if (previous.
isSet())
460 ForwardingListener::notifyOperationInserted(op, previous);
463 void notifyOperationModified(
Operation *op)
override {
465 ForwardingListener::notifyOperationModified(op);
468 void notifyOperationErased(
Operation *op)
override {
470 ForwardingListener::notifyOperationErased(op);
485 explicit GreedyPatternRewriteDriver(
MLIRContext *ctx,
490 void addSingleOpToWorklist(
Operation *op);
497 void notifyOperationModified(
Operation *op)
override;
502 void notifyOperationInserted(
Operation *op,
508 void notifyOperationErased(
Operation *op)
override;
517 bool processWorklist();
525#ifdef MLIR_GREEDY_REWRITE_RANDOMIZER_SEED
526 RandomizedWorklist worklist;
538 llvm::SmallDenseSet<Operation *, 4> strictModeFilteredOps;
542 ReachabilityListener reachabilityListener;
549 void addOperandsToWorklist(
Operation *op);
552 void notifyBlockInserted(
Block *block,
Region *previous,
556 void notifyBlockErased(
Block *block)
override;
566 llvm::impl::raw_ldbg_ostream os{(Twine(
"[") +
DEBUG_TYPE +
":1] ").str(),
569 llvm::ScopedPrinter logger{os};
575 DeadnessListener deadnessListener;
577#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
578 ExpensiveChecks expensiveChecks;
595 if (successor->getParent() == block->
getParent())
596 successors.insert(successor);
600void ReachabilityListener::RegionState::traverse(Region *region) {
605 changedBlocks.clear();
606 removedBlocks.clear();
607 entry = ®ion->
front();
608 addReachable({entry},
false);
611void ReachabilityListener::RegionState::addReachable(SmallVector<Block *> roots,
613 while (!roots.empty()) {
614 auto [it,
inserted] = reachable.try_emplace(roots.pop_back_val());
618 it->second.append(successors.begin(), successors.end());
620 uncertain.insert(it->first);
621 roots.append(it->second);
625void ReachabilityListener::RegionState::markUncertain(
Block *block) {
626 SmallVector<Block *> worklist{block};
627 while (!worklist.empty()) {
628 Block *current = worklist.pop_back_val();
629 auto it = reachable.find(current);
630 if (it == reachable.end() || !uncertain.insert(current).second)
632 worklist.append(it->second);
636LogicalResult ReachabilityListener::RegionState::applyChanges() {
637 if (changedBlocks.empty() && removedBlocks.empty())
641 SmallVector<Block *> unreachable;
642 for (
Block *changed : changedBlocks) {
645 if (removedBlocks.contains(changed))
647 auto it = reachable.find(changed);
648 if (it == reachable.end())
653 if (changed != entry && changed->hasNoPredecessors())
654 markUncertain(changed);
657 const auto &old = it->second;
659 for (
Block *lost : old) {
660 if (current.contains(lost))
665 auto lostIt = reachable.find(lost);
666 if (lostIt == reachable.end())
675 bool isGone = removedBlocks.contains(lost) || lost->hasNoPredecessors();
676 if (isGone && llvm::all_of(lostIt->second, [&](
Block *successor) {
677 return current.contains(successor);
679 unreachable.push_back(lost);
686 SmallVector<Block *> roots;
687 for (
Block *successor : current)
688 if (!reachable.contains(successor))
689 roots.push_back(successor);
691 it->second.assign(current.begin(), current.end());
692 addReachable(std::move(roots), uncertain.contains(changed));
696 unreachable.append(removedBlocks.begin(), removedBlocks.end());
697 for (
Block *block : unreachable) {
698 reachable.erase(block);
699 uncertain.erase(block);
701 changedBlocks.clear();
702 removedBlocks.clear();
706bool ReachabilityListener::isBlockReachable(
Block *block) {
709 if (!region || block == ®ion->
front())
713 auto [it,
inserted] = regionStates.try_emplace(region);
714 RegionState &state = it->second;
716 if (isStale ||
failed(state.applyChanges()) ||
717 state.uncertain.contains(block))
718 state.traverse(region);
719 bool result = state.reachable.contains(block);
720#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
722 "reachability cache disagrees with a traversal");
727bool ReachabilityListener::isReachable(Operation *op) {
731 if (!isBlockReachable(block))
734 if (!region || region == scope)
741void ReachabilityListener::notifyBlockInserted(
Block *block, Region *previous,
748 if (previous != region) {
750 markRemoved(previous, block);
751 auto it = regionStates.find(region);
752 if (it != regionStates.end() && (it->second.removedBlocks.contains(block) ||
753 it->second.reachable.contains(block)))
754 regionStates.erase(it);
760void ReachabilityListener::notifyBlockErased(
Block *block) {
765void ReachabilityListener::notifyOperationInserted(
766 Operation *op, OpBuilder::InsertPoint previous) {
769 if (previous.
isSet())
775void ReachabilityListener::notifyOperationModified(Operation *op) {
781void ReachabilityListener::notifyOperationErased(Operation *op) {
786 regionStates.erase(®ion);
790GreedyPatternRewriteDriver::GreedyPatternRewriteDriver(
791 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
792 const GreedyRewriteConfig &config)
793 : rewriter(ctx), config(config),
794 reachabilityListener(this, config.getScope()), matcher(patterns),
795 deadnessListener(&reachabilityListener)
796#
if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
800 config.getScope() ? config.getScope()->getParentOp()
806 matcher.applyDefaultCostModel();
809#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
818bool GreedyPatternRewriteDriver::processWorklist() {
822 llvm::scope_exit clearReachability([&] { reachabilityListener.clear(); });
825 const char *logLineComment =
826 "//===-------------------------------------------===//\n";
829 auto logResult = [&](StringRef
result,
const llvm::Twine &msg = {}) {
831 logger.startLine() <<
"} -> " <<
result;
832 if (!msg.isTriviallyEmpty())
833 logger.getOStream() <<
" : " << msg;
834 logger.getOStream() <<
"\n";
836 auto logResultWithLine = [&](StringRef
result,
const llvm::Twine &msg = {}) {
838 logger.startLine() << logLineComment;
842 bool changed =
false;
843 int64_t numRewrites = 0;
844 while (!worklist.empty() &&
847 auto *op = worklist.pop();
848 if (!reachabilityListener.isReachable(op)) {
849 LLVM_DEBUG(logger.startLine() <<
"Skipping unreachable operation : '"
850 << op->
getName() <<
"'(" << op <<
")\n");
855 logger.getOStream() <<
"\n";
856 logger.startLine() << logLineComment;
857 logger.startLine() <<
"Processing operation : '" << op->
getName() <<
"'("
865 OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs());
866 logger.getOStream() <<
"\n\n";
871 if (deadnessListener.isOpTriviallyDead(op)) {
875 LLVM_DEBUG(logResultWithLine(
"success",
"operation is trivially dead"));
884 SmallVector<OpFoldResult> foldResults;
885 if (succeeded(op->
fold(foldResults))) {
886 LLVM_DEBUG(logResultWithLine(
"success",
"operation was folded"));
890 if (foldResults.empty()) {
893 deadnessListener.notifyOperationModified(op);
895 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
896#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
897 expensiveChecks.notifyFoldingSuccess();
904 "folder produced incorrect number of results");
905 OpBuilder::InsertionGuard g(rewriter);
907 SmallVector<Value> replacements;
908 bool materializationSucceeded =
true;
909 for (
auto [ofr, resultType] :
911 if (
auto value = dyn_cast<Value>(ofr)) {
912 assert(value.getType() == resultType &&
913 "folder produced value of incorrect type");
914 replacements.push_back(value);
919 rewriter, cast<Attribute>(ofr), resultType, op->
getLoc());
924 llvm::SmallDenseSet<Operation *> replacementOps;
927 "folder reused existing op for one result but constant "
928 "materialization failed for another result");
929 replacementOps.insert(
replacement.getDefiningOp());
931 for (Operation *op : replacementOps) {
935 materializationSucceeded =
false;
939 assert(constOp->
hasTrait<OpTrait::ConstantLike>() &&
940 "materializeConstant produced op that is not a ConstantLike");
942 "materializeConstant produced incorrect result type");
943 replacements.push_back(constOp->
getResult(0));
946 if (materializationSucceeded) {
949 LLVM_DEBUG(logSuccessfulFolding(dumpRootOp));
950#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
951 expensiveChecks.notifyFoldingSuccess();
961 auto canApplyCallback = [&](
const Pattern &pattern) {
963 logger.getOStream() <<
"\n";
964 logger.startLine() <<
"* Pattern " << pattern.getDebugName() <<
" : '"
966 llvm::interleaveComma(pattern.getGeneratedOps(), logger.getOStream());
967 logger.getOStream() <<
")' {\n";
970 if (RewriterBase::Listener *listener = config.
getListener())
971 listener->notifyPatternBegin(pattern, op);
974 function_ref<bool(
const Pattern &)> canApply = canApplyCallback;
975 auto onFailureCallback = [&](
const Pattern &pattern) {
976 LLVM_DEBUG(logResult(
"failure",
"pattern failed to match"));
977 if (RewriterBase::Listener *listener = config.
getListener())
978 listener->notifyPatternEnd(pattern, failure());
980 function_ref<void(
const Pattern &)> onFailure = onFailureCallback;
981 auto onSuccessCallback = [&](
const Pattern &pattern) {
982 LLVM_DEBUG(logResult(
"success",
"pattern applied successfully"));
983 if (RewriterBase::Listener *listener = config.
getListener())
984 listener->notifyPatternEnd(pattern,
success());
987 function_ref<LogicalResult(
const Pattern &)> onSuccess = onSuccessCallback;
999#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1003 llvm::scope_exit clearFingerprints([&]() { expensiveChecks.clear(); });
1006 LogicalResult matchResult =
1007 matcher.
matchAndRewrite(op, rewriter, canApply, onFailure, onSuccess);
1009 if (succeeded(matchResult)) {
1010 LLVM_DEBUG(logResultWithLine(
"success",
"at least one pattern matched"));
1011#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1012 expensiveChecks.notifyRewriteSuccess();
1017 LLVM_DEBUG(logResultWithLine(
"failure",
"all patterns failed to match"));
1018#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1019 expensiveChecks.notifyRewriteFailure();
1027void GreedyPatternRewriteDriver::addToWorklist(Operation *op) {
1028 assert(op &&
"expected valid op");
1030 SmallVector<Operation *, 8> ancestors;
1031 Region *region =
nullptr;
1033 ancestors.push_back(op);
1037 for (Operation *op : ancestors)
1038 addSingleOpToWorklist(op);
1041 if (region ==
nullptr)
1046void GreedyPatternRewriteDriver::addSingleOpToWorklist(Operation *op) {
1047 if (config.
getStrictness() == GreedyRewriteStrictness::AnyOp ||
1048 strictModeFilteredOps.contains(op))
1052void GreedyPatternRewriteDriver::notifyBlockInserted(
1054 if (RewriterBase::Listener *listener = config.
getListener())
1055 listener->notifyBlockInserted(block, previous, previousIt);
1058void GreedyPatternRewriteDriver::notifyBlockErased(
Block *block) {
1059 if (RewriterBase::Listener *listener = config.
getListener())
1060 listener->notifyBlockErased(block);
1063void GreedyPatternRewriteDriver::notifyOperationInserted(
1064 Operation *op, OpBuilder::InsertPoint previous) {
1066 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
1069 if (RewriterBase::Listener *listener = config.
getListener())
1070 listener->notifyOperationInserted(op, previous);
1071 if (config.
getStrictness() == GreedyRewriteStrictness::ExistingAndNewOps)
1072 strictModeFilteredOps.insert(op);
1076void GreedyPatternRewriteDriver::notifyOperationModified(Operation *op) {
1078 logger.startLine() <<
"** Modified: '" << op->
getName() <<
"'(" << op
1081 if (RewriterBase::Listener *listener = config.
getListener())
1082 listener->notifyOperationModified(op);
1086void GreedyPatternRewriteDriver::addOperandsToWorklist(Operation *op) {
1096 auto *defOp = operand.getDefiningOp();
1100 Operation *otherUser =
nullptr;
1101 bool hasMoreThanTwoUses =
false;
1102 for (
auto *user : operand.getUsers()) {
1103 if (user == op || user == otherUser)
1109 hasMoreThanTwoUses =
true;
1112 if (hasMoreThanTwoUses)
1115 addToWorklist(defOp);
1119void GreedyPatternRewriteDriver::notifyOperationErased(Operation *op) {
1121 logger.startLine() <<
"** Erase : '" << op->
getName() <<
"'(" << op
1133 "scope region must not be erased during greedy pattern rewrite");
1136 if (RewriterBase::Listener *listener = config.
getListener())
1137 listener->notifyOperationErased(op);
1139 addOperandsToWorklist(op);
1140 worklist.remove(op);
1142 if (config.
getStrictness() != GreedyRewriteStrictness::AnyOp)
1143 strictModeFilteredOps.erase(op);
1146void GreedyPatternRewriteDriver::notifyOperationReplaced(
1149 logger.startLine() <<
"** Replace : '" << op->
getName() <<
"'(" << op
1152 if (RewriterBase::Listener *listener = config.
getListener())
1153 listener->notifyOperationReplaced(op,
replacement);
1156void GreedyPatternRewriteDriver::notifyMatchFailure(
1157 Location loc,
function_ref<
void(Diagnostic &)> reasonCallback) {
1159 Diagnostic diag(loc, DiagnosticSeverity::Remark);
1160 reasonCallback(diag);
1161 logger.startLine() <<
"** Match Failure : " << diag.str() <<
"\n";
1163 if (RewriterBase::Listener *listener = config.
getListener())
1164 listener->notifyMatchFailure(loc, reasonCallback);
1174class RegionPatternRewriteDriver :
public GreedyPatternRewriteDriver {
1176 explicit RegionPatternRewriteDriver(MLIRContext *ctx,
1177 const FrozenRewritePatternSet &patterns,
1178 const GreedyRewriteConfig &config,
1183 LogicalResult simplify(
bool *changed) &&;
1191RegionPatternRewriteDriver::RegionPatternRewriteDriver(
1192 MLIRContext *ctx,
const FrozenRewritePatternSet &patterns,
1193 const GreedyRewriteConfig &config, Region ®ion)
1194 : GreedyPatternRewriteDriver(ctx, patterns, config), region(region) {
1197 region.walk([&](Operation *op) { strictModeFilteredOps.insert(op); });
1202 Region *r = ®ion;
1203 while (r && r != scope)
1204 r = r->getParentRegion();
1205 assert(r &&
"provided region is not within the config scope");
1211class GreedyPatternRewriteIteration
1215 GreedyPatternRewriteIteration(ArrayRef<IRUnit> units, int64_t iteration)
1216 : tracing::ActionImpl<GreedyPatternRewriteIteration>(units),
1217 iteration(iteration) {}
1218 static constexpr StringLiteral tag =
"GreedyPatternRewriteIteration";
1219 void print(raw_ostream &os)
const override {
1220 os <<
"GreedyPatternRewriteIteration(" << iteration <<
")";
1224 int64_t iteration = 0;
1228LogicalResult RegionPatternRewriteDriver::simplify(
bool *changed) && {
1229 bool continueRewrites =
false;
1230 bool anyChanged =
false;
1245 auto insertKnownConstant = [&](
Operation *op) {
1251 auto result = folder.insertKnownConstant(op, constValue);
1279 continueRewrites =
false;
1293 continueRewrites |= processWorklist();
1309 bool cseChanged =
false;
1312 continueRewrites |= cseChanged;
1315 {®ion}, iteration);
1316 anyChanged |= continueRewrites;
1317 }
while (continueRewrites);
1320 *changed = anyChanged;
1323 return success(!continueRewrites);
1334 "patterns can only be applied to operations IsolatedFromAbove");
1340#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1342 llvm::report_fatal_error(
1343 "greedy pattern rewriter input IR failed to verify");
1346#ifdef EXPENSIVE_CHECKS
1349 bool rewriteChanged =
false;
1352 RegionPatternRewriteDriver driver(region.
getContext(), patterns, config,
1354 LogicalResult converged = std::move(driver).simplify(&rewriteChanged);
1355#ifdef EXPENSIVE_CHECKS
1356 if (rewriteChanged !=
1358 llvm::report_fatal_error(
1359 "greedy pattern rewriter changed flag does not match the IR");
1362 *changed = rewriteChanged;
1363 if (failed(converged))
1364 LDBG() <<
"The pattern rewrite did not converge after scanning "
1375class MultiOpPatternRewriteDriver :
public GreedyPatternRewriteDriver {
1377 explicit MultiOpPatternRewriteDriver(
1380 llvm::SmallDenseSet<Operation *, 4> *survivingOps =
nullptr);
1386 void notifyOperationErased(
Operation *op)
override {
1387 GreedyPatternRewriteDriver::notifyOperationErased(op);
1389 survivingOps->erase(op);
1395 llvm::SmallDenseSet<Operation *, 4> *
const survivingOps =
nullptr;
1399MultiOpPatternRewriteDriver::MultiOpPatternRewriteDriver(
1402 llvm::SmallDenseSet<Operation *, 4> *survivingOps)
1403 : GreedyPatternRewriteDriver(ctx, patterns, config),
1404 survivingOps(survivingOps) {
1406 strictModeFilteredOps.insert_range(ops);
1409 survivingOps->clear();
1410 survivingOps->insert_range(ops);
1418 addSingleOpToWorklist(op);
1421 bool result = processWorklist();
1425 return success(worklist.empty());
1433 assert(!ops.empty() &&
"expected at least one op");
1435 if (ops.size() == 1)
1436 return ops.front()->getParentRegion();
1438 Region *region = ops.front()->getParentRegion();
1439 ops = ops.drop_front();
1440 int sz = ops.size();
1441 llvm::BitVector remainingOps(sz,
true);
1445 while ((pos = remainingOps.find_first_in(pos + 1, sz)) != -1) {
1448 remainingOps.reset(pos);
1450 if (remainingOps.none())
1476 bool allOpsInScope = llvm::all_of(ops, [&](
Operation *op) {
1479 assert(allOpsInScope &&
"ops must be within the specified scope");
1483#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1485 llvm::report_fatal_error(
1486 "greedy pattern rewriter input IR failed to verify");
1489#ifdef EXPENSIVE_CHECKS
1490 std::optional<OperationFingerPrint> before;
1494 bool rewriteChanged =
false;
1497 llvm::SmallDenseSet<Operation *, 4> surviving;
1498 MultiOpPatternRewriteDriver driver(ops.front()->getContext(), patterns,
1500 allErased ? &surviving :
nullptr);
1501 LogicalResult converged = std::move(driver).simplify(ops, &rewriteChanged);
1502#ifdef EXPENSIVE_CHECKS
1506 llvm::report_fatal_error(
1507 "greedy pattern rewriter changed flag does not match the IR");
1510 *changed = rewriteChanged;
1512 *allErased = surviving.empty();
1513 if (failed(converged))
1514 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.
A cache for repeated deadness queries on nested operations.
bool isOpTriviallyDead(Operation *op)
Return true if the operation is unused and can be erased.
void invalidateAncestors(Operation *op)
Invalidate the operation and its ancestors, preserving descendant entries.
void invalidate(Operation *op)
Invalidate the operation, its descendants, and its ancestors.
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.