10 #include "mlir/Config/mlir-config.h"
19 #include "llvm/ADT/ScopeExit.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/SmallPtrSet.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/FormatVariadic.h"
24 #include "llvm/Support/SaveAndRestore.h"
25 #include "llvm/Support/ScopedPrinter.h"
31 #define DEBUG_TYPE "dialect-conversion"
34 template <
typename... Args>
35 static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
38 os.startLine() <<
"} -> SUCCESS";
40 os.getOStream() <<
" : "
41 << llvm::formatv(fmt.data(), std::forward<Args>(args)...);
42 os.getOStream() <<
"\n";
47 template <
typename... Args>
48 static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
51 os.startLine() <<
"} -> FAILURE : "
52 << llvm::formatv(fmt.data(), std::forward<Args>(args)...)
62 if (
OpResult inputRes = dyn_cast<OpResult>(value))
63 insertPt = ++inputRes.getOwner()->getIterator();
70 assert(!vals.empty() &&
"expected at least one value");
73 for (
Value v : vals.drop_front()) {
87 assert(dom &&
"unable to find valid insertion point");
105 struct ValueVectorMapInfo {
108 static ::llvm::hash_code getHashValue(
const ValueVector &val) {
109 return ::llvm::hash_combine_range(val);
118 struct ConversionValueMapping {
121 bool isMappedTo(
Value value)
const {
return mappedTo.contains(value); }
140 template <
typename T>
141 struct IsValueVector : std::is_same<std::decay_t<T>, ValueVector> {};
144 template <
typename OldVal,
typename NewVal>
145 std::enable_if_t<IsValueVector<OldVal>::value && IsValueVector<NewVal>::value>
146 map(OldVal &&oldVal, NewVal &&newVal) {
150 assert(next != oldVal &&
"inserting cyclic mapping");
151 auto it = mapping.find(next);
152 if (it == mapping.end())
157 mappedTo.insert_range(newVal);
159 mapping[std::forward<OldVal>(oldVal)] = std::forward<NewVal>(newVal);
163 template <
typename OldVal,
typename NewVal>
164 std::enable_if_t<!IsValueVector<OldVal>::value ||
165 !IsValueVector<NewVal>::value>
166 map(OldVal &&oldVal, NewVal &&newVal) {
167 if constexpr (IsValueVector<OldVal>{}) {
168 map(std::forward<OldVal>(oldVal),
ValueVector{newVal});
169 }
else if constexpr (IsValueVector<NewVal>{}) {
170 map(
ValueVector{oldVal}, std::forward<NewVal>(newVal));
176 void map(
Value oldVal, SmallVector<Value> &&newVal) {
181 void erase(
const ValueVector &value) { mapping.erase(value); }
193 ConversionValueMapping::lookupOrDefault(
Value from,
202 desiredValue = current;
206 for (
Value v : current) {
207 auto it = mapping.find({v});
208 if (it != mapping.end()) {
209 llvm::append_range(next, it->second);
214 if (next != current) {
216 current = std::move(next);
228 auto it = mapping.find(current);
229 if (it == mapping.end()) {
233 current = it->second;
239 return !desiredValue.empty() ? std::move(desiredValue) : std::move(current);
244 ValueVector result = lookupOrDefault(from, desiredTypes);
257 struct RewriterState {
258 RewriterState(
unsigned numRewrites,
unsigned numIgnoredOperations,
259 unsigned numReplacedOps)
260 : numRewrites(numRewrites), numIgnoredOperations(numIgnoredOperations),
261 numReplacedOps(numReplacedOps) {}
264 unsigned numRewrites;
267 unsigned numIgnoredOperations;
270 unsigned numReplacedOps;
302 UnresolvedMaterialization
305 virtual ~IRRewrite() =
default;
308 virtual void rollback() = 0;
327 Kind getKind()
const {
return kind; }
329 static bool classof(
const IRRewrite *
rewrite) {
return true; }
333 :
kind(
kind), rewriterImpl(rewriterImpl) {}
342 class BlockRewrite :
public IRRewrite {
345 Block *getBlock()
const {
return block; }
347 static bool classof(
const IRRewrite *
rewrite) {
348 return rewrite->getKind() >= Kind::CreateBlock &&
349 rewrite->getKind() <= Kind::ReplaceBlockArg;
355 : IRRewrite(
kind, rewriterImpl), block(block) {}
364 class CreateBlockRewrite :
public BlockRewrite {
367 : BlockRewrite(Kind::CreateBlock, rewriterImpl, block) {}
369 static bool classof(
const IRRewrite *
rewrite) {
370 return rewrite->getKind() == Kind::CreateBlock;
376 listener->notifyBlockInserted(block, {}, {});
379 void rollback()
override {
383 while (!blockOps.empty())
384 blockOps.remove(blockOps.begin());
397 class EraseBlockRewrite :
public BlockRewrite {
400 : BlockRewrite(Kind::EraseBlock, rewriterImpl, block),
401 region(block->
getParent()), insertBeforeBlock(block->getNextNode()) {}
403 static bool classof(
const IRRewrite *
rewrite) {
404 return rewrite->getKind() == Kind::EraseBlock;
407 ~EraseBlockRewrite()
override {
409 "rewrite was neither rolled back nor committed/cleaned up");
412 void rollback()
override {
415 assert(block &&
"expected block");
416 auto &blockList = region->getBlocks();
420 blockList.insert(before, block);
426 assert(block &&
"expected block");
427 assert(block->
empty() &&
"expected empty block");
431 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
432 listener->notifyBlockErased(block);
448 Block *insertBeforeBlock;
454 class InlineBlockRewrite :
public BlockRewrite {
458 : BlockRewrite(Kind::InlineBlock, rewriterImpl, block),
459 sourceBlock(sourceBlock),
460 firstInlinedInst(sourceBlock->
empty() ?
nullptr
461 : &sourceBlock->
front()),
462 lastInlinedInst(sourceBlock->
empty() ?
nullptr : &sourceBlock->
back()) {
468 assert(!getConfig().listener &&
469 "InlineBlockRewrite not supported if listener is attached");
472 static bool classof(
const IRRewrite *
rewrite) {
473 return rewrite->getKind() == Kind::InlineBlock;
476 void rollback()
override {
479 if (firstInlinedInst) {
480 assert(lastInlinedInst &&
"expected operation");
500 class MoveBlockRewrite :
public BlockRewrite {
504 : BlockRewrite(Kind::MoveBlock, rewriterImpl, block), region(region),
505 insertBeforeBlock(insertBeforeBlock) {}
507 static bool classof(
const IRRewrite *
rewrite) {
508 return rewrite->getKind() == Kind::MoveBlock;
516 listener->notifyBlockInserted(block, region,
521 void rollback()
override {
534 Block *insertBeforeBlock;
538 class BlockTypeConversionRewrite :
public BlockRewrite {
542 : BlockRewrite(Kind::BlockTypeConversion, rewriterImpl, origBlock),
543 newBlock(newBlock) {}
545 static bool classof(
const IRRewrite *
rewrite) {
546 return rewrite->getKind() == Kind::BlockTypeConversion;
549 Block *getOrigBlock()
const {
return block; }
551 Block *getNewBlock()
const {
return newBlock; }
555 void rollback()
override;
565 class ReplaceBlockArgRewrite :
public BlockRewrite {
570 : BlockRewrite(Kind::ReplaceBlockArg, rewriterImpl, block), arg(arg),
571 converter(converter) {}
573 static bool classof(
const IRRewrite *
rewrite) {
574 return rewrite->getKind() == Kind::ReplaceBlockArg;
579 void rollback()
override;
589 class OperationRewrite :
public IRRewrite {
592 Operation *getOperation()
const {
return op; }
594 static bool classof(
const IRRewrite *
rewrite) {
595 return rewrite->getKind() >= Kind::MoveOperation &&
596 rewrite->getKind() <= Kind::UnresolvedMaterialization;
602 : IRRewrite(
kind, rewriterImpl), op(op) {}
609 class MoveOperationRewrite :
public OperationRewrite {
613 : OperationRewrite(Kind::MoveOperation, rewriterImpl, op), block(block),
614 insertBeforeOp(insertBeforeOp) {}
616 static bool classof(
const IRRewrite *
rewrite) {
617 return rewrite->getKind() == Kind::MoveOperation;
625 listener->notifyOperationInserted(
631 void rollback()
override {
649 class ModifyOperationRewrite :
public OperationRewrite {
653 : OperationRewrite(Kind::ModifyOperation, rewriterImpl, op),
661 name.initOpProperties(propCopy, prop);
665 static bool classof(
const IRRewrite *
rewrite) {
666 return rewrite->getKind() == Kind::ModifyOperation;
669 ~ModifyOperationRewrite()
override {
670 assert(!propertiesStorage &&
671 "rewrite was neither committed nor rolled back");
677 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
678 listener->notifyOperationModified(op);
680 if (propertiesStorage) {
684 name.destroyOpProperties(propCopy);
685 operator delete(propertiesStorage);
686 propertiesStorage =
nullptr;
690 void rollback()
override {
696 if (propertiesStorage) {
699 name.destroyOpProperties(propCopy);
700 operator delete(propertiesStorage);
701 propertiesStorage =
nullptr;
708 DictionaryAttr attrs;
711 void *propertiesStorage =
nullptr;
718 class ReplaceOperationRewrite :
public OperationRewrite {
722 : OperationRewrite(Kind::ReplaceOperation, rewriterImpl, op),
723 converter(converter) {}
725 static bool classof(
const IRRewrite *
rewrite) {
726 return rewrite->getKind() == Kind::ReplaceOperation;
731 void rollback()
override;
741 class CreateOperationRewrite :
public OperationRewrite {
745 : OperationRewrite(Kind::CreateOperation, rewriterImpl, op) {}
747 static bool classof(
const IRRewrite *
rewrite) {
748 return rewrite->getKind() == Kind::CreateOperation;
754 listener->notifyOperationInserted(op, {});
757 void rollback()
override;
761 enum MaterializationKind {
774 class UnresolvedMaterializationRewrite :
public OperationRewrite {
777 UnrealizedConversionCastOp op,
779 MaterializationKind
kind,
Type originalType,
782 static bool classof(
const IRRewrite *
rewrite) {
783 return rewrite->getKind() == Kind::UnresolvedMaterialization;
786 void rollback()
override;
788 UnrealizedConversionCastOp getOperation()
const {
789 return cast<UnrealizedConversionCastOp>(op);
794 return converterAndKind.getPointer();
798 MaterializationKind getMaterializationKind()
const {
799 return converterAndKind.getInt();
803 Type getOriginalType()
const {
return originalType; }
808 llvm::PointerIntPair<const TypeConverter *, 2, MaterializationKind>
821 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
824 template <
typename RewriteTy,
typename R>
825 static bool hasRewrite(R &&rewrites,
Operation *op) {
826 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
827 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
828 return rewriteTy && rewriteTy->getOperation() == op;
834 template <
typename RewriteTy,
typename R>
835 static bool hasRewrite(R &&rewrites,
Block *block) {
836 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
837 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
838 return rewriteTy && rewriteTy->getBlock() == block;
858 RewriterState getCurrentState();
862 void applyRewrites();
867 void resetState(RewriterState state, StringRef patternName =
"");
871 template <
typename RewriteTy,
typename... Args>
874 std::make_unique<RewriteTy>(*
this, std::forward<Args>(args)...));
880 void undoRewrites(
unsigned numRewritesToKeep = 0, StringRef patternName =
"");
886 LogicalResult remapValues(StringRef valueDiagTag,
887 std::optional<Location> inputLoc,
914 Block *applySignatureConversion(
937 UnrealizedConversionCastOp *castOp =
nullptr);
944 Value findOrBuildReplacementValue(
Value value,
952 void notifyOperationInserted(
Operation *op,
960 void notifyBlockIsBeingErased(
Block *block);
963 void notifyBlockInserted(
Block *block,
Region *previous,
967 void notifyBlockBeingInlined(
Block *block,
Block *srcBlock,
997 if (wasErased(block))
999 assert(block->
empty() &&
"expected empty block");
1004 bool wasErased(
void *ptr)
const {
return erased.contains(ptr); }
1068 llvm::ScopedPrinter logger{llvm::dbgs()};
1075 return rewriterImpl.config;
1078 void BlockTypeConversionRewrite::commit(
RewriterBase &rewriter) {
1082 if (
auto *listener =
1083 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
1084 for (
Operation *op : getNewBlock()->getUsers())
1085 listener->notifyOperationModified(op);
1088 void BlockTypeConversionRewrite::rollback() {
1089 getNewBlock()->replaceAllUsesWith(getOrigBlock());
1092 void ReplaceBlockArgRewrite::commit(
RewriterBase &rewriter) {
1093 Value repl = rewriterImpl.findOrBuildReplacementValue(arg, converter);
1097 if (isa<BlockArgument>(repl)) {
1105 Operation *replOp = cast<OpResult>(repl).getOwner();
1113 void ReplaceBlockArgRewrite::rollback() { rewriterImpl.mapping.erase({arg}); }
1115 void ReplaceOperationRewrite::commit(
RewriterBase &rewriter) {
1117 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener());
1120 SmallVector<Value> replacements =
1122 return rewriterImpl.findOrBuildReplacementValue(result, converter);
1127 listener->notifyOperationReplaced(op, replacements);
1130 for (
auto [result, newValue] :
1131 llvm::zip_equal(op->
getResults(), replacements))
1137 if (getConfig().unlegalizedOps)
1138 getConfig().unlegalizedOps->erase(op);
1144 [&](
Operation *op) { listener->notifyOperationErased(op); });
1152 void ReplaceOperationRewrite::rollback() {
1154 rewriterImpl.mapping.erase({result});
1157 void ReplaceOperationRewrite::cleanup(
RewriterBase &rewriter) {
1161 void CreateOperationRewrite::rollback() {
1163 while (!region.getBlocks().empty())
1164 region.getBlocks().remove(region.getBlocks().begin());
1170 UnresolvedMaterializationRewrite::UnresolvedMaterializationRewrite(
1174 : OperationRewrite(
Kind::UnresolvedMaterialization, rewriterImpl, op),
1175 converterAndKind(converter,
kind), originalType(originalType),
1176 mappedValues(std::move(mappedValues)) {
1177 assert((!originalType || kind == MaterializationKind::Target) &&
1178 "original type is valid only for target materializations");
1182 void UnresolvedMaterializationRewrite::rollback() {
1183 if (!mappedValues.empty())
1184 rewriterImpl.
mapping.erase(mappedValues);
1194 for (
size_t i = 0; i <
rewrites.size(); ++i)
1211 StringRef patternName) {
1216 while (
ignoredOps.size() != state.numIgnoredOperations)
1219 while (
replacedOps.size() != state.numReplacedOps)
1224 StringRef patternName) {
1226 llvm::reverse(llvm::drop_begin(
rewrites, numRewritesToKeep))) {
1228 !isa<UnresolvedMaterializationRewrite>(
rewrite)) {
1230 llvm::report_fatal_error(
"pattern '" + patternName +
1231 "' rollback of IR modifications requested");
1235 rewrites.resize(numRewritesToKeep);
1239 StringRef valueDiagTag, std::optional<Location> inputLoc,
1242 remapped.reserve(llvm::size(values));
1245 Value operand = it.value();
1253 remapped.push_back(
mapping.lookupOrDefault(operand));
1261 diag <<
"unable to convert type for " << valueDiagTag <<
" #"
1262 << it.index() <<
", type was " << origType;
1267 if (legalTypes.empty()) {
1268 remapped.push_back({});
1277 remapped.push_back(std::move(repl));
1282 repl =
mapping.lookupOrDefault(operand);
1285 repl, repl, legalTypes,
1287 remapped.push_back(castValues);
1311 if (region->
empty())
1316 llvm::make_early_inc_range(llvm::drop_begin(*region, 1))) {
1318 std::optional<TypeConverter::SignatureConversion> conversion =
1328 if (entryConversion)
1331 std::optional<TypeConverter::SignatureConversion> conversion =
1343 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1345 if (hasRewrite<BlockTypeConversionRewrite>(
rewrites, block))
1346 llvm::report_fatal_error(
"block was already converted");
1360 for (
unsigned i = 0; i < origArgCount; ++i) {
1362 if (!inputMap || inputMap->replacedWithValues())
1365 for (
unsigned j = 0;
j < inputMap->size; ++
j)
1366 newLocs[inputMap->inputNo +
j] = origLoc;
1373 convertedTypes, newLocs);
1383 appendRewrite<InlineBlockRewrite>(newBlock, block, newBlock->
end());
1386 while (!block->
empty())
1393 for (
unsigned i = 0; i != origArgCount; ++i) {
1397 std::optional<TypeConverter::SignatureConversion::InputMapping> inputMap =
1403 MaterializationKind::Source,
1406 origArgType,
Type(), converter);
1407 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1411 if (inputMap->replacedWithValues()) {
1413 assert(inputMap->size == 0 &&
1414 "invalid to provide a replacement value when the argument isn't "
1416 mapping.map(origArg, inputMap->replacementValues);
1417 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1423 newBlock->
getArguments().slice(inputMap->inputNo, inputMap->size);
1424 ValueVector replArgVals = llvm::to_vector_of<Value, 1>(replArgs);
1425 mapping.map(origArg, std::move(replArgVals));
1426 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1429 appendRewrite<BlockTypeConversionRewrite>(block, newBlock);
1448 UnrealizedConversionCastOp *castOp) {
1449 assert((!originalType ||
kind == MaterializationKind::Target) &&
1450 "original type is valid only for target materializations");
1451 assert(
TypeRange(inputs) != outputTypes &&
1452 "materialization is not necessary");
1456 OpBuilder builder(outputTypes.front().getContext());
1459 builder.
create<UnrealizedConversionCastOp>(loc, outputTypes, inputs);
1460 if (!valuesToMap.empty())
1461 mapping.map(valuesToMap, convertOp.getResults());
1463 *castOp = convertOp;
1464 appendRewrite<UnresolvedMaterializationRewrite>(
1465 convertOp, converter,
kind, originalType, std::move(valuesToMap));
1466 return convertOp.getResults();
1476 return repl.front();
1483 [&](
Operation *op) { return replacedOps.contains(op); }) &&
1490 repl =
mapping.lookupOrNull(value);
1524 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
1528 "attempting to insert into a block within a replaced/erased op");
1530 if (!previous.
isSet()) {
1532 appendRewrite<CreateOperationRewrite>(op);
1538 appendRewrite<MoveOperationRewrite>(op, previous.
getBlock(), prevOp);
1544 assert(!
ignoredOps.contains(op) &&
"operation was already replaced");
1548 bool isUnresolvedMaterialization =
false;
1549 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1551 isUnresolvedMaterialization =
true;
1554 for (
auto [repl, result] : llvm::zip_equal(newValues, op->
getResults())) {
1557 if (isUnresolvedMaterialization) {
1577 assert(!isUnresolvedMaterialization &&
1578 "attempting to replace an unresolved materialization");
1584 mapping.map(
static_cast<Value>(result), std::move(repl));
1593 appendRewrite<EraseBlockRewrite>(block);
1599 "attempting to insert into a region within a replaced/erased op");
1604 logger.startLine() <<
"** Insert Block into : '" << parent->
getName()
1605 <<
"'(" << parent <<
")\n";
1608 <<
"** Insert Block into detached Region (nullptr parent op)'";
1614 appendRewrite<CreateBlockRewrite>(block);
1617 Block *prevBlock = previousIt == previous->
end() ? nullptr : &*previousIt;
1618 appendRewrite<MoveBlockRewrite>(block, previous, prevBlock);
1623 appendRewrite<InlineBlockRewrite>(block, srcBlock, before);
1630 reasonCallback(
diag);
1631 logger.startLine() <<
"** Failure : " <<
diag.str() <<
"\n";
1641 ConversionPatternRewriter::ConversionPatternRewriter(
1645 setListener(
impl.get());
1651 assert(op && newOp &&
"expected non-null op");
1657 "incorrect # of replacement values");
1659 impl->logger.startLine()
1660 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1666 impl->notifyOpReplaced(op, std::move(newVals));
1672 "incorrect # of replacement values");
1674 impl->logger.startLine()
1675 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1677 impl->notifyOpReplaced(op, std::move(newValues));
1682 impl->logger.startLine()
1683 <<
"** Erase : '" << op->
getName() <<
"'(" << op <<
")\n";
1686 impl->notifyOpReplaced(op, std::move(nullRepls));
1691 "attempting to erase a block within a replaced/erased op");
1701 impl->notifyBlockIsBeingErased(block);
1709 "attempting to apply a signature conversion to a block within a "
1710 "replaced/erased op");
1711 return impl->applySignatureConversion(*
this, block, converter, conversion);
1718 "attempting to apply a signature conversion to a block within a "
1719 "replaced/erased op");
1720 return impl->convertRegionTypes(*
this, region, converter, entryConversion);
1726 impl->logger.startLine() <<
"** Replace Argument : '" << from <<
"'";
1728 impl->logger.getOStream() <<
" (in region of '" << parentOp->getName()
1729 <<
"' (" << parentOp <<
")\n";
1731 impl->logger.getOStream() <<
" (unlinked block)\n";
1734 impl->appendRewrite<ReplaceBlockArgRewrite>(from.
getOwner(), from,
1735 impl->currentTypeConverter);
1736 impl->mapping.map(
impl->mapping.lookupOrDefault(from), to);
1741 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, key,
1744 assert(remappedValues.front().size() == 1 &&
"1:N conversion not supported");
1745 return remappedValues.front().front();
1754 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, keys,
1757 for (
const auto &values : remapped) {
1758 assert(values.size() == 1 &&
"1:N conversion not supported");
1759 results.push_back(values.front());
1769 "incorrect # of argument replacement values");
1771 "attempting to inline a block from a replaced/erased op");
1773 "attempting to inline a block into a replaced/erased op");
1774 auto opIgnored = [&](
Operation *op) {
return impl->isOpIgnored(op); };
1777 assert(llvm::all_of(source->
getUsers(), opIgnored) &&
1778 "expected 'source' to have no predecessors");
1787 bool fastPath = !
impl->config.listener;
1790 impl->notifyBlockBeingInlined(dest, source, before);
1793 for (
auto it : llvm::zip(source->
getArguments(), argValues))
1794 replaceUsesOfBlockArgument(std::get<0>(it), std::get<1>(it));
1801 while (!source->
empty())
1802 moveOpBefore(&source->
front(), dest, before);
1810 assert(!
impl->wasOpReplaced(op) &&
1811 "attempting to modify a replaced/erased op");
1813 impl->pendingRootUpdates.insert(op);
1815 impl->appendRewrite<ModifyOperationRewrite>(op);
1819 assert(!
impl->wasOpReplaced(op) &&
1820 "attempting to modify a replaced/erased op");
1825 assert(
impl->pendingRootUpdates.erase(op) &&
1826 "operation did not have a pending in-place update");
1832 assert(
impl->pendingRootUpdates.erase(op) &&
1833 "operation did not have a pending in-place update");
1836 auto it = llvm::find_if(
1837 llvm::reverse(
impl->rewrites), [&](std::unique_ptr<IRRewrite> &
rewrite) {
1838 auto *modifyRewrite = dyn_cast<ModifyOperationRewrite>(rewrite.get());
1839 return modifyRewrite && modifyRewrite->getOperation() == op;
1841 assert(it !=
impl->rewrites.rend() &&
"no root update started on op");
1843 int updateIdx = std::prev(
impl->rewrites.rend()) - it;
1844 impl->rewrites.erase(
impl->rewrites.begin() + updateIdx);
1858 oneToOneOperands.reserve(operands.size());
1860 if (operand.size() != 1)
1861 llvm::report_fatal_error(
"pattern '" + getDebugName() +
1862 "' does not support 1:N conversion");
1863 oneToOneOperands.push_back(operand.front());
1865 return oneToOneOperands;
1872 auto &rewriterImpl = dialectRewriter.getImpl();
1876 getTypeConverter());
1885 llvm::to_vector_of<ValueRange>(remapped);
1886 return matchAndRewrite(op, remappedAsRange, dialectRewriter);
1898 class OperationLegalizer {
1918 LogicalResult legalizeWithFold(
Operation *op,
1923 LogicalResult legalizeWithPattern(
Operation *op,
1934 RewriterState &curState);
1938 legalizePatternBlockRewrites(
Operation *op,
1941 RewriterState &state, RewriterState &newState);
1942 LogicalResult legalizePatternCreatedOperations(
1944 RewriterState &state, RewriterState &newState);
1947 RewriterState &state,
1948 RewriterState &newState);
1958 void buildLegalizationGraph(
1959 LegalizationPatterns &anyOpLegalizerPatterns,
1970 void computeLegalizationGraphBenefit(
1971 LegalizationPatterns &anyOpLegalizerPatterns,
1976 unsigned computeOpLegalizationDepth(
1983 unsigned applyCostModelToPatterns(
2009 LegalizationPatterns anyOpLegalizerPatterns;
2011 buildLegalizationGraph(anyOpLegalizerPatterns, legalizerPatterns);
2012 computeLegalizationGraphBenefit(anyOpLegalizerPatterns, legalizerPatterns);
2015 bool OperationLegalizer::isIllegal(
Operation *op)
const {
2016 return target.isIllegal(op);
2020 OperationLegalizer::legalize(
Operation *op,
2023 const char *logLineComment =
2024 "//===-------------------------------------------===//\n";
2029 logger.getOStream() <<
"\n";
2030 logger.startLine() << logLineComment;
2031 logger.startLine() <<
"Legalizing operation : '" << op->
getName() <<
"'("
2037 op->print(logger.startLine(), OpPrintingFlags().printGenericOpForm());
2038 logger.getOStream() <<
"\n\n";
2043 if (
auto legalityInfo = target.isLegal(op)) {
2046 logger,
"operation marked legal by the target{0}",
2047 legalityInfo->isRecursivelyLegal
2048 ?
"; NOTE: operation is recursively legal; skipping internals"
2050 logger.startLine() << logLineComment;
2055 if (legalityInfo->isRecursivelyLegal) {
2068 logSuccess(logger,
"operation marked 'ignored' during conversion");
2069 logger.startLine() << logLineComment;
2077 if (succeeded(legalizeWithFold(op, rewriter))) {
2080 logger.startLine() << logLineComment;
2086 if (succeeded(legalizeWithPattern(op, rewriter))) {
2089 logger.startLine() << logLineComment;
2095 logFailure(logger,
"no matched legalization pattern");
2096 logger.startLine() << logLineComment;
2102 OperationLegalizer::legalizeWithFold(
Operation *op,
2104 auto &rewriterImpl = rewriter.
getImpl();
2106 rewriterImpl.
logger.startLine() <<
"* Fold {\n";
2107 rewriterImpl.
logger.indent();
2112 SmallVector<Value, 2> replacementValues;
2113 SmallVector<Operation *, 2> newOps;
2115 if (failed(rewriter.
tryFold(op, replacementValues, &newOps))) {
2122 if (replacementValues.empty())
2123 return legalize(op, rewriter);
2127 if (failed(legalize(newOp, rewriter))) {
2129 "failed to legalize generated constant '{0}'",
2139 rewriter.
replaceOp(op, replacementValues);
2146 OperationLegalizer::legalizeWithPattern(
Operation *op,
2148 auto &rewriterImpl = rewriter.
getImpl();
2151 auto canApply = [&](
const Pattern &pattern) {
2152 bool canApply = canApplyPattern(op, pattern, rewriter);
2153 if (canApply &&
config.listener)
2154 config.listener->notifyPatternBegin(pattern, op);
2160 auto onFailure = [&](
const Pattern &pattern) {
2166 diag <<
"Failed to apply pattern \"" << pattern.getDebugName()
2173 config.listener->notifyPatternEnd(pattern, failure());
2174 rewriterImpl.
resetState(curState, pattern.getDebugName());
2175 appliedPatterns.erase(&pattern);
2180 auto onSuccess = [&](
const Pattern &pattern) {
2182 auto result = legalizePatternResult(op, pattern, rewriter, curState);
2183 appliedPatterns.erase(&pattern);
2184 if (failed(result)) {
2187 << pattern.getDebugName()
2188 <<
"' produced IR that could not be legalized";
2189 rewriterImpl.
resetState(curState, pattern.getDebugName());
2192 config.listener->notifyPatternEnd(pattern, result);
2197 return applicator.matchAndRewrite(op, rewriter, canApply, onFailure,
2201 bool OperationLegalizer::canApplyPattern(
Operation *op,
const Pattern &pattern,
2204 auto &os = rewriter.
getImpl().logger;
2205 os.getOStream() <<
"\n";
2206 os.startLine() <<
"* Pattern : '" << op->
getName() <<
" -> (";
2208 os.getOStream() <<
")' {\n";
2215 !appliedPatterns.insert(&pattern).second) {
2224 OperationLegalizer::legalizePatternResult(
Operation *op,
const Pattern &pattern,
2226 RewriterState &curState) {
2228 assert(
impl.pendingRootUpdates.empty() &&
"dangling root updates");
2230 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2232 auto newRewrites = llvm::drop_begin(
impl.rewrites, curState.numRewrites);
2233 auto replacedRoot = [&] {
2234 return hasRewrite<ReplaceOperationRewrite>(newRewrites, op);
2236 auto updatedRootInPlace = [&] {
2237 return hasRewrite<ModifyOperationRewrite>(newRewrites, op);
2239 if (!replacedRoot() && !updatedRootInPlace())
2240 llvm::report_fatal_error(
"expected pattern to replace the root operation");
2244 RewriterState newState =
impl.getCurrentState();
2245 if (failed(legalizePatternBlockRewrites(op, rewriter,
impl, curState,
2247 failed(legalizePatternRootUpdates(rewriter,
impl, curState, newState)) ||
2248 failed(legalizePatternCreatedOperations(rewriter,
impl, curState,
2253 LLVM_DEBUG(
logSuccess(
impl.logger,
"pattern applied successfully"));
2257 LogicalResult OperationLegalizer::legalizePatternBlockRewrites(
2260 RewriterState &newState) {
2265 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2266 BlockRewrite *
rewrite = dyn_cast<BlockRewrite>(
impl.rewrites[i].get());
2270 if (isa<BlockTypeConversionRewrite, EraseBlockRewrite,
2271 ReplaceBlockArgRewrite>(
rewrite))
2280 if (
auto *converter =
impl.regionToConverter.lookup(block->
getParent())) {
2281 std::optional<TypeConverter::SignatureConversion> conversion =
2284 LLVM_DEBUG(
logFailure(
impl.logger,
"failed to convert types of moved "
2288 impl.applySignatureConversion(rewriter, block, converter, *conversion);
2296 if (operationsToIgnore.empty()) {
2297 for (
unsigned i = state.numRewrites, e =
impl.rewrites.size(); i != e;
2300 dyn_cast<CreateOperationRewrite>(
impl.rewrites[i].get());
2303 operationsToIgnore.insert(createOp->getOperation());
2308 if (operationsToIgnore.insert(parentOp).second &&
2309 failed(legalize(parentOp, rewriter))) {
2311 "operation '{0}'({1}) became illegal after rewrite",
2312 parentOp->
getName(), parentOp));
2319 LogicalResult OperationLegalizer::legalizePatternCreatedOperations(
2321 RewriterState &state, RewriterState &newState) {
2322 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2323 auto *createOp = dyn_cast<CreateOperationRewrite>(
impl.rewrites[i].get());
2326 Operation *op = createOp->getOperation();
2327 if (failed(legalize(op, rewriter))) {
2329 "failed to legalize generated operation '{0}'({1})",
2337 LogicalResult OperationLegalizer::legalizePatternRootUpdates(
2339 RewriterState &state, RewriterState &newState) {
2340 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2341 auto *
rewrite = dyn_cast<ModifyOperationRewrite>(
impl.rewrites[i].get());
2345 if (failed(legalize(op, rewriter))) {
2347 impl.logger,
"failed to legalize operation updated in-place '{0}'",
2359 void OperationLegalizer::buildLegalizationGraph(
2360 LegalizationPatterns &anyOpLegalizerPatterns,
2371 applicator.walkAllPatterns([&](
const Pattern &pattern) {
2372 std::optional<OperationName> root = pattern.
getRootKind();
2378 anyOpLegalizerPatterns.push_back(&pattern);
2383 if (target.getOpAction(*root) == LegalizationAction::Legal)
2388 invalidPatterns[*root].insert(&pattern);
2390 parentOps[op].insert(*root);
2393 patternWorklist.insert(&pattern);
2401 if (!anyOpLegalizerPatterns.empty()) {
2402 for (
const Pattern *pattern : patternWorklist)
2403 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2407 while (!patternWorklist.empty()) {
2408 auto *pattern = patternWorklist.pop_back_val();
2412 std::optional<LegalizationAction> action = target.getOpAction(op);
2413 return !legalizerPatterns.count(op) &&
2414 (!action || action == LegalizationAction::Illegal);
2420 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2421 invalidPatterns[*pattern->
getRootKind()].erase(pattern);
2425 for (
auto op : parentOps[*pattern->
getRootKind()])
2426 patternWorklist.set_union(invalidPatterns[op]);
2430 void OperationLegalizer::computeLegalizationGraphBenefit(
2431 LegalizationPatterns &anyOpLegalizerPatterns,
2437 for (
auto &opIt : legalizerPatterns)
2438 if (!minOpPatternDepth.count(opIt.first))
2439 computeOpLegalizationDepth(opIt.first, minOpPatternDepth,
2445 if (!anyOpLegalizerPatterns.empty())
2446 applyCostModelToPatterns(anyOpLegalizerPatterns, minOpPatternDepth,
2452 applicator.applyCostModel([&](
const Pattern &pattern) {
2454 if (std::optional<OperationName> rootName = pattern.
getRootKind())
2455 orderedPatternList = legalizerPatterns[*rootName];
2457 orderedPatternList = anyOpLegalizerPatterns;
2460 auto *it = llvm::find(orderedPatternList, &pattern);
2461 if (it == orderedPatternList.end())
2465 return PatternBenefit(std::distance(it, orderedPatternList.end()));
2469 unsigned OperationLegalizer::computeOpLegalizationDepth(
2473 auto depthIt = minOpPatternDepth.find(op);
2474 if (depthIt != minOpPatternDepth.end())
2475 return depthIt->second;
2479 auto opPatternsIt = legalizerPatterns.find(op);
2480 if (opPatternsIt == legalizerPatterns.end() || opPatternsIt->second.empty())
2489 unsigned minDepth = applyCostModelToPatterns(
2490 opPatternsIt->second, minOpPatternDepth, legalizerPatterns);
2491 minOpPatternDepth[op] = minDepth;
2495 unsigned OperationLegalizer::applyCostModelToPatterns(
2502 SmallVector<std::pair<const Pattern *, unsigned>, 4> patternsByDepth;
2503 patternsByDepth.reserve(
patterns.size());
2507 unsigned generatedOpDepth = computeOpLegalizationDepth(
2508 generatedOp, minOpPatternDepth, legalizerPatterns);
2509 depth =
std::max(depth, generatedOpDepth + 1);
2511 patternsByDepth.emplace_back(pattern, depth);
2514 minDepth =
std::min(minDepth, depth);
2519 if (patternsByDepth.size() == 1)
2523 llvm::stable_sort(patternsByDepth,
2524 [](
const std::pair<const Pattern *, unsigned> &lhs,
2525 const std::pair<const Pattern *, unsigned> &rhs) {
2528 if (lhs.second != rhs.second)
2529 return lhs.second < rhs.second;
2532 auto lhsBenefit = lhs.first->getBenefit();
2533 auto rhsBenefit = rhs.first->getBenefit();
2534 return lhsBenefit > rhsBenefit;
2539 for (
auto &patternIt : patternsByDepth)
2540 patterns.push_back(patternIt.first);
2548 enum OpConversionMode {
2571 OpConversionMode mode)
2586 OperationLegalizer opLegalizer;
2589 OpConversionMode mode;
2596 if (failed(opLegalizer.legalize(op, rewriter))) {
2599 if (mode == OpConversionMode::Full)
2601 <<
"failed to legalize operation '" << op->
getName() <<
"'";
2605 if (mode == OpConversionMode::Partial) {
2606 if (opLegalizer.isIllegal(op))
2608 <<
"failed to legalize operation '" << op->
getName()
2609 <<
"' that was explicitly marked illegal";
2613 }
else if (mode == OpConversionMode::Analysis) {
2623 static LogicalResult
2625 UnresolvedMaterializationRewrite *
rewrite) {
2626 UnrealizedConversionCastOp op =
rewrite->getOperation();
2627 assert(!op.use_empty() &&
2628 "expected that dead materializations have already been DCE'd");
2634 SmallVector<Value> newMaterialization;
2635 switch (
rewrite->getMaterializationKind()) {
2636 case MaterializationKind::Target:
2638 rewriter, op->getLoc(), op.getResultTypes(), inputOperands,
2641 case MaterializationKind::Source:
2642 assert(op->getNumResults() == 1 &&
"expected single result");
2644 rewriter, op->getLoc(), op.getResultTypes().front(), inputOperands);
2646 newMaterialization.push_back(sourceMat);
2649 if (!newMaterialization.empty()) {
2651 ValueRange newMaterializationRange(newMaterialization);
2652 assert(
TypeRange(newMaterializationRange) == op.getResultTypes() &&
2653 "materialization callback produced value of incorrect type");
2655 rewriter.
replaceOp(op, newMaterialization);
2661 <<
"failed to legalize unresolved materialization "
2663 << inputOperands.
getTypes() <<
") to ("
2664 << op.getResultTypes()
2665 <<
") that remained live after conversion";
2666 diag.attachNote(op->getUsers().begin()->getLoc())
2667 <<
"see existing live user here: " << *op->getUsers().begin();
2678 for (
auto *op : ops) {
2681 toConvert.push_back(op);
2684 auto legalityInfo = target.
isLegal(op);
2685 if (legalityInfo && legalityInfo->isRecursivelyLegal)
2695 for (
auto *op : toConvert) {
2696 if (failed(convert(rewriter, op))) {
2717 for (
auto it : materializations) {
2720 allCastOps.push_back(it.first);
2732 for (UnrealizedConversionCastOp castOp : remainingCastOps) {
2733 auto it = materializations.find(castOp);
2734 assert(it != materializations.end() &&
"inconsistent state");
2756 auto enqueueOperands = [&](UnrealizedConversionCastOp castOp) {
2757 for (
Value v : castOp.getInputs())
2758 if (
auto inputCastOp = v.getDefiningOp<UnrealizedConversionCastOp>())
2759 worklist.insert(inputCastOp);
2766 [](UnrealizedConversionCastOp castOp) -> UnrealizedConversionCastOp {
2767 if (castOp.getInputs().empty())
2770 castOp.getInputs().front().getDefiningOp<UnrealizedConversionCastOp>();
2773 if (inputCastOp.getOutputs() != castOp.getInputs())
2779 while (!worklist.empty()) {
2780 UnrealizedConversionCastOp castOp = worklist.pop_back_val();
2781 if (castOp->use_empty()) {
2784 enqueueOperands(castOp);
2785 if (remainingCastOps)
2786 erasedOps.insert(castOp.getOperation());
2793 UnrealizedConversionCastOp nextCast = castOp;
2795 if (nextCast.getInputs().getTypes() == castOp.getResultTypes()) {
2799 enqueueOperands(castOp);
2800 castOp.replaceAllUsesWith(nextCast.getInputs());
2801 if (remainingCastOps)
2802 erasedOps.insert(castOp.getOperation());
2806 nextCast = getInputCast(nextCast);
2810 if (remainingCastOps)
2811 for (UnrealizedConversionCastOp op : castOps)
2812 if (!erasedOps.contains(op.getOperation()))
2813 remainingCastOps->push_back(op);
2822 assert(!types.empty() &&
"expected valid types");
2823 remapInput(origInputNo, argTypes.size(), types.size());
2828 assert(!types.empty() &&
2829 "1->0 type remappings don't need to be added explicitly");
2830 argTypes.append(types.begin(), types.end());
2834 unsigned newInputNo,
2835 unsigned newInputCount) {
2836 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2837 assert(newInputCount != 0 &&
"expected valid input count");
2838 remappedInputs[origInputNo] =
2839 InputMapping{newInputNo, newInputCount, {}};
2844 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2852 assert(t &&
"expected non-null type");
2855 std::shared_lock<decltype(cacheMutex)> cacheReadLock(cacheMutex,
2858 cacheReadLock.lock();
2859 auto existingIt = cachedDirectConversions.find(t);
2860 if (existingIt != cachedDirectConversions.end()) {
2861 if (existingIt->second)
2862 results.push_back(existingIt->second);
2863 return success(existingIt->second !=
nullptr);
2865 auto multiIt = cachedMultiConversions.find(t);
2866 if (multiIt != cachedMultiConversions.end()) {
2867 results.append(multiIt->second.begin(), multiIt->second.end());
2873 size_t currentCount = results.size();
2875 std::unique_lock<decltype(cacheMutex)> cacheWriteLock(cacheMutex,
2878 for (
const ConversionCallbackFn &converter : llvm::reverse(conversions)) {
2879 if (std::optional<LogicalResult> result = converter(t, results)) {
2881 cacheWriteLock.lock();
2882 if (!succeeded(*result)) {
2883 assert(results.size() == currentCount &&
2884 "failed type conversion should not change results");
2885 cachedDirectConversions.try_emplace(t,
nullptr);
2888 auto newTypes =
ArrayRef<Type>(results).drop_front(currentCount);
2889 if (newTypes.size() == 1)
2890 cachedDirectConversions.try_emplace(t, newTypes.front());
2892 cachedMultiConversions.try_emplace(t, llvm::to_vector<2>(newTypes));
2895 assert(results.size() == currentCount &&
2896 "failed type conversion should not change results");
2909 return results.size() == 1 ? results.front() :
nullptr;
2915 for (
Type type : types)
2929 return llvm::all_of(*region, [
this](
Block &block) {
2935 return isLegal(llvm::concat<const Type>(ty.getInputs(), ty.getResults()));
2947 if (convertedTypes.empty())
2951 result.
addInputs(inputNo, convertedTypes);
2957 unsigned origInputOffset)
const {
2958 for (
unsigned i = 0, e = types.size(); i != e; ++i)
2967 for (
const SourceMaterializationCallbackFn &fn :
2968 llvm::reverse(sourceMaterializations))
2969 if (
Value result = fn(builder, resultType, inputs, loc))
2977 Type originalType)
const {
2979 builder, loc,
TypeRange(resultType), inputs, originalType);
2982 assert(result.size() == 1 &&
"expected single result");
2983 return result.front();
2988 Type originalType)
const {
2989 for (
const TargetMaterializationCallbackFn &fn :
2990 llvm::reverse(targetMaterializations)) {
2992 fn(builder, resultTypes, inputs, loc, originalType);
2996 "callback produced incorrect number of values or values with "
3003 std::optional<TypeConverter::SignatureConversion>
3007 return std::nullopt;
3030 return impl.getInt() == resultTag;
3034 return impl.getInt() == naTag;
3038 return impl.getInt() == abortTag;
3042 assert(hasResult() &&
"Cannot get result from N/A or abort");
3043 return impl.getPointer();
3046 std::optional<Attribute>
3048 for (
const TypeAttributeConversionCallbackFn &fn :
3049 llvm::reverse(typeAttributeConversions)) {
3054 return std::nullopt;
3056 return std::nullopt;
3066 FunctionType type = dyn_cast<FunctionType>(funcOp.getFunctionType());
3072 SmallVector<Type, 1> newResults;
3074 failed(typeConverter.
convertTypes(type.getResults(), newResults)) ||
3076 typeConverter, &result)))
3093 FunctionOpInterfaceSignatureConversion(StringRef functionLikeOpName,
3101 FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
3106 struct AnyFunctionOpInterfaceSignatureConversion
3118 FailureOr<Operation *>
3122 assert(op &&
"Invalid op");
3136 return rewriter.
create(newOp);
3142 patterns.add<FunctionOpInterfaceSignatureConversion>(
3143 functionLikeOpName,
patterns.getContext(), converter);
3148 patterns.add<AnyFunctionOpInterfaceSignatureConversion>(
3158 legalOperations[op].action = action;
3163 for (StringRef dialect : dialectNames)
3164 legalDialects[dialect] = action;
3168 -> std::optional<LegalizationAction> {
3169 std::optional<LegalizationInfo> info = getOpInfo(op);
3170 return info ? info->action : std::optional<LegalizationAction>();
3174 -> std::optional<LegalOpDetails> {
3175 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3177 return std::nullopt;
3180 auto isOpLegal = [&] {
3182 if (info->action == LegalizationAction::Dynamic) {
3183 std::optional<bool> result = info->legalityFn(op);
3189 return info->action == LegalizationAction::Legal;
3192 return std::nullopt;
3196 if (info->isRecursivelyLegal) {
3197 auto legalityFnIt = opRecursiveLegalityFns.find(op->
getName());
3198 if (legalityFnIt != opRecursiveLegalityFns.end()) {
3200 legalityFnIt->second(op).value_or(
true);
3205 return legalityDetails;
3209 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3213 if (info->action == LegalizationAction::Dynamic) {
3214 std::optional<bool> result = info->legalityFn(op);
3221 return info->action == LegalizationAction::Illegal;
3230 auto chain = [oldCl = std::move(oldCallback), newCl = std::move(newCallback)](
3232 if (std::optional<bool> result = newCl(op))
3240 void ConversionTarget::setLegalityCallback(
3241 OperationName name,
const DynamicLegalityCallbackFn &callback) {
3242 assert(callback &&
"expected valid legality callback");
3243 auto *infoIt = legalOperations.find(name);
3244 assert(infoIt != legalOperations.end() &&
3245 infoIt->second.action == LegalizationAction::Dynamic &&
3246 "expected operation to already be marked as dynamically legal");
3247 infoIt->second.legalityFn =
3253 auto *infoIt = legalOperations.find(name);
3254 assert(infoIt != legalOperations.end() &&
3255 infoIt->second.action != LegalizationAction::Illegal &&
3256 "expected operation to already be marked as legal");
3257 infoIt->second.isRecursivelyLegal =
true;
3260 std::move(opRecursiveLegalityFns[name]), callback);
3262 opRecursiveLegalityFns.erase(name);
3265 void ConversionTarget::setLegalityCallback(
3267 assert(callback &&
"expected valid legality callback");
3268 for (StringRef dialect : dialects)
3270 std::move(dialectLegalityFns[dialect]), callback);
3273 void ConversionTarget::setLegalityCallback(
3274 const DynamicLegalityCallbackFn &callback) {
3275 assert(callback &&
"expected valid legality callback");
3280 -> std::optional<LegalizationInfo> {
3282 const auto *it = legalOperations.find(op);
3283 if (it != legalOperations.end())
3286 auto dialectIt = legalDialects.find(op.getDialectNamespace());
3287 if (dialectIt != legalDialects.end()) {
3288 DynamicLegalityCallbackFn callback;
3289 auto dialectFn = dialectLegalityFns.find(op.getDialectNamespace());
3290 if (dialectFn != dialectLegalityFns.end())
3291 callback = dialectFn->second;
3292 return LegalizationInfo{dialectIt->second,
false,
3296 if (unknownLegalityFn)
3297 return LegalizationInfo{LegalizationAction::Dynamic,
3298 false, unknownLegalityFn};
3299 return std::nullopt;
3302 #if MLIR_ENABLE_PDL_IN_PATTERNMATCH
3308 auto &rewriterImpl =
3314 auto &rewriterImpl =
3321 static FailureOr<SmallVector<Value>>
3323 SmallVector<Value> mappedValues;
3326 return std::move(mappedValues);
3330 patterns.getPDLPatterns().registerRewriteFunction(
3335 if (failed(results))
3337 return results->front();
3339 patterns.getPDLPatterns().registerRewriteFunction(
3344 patterns.getPDLPatterns().registerRewriteFunction(
3347 auto &rewriterImpl =
3357 patterns.getPDLPatterns().registerRewriteFunction(
3360 TypeRange types) -> FailureOr<SmallVector<Type>> {
3361 auto &rewriterImpl =
3368 if (failed(converter->
convertTypes(types, remappedTypes)))
3370 return std::move(remappedTypes);
3387 OpConversionMode::Partial);
3406 OpConversionMode::Full);
3430 "expected top-level op to be isolated from above");
3433 "expected ops to have a common ancestor");
3442 for (
Operation *op : ops.drop_front()) {
3446 assert(commonAncestor &&
3447 "expected to find a common isolated from above ancestor");
3451 return commonAncestor;
3458 if (
config.legalizableOps)
3459 assert(
config.legalizableOps->empty() &&
"expected empty set");
3469 inverseOperationMap[it.second] = it.first;
3475 OpConversionMode::Analysis);
3476 LogicalResult status = opConverter.convertOperations(opsToConvert);
3480 if (
config.legalizableOps) {
3483 originalLegalizableOps.insert(inverseOperationMap[op]);
3484 *
config.legalizableOps = std::move(originalLegalizableOps);
3488 clonedAncestor->
erase();
static ConversionTarget::DynamicLegalityCallbackFn composeLegalityCallbacks(ConversionTarget::DynamicLegalityCallbackFn oldCallback, ConversionTarget::DynamicLegalityCallbackFn newCallback)
static FailureOr< SmallVector< Value > > pdllConvertValues(ConversionPatternRewriter &rewriter, ValueRange values)
Remap the given value using the rewriter and the type converter in the provided config.
static LogicalResult convertFuncOpTypes(FunctionOpInterface funcOp, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args)
A utility function to log a failure result for the given reason.
static LogicalResult legalizeUnresolvedMaterialization(RewriterBase &rewriter, UnresolvedMaterializationRewrite *rewrite)
static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args)
A utility function to log a successful result for the given reason.
SmallVector< Value, 1 > ValueVector
A vector of SSA values, optimized for the most common case of a single value.
static Operation * findCommonAncestor(ArrayRef< Operation * > ops)
Find a common IsolatedFromAbove ancestor of the given ops.
static OpBuilder::InsertPoint computeInsertPoint(Value value)
Helper function that computes an insertion point where the given value is defined and can be used wit...
union mlir::linalg::@1194::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void rewrite(DataFlowSolver &solver, MLIRContext *context, MutableArrayRef< Region > initialRegions)
Rewrite the given regions using the computing analysis.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block * getOwner() const
Returns the block that owns this argument.
Location getLoc() const
Return the location for this argument.
Block represents an ordered list of Operations.
OpListType::iterator iterator
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
void erase()
Unlink this Block from its parent region and delete it.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
OpListType & getOperations()
BlockArgListType getArguments()
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
MLIRContext * getContext() const
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
LogicalResult getRemappedValues(ValueRange keys, SmallVectorImpl< Value > &results)
Return the converted values that replace 'keys' with types defined by the type converter of the curre...
FailureOr< Block * > convertRegionTypes(Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion=nullptr)
Apply a signature conversion to each block in the given region.
void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues=std::nullopt) override
PatternRewriter hook for inlining the ops of a block into another block.
void replaceOpWithMultiple(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Replace the given operation with the new value ranges.
Block * applySignatureConversion(Block *block, TypeConverter::SignatureConversion &conversion, const TypeConverter *converter=nullptr)
Apply a signature conversion to given block.
void startOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
detail::ConversionPatternRewriterImpl & getImpl()
Return a reference to the internal implementation.
void eraseBlock(Block *block) override
PatternRewriter hook for erase all operations in a block.
void cancelOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
Value getRemappedValue(Value key)
Return the converted value of 'key' with a type defined by the type converter of the currently execut...
void finalizeOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void replaceUsesOfBlockArgument(BlockArgument from, Value to)
Replace all the uses of the block argument from with value to.
~ConversionPatternRewriter() override
Base class for the conversion patterns.
SmallVector< Value > getOneToOneAdaptorOperands(ArrayRef< ValueRange > operands) const
Given an array of value ranges, which are the inputs to a 1:N adaptor, try to extract the single valu...
virtual LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const
Hook for derived classes to implement combined matching and rewriting.
This class describes a specific conversion target.
void setDialectAction(ArrayRef< StringRef > dialectNames, LegalizationAction action)
Register a legality action for the given dialects.
void setOpAction(OperationName op, LegalizationAction action)
Register a legality action for the given operation.
std::optional< LegalOpDetails > isLegal(Operation *op) const
If the given operation instance is legal on this target, a structure containing legality information ...
std::optional< LegalizationAction > getOpAction(OperationName op) const
Get the legality action for the given operation.
LegalizationAction
This enumeration corresponds to the specific action to take when considering an operation legal for t...
void markOpRecursivelyLegal(OperationName name, const DynamicLegalityCallbackFn &callback)
Mark an operation, that must have either been set as Legal or DynamicallyLegal, as being recursively ...
std::function< std::optional< bool >(Operation *)> DynamicLegalityCallbackFn
The signature of the callback used to determine if an operation is dynamically legal on the target.
bool isIllegal(Operation *op) const
Returns true is operation instance is illegal on this target.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This is a utility class for mapping one set of IR entities to another.
const DenseMap< Operation *, Operation * > & getOperationMap() const
Return the held operation mapping.
auto lookup(T from) const
Lookup a mapped value within the map.
user_range getUsers() const
Returns a range of all users.
void dropAllUses()
Drop all uses of this object from their respective owners.
void replaceAllUsesWith(ValueT &&newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
This class represents a diagnostic that is inflight and set to be reported.
Location objects represent source locations information in MLIR.
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.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
This class represents a saved insertion point.
Block::iterator getPoint() const
bool isSet() const
Returns true if this insert point is set.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Listener * getListener() const
Returns the current listener of this builder, or nullptr if this builder doesn't have a listener.
LogicalResult tryFold(Operation *op, SmallVectorImpl< Value > &results, SmallVectorImpl< Operation * > *materializedConstants=nullptr)
Attempts to fold the given operation and places new results within results.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes=std::nullopt, ArrayRef< Location > locs=std::nullopt)
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
OpInterfaceConversionPattern is a wrapper around ConversionPattern that allows for matching and rewri...
OpInterfaceConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
This class represents an operand of an operation.
This is a value defined by a result of an operation.
This class provides the API for ops that are known to be isolated from above.
Simple wrapper around a void* in order to express generically how to pass in op properties through AP...
This class implements the operand iterators for the Operation class.
type_range getTypes() const
Operation is the basic unit of execution within MLIR.
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
void dropAllUses()
Drop all uses of results of this operation.
void setAttrs(DictionaryAttr newAttrs)
Set the attributes from a dictionary on this operation.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
operand_iterator operand_begin()
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),...
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...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
operand_iterator operand_end()
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
void setSuccessor(Block *block, unsigned index)
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
result_range getResults()
int getPropertiesStorageSize() const
Returns the properties storage size.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
succ_iterator successor_end()
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
void erase()
Remove this operation from its parent block and delete it.
void copyProperties(OpaqueProperties rhs)
Copy properties from an existing other properties object.
succ_iterator successor_begin()
unsigned getNumResults()
Return the number of results held by this operation.
void notifyRewriteEnd(PatternRewriter &rewriter) final
void notifyRewriteBegin(PatternRewriter &rewriter) final
Hooks that are invoked at the beginning and end of a rewrite of a matched pattern.
This class manages the application of a group of rewrite patterns, with a user-provided cost model.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
static PatternBenefit impossibleToMatch()
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class contains all of the data related to a pattern, but does not contain any methods or logic f...
bool hasBoundedRewriteRecursion() const
Returns true if this pattern is known to result in recursive application, i.e.
std::optional< OperationName > getRootKind() const
Return the root node that this pattern matches.
ArrayRef< OperationName > getGeneratedOps() const
Return a list of operations that may be generated when rewriting an operation instance with this patt...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Operation * getParentOp()
Return the parent operation this region is attached to.
BlockListType & getBlocks()
BlockListType::iterator iterator
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
virtual void eraseBlock(Block *block)
This method erases all operations in a block.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
virtual void finalizeOpModification(Operation *op)
This method is used to signal the end of an in-place modification of the given operation.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void replaceUsesWithIf(Value from, Value to, function_ref< bool(OpOperand &)> functor, bool *allUsesReplaced=nullptr)
Find uses of from and replace them with to if the functor returns true.
void moveOpBefore(Operation *op, Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
The general result of a type attribute conversion callback, allowing for early termination.
Attribute getResult() const
static AttributeConversionResult abort()
static AttributeConversionResult na()
static AttributeConversionResult result(Attribute attr)
This class provides all of the information necessary to convert a type signature.
void addInputs(unsigned origInputNo, ArrayRef< Type > types)
Remap an input of the original signature with a new set of types.
std::optional< InputMapping > getInputMapping(unsigned input) const
Get the input mapping for the given argument.
ArrayRef< Type > getConvertedTypes() const
Return the argument types for the new signature.
void remapInput(unsigned origInputNo, ArrayRef< Value > replacements)
Remap an input of the original signature to replacements values.
std::optional< Attribute > convertTypeAttribute(Type type, Attribute attr) const
Convert an attribute present attr from within the type type using the registered conversion functions...
Value materializeSourceConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs) const
Materialize a conversion from a set of types into one result type by generating a cast sequence of so...
bool isLegal(Type type) const
Return true if the given type is legal for this type converter, i.e.
LogicalResult convertSignatureArgs(TypeRange types, SignatureConversion &result, unsigned origInputOffset=0) const
LogicalResult convertSignatureArg(unsigned inputNo, Type type, SignatureConversion &result) const
This method allows for converting a specific argument of a signature.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
std::optional< SignatureConversion > convertBlockSignature(Block *block) const
This function converts the type signature of the given block, by invoking 'convertSignatureArg' for e...
LogicalResult convertTypes(TypeRange types, SmallVectorImpl< Type > &results) const
Convert the given set of types, filling 'results' as necessary.
bool isSignatureLegal(FunctionType ty) const
Return true if the inputs and outputs of the given function type are legal.
Value materializeTargetConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs, Type originalType={}) const
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Block * getParentBlock()
Return the Block in which this Value is defined.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
static WalkResult advance()
Operation * getOwner() const
Return the owner of this operand.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
@ Full
Documents are synced by always sending the full content of the document.
Kind
An enumeration of the kinds of predicates.
Include the generated interface declarations.
void populateFunctionOpInterfaceTypeConversionPattern(StringRef functionLikeOpName, RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to convert the signature of a FunctionOpInterface op with the...
void populateAnyFunctionOpInterfaceTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
const FrozenRewritePatternSet GreedyRewriteConfig config
LogicalResult applyFullConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply a complete conversion on the given operations, and all nested operations.
FailureOr< Operation * > convertOpResultTypes(Operation *op, ValueRange operands, const TypeConverter &converter, ConversionPatternRewriter &rewriter)
Generic utility to convert op result types according to type converter without knowing exact op type.
const FrozenRewritePatternSet & patterns
LogicalResult applyAnalysisConversion(ArrayRef< Operation * > ops, ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply an analysis conversion on the given operations, and all nested operations.
void reconcileUnrealizedCasts(ArrayRef< UnrealizedConversionCastOp > castOps, SmallVectorImpl< UnrealizedConversionCastOp > *remainingCastOps=nullptr)
Try to reconcile all given UnrealizedConversionCastOps and store the left-over ops in remainingCastOp...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void registerConversionPDLFunctions(RewritePatternSet &patterns)
Register the dialect conversion PDL functions with the given pattern set.
LogicalResult applyPartialConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Below we define several entry points for operation conversion.
Dialect conversion configuration.
bool allowPatternRollback
If set to "true", pattern rollback is allowed.
RewriterBase::Listener * listener
An optional listener that is notified about all IR modifications in case dialect conversion succeeds.
function_ref< void(Diagnostic &)> notifyCallback
An optional callback used to notify about match failure diagnostics during the conversion.
DenseSet< Operation * > * legalizableOps
Analysis conversion only.
DenseSet< Operation * > * unlegalizedOps
Partial conversion only.
bool buildMaterializations
If set to "true", the dialect conversion attempts to build source/target materializations through the...
A structure containing additional information describing a specific legal operation instance.
bool isRecursivelyLegal
A flag that indicates if this operation is 'recursively' legal.
This iterator enumerates elements according to their dominance relationship.
LogicalResult convertOperations(ArrayRef< Operation * > ops)
Converts the given operations to the conversion target.
OperationConverter(const ConversionTarget &target, const FrozenRewritePatternSet &patterns, const ConversionConfig &config, OpConversionMode mode)
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addTypes(ArrayRef< Type > newTypes)
A rewriter that keeps track of erased ops and blocks.
bool wasErased(void *ptr) const
SingleEraseRewriter(MLIRContext *context)
void eraseOp(Operation *op) override
Erase the given op (unless it was already erased).
void notifyBlockErased(Block *block) override
Notify the listener that the specified block is about to be erased.
void notifyOperationErased(Operation *op) override
Notify the listener that the specified operation is about to be erased.
void eraseBlock(Block *block) override
Erase the given block (unless it was already erased).
void notifyOperationInserted(Operation *op, OpBuilder::InsertPoint previous) override
Notify the listener that the specified operation was inserted.
Value findOrBuildReplacementValue(Value value, const TypeConverter *converter)
Find a replacement value for the given SSA value in the conversion value mapping.
ConversionPatternRewriterImpl(MLIRContext *ctx, const ConversionConfig &config)
DenseMap< Region *, const TypeConverter * > regionToConverter
A mapping of regions to type converters that should be used when converting the arguments of blocks w...
bool wasOpReplaced(Operation *op) const
Return "true" if the given operation was replaced or erased.
void notifyBlockInserted(Block *block, Region *previous, Region::iterator previousIt) override
Notifies that a block was inserted.
void undoRewrites(unsigned numRewritesToKeep=0, StringRef patternName="")
Undo the rewrites (motions, splits) one by one in reverse order until "numRewritesToKeep" rewrites re...
DenseMap< UnrealizedConversionCastOp, UnresolvedMaterializationRewrite * > unresolvedMaterializations
A mapping of all unresolved materializations (UnrealizedConversionCastOp) to the corresponding rewrit...
LogicalResult remapValues(StringRef valueDiagTag, std::optional< Location > inputLoc, PatternRewriter &rewriter, ValueRange values, SmallVector< ValueVector > &remapped)
Remap the given values to those with potentially different types.
Block * applySignatureConversion(ConversionPatternRewriter &rewriter, Block *block, const TypeConverter *converter, TypeConverter::SignatureConversion &signatureConversion)
Apply the given signature conversion on the given block.
FailureOr< Block * > convertRegionTypes(ConversionPatternRewriter &rewriter, Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion)
Convert the types of block arguments within the given region.
void resetState(RewriterState state, StringRef patternName="")
Reset the state of the rewriter to a previously saved point.
ConversionValueMapping mapping
void applyRewrites()
Apply all requested operation rewrites.
RewriterState getCurrentState()
Return the current state of the rewriter.
llvm::ScopedPrinter logger
A logger used to emit diagnostics during the conversion process.
void notifyBlockBeingInlined(Block *block, Block *srcBlock, Block::iterator before)
Notifies that a block is being inlined into another block.
void appendRewrite(Args &&...args)
Append a rewrite.
SmallPtrSet< Operation *, 1 > pendingRootUpdates
A set of operations that have pending updates.
void notifyMatchFailure(Location loc, function_ref< void(Diagnostic &)> reasonCallback) override
Notifies that a pattern match failed for the given reason.
SingleEraseRewriter eraseRewriter
A rewriter that keeps track of ops/block that were already erased and skips duplicate op/block erasur...
MLIRContext * context
MLIR context.
bool isOpIgnored(Operation *op) const
Return "true" if the given operation is ignored, and does not need to be converted.
ValueRange buildUnresolvedMaterialization(MaterializationKind kind, OpBuilder::InsertPoint ip, Location loc, ValueVector valuesToMap, ValueRange inputs, TypeRange outputTypes, Type originalType, const TypeConverter *converter, UnrealizedConversionCastOp *castOp=nullptr)
Build an unresolved materialization operation given a range of output types and a list of input opera...
SetVector< Operation * > ignoredOps
A set of operations that should no longer be considered for legalization.
SmallVector< std::unique_ptr< IRRewrite > > rewrites
Ordered list of block operations (creations, splits, motions).
const ConversionConfig & config
Dialect conversion configuration.
void notifyOpReplaced(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Notifies that an op is about to be replaced with the given values.
SetVector< Operation * > replacedOps
A set of operations that were replaced/erased.
void notifyBlockIsBeingErased(Block *block)
Notifies that a block is about to be erased.
const TypeConverter * currentTypeConverter
The current type converter, or nullptr if no type converter is currently active.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.