10#include "mlir/Config/mlir-config.h"
20#include "llvm/ADT/ScopeExit.h"
21#include "llvm/ADT/SmallPtrSet.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/DebugLog.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/SaveAndRestore.h"
27#include "llvm/Support/ScopedPrinter.h"
34#define DEBUG_TYPE "dialect-conversion"
37template <
typename... Args>
38static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
41 os.startLine() <<
"} -> SUCCESS";
43 os.getOStream() <<
" : "
44 << llvm::formatv(fmt.data(), std::forward<Args>(args)...);
45 os.getOStream() <<
"\n";
50template <
typename... Args>
51static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
54 os.startLine() <<
"} -> FAILURE : "
55 << llvm::formatv(fmt.data(), std::forward<Args>(args)...)
65 if (
OpResult inputRes = dyn_cast<OpResult>(value))
66 insertPt = ++inputRes.getOwner()->getIterator();
73 assert(!vals.empty() &&
"expected at least one value");
76 for (
Value v : vals.drop_front()) {
90 assert(dom &&
"unable to find valid insertion point");
98enum OpConversionMode {
125struct ValueVectorMapInfo {
126 static ::llvm::hash_code getHashValue(
const ValueVector &val) {
127 return ::llvm::hash_combine_range(val);
136struct ConversionValueMapping {
139 bool isMappedTo(
Value value)
const {
return mappedTo.contains(value); }
144 template <
typename T>
145 struct IsValueVector : std::is_same<std::decay_t<T>, ValueVector> {};
148 template <
typename OldVal,
typename NewVal>
149 std::enable_if_t<IsValueVector<OldVal>::value && IsValueVector<NewVal>::value>
150 map(OldVal &&oldVal, NewVal &&newVal) {
154 assert(next != oldVal &&
"inserting cyclic mapping");
155 auto it = mapping.find(next);
156 if (it == mapping.end())
161 mappedTo.insert_range(newVal);
163 mapping[std::forward<OldVal>(oldVal)] = std::forward<NewVal>(newVal);
167 template <
typename OldVal,
typename NewVal>
168 std::enable_if_t<!IsValueVector<OldVal>::value ||
169 !IsValueVector<NewVal>::value>
170 map(OldVal &&oldVal, NewVal &&newVal) {
171 if constexpr (IsValueVector<OldVal>{}) {
172 map(std::forward<OldVal>(oldVal),
ValueVector{newVal});
173 }
else if constexpr (IsValueVector<NewVal>{}) {
174 map(
ValueVector{oldVal}, std::forward<NewVal>(newVal));
185 void erase(
const ValueVector &value) { mapping.erase(value); }
205 assert(!values.empty() &&
"expected non-empty value vector");
206 Operation *op = values.front().getDefiningOp();
207 for (
Value v : llvm::drop_begin(values)) {
208 if (v.getDefiningOp() != op)
218 assert(!values.empty() &&
"expected non-empty value vector");
224 auto it = mapping.find(from);
225 if (it == mapping.end()) {
238struct RewriterState {
239 RewriterState(
unsigned numRewrites,
unsigned numIgnoredOperations,
240 unsigned numReplacedOps)
241 : numRewrites(numRewrites), numIgnoredOperations(numIgnoredOperations),
242 numReplacedOps(numReplacedOps) {}
245 unsigned numRewrites;
248 unsigned numIgnoredOperations;
251 unsigned numReplacedOps;
258static void notifyIRErased(RewriterBase::Listener *listener, Operation &op);
261static void notifyIRErased(RewriterBase::Listener *listener,
Block &
b) {
262 for (Operation &op :
b)
263 notifyIRErased(listener, op);
269static void notifyIRErased(RewriterBase::Listener *listener, Operation &op) {
272 notifyIRErased(listener,
b);
302 UnresolvedMaterialization,
307 virtual ~IRRewrite() =
default;
310 virtual void rollback() = 0;
324 virtual void commit(RewriterBase &rewriter) {}
327 virtual void cleanup(RewriterBase &rewriter) {}
329 Kind getKind()
const {
return kind; }
331 static bool classof(
const IRRewrite *
rewrite) {
return true; }
334 IRRewrite(Kind kind, ConversionPatternRewriterImpl &rewriterImpl)
335 : kind(kind), rewriterImpl(rewriterImpl) {}
337 const ConversionConfig &getConfig()
const;
340 ConversionPatternRewriterImpl &rewriterImpl;
344class BlockRewrite :
public IRRewrite {
347 Block *getBlock()
const {
return block; }
349 static bool classof(
const IRRewrite *
rewrite) {
350 return rewrite->getKind() >= Kind::CreateBlock &&
351 rewrite->getKind() <= Kind::BlockTypeConversion;
355 BlockRewrite(Kind kind, ConversionPatternRewriterImpl &rewriterImpl,
357 : IRRewrite(kind, rewriterImpl), block(block) {}
364class ValueRewrite :
public IRRewrite {
367 Value getValue()
const {
return value; }
369 static bool classof(
const IRRewrite *
rewrite) {
370 return rewrite->getKind() == Kind::ReplaceValue;
374 ValueRewrite(Kind kind, ConversionPatternRewriterImpl &rewriterImpl,
376 : IRRewrite(kind, rewriterImpl), value(value) {}
385class CreateBlockRewrite :
public BlockRewrite {
387 CreateBlockRewrite(ConversionPatternRewriterImpl &rewriterImpl,
Block *block)
388 : BlockRewrite(
Kind::CreateBlock, rewriterImpl, block) {}
390 static bool classof(
const IRRewrite *
rewrite) {
391 return rewrite->getKind() == Kind::CreateBlock;
394 void commit(RewriterBase &rewriter)
override {
400 void rollback()
override {
403 auto &blockOps = block->getOperations();
404 while (!blockOps.empty())
405 blockOps.remove(blockOps.begin());
406 block->dropAllUses();
407 if (block->getParent())
418class EraseBlockRewrite :
public BlockRewrite {
420 EraseBlockRewrite(ConversionPatternRewriterImpl &rewriterImpl,
Block *block)
421 : BlockRewrite(
Kind::EraseBlock, rewriterImpl, block),
422 region(block->getParent()), insertBeforeBlock(block->getNextNode()) {}
424 static bool classof(
const IRRewrite *
rewrite) {
425 return rewrite->getKind() == Kind::EraseBlock;
428 ~EraseBlockRewrite()
override {
430 "rewrite was neither rolled back nor committed/cleaned up");
433 void rollback()
override {
436 assert(block &&
"expected block");
441 blockList.insert(before, block);
445 void commit(RewriterBase &rewriter)
override {
446 assert(block &&
"expected block");
450 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
451 notifyIRErased(listener, *block);
454 void cleanup(RewriterBase &rewriter)
override {
456 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(*block)))
458 assert(block->empty() &&
"expected empty block");
461 block->dropAllDefinedValueUses();
472 Block *insertBeforeBlock;
478class InlineBlockRewrite :
public BlockRewrite {
480 InlineBlockRewrite(ConversionPatternRewriterImpl &rewriterImpl,
Block *block,
482 : BlockRewrite(
Kind::InlineBlock, rewriterImpl, block),
483 sourceBlock(sourceBlock),
484 firstInlinedInst(sourceBlock->empty() ?
nullptr
485 : &sourceBlock->front()),
486 lastInlinedInst(sourceBlock->empty() ?
nullptr : &sourceBlock->back()) {
492 assert(!getConfig().listener &&
493 "InlineBlockRewrite not supported if listener is attached");
496 static bool classof(
const IRRewrite *
rewrite) {
497 return rewrite->getKind() == Kind::InlineBlock;
500 void rollback()
override {
503 if (firstInlinedInst) {
504 assert(lastInlinedInst &&
"expected operation");
517 Operation *firstInlinedInst;
520 Operation *lastInlinedInst;
524class MoveBlockRewrite :
public BlockRewrite {
526 MoveBlockRewrite(ConversionPatternRewriterImpl &rewriterImpl,
Block *block,
528 : BlockRewrite(
Kind::MoveBlock, rewriterImpl, block),
529 region(previousRegion),
530 insertBeforeBlock(previousIt == previousRegion->end() ?
nullptr
533 static bool classof(
const IRRewrite *
rewrite) {
534 return rewrite->getKind() == Kind::MoveBlock;
537 void commit(RewriterBase &rewriter)
override {
547 void rollback()
override {
551 if (Region *currentParent = block->
getParent()) {
553 region->getBlocks().splice(before, currentParent->getBlocks(), block);
557 region->
getBlocks().insert(before, block);
566 Block *insertBeforeBlock;
570class BlockTypeConversionRewrite :
public BlockRewrite {
572 BlockTypeConversionRewrite(ConversionPatternRewriterImpl &rewriterImpl,
574 : BlockRewrite(
Kind::BlockTypeConversion, rewriterImpl, origBlock),
575 newBlock(newBlock) {}
577 static bool classof(
const IRRewrite *
rewrite) {
578 return rewrite->getKind() == Kind::BlockTypeConversion;
581 Block *getOrigBlock()
const {
return block; }
583 Block *getNewBlock()
const {
return newBlock; }
585 void commit(RewriterBase &rewriter)
override;
587 void rollback()
override;
597class ReplaceValueRewrite :
public ValueRewrite {
599 ReplaceValueRewrite(ConversionPatternRewriterImpl &rewriterImpl, Value value,
600 const TypeConverter *converter)
601 : ValueRewrite(
Kind::ReplaceValue, rewriterImpl, value),
602 converter(converter) {}
604 static bool classof(
const IRRewrite *
rewrite) {
605 return rewrite->getKind() == Kind::ReplaceValue;
608 void commit(RewriterBase &rewriter)
override;
610 void rollback()
override;
614 const TypeConverter *converter;
618class OperationRewrite :
public IRRewrite {
621 Operation *getOperation()
const {
return op; }
623 static bool classof(
const IRRewrite *
rewrite) {
624 return rewrite->getKind() >= Kind::MoveOperation &&
625 rewrite->getKind() <= Kind::UnresolvedMaterialization;
629 OperationRewrite(Kind kind, ConversionPatternRewriterImpl &rewriterImpl,
631 : IRRewrite(kind, rewriterImpl), op(op) {}
638class MoveOperationRewrite :
public OperationRewrite {
640 MoveOperationRewrite(ConversionPatternRewriterImpl &rewriterImpl,
641 Operation *op, OpBuilder::InsertPoint previous)
642 : OperationRewrite(
Kind::MoveOperation, rewriterImpl, op),
643 block(previous.getBlock()),
644 insertBeforeOp(previous.getPoint() == previous.getBlock()->end()
646 : &*previous.getPoint()) {}
648 static bool classof(
const IRRewrite *
rewrite) {
649 return rewrite->getKind() == Kind::MoveOperation;
652 void commit(RewriterBase &rewriter)
override {
658 op, OpBuilder::InsertPoint(block,
663 void rollback()
override {
676 Operation *insertBeforeOp;
681class ModifyOperationRewrite :
public OperationRewrite {
683 ModifyOperationRewrite(ConversionPatternRewriterImpl &rewriterImpl,
685 : OperationRewrite(
Kind::ModifyOperation, rewriterImpl, op),
686 name(op->getName()), loc(op->getLoc()),
687 attrs(op->getDiscardableAttrDictionary()),
688 operands(op->operand_begin(), op->operand_end()),
689 successors(op->successor_begin(), op->successor_end()) {
692 propertiesStorage = operator new(op->getPropertiesStorageSize());
693 PropertyRef propCopy(name.getOpPropertiesTypeID(), propertiesStorage);
694 name.initOpProperties(propCopy, prop);
698 static bool classof(
const IRRewrite *
rewrite) {
699 return rewrite->getKind() == Kind::ModifyOperation;
702 ~ModifyOperationRewrite()
override {
703 assert(!propertiesStorage &&
704 "rewrite was neither committed nor rolled back");
707 void commit(RewriterBase &rewriter)
override {
710 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
713 if (propertiesStorage) {
718 operator delete(propertiesStorage);
719 propertiesStorage =
nullptr;
723 void rollback()
override {
727 for (
const auto &it : llvm::enumerate(successors))
729 if (propertiesStorage) {
733 operator delete(propertiesStorage);
734 propertiesStorage =
nullptr;
741 DictionaryAttr attrs;
742 SmallVector<Value, 8> operands;
743 SmallVector<Block *, 2> successors;
744 void *propertiesStorage =
nullptr;
751class ReplaceOperationRewrite :
public OperationRewrite {
753 ReplaceOperationRewrite(ConversionPatternRewriterImpl &rewriterImpl,
754 Operation *op,
const TypeConverter *converter)
755 : OperationRewrite(
Kind::ReplaceOperation, rewriterImpl, op),
756 converter(converter) {}
758 static bool classof(
const IRRewrite *
rewrite) {
759 return rewrite->getKind() == Kind::ReplaceOperation;
762 void commit(RewriterBase &rewriter)
override;
764 void rollback()
override;
766 void cleanup(RewriterBase &rewriter)
override;
771 const TypeConverter *converter;
774class CreateOperationRewrite :
public OperationRewrite {
776 CreateOperationRewrite(ConversionPatternRewriterImpl &rewriterImpl,
778 : OperationRewrite(
Kind::CreateOperation, rewriterImpl, op) {}
780 static bool classof(
const IRRewrite *
rewrite) {
781 return rewrite->getKind() == Kind::CreateOperation;
784 void commit(RewriterBase &rewriter)
override {
790 void rollback()
override;
794enum MaterializationKind {
805class UnresolvedMaterializationInfo {
807 UnresolvedMaterializationInfo() =
default;
808 UnresolvedMaterializationInfo(
const TypeConverter *converter,
809 MaterializationKind kind, Type originalType)
810 : converterAndKind(converter, kind), originalType(originalType) {}
813 const TypeConverter *getConverter()
const {
814 return converterAndKind.getPointer();
818 MaterializationKind getMaterializationKind()
const {
819 return converterAndKind.getInt();
823 Type getOriginalType()
const {
return originalType; }
828 llvm::PointerIntPair<const TypeConverter *, 2, MaterializationKind>
839class UnresolvedMaterializationRewrite :
public OperationRewrite {
841 UnresolvedMaterializationRewrite(ConversionPatternRewriterImpl &rewriterImpl,
842 UnrealizedConversionCastOp op,
844 : OperationRewrite(
Kind::UnresolvedMaterialization, rewriterImpl, op),
845 mappedValues(std::move(mappedValues)) {}
847 static bool classof(
const IRRewrite *
rewrite) {
848 return rewrite->getKind() == Kind::UnresolvedMaterialization;
851 void rollback()
override;
853 UnrealizedConversionCastOp getOperation()
const {
854 return cast<UnrealizedConversionCastOp>(op);
864#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
867template <
typename RewriteTy,
typename R>
868static bool hasRewrite(R &&rewrites, Operation *op) {
869 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
870 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
871 return rewriteTy && rewriteTy->getOperation() == op;
877template <
typename RewriteTy,
typename R>
878static bool hasRewrite(R &&rewrites,
Block *block) {
879 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
880 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
881 return rewriteTy && rewriteTy->getBlock() == block;
893 const ConversionConfig &
config,
903 RewriterState getCurrentState();
907 void applyRewrites();
912 void resetState(RewriterState state, StringRef patternName =
"");
916 template <
typename RewriteTy,
typename... Args>
918 assert(
config.allowPatternRollback &&
"appending rewrites is not allowed");
920 std::make_unique<RewriteTy>(*
this, std::forward<Args>(args)...));
926 void undoRewrites(
unsigned numRewritesToKeep = 0, StringRef patternName =
"");
932 LogicalResult remapValues(StringRef valueDiagTag,
933 std::optional<Location> inputLoc,
ValueRange values,
950 bool skipPureTypeConversions =
false)
const;
964 TypeConverter::SignatureConversion *entryConversion);
972 Block *applySignatureConversion(
974 TypeConverter::SignatureConversion &signatureConversion);
994 void eraseBlock(
Block *block);
1032 Value findOrBuildReplacementValue(
Value value,
1040 void notifyOperationInserted(
Operation *op,
1044 void notifyBlockInserted(
Block *block,
Region *previous,
1063 std::function<
void(
Operation *)> opErasedCallback =
nullptr)
1065 opErasedCallback(std::move(opErasedCallback)) {}
1079 assert(block->empty() &&
"expected empty block");
1080 block->dropAllDefinedValueUses();
1088 if (opErasedCallback)
1089 opErasedCallback(op);
1141 llvm::MapVector<UnrealizedConversionCastOp, UnresolvedMaterializationInfo>
1197const ConversionConfig &IRRewrite::getConfig()
const {
1198 return rewriterImpl.
config;
1201void BlockTypeConversionRewrite::commit(RewriterBase &rewriter) {
1205 if (
auto *listener =
1206 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
1207 for (Operation *op : getNewBlock()->getUsers())
1211void BlockTypeConversionRewrite::rollback() {
1212 getNewBlock()->replaceAllUsesWith(getOrigBlock());
1219 if (isa<BlockArgument>(repl)) {
1259 result &= functor(operand);
1264void ReplaceValueRewrite::commit(RewriterBase &rewriter) {
1271void ReplaceValueRewrite::rollback() {
1272 rewriterImpl.
mapping.erase({value});
1278void ReplaceOperationRewrite::commit(RewriterBase &rewriter) {
1280 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener());
1283 SmallVector<Value> replacements =
1285 return rewriterImpl.findOrBuildReplacementValue(result, converter);
1293 for (
auto [
result, newValue] :
1294 llvm::zip_equal(op->
getResults(), replacements))
1300 if (getConfig().unlegalizedOps)
1301 getConfig().unlegalizedOps->erase(op);
1305 notifyIRErased(listener, *op);
1310 llvm::reportFatalInternalError(
1311 "dialect conversion attempted to replace a root operation that has no "
1312 "parent block; the pass must ensure its target op is nested in a "
1317void ReplaceOperationRewrite::rollback() {
1322void ReplaceOperationRewrite::cleanup(RewriterBase &rewriter) {
1326void CreateOperationRewrite::rollback() {
1328 while (!region.getBlocks().empty())
1329 region.getBlocks().remove(region.getBlocks().begin());
1335void UnresolvedMaterializationRewrite::rollback() {
1336 if (!mappedValues.empty())
1337 rewriterImpl.
mapping.erase(mappedValues);
1348 for (
size_t i = 0; i <
rewrites.size(); ++i)
1354 if (auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1355 unresolvedMaterializations.erase(castOp);
1358 rewrite->cleanup(eraseRewriter);
1366 Value from,
TypeRange desiredTypes,
bool skipPureTypeConversions)
const {
1369 assert(!values.empty() &&
"expected non-empty value vector");
1373 if (
config.allowPatternRollback)
1374 return mapping.lookup(values);
1381 auto castOp = dyn_cast<UnrealizedConversionCastOp>(op);
1386 if (castOp.getOutputs() != values)
1388 return castOp.getInputs();
1397 for (
Value v : values) {
1400 llvm::append_range(next, r);
1405 if (next != values) {
1434 if (skipPureTypeConversions) {
1437 match &= !pureConversion;
1440 if (!pureConversion)
1441 lastNonMaterialization = current;
1444 desiredValue = current;
1450 current = std::move(next);
1455 if (!desiredTypes.empty())
1456 return desiredValue;
1457 if (skipPureTypeConversions)
1458 return lastNonMaterialization;
1477 StringRef patternName) {
1482 while (
ignoredOps.size() != state.numIgnoredOperations)
1485 while (
replacedOps.size() != state.numReplacedOps)
1490 StringRef patternName) {
1492 llvm::reverse(llvm::drop_begin(
rewrites, numRewritesToKeep)))
1494 rewrites.resize(numRewritesToKeep);
1498 StringRef valueDiagTag, std::optional<Location> inputLoc,
ValueRange values,
1500 remapped.reserve(llvm::size(values));
1502 for (
const auto &it : llvm::enumerate(values)) {
1503 Value operand = it.value();
1522 diag <<
"unable to convert type for " << valueDiagTag <<
" #"
1523 << it.index() <<
", type was " << origType;
1528 if (legalTypes.empty()) {
1529 remapped.push_back({});
1538 remapped.push_back(std::move(repl));
1547 repl, repl, legalTypes,
1549 remapped.push_back(castValues);
1570 TypeConverter::SignatureConversion *entryConversion) {
1572 if (region->
empty())
1577 llvm::make_early_inc_range(llvm::drop_begin(*region, 1))) {
1579 std::optional<TypeConverter::SignatureConversion> conversion =
1580 converter.convertBlockSignature(&block);
1589 if (entryConversion)
1592 std::optional<TypeConverter::SignatureConversion> conversion =
1593 converter.convertBlockSignature(®ion->
front());
1601 TypeConverter::SignatureConversion &signatureConversion) {
1602#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1604 if (hasRewrite<BlockTypeConversionRewrite>(
rewrites, block))
1605 llvm::reportFatalInternalError(
"block was already converted");
1612 auto convertedTypes = signatureConversion.getConvertedTypes();
1619 for (
unsigned i = 0; i < origArgCount; ++i) {
1620 auto inputMap = signatureConversion.getInputMapping(i);
1621 if (!inputMap || inputMap->replacedWithValues())
1624 for (
unsigned j = 0;
j < inputMap->size; ++
j)
1625 newLocs[inputMap->inputNo +
j] = origLoc;
1632 convertedTypes, newLocs);
1640 bool fastPath = !
config.listener;
1642 if (
config.allowPatternRollback)
1646 while (!block->
empty())
1653 for (
unsigned i = 0; i != origArgCount; ++i) {
1657 std::optional<TypeConverter::SignatureConversion::InputMapping> inputMap =
1658 signatureConversion.getInputMapping(i);
1666 MaterializationKind::Source,
1670 origArgType,
Type(), converter,
1677 if (inputMap->replacedWithValues()) {
1679 assert(inputMap->size == 0 &&
1680 "invalid to provide a replacement value when the argument isn't "
1688 newBlock->
getArguments().slice(inputMap->inputNo, inputMap->size);
1692 if (
config.allowPatternRollback)
1713 assert((!originalType || kind == MaterializationKind::Target) &&
1714 "original type is valid only for target materializations");
1715 assert(
TypeRange(inputs) != outputTypes &&
1716 "materialization is not necessary");
1720 OpBuilder builder(outputTypes.front().getContext());
1722 UnrealizedConversionCastOp convertOp =
1723 UnrealizedConversionCastOp::create(builder, loc, outputTypes, inputs);
1724 if (
config.attachDebugMaterializationKind) {
1726 kind == MaterializationKind::Source ?
"source" :
"target";
1727 convertOp->setDiscardableAttr(
"__kind__", builder.
getStringAttr(kindStr));
1735 UnresolvedMaterializationInfo(converter, kind, originalType);
1736 if (
config.allowPatternRollback) {
1737 if (!valuesToMap.empty())
1738 mapping.map(valuesToMap, convertOp.getResults());
1740 std::move(valuesToMap));
1744 return convertOp.getResults();
1749 assert(
config.allowPatternRollback &&
1750 "this code path is valid only in rollback mode");
1757 return repl.front();
1764 [&](
Operation *op) { return replacedOps.contains(op); }) &&
1789 MaterializationKind::Source, ip, value.
getLoc(),
1805 bool wasDetached = !previous.
isSet();
1807 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"' (" << op
1810 logger.getOStream() <<
" (was detached)";
1811 logger.getOStream() <<
"\n";
1817 "attempting to insert into a block within a replaced/erased op");
1821 config.listener->notifyOperationInserted(op, previous);
1830 if (
config.allowPatternRollback) {
1844 if (
config.allowPatternRollback)
1854 assert(!
impl.config.allowPatternRollback &&
1855 "this code path is valid only in 'no rollback' mode");
1857 for (
auto [from, to] : llvm::zip_equal(fromRange, toRange)) {
1860 repls.push_back(
Value());
1867 Value srcMat =
impl.buildUnresolvedMaterialization(
1872 repls.push_back(srcMat);
1878 repls.push_back(to[0]);
1887 Value srcMat =
impl.buildUnresolvedMaterialization(
1890 Type(), converter)[0];
1891 repls.push_back(srcMat);
1900 "incorrect number of replacement values");
1902 logger.startLine() <<
"** Replace : '" << op->
getName() <<
"'(" << op
1910 for (
auto [
result, repls] :
1911 llvm::zip_equal(op->
getResults(), newValues)) {
1913 auto logProlog = [&, repls = repls]() {
1914 logger.startLine() <<
" Note: Replacing op result of type "
1915 << resultType <<
" with value(s) of type (";
1916 llvm::interleaveComma(repls,
logger.getOStream(), [&](
Value v) {
1917 logger.getOStream() << v.getType();
1919 logger.getOStream() <<
")";
1925 logger.getOStream() <<
", but the type converter failed to legalize "
1926 "the original type.\n";
1931 logger.getOStream() <<
", but the legalized type(s) is/are (";
1932 llvm::interleaveComma(convertedTypes,
logger.getOStream(),
1933 [&](
Type t) { logger.getOStream() << t; });
1934 logger.getOStream() <<
")\n";
1940 if (!
config.allowPatternRollback) {
1949 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op)) {
1955 if (
config.unlegalizedOps)
1956 config.unlegalizedOps->erase(op);
1964 assert(!
ignoredOps.contains(op) &&
"operation was already replaced");
1968 "attempting to replace a value that was already replaced");
1973 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op)) {
1978 "attempting to replace/erase an unresolved materialization");
1994 logger.startLine() <<
"** Replace Value : '" << from <<
"'";
1995 if (
auto blockArg = dyn_cast<BlockArgument>(from)) {
1997 logger.getOStream() <<
" (in region of '" << parentOp->getName()
1998 <<
"' (" << parentOp <<
")";
2000 logger.getOStream() <<
" (unlinked block)";
2004 logger.getOStream() <<
", conditional replacement";
2008 if (!
config.allowPatternRollback) {
2013 Value repl = repls.front();
2030 "attempting to replace a value that was already replaced");
2032 "attempting to replace a op result that was already replaced");
2037 llvm::reportFatalInternalError(
2038 "conditional value replacement is not supported in rollback mode");
2044 if (!
config.allowPatternRollback) {
2051 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op)) {
2057 if (
config.unlegalizedOps)
2058 config.unlegalizedOps->erase(op);
2067 "attempting to erase a block within a replaced/erased op");
2083 bool wasDetached = !previous;
2089 logger.startLine() <<
"** Insert Block into : '" << parent->
getName()
2090 <<
"' (" << parent <<
")";
2093 <<
"** Insert Block into detached Region (nullptr parent op)";
2096 logger.getOStream() <<
" (was detached)";
2097 logger.getOStream() <<
"\n";
2103 "attempting to insert into a region within a replaced/erased op");
2108 config.listener->notifyBlockInserted(block, previous, previousIt);
2112 if (
config.allowPatternRollback) {
2126 if (
config.allowPatternRollback)
2140 reasonCallback(
diag);
2141 logger.startLine() <<
"** Failure : " <<
diag.str() <<
"\n";
2142 if (
config.notifyCallback)
2151ConversionPatternRewriter::ConversionPatternRewriter(
2155 *this, config, opConverter)) {
2156 setListener(
impl.get());
2159ConversionPatternRewriter::~ConversionPatternRewriter() =
default;
2161const ConversionConfig &ConversionPatternRewriter::getConfig()
const {
2162 return impl->config;
2166 assert(op && newOp &&
"expected non-null op");
2170void ConversionPatternRewriter::replaceOp(Operation *op,
ValueRange newValues) {
2172 "incorrect # of replacement values");
2176 if (getInsertionPoint() == op->getIterator())
2179 SmallVector<SmallVector<Value>> newVals =
2180 llvm::map_to_vector(newValues, [](Value v) -> SmallVector<Value> {
2181 return v ? SmallVector<Value>{v} : SmallVector<Value>();
2183 impl->replaceOp(op, std::move(newVals));
2186void ConversionPatternRewriter::replaceOpWithMultiple(
2187 Operation *op, SmallVector<SmallVector<Value>> &&newValues) {
2189 "incorrect # of replacement values");
2193 if (getInsertionPoint() == op->getIterator())
2196 impl->replaceOp(op, std::move(newValues));
2199void ConversionPatternRewriter::eraseOp(Operation *op) {
2201 impl->logger.startLine()
2202 <<
"** Erase : '" << op->
getName() <<
"'(" << op <<
")\n";
2207 if (getInsertionPoint() == op->getIterator())
2210 SmallVector<SmallVector<Value>> nullRepls(op->
getNumResults(), {});
2211 impl->replaceOp(op, std::move(nullRepls));
2214void ConversionPatternRewriter::eraseBlock(
Block *block) {
2215 impl->eraseBlock(block);
2218Block *ConversionPatternRewriter::applySignatureConversion(
2219 Block *block, TypeConverter::SignatureConversion &conversion,
2220 const TypeConverter *converter) {
2221 assert(!impl->wasOpReplaced(block->
getParentOp()) &&
2222 "attempting to apply a signature conversion to a block within a "
2223 "replaced/erased op");
2224 return impl->applySignatureConversion(block, converter, conversion);
2227FailureOr<Block *> ConversionPatternRewriter::convertRegionTypes(
2228 Region *region,
const TypeConverter &converter,
2229 TypeConverter::SignatureConversion *entryConversion) {
2230 assert(!impl->wasOpReplaced(region->
getParentOp()) &&
2231 "attempting to apply a signature conversion to a block within a "
2232 "replaced/erased op");
2233 return impl->convertRegionTypes(region, converter, entryConversion);
2236void ConversionPatternRewriter::replaceAllUsesWith(Value from,
ValueRange to) {
2237 impl->replaceValueUses(from, to, impl->currentTypeConverter);
2240void ConversionPatternRewriter::replaceUsesWithIf(
2242 bool *allUsesReplaced) {
2243 assert(!allUsesReplaced &&
2244 "allUsesReplaced is not supported in a dialect conversion");
2245 impl->replaceValueUses(from, to, impl->currentTypeConverter, functor);
2248Value ConversionPatternRewriter::getRemappedValue(Value key) {
2249 SmallVector<ValueVector> remappedValues;
2250 if (
failed(impl->remapValues(
"value", std::nullopt, key,
2253 assert(remappedValues.front().size() == 1 &&
"1:N conversion not supported");
2254 return remappedValues.front().front();
2258ConversionPatternRewriter::getRemappedValues(
ValueRange keys,
2259 SmallVectorImpl<Value> &results) {
2262 SmallVector<ValueVector> remapped;
2263 if (
failed(impl->remapValues(
"value", std::nullopt, keys,
2266 for (
const auto &values : remapped) {
2267 assert(values.size() == 1 &&
"1:N conversion not supported");
2268 results.push_back(values.front());
2273void ConversionPatternRewriter::inlineBlockBefore(
Block *source,
Block *dest,
2278 "incorrect # of argument replacement values");
2279 assert(!impl->wasOpReplaced(source->
getParentOp()) &&
2280 "attempting to inline a block from a replaced/erased op");
2281 assert(!impl->wasOpReplaced(dest->
getParentOp()) &&
2282 "attempting to inline a block into a replaced/erased op");
2283 auto opIgnored = [&](Operation *op) {
return impl->isOpIgnored(op); };
2286 assert(llvm::all_of(source->
getUsers(), opIgnored) &&
2287 "expected 'source' to have no predecessors");
2296 bool fastPath = !getConfig().listener;
2298 if (fastPath && impl->config.allowPatternRollback)
2299 impl->inlineBlockBefore(source, dest, before);
2302 for (
auto it : llvm::zip(source->
getArguments(), argValues))
2303 replaceAllUsesWith(std::get<0>(it), std::get<1>(it));
2310 while (!source->
empty())
2311 moveOpBefore(&source->
front(), dest, before);
2316 if (getInsertionBlock() == source)
2317 setInsertionPoint(dest, getInsertionPoint());
2323void ConversionPatternRewriter::startOpModification(Operation *op) {
2324 if (!impl->config.allowPatternRollback) {
2329 assert(!impl->wasOpReplaced(op) &&
2330 "attempting to modify a replaced/erased op");
2332 impl->pendingRootUpdates.insert(op);
2334 impl->appendRewrite<ModifyOperationRewrite>(op);
2337void ConversionPatternRewriter::finalizeOpModification(Operation *op) {
2338 impl->patternModifiedOps.insert(op);
2339 if (!impl->config.allowPatternRollback) {
2341 if (getConfig().listener)
2342 getConfig().listener->notifyOperationModified(op);
2349 assert(!impl->wasOpReplaced(op) &&
2350 "attempting to modify a replaced/erased op");
2351 assert(impl->pendingRootUpdates.erase(op) &&
2352 "operation did not have a pending in-place update");
2356void ConversionPatternRewriter::cancelOpModification(Operation *op) {
2357 if (!impl->config.allowPatternRollback) {
2362 assert(impl->pendingRootUpdates.erase(op) &&
2363 "operation did not have a pending in-place update");
2366 auto it = llvm::find_if(
2367 llvm::reverse(impl->rewrites), [&](std::unique_ptr<IRRewrite> &
rewrite) {
2368 auto *modifyRewrite = dyn_cast<ModifyOperationRewrite>(rewrite.get());
2369 return modifyRewrite && modifyRewrite->getOperation() == op;
2371 assert(it != impl->rewrites.rend() &&
"no root update started on op");
2373 int updateIdx = std::prev(impl->rewrites.rend()) - it;
2374 impl->rewrites.erase(impl->rewrites.begin() + updateIdx);
2377detail::ConversionPatternRewriterImpl &ConversionPatternRewriter::getImpl() {
2385FailureOr<SmallVector<Value>> ConversionPattern::getOneToOneAdaptorOperands(
2386 ArrayRef<ValueRange> operands)
const {
2387 SmallVector<Value> oneToOneOperands;
2388 oneToOneOperands.reserve(operands.size());
2390 if (operand.size() != 1)
2393 oneToOneOperands.push_back(operand.front());
2395 return std::move(oneToOneOperands);
2399ConversionPattern::matchAndRewrite(Operation *op,
2400 PatternRewriter &rewriter)
const {
2401 auto &dialectRewriter =
static_cast<ConversionPatternRewriter &
>(rewriter);
2402 auto &rewriterImpl = dialectRewriter.getImpl();
2406 getTypeConverter());
2409 SmallVector<ValueVector> remapped;
2414 SmallVector<ValueRange> remappedAsRange =
2415 llvm::to_vector_of<ValueRange>(remapped);
2416 return matchAndRewrite(op, remappedAsRange, dialectRewriter);
2425using LegalizationPatterns = SmallVector<const Pattern *, 1>;
2428class OperationLegalizer {
2430 using LegalizationAction = ConversionTarget::LegalizationAction;
2432 OperationLegalizer(ConversionPatternRewriter &rewriter,
2433 const ConversionTarget &targetInfo,
2434 const FrozenRewritePatternSet &patterns);
2437 bool isIllegal(Operation *op)
const;
2441 LogicalResult legalize(Operation *op);
2444 const ConversionTarget &getTarget() {
return target; }
2448 LogicalResult legalizeWithFold(Operation *op);
2452 LogicalResult legalizeWithPattern(Operation *op);
2456 bool canApplyPattern(Operation *op,
const Pattern &pattern);
2460 legalizePatternResult(Operation *op,
const Pattern &pattern,
2461 const RewriterState &curState,
2478 void buildLegalizationGraph(
2479 LegalizationPatterns &anyOpLegalizerPatterns,
2490 void computeLegalizationGraphBenefit(
2491 LegalizationPatterns &anyOpLegalizerPatterns,
2496 unsigned computeOpLegalizationDepth(
2503 unsigned applyCostModelToPatterns(
2504 LegalizationPatterns &patterns,
2509 SmallPtrSet<const Pattern *, 8> appliedPatterns;
2512 ConversionPatternRewriter &rewriter;
2515 const ConversionTarget &
target;
2518 PatternApplicator applicator;
2522OperationLegalizer::OperationLegalizer(ConversionPatternRewriter &rewriter,
2523 const ConversionTarget &targetInfo,
2524 const FrozenRewritePatternSet &patterns)
2525 : rewriter(rewriter),
target(targetInfo), applicator(patterns) {
2529 LegalizationPatterns anyOpLegalizerPatterns;
2531 buildLegalizationGraph(anyOpLegalizerPatterns, legalizerPatterns);
2532 computeLegalizationGraphBenefit(anyOpLegalizerPatterns, legalizerPatterns);
2535bool OperationLegalizer::isIllegal(Operation *op)
const {
2536 return target.isIllegal(op);
2539LogicalResult OperationLegalizer::legalize(Operation *op) {
2541 const char *logLineComment =
2542 "//===-------------------------------------------===//\n";
2544 auto &logger = rewriter.getImpl().logger;
2548 bool isIgnored = rewriter.getImpl().isOpIgnored(op);
2551 logger.getOStream() <<
"\n";
2552 logger.startLine() << logLineComment;
2553 logger.startLine() <<
"Legalizing operation : ";
2558 logger.getOStream() <<
"'" << op->
getName() <<
"' ";
2559 logger.getOStream() <<
"(" << op <<
") {\n";
2564 logger.startLine() << OpWithFlags(op,
2565 OpPrintingFlags().printGenericOpForm())
2572 logSuccess(logger,
"operation marked 'ignored' during conversion");
2573 logger.startLine() << logLineComment;
2579 if (
auto legalityInfo =
target.isLegal(op)) {
2582 logger,
"operation marked legal by the target{0}",
2583 legalityInfo->isRecursivelyLegal
2584 ?
"; NOTE: operation is recursively legal; skipping internals"
2586 logger.startLine() << logLineComment;
2591 if (legalityInfo->isRecursivelyLegal) {
2592 op->
walk([&](Operation *nested) {
2594 rewriter.getImpl().ignoredOps.
insert(nested);
2603 const ConversionConfig &config = rewriter.getConfig();
2604 if (config.foldingMode == DialectConversionFoldingMode::BeforePatterns) {
2605 if (succeeded(legalizeWithFold(op))) {
2608 logger.startLine() << logLineComment;
2615 if (succeeded(legalizeWithPattern(op))) {
2618 logger.startLine() << logLineComment;
2625 if (config.foldingMode == DialectConversionFoldingMode::AfterPatterns) {
2626 if (succeeded(legalizeWithFold(op))) {
2629 logger.startLine() << logLineComment;
2636 logFailure(logger,
"no matched legalization pattern");
2637 logger.startLine() << logLineComment;
2644template <
typename T>
2646 T
result = std::move(obj);
2651LogicalResult OperationLegalizer::legalizeWithFold(Operation *op) {
2652 auto &rewriterImpl = rewriter.getImpl();
2654 rewriterImpl.
logger.startLine() <<
"* Fold {\n";
2655 rewriterImpl.
logger.indent();
2660 llvm::scope_exit cleanup([&]() {
2670 SmallVector<Value, 2> replacementValues;
2671 SmallVector<Operation *, 2> newOps;
2674 if (
failed(rewriter.
tryFold(op, replacementValues, &newOps))) {
2683 if (replacementValues.empty())
2684 return legalize(op);
2687 rewriter.
replaceOp(op, replacementValues);
2690 for (Operation *newOp : newOps) {
2691 if (
failed(legalize(newOp))) {
2693 "failed to legalize generated constant '{0}'",
2695 if (!rewriter.getConfig().allowPatternRollback) {
2697 llvm::reportFatalInternalError(
2699 "' folder rollback of IR modifications requested");
2701 rewriterImpl.
resetState(curState, std::string(opName) +
" folder");
2716 auto newOpNames = llvm::map_range(
2718 auto modifiedOpNames = llvm::map_range(
2720 llvm::reportFatalInternalError(
"pattern '" + pattern.
getDebugName() +
2721 "' produced IR that could not be legalized. " +
2722 "new ops: {" + llvm::join(newOpNames,
", ") +
2723 "}, " +
"modified ops: {" +
2724 llvm::join(modifiedOpNames,
", ") +
"}");
2727LogicalResult OperationLegalizer::legalizeWithPattern(Operation *op) {
2728 auto &rewriterImpl = rewriter.getImpl();
2729 const ConversionConfig &config = rewriter.getConfig();
2731#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2733 std::optional<OperationFingerPrint> topLevelFingerPrint;
2734 if (!rewriterImpl.
config.allowPatternRollback) {
2741 topLevelFingerPrint = OperationFingerPrint(checkOp);
2747 rewriterImpl.
logger.startLine()
2748 <<
"WARNING: Multi-threadeding is enabled. Some dialect "
2749 "conversion expensive checks are skipped in multithreading "
2758 auto canApply = [&](
const Pattern &pattern) {
2759 bool canApply = canApplyPattern(op, pattern);
2760 if (canApply && config.listener)
2761 config.listener->notifyPatternBegin(pattern, op);
2767 auto onFailure = [&](
const Pattern &pattern) {
2769 if (!rewriterImpl.
config.allowPatternRollback) {
2776#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2778 if (checkOp && topLevelFingerPrint) {
2779 OperationFingerPrint fingerPrintAfterPattern(checkOp);
2780 if (fingerPrintAfterPattern != *topLevelFingerPrint)
2781 llvm::reportFatalInternalError(
2782 "pattern '" + pattern.getDebugName() +
2783 "' returned failure but IR did change");
2791 if (rewriterImpl.
config.notifyCallback) {
2793 diag <<
"Failed to apply pattern \"" << pattern.getDebugName()
2799 if (config.listener)
2800 config.listener->notifyPatternEnd(pattern, failure());
2801 rewriterImpl.
resetState(curState, pattern.getDebugName());
2802 appliedPatterns.erase(&pattern);
2807 auto onSuccess = [&](
const Pattern &pattern) {
2809 if (!rewriterImpl.
config.allowPatternRollback) {
2823 legalizePatternResult(op, pattern, curState, newOps, modifiedOps);
2824 appliedPatterns.erase(&pattern);
2826 if (!rewriterImpl.
config.allowPatternRollback)
2828 rewriterImpl.
resetState(curState, pattern.getDebugName());
2830 if (config.listener)
2831 config.listener->notifyPatternEnd(pattern,
result);
2836 return applicator.matchAndRewrite(op, rewriter, canApply, onFailure,
2840bool OperationLegalizer::canApplyPattern(Operation *op,
2841 const Pattern &pattern) {
2843 auto &os = rewriter.getImpl().logger;
2844 os.getOStream() <<
"\n";
2845 os.startLine() <<
"* Pattern : '" << op->
getName() <<
" -> (";
2847 os.getOStream() <<
")' {\n";
2854 !appliedPatterns.insert(&pattern).second) {
2856 logFailure(rewriter.getImpl().logger,
"pattern was already applied"));
2862LogicalResult OperationLegalizer::legalizePatternResult(
2863 Operation *op,
const Pattern &pattern,
const RewriterState &curState,
2866 [[maybe_unused]]
auto &impl = rewriter.getImpl();
2867 assert(impl.pendingRootUpdates.empty() &&
"dangling root updates");
2869#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2870 if (impl.config.allowPatternRollback) {
2872 auto newRewrites = llvm::drop_begin(impl.rewrites, curState.numRewrites);
2873 auto replacedRoot = [&] {
2874 return hasRewrite<ReplaceOperationRewrite>(newRewrites, op);
2876 auto updatedRootInPlace = [&] {
2877 return hasRewrite<ModifyOperationRewrite>(newRewrites, op);
2879 if (!replacedRoot() && !updatedRootInPlace())
2880 llvm::reportFatalInternalError(
2881 "expected pattern to replace the root operation "
2882 "or modify it in place");
2887 if (
failed(legalizePatternRootUpdates(modifiedOps)) ||
2888 failed(legalizePatternCreatedOperations(newOps))) {
2892 LLVM_DEBUG(
logSuccess(impl.logger,
"pattern applied successfully"));
2896LogicalResult OperationLegalizer::legalizePatternCreatedOperations(
2898 for (Operation *op : newOps) {
2899 if (
failed(legalize(op))) {
2900 LLVM_DEBUG(
logFailure(rewriter.getImpl().logger,
2901 "failed to legalize generated operation '{0}'({1})",
2909LogicalResult OperationLegalizer::legalizePatternRootUpdates(
2911 for (Operation *op : modifiedOps) {
2912 if (
failed(legalize(op))) {
2915 "failed to legalize operation updated in-place '{0}'",
2927void OperationLegalizer::buildLegalizationGraph(
2928 LegalizationPatterns &anyOpLegalizerPatterns,
2939 applicator.walkAllPatterns([&](
const Pattern &pattern) {
2940 std::optional<OperationName> root = pattern.
getRootKind();
2946 anyOpLegalizerPatterns.push_back(&pattern);
2951 if (
target.getOpAction(*root) == LegalizationAction::Legal)
2956 invalidPatterns[*root].insert(&pattern);
2958 parentOps[op].insert(*root);
2961 patternWorklist.insert(&pattern);
2969 if (!anyOpLegalizerPatterns.empty()) {
2970 for (
const Pattern *pattern : patternWorklist)
2971 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2975 while (!patternWorklist.empty()) {
2976 auto *pattern = patternWorklist.pop_back_val();
2980 std::optional<LegalizationAction> action = target.getOpAction(op);
2981 return !legalizerPatterns.count(op) &&
2982 (!action || action == LegalizationAction::Illegal);
2988 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2989 invalidPatterns[*pattern->
getRootKind()].erase(pattern);
2993 for (
auto op : parentOps[*pattern->
getRootKind()])
2994 patternWorklist.set_union(invalidPatterns[op]);
2998void OperationLegalizer::computeLegalizationGraphBenefit(
2999 LegalizationPatterns &anyOpLegalizerPatterns,
3005 for (
auto &opIt : legalizerPatterns)
3006 if (!minOpPatternDepth.count(opIt.first))
3007 computeOpLegalizationDepth(opIt.first, minOpPatternDepth,
3013 if (!anyOpLegalizerPatterns.empty())
3014 applyCostModelToPatterns(anyOpLegalizerPatterns, minOpPatternDepth,
3020 applicator.applyCostModel([&](
const Pattern &pattern) {
3021 ArrayRef<const Pattern *> orderedPatternList;
3022 if (std::optional<OperationName> rootName = pattern.
getRootKind())
3023 orderedPatternList = legalizerPatterns[*rootName];
3025 orderedPatternList = anyOpLegalizerPatterns;
3028 auto *it = llvm::find(orderedPatternList, &pattern);
3029 if (it == orderedPatternList.end())
3033 return PatternBenefit(std::distance(it, orderedPatternList.end()));
3037unsigned OperationLegalizer::computeOpLegalizationDepth(
3041 auto depthIt = minOpPatternDepth.find(op);
3042 if (depthIt != minOpPatternDepth.end())
3043 return depthIt->second;
3047 auto opPatternsIt = legalizerPatterns.find(op);
3048 if (opPatternsIt == legalizerPatterns.end() || opPatternsIt->second.empty())
3053 minOpPatternDepth.try_emplace(op, std::numeric_limits<unsigned>::max());
3057 unsigned minDepth = applyCostModelToPatterns(
3058 opPatternsIt->second, minOpPatternDepth, legalizerPatterns);
3059 minOpPatternDepth[op] = minDepth;
3063unsigned OperationLegalizer::applyCostModelToPatterns(
3064 LegalizationPatterns &patterns,
3067 unsigned minDepth = std::numeric_limits<unsigned>::max();
3070 SmallVector<std::pair<const Pattern *, unsigned>, 4> patternsByDepth;
3071 patternsByDepth.reserve(patterns.size());
3072 for (
const Pattern *pattern : patterns) {
3075 unsigned generatedOpDepth = computeOpLegalizationDepth(
3076 generatedOp, minOpPatternDepth, legalizerPatterns);
3077 depth = std::max(depth, generatedOpDepth + 1);
3079 patternsByDepth.emplace_back(pattern, depth);
3082 minDepth = std::min(minDepth, depth);
3087 if (patternsByDepth.size() == 1)
3091 llvm::stable_sort(patternsByDepth,
3092 [](
const std::pair<const Pattern *, unsigned> &
lhs,
3093 const std::pair<const Pattern *, unsigned> &
rhs) {
3096 if (
lhs.second !=
rhs.second)
3097 return lhs.second <
rhs.second;
3100 auto lhsBenefit =
lhs.first->getBenefit();
3101 auto rhsBenefit =
rhs.first->getBenefit();
3102 return lhsBenefit > rhsBenefit;
3107 for (
auto &patternIt : patternsByDepth)
3108 patterns.push_back(patternIt.first);
3122template <
typename RangeT>
3125 function_ref<
bool(UnrealizedConversionCastOp)> isCastOpOfInterestFn,
3134 [](UnrealizedConversionCastOp castOp) -> UnrealizedConversionCastOp {
3135 if (castOp.getInputs().empty())
3138 castOp.getInputs().front().getDefiningOp<UnrealizedConversionCastOp>();
3141 if (inputCastOp.getOutputs() != castOp.getInputs())
3147 while (!worklist.empty()) {
3148 UnrealizedConversionCastOp castOp = worklist.pop_back_val();
3152 UnrealizedConversionCastOp nextCast = castOp;
3154 if (nextCast.getInputs().getTypes() == castOp.getResultTypes()) {
3155 if (llvm::any_of(nextCast.getInputs(), [&](
Value v) {
3156 return v.getDefiningOp() == castOp;
3164 castOp.replaceAllUsesWith(nextCast.getInputs());
3167 nextCast = getInputCast(nextCast);
3177 auto markOpLive = [&](
Operation *rootOp) {
3179 worklist.push_back(rootOp);
3180 while (!worklist.empty()) {
3181 Operation *op = worklist.pop_back_val();
3182 if (liveOps.insert(op).second) {
3185 if (
auto castOp = v.
getDefiningOp<UnrealizedConversionCastOp>())
3186 if (isCastOpOfInterestFn(castOp))
3187 worklist.push_back(castOp);
3193 for (UnrealizedConversionCastOp op : castOps) {
3196 if (liveOps.contains(op.getOperation()))
3200 if (llvm::any_of(op->getUsers(), [&](
Operation *user) {
3201 auto castOp = dyn_cast<UnrealizedConversionCastOp>(user);
3202 return !castOp || !isCastOpOfInterestFn(castOp);
3208 for (UnrealizedConversionCastOp op : castOps) {
3209 if (liveOps.contains(op)) {
3211 if (remainingCastOps)
3212 remainingCastOps->push_back(op);
3223 ArrayRef<UnrealizedConversionCastOp> castOps,
3224 SmallVectorImpl<UnrealizedConversionCastOp> *remainingCastOps) {
3226 DenseSet<UnrealizedConversionCastOp> castOpSet;
3227 for (UnrealizedConversionCastOp op : castOps)
3228 castOpSet.insert(op);
3233 const DenseSet<UnrealizedConversionCastOp> &castOps,
3234 SmallVectorImpl<UnrealizedConversionCastOp> *remainingCastOps) {
3236 llvm::make_range(castOps.begin(), castOps.end()),
3237 [&](UnrealizedConversionCastOp castOp) {
3238 return castOps.contains(castOp);
3245 const llvm::MapVector<UnrealizedConversionCastOp,
3246 UnresolvedMaterializationInfo> &castOps,
3250 [&](UnrealizedConversionCastOp castOp) {
3251 return castOps.contains(castOp);
3268 const ConversionConfig &config,
3269 OpConversionMode mode)
3270 : rewriter(ctx, config, *this), opLegalizer(rewriter,
target, patterns),
3279 template <
typename Fn>
3281 bool isRecursiveLegalization =
false);
3283 bool isRecursiveLegalization =
false) {
3285 ops, [&]() {}, isRecursiveLegalization);
3293 LogicalResult convert(
Operation *op,
bool isRecursiveLegalization =
false);
3299 ConversionPatternRewriter rewriter;
3302 OperationLegalizer opLegalizer;
3305 OpConversionMode mode;
3310 bool isRecursiveLegalization) {
3311 const ConversionConfig &config = rewriter.getConfig();
3312 auto emitFailedToLegalizeDiag = [&](
bool wasExplicitlyIllegal) {
3314 <<
"failed to legalize operation '"
3316 if (wasExplicitlyIllegal)
3317 diag <<
" that was explicitly marked illegal";
3322 if (failed(opLegalizer.legalize(op))) {
3325 if (mode == OpConversionMode::Full) {
3326 if (!isRecursiveLegalization)
3327 emitFailedToLegalizeDiag(
false);
3333 if (mode == OpConversionMode::Partial) {
3334 if (opLegalizer.isIllegal(op)) {
3335 if (!isRecursiveLegalization)
3336 emitFailedToLegalizeDiag(
true);
3339 if (config.unlegalizedOps && !isRecursiveLegalization)
3340 config.unlegalizedOps->insert(op);
3342 }
else if (mode == OpConversionMode::Analysis) {
3346 if (config.legalizableOps && !isRecursiveLegalization)
3347 config.legalizableOps->insert(op);
3354 UnrealizedConversionCastOp op,
3355 const UnresolvedMaterializationInfo &info) {
3356 assert(!op.use_empty() &&
3357 "expected that dead materializations have already been DCE'd");
3364 switch (info.getMaterializationKind()) {
3365 case MaterializationKind::Target:
3366 newMaterialization = converter->materializeTargetConversion(
3367 rewriter, op->getLoc(), op.getResultTypes(), inputOperands,
3368 info.getOriginalType());
3370 case MaterializationKind::Source:
3371 assert(op->getNumResults() == 1 &&
"expected single result");
3372 Value sourceMat = converter->materializeSourceConversion(
3373 rewriter, op->getLoc(), op.getResultTypes().front(), inputOperands);
3375 newMaterialization.push_back(sourceMat);
3378 if (!newMaterialization.empty()) {
3380 ValueRange newMaterializationRange(newMaterialization);
3381 assert(
TypeRange(newMaterializationRange) == op.getResultTypes() &&
3382 "materialization callback produced value of incorrect type");
3384 rewriter.
replaceOp(op, newMaterialization);
3387 StringRef direction =
3388 info.getMaterializationKind() == MaterializationKind::Target ?
"target"
3392 <<
"failed to legalize unresolved " << direction
3393 <<
" materialization from (" << inputOperands.
getTypes() <<
") to ("
3394 << op.getResultTypes()
3395 <<
") that remained live after conversion (no matching callback)";
3396 diag.attachNote(op->getUsers().begin()->getLoc())
3397 <<
"see existing live user here: " << *op->getUsers().begin();
3403 <<
"failed to legalize unresolved materialization "
3405 << inputOperands.
getTypes() <<
") to (" << op.getResultTypes()
3406 <<
") that remained live after conversion (no type converter specified)";
3407 diag.attachNote(op->getUsers().begin()->getLoc())
3408 <<
"see existing live user here: " << *op->getUsers().begin();
3412template <
typename Fn>
3415 bool isRecursiveLegalization) {
3423 toConvert.push_back(op);
3426 auto legalityInfo =
target.isLegal(op);
3427 if (legalityInfo && legalityInfo->isRecursivelyLegal)
3433 if (failed(
convert(op, isRecursiveLegalization))) {
3442LogicalResult ConversionPatternRewriter::legalize(
Operation *op) {
3443 return impl->opConverter.legalizeOperations(op,
3447LogicalResult ConversionPatternRewriter::legalize(
Region *r) {
3463 std::optional<TypeConverter::SignatureConversion> conversion =
3464 converter->convertBlockSignature(&r->front());
3467 applySignatureConversion(&r->front(), *conversion, converter);
3472 return impl->opConverter.legalizeOperations(ops,
3482 if (rewriterImpl.
config.allowPatternRollback) {
3500 const llvm::MapVector<UnrealizedConversionCastOp,
3501 UnresolvedMaterializationInfo> &materializations =
3507 for (UnrealizedConversionCastOp castOp : remainingCastOps)
3511 if (rewriter.getConfig().buildMaterializations) {
3515 rewriter.getConfig().listener);
3516 for (UnrealizedConversionCastOp castOp : remainingCastOps) {
3517 auto it = materializations.find(castOp);
3518 assert(it != materializations.end() &&
"inconsistent state");
3532void TypeConverter::SignatureConversion::addInputs(
unsigned origInputNo,
3534 assert(!types.empty() &&
"expected valid types");
3535 remapInput(origInputNo, argTypes.size(), types.size());
3539void TypeConverter::SignatureConversion::addInputs(
ArrayRef<Type> types) {
3540 assert(!types.empty() &&
3541 "1->0 type remappings don't need to be added explicitly");
3542 argTypes.append(types.begin(), types.end());
3545void TypeConverter::SignatureConversion::remapInput(
unsigned origInputNo,
3546 unsigned newInputNo,
3547 unsigned newInputCount) {
3548 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
3549 assert(newInputCount != 0 &&
"expected valid input count");
3550 remappedInputs[origInputNo] =
3551 InputMapping{newInputNo, newInputCount, {}};
3554void TypeConverter::SignatureConversion::remapInput(
3555 unsigned origInputNo, ArrayRef<Value> replacements) {
3556 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
3557 remappedInputs[origInputNo] = InputMapping{
3559 SmallVector<Value, 1>(replacements.begin(), replacements.end())};
3570TypeConverter::convertTypeImpl(PointerUnion<Type, Value> typeOrValue,
3571 SmallVectorImpl<Type> &results)
const {
3572 assert(typeOrValue &&
"expected non-null type");
3573 Type t = (isa<Value>(typeOrValue)) ? cast<Value>(typeOrValue).getType()
3574 : cast<Type>(typeOrValue);
3576 std::shared_lock<
decltype(cacheMutex)> cacheReadLock(cacheMutex,
3579 cacheReadLock.lock();
3580 auto existingIt = cachedDirectConversions.find(t);
3581 if (existingIt != cachedDirectConversions.end()) {
3582 if (existingIt->second)
3583 results.push_back(existingIt->second);
3584 return success(existingIt->second !=
nullptr);
3586 auto multiIt = cachedMultiConversions.find(t);
3587 if (multiIt != cachedMultiConversions.end()) {
3588 results.append(multiIt->second.begin(), multiIt->second.end());
3594 size_t currentCount = results.size();
3598 auto isCacheable = [&](
int index) {
3599 int numberOfConversionsUntilContextAware =
3600 conversions.size() - 1 - contextAwareTypeConversionsIndex;
3601 return index < numberOfConversionsUntilContextAware;
3604 std::unique_lock<
decltype(cacheMutex)> cacheWriteLock(cacheMutex,
3607 for (
auto indexedConverter : llvm::enumerate(llvm::reverse(conversions))) {
3608 const ConversionCallbackFn &converter = indexedConverter.value();
3609 std::optional<LogicalResult>
result = converter(typeOrValue, results);
3611 assert(results.size() == currentCount &&
3612 "failed type conversion should not change results");
3615 if (!isCacheable(indexedConverter.index()))
3618 cacheWriteLock.lock();
3619 if (!succeeded(*
result)) {
3620 assert(results.size() == currentCount &&
3621 "failed type conversion should not change results");
3622 cachedDirectConversions.try_emplace(t,
nullptr);
3625 auto newTypes = ArrayRef<Type>(results).drop_front(currentCount);
3626 if (newTypes.size() == 1)
3627 cachedDirectConversions.try_emplace(t, newTypes.front());
3629 cachedMultiConversions.try_emplace(t, llvm::to_vector<2>(newTypes));
3635LogicalResult TypeConverter::convertType(Type t,
3636 SmallVectorImpl<Type> &results)
const {
3637 return convertTypeImpl(t, results);
3640LogicalResult TypeConverter::convertType(Value v,
3641 SmallVectorImpl<Type> &results)
const {
3642 return convertTypeImpl(v, results);
3645Type TypeConverter::convertType(Type t)
const {
3647 SmallVector<Type, 1> results;
3648 if (
failed(convertType(t, results)))
3652 return results.size() == 1 ? results.front() :
nullptr;
3655Type TypeConverter::convertType(Value v)
const {
3657 SmallVector<Type, 1> results;
3658 if (
failed(convertType(v, results)))
3662 return results.size() == 1 ? results.front() :
nullptr;
3666TypeConverter::convertTypes(
TypeRange types,
3667 SmallVectorImpl<Type> &results)
const {
3668 for (Type type : types)
3669 if (
failed(convertType(type, results)))
3675TypeConverter::convertTypes(
ValueRange values,
3676 SmallVectorImpl<Type> &results)
const {
3677 for (Value value : values)
3678 if (
failed(convertType(value, results)))
3683bool TypeConverter::isLegal(Type type)
const {
3684 return convertType(type) == type;
3687bool TypeConverter::isLegal(Value value)
const {
3688 return convertType(value) == value.
getType();
3691bool TypeConverter::isLegal(Operation *op)
const {
3695bool TypeConverter::isLegal(Region *region)
const {
3696 return llvm::all_of(
3700bool TypeConverter::isSignatureLegal(FunctionType ty)
const {
3701 if (!isLegal(ty.getInputs()))
3703 if (!isLegal(ty.getResults()))
3709TypeConverter::convertSignatureArg(
unsigned inputNo, Type type,
3710 SignatureConversion &
result)
const {
3712 SmallVector<Type, 1> convertedTypes;
3713 if (
failed(convertType(type, convertedTypes)))
3717 if (convertedTypes.empty())
3721 result.addInputs(inputNo, convertedTypes);
3725TypeConverter::convertSignatureArgs(
TypeRange types,
3726 SignatureConversion &
result,
3727 unsigned origInputOffset)
const {
3728 for (
unsigned i = 0, e = types.size(); i != e; ++i)
3729 if (
failed(convertSignatureArg(origInputOffset + i, types[i],
result)))
3734TypeConverter::convertSignatureArg(
unsigned inputNo, Value value,
3735 SignatureConversion &
result)
const {
3737 SmallVector<Type, 1> convertedTypes;
3738 if (
failed(convertType(value, convertedTypes)))
3742 if (convertedTypes.empty())
3746 result.addInputs(inputNo, convertedTypes);
3750TypeConverter::convertSignatureArgs(
ValueRange values,
3751 SignatureConversion &
result,
3752 unsigned origInputOffset)
const {
3753 for (
unsigned i = 0, e = values.size(); i != e; ++i)
3754 if (
failed(convertSignatureArg(origInputOffset + i, values[i],
result)))
3759Value TypeConverter::materializeSourceConversion(OpBuilder &builder,
3760 Location loc, Type resultType,
3762 for (
const SourceMaterializationCallbackFn &fn :
3763 llvm::reverse(sourceMaterializations))
3764 if (Value
result = fn(builder, resultType, inputs, loc))
3769Value TypeConverter::materializeTargetConversion(OpBuilder &builder,
3770 Location loc, Type resultType,
3772 Type originalType)
const {
3773 SmallVector<Value>
result = materializeTargetConversion(
3774 builder, loc,
TypeRange(resultType), inputs, originalType);
3777 assert(
result.size() == 1 &&
"expected single result");
3781SmallVector<Value> TypeConverter::materializeTargetConversion(
3783 Type originalType)
const {
3784 for (
const TargetMaterializationCallbackFn &fn :
3785 llvm::reverse(targetMaterializations)) {
3786 SmallVector<Value>
result =
3787 fn(builder, resultTypes, inputs, loc, originalType);
3791 "callback produced incorrect number of values or values with "
3798std::optional<TypeConverter::SignatureConversion>
3799TypeConverter::convertBlockSignature(
Block *block)
const {
3802 return std::nullopt;
3809TypeConverter::AttributeConversionResult
3810TypeConverter::AttributeConversionResult::result(Attribute attr) {
3811 return AttributeConversionResult(attr, resultTag);
3814TypeConverter::AttributeConversionResult
3815TypeConverter::AttributeConversionResult::na() {
3816 return AttributeConversionResult(
nullptr, naTag);
3819TypeConverter::AttributeConversionResult
3820TypeConverter::AttributeConversionResult::abort() {
3821 return AttributeConversionResult(
nullptr, abortTag);
3824bool TypeConverter::AttributeConversionResult::hasResult()
const {
3825 return impl.getInt() == resultTag;
3828bool TypeConverter::AttributeConversionResult::isNa()
const {
3829 return impl.getInt() == naTag;
3832bool TypeConverter::AttributeConversionResult::isAbort()
const {
3833 return impl.getInt() == abortTag;
3836Attribute TypeConverter::AttributeConversionResult::getResult()
const {
3837 assert(hasResult() &&
"Cannot get result from N/A or abort");
3838 return impl.getPointer();
3841std::optional<Attribute>
3842TypeConverter::convertTypeAttribute(Type type, Attribute attr)
const {
3843 for (
const TypeAttributeConversionCallbackFn &fn :
3844 llvm::reverse(typeAttributeConversions)) {
3845 AttributeConversionResult res = fn(type, attr);
3846 if (res.hasResult())
3847 return res.getResult();
3849 return std::nullopt;
3851 return std::nullopt;
3860 ConversionPatternRewriter &rewriter) {
3861 FunctionType type = dyn_cast<FunctionType>(funcOp.getFunctionType());
3866 TypeConverter::SignatureConversion funcConversion(type.getNumInputs());
3868 if (failed(typeConverter.convertSignatureArgs(type.getInputs(),
3870 failed(typeConverter.convertTypes(type.getResults(), newResults)))
3879 if (!funcOp.getFunctionBody().empty()) {
3880 Block *entryBlock = &funcOp.getFunctionBody().
front();
3882 unsigned numFuncTypeInputs = type.getNumInputs();
3883 TypeConverter::SignatureConversion blockConversion(numEntryBlockArgs);
3885 if (failed(typeConverter.convertSignatureArgs(type.getInputs(),
3890 for (
unsigned i = numFuncTypeInputs; i < numEntryBlockArgs; ++i)
3892 rewriter.applySignatureConversion(entryBlock, blockConversion,
3896 auto newType = FunctionType::get(
3897 rewriter.getContext(), funcConversion.getConvertedTypes(), newResults);
3899 rewriter.modifyOpInPlace(funcOp, [&] { funcOp.setType(newType); });
3908struct FunctionOpInterfaceSignatureConversion :
public ConversionPattern {
3909 FunctionOpInterfaceSignatureConversion(StringRef functionLikeOpName,
3911 const TypeConverter &converter,
3912 PatternBenefit benefit)
3913 : ConversionPattern(converter, functionLikeOpName, benefit, ctx) {}
3916 matchAndRewrite(Operation *op, ArrayRef<Value> ,
3917 ConversionPatternRewriter &rewriter)
const override {
3918 FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
3923struct AnyFunctionOpInterfaceSignatureConversion
3924 :
public OpInterfaceConversionPattern<FunctionOpInterface> {
3925 using OpInterfaceConversionPattern::OpInterfaceConversionPattern;
3928 matchAndRewrite(FunctionOpInterface funcOp, ArrayRef<Value> ,
3929 ConversionPatternRewriter &rewriter)
const override {
3935FailureOr<Operation *>
3936mlir::convertOpResultTypes(Operation *op,
ValueRange operands,
3937 const TypeConverter &converter,
3938 ConversionPatternRewriter &rewriter) {
3939 assert(op &&
"Invalid op");
3940 Location loc = op->
getLoc();
3941 if (converter.isLegal(op))
3942 return rewriter.notifyMatchFailure(loc,
"op already legal");
3944 OperationState newOp(loc, op->
getName());
3945 newOp.addOperands(operands);
3947 SmallVector<Type> newResultTypes;
3949 return rewriter.notifyMatchFailure(loc,
"couldn't convert return types");
3951 newOp.addTypes(newResultTypes);
3954 return rewriter.create(newOp);
3957void mlir::populateFunctionOpInterfaceTypeConversionPattern(
3958 StringRef functionLikeOpName, RewritePatternSet &patterns,
3959 const TypeConverter &converter, PatternBenefit benefit) {
3960 patterns.
add<FunctionOpInterfaceSignatureConversion>(
3961 functionLikeOpName, patterns.
getContext(), converter, benefit);
3964void mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
3965 RewritePatternSet &patterns,
const TypeConverter &converter,
3966 PatternBenefit benefit) {
3967 patterns.
add<AnyFunctionOpInterfaceSignatureConversion>(
3975void ConversionTarget::setOpAction(OperationName op,
3976 LegalizationAction action) {
3977 legalOperations[op].action = action;
3980void ConversionTarget::setDialectAction(ArrayRef<StringRef> dialectNames,
3981 LegalizationAction action) {
3982 for (StringRef dialect : dialectNames)
3983 legalDialects[dialect] = action;
3986auto ConversionTarget::getOpAction(OperationName op)
const
3987 -> std::optional<LegalizationAction> {
3988 std::optional<LegalizationInfo> info = getOpInfo(op);
3989 return info ? info->action : std::optional<LegalizationAction>();
3992auto ConversionTarget::isLegal(Operation *op)
const
3993 -> std::optional<LegalOpDetails> {
3994 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3996 return std::nullopt;
3999 auto isOpLegal = [&] {
4001 if (info->action == LegalizationAction::Dynamic) {
4002 std::optional<bool>
result = info->legalityFn(op);
4008 return info->action == LegalizationAction::Legal;
4011 return std::nullopt;
4014 LegalOpDetails legalityDetails;
4015 if (info->isRecursivelyLegal) {
4016 auto legalityFnIt = opRecursiveLegalityFns.find(op->
getName());
4017 if (legalityFnIt != opRecursiveLegalityFns.end()) {
4018 legalityDetails.isRecursivelyLegal =
4019 legalityFnIt->second(op).value_or(
true);
4021 legalityDetails.isRecursivelyLegal =
true;
4024 return legalityDetails;
4027bool ConversionTarget::isIllegal(Operation *op)
const {
4028 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
4032 if (info->action == LegalizationAction::Dynamic) {
4033 std::optional<bool>
result = info->legalityFn(op);
4040 return info->action == LegalizationAction::Illegal;
4044 ConversionTarget::DynamicLegalityCallbackFn oldCallback,
4045 ConversionTarget::DynamicLegalityCallbackFn newCallback) {
4049 auto chain = [oldCl = std::move(oldCallback), newCl = std::move(newCallback)](
4051 if (std::optional<bool>
result = newCl(op))
4059void ConversionTarget::setLegalityCallback(
4060 OperationName name,
const DynamicLegalityCallbackFn &callback) {
4061 assert(callback &&
"expected valid legality callback");
4062 auto *infoIt = legalOperations.find(name);
4063 assert(infoIt != legalOperations.end() &&
4064 infoIt->second.action == LegalizationAction::Dynamic &&
4065 "expected operation to already be marked as dynamically legal");
4066 infoIt->second.legalityFn =
4070void ConversionTarget::markOpRecursivelyLegal(
4071 OperationName name,
const DynamicLegalityCallbackFn &callback) {
4072 auto *infoIt = legalOperations.find(name);
4073 assert(infoIt != legalOperations.end() &&
4074 infoIt->second.action != LegalizationAction::Illegal &&
4075 "expected operation to already be marked as legal");
4076 infoIt->second.isRecursivelyLegal =
true;
4079 std::move(opRecursiveLegalityFns[name]), callback);
4081 opRecursiveLegalityFns.erase(name);
4084void ConversionTarget::setLegalityCallback(
4085 ArrayRef<StringRef> dialects,
const DynamicLegalityCallbackFn &callback) {
4086 assert(callback &&
"expected valid legality callback");
4087 for (StringRef dialect : dialects)
4089 std::move(dialectLegalityFns[dialect]), callback);
4092void ConversionTarget::setLegalityCallback(
4093 const DynamicLegalityCallbackFn &callback) {
4094 assert(callback &&
"expected valid legality callback");
4098auto ConversionTarget::getOpInfo(OperationName op)
const
4099 -> std::optional<LegalizationInfo> {
4101 const auto *it = legalOperations.find(op);
4102 if (it != legalOperations.end())
4105 auto dialectIt = legalDialects.find(op.getDialectNamespace());
4106 if (dialectIt != legalDialects.end()) {
4107 DynamicLegalityCallbackFn callback;
4108 auto dialectFn = dialectLegalityFns.find(op.getDialectNamespace());
4109 if (dialectFn != dialectLegalityFns.end())
4110 callback = dialectFn->second;
4111 return LegalizationInfo{dialectIt->second,
false,
4115 if (unknownLegalityFn)
4116 return LegalizationInfo{LegalizationAction::Dynamic,
4117 false, unknownLegalityFn};
4118 return std::nullopt;
4121#if MLIR_ENABLE_PDL_IN_PATTERNMATCH
4126void PDLConversionConfig::notifyRewriteBegin(PatternRewriter &rewriter) {
4127 auto &rewriterImpl =
4128 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4132void PDLConversionConfig::notifyRewriteEnd(PatternRewriter &rewriter) {
4133 auto &rewriterImpl =
4134 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4140static FailureOr<SmallVector<Value>>
4141pdllConvertValues(ConversionPatternRewriter &rewriter,
ValueRange values) {
4142 SmallVector<Value> mappedValues;
4143 if (
failed(rewriter.getRemappedValues(values, mappedValues)))
4145 return std::move(mappedValues);
4148void mlir::registerConversionPDLFunctions(RewritePatternSet &patterns) {
4151 [](PatternRewriter &rewriter, Value value) -> FailureOr<Value> {
4152 auto results = pdllConvertValues(
4153 static_cast<ConversionPatternRewriter &
>(rewriter), value);
4156 return results->front();
4159 "convertValues", [](PatternRewriter &rewriter,
ValueRange values) {
4160 return pdllConvertValues(
4161 static_cast<ConversionPatternRewriter &
>(rewriter), values);
4165 [](PatternRewriter &rewriter, Type type) -> FailureOr<Type> {
4166 auto &rewriterImpl =
4167 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4168 if (
const TypeConverter *converter =
4170 if (Type newType = converter->convertType(type))
4178 [](PatternRewriter &rewriter,
4179 TypeRange types) -> FailureOr<SmallVector<Type>> {
4180 auto &rewriterImpl =
4181 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4184 return SmallVector<Type>(types);
4186 SmallVector<Type> remappedTypes;
4187 if (
failed(converter->convertTypes(types, remappedTypes)))
4189 return std::move(remappedTypes);
4204 static constexpr StringLiteral
tag =
"apply-conversion";
4205 static constexpr StringLiteral
desc =
4206 "Encapsulate the application of a dialect conversion";
4214 ConversionConfig config,
4215 OpConversionMode mode) {
4219 LogicalResult status =
success();
4224 patterns, config, mode);
4235LogicalResult mlir::applyPartialConversion(
4236 ArrayRef<Operation *> ops,
const ConversionTarget &
target,
4237 const FrozenRewritePatternSet &patterns, ConversionConfig config) {
4239 OpConversionMode::Partial);
4242mlir::applyPartialConversion(Operation *op,
const ConversionTarget &
target,
4243 const FrozenRewritePatternSet &patterns,
4244 ConversionConfig config) {
4245 return applyPartialConversion(llvm::ArrayRef(op),
target, patterns, config);
4252LogicalResult mlir::applyFullConversion(ArrayRef<Operation *> ops,
4253 const ConversionTarget &
target,
4254 const FrozenRewritePatternSet &patterns,
4255 ConversionConfig config) {
4258LogicalResult mlir::applyFullConversion(Operation *op,
4259 const ConversionTarget &
target,
4260 const FrozenRewritePatternSet &patterns,
4261 ConversionConfig config) {
4262 return applyFullConversion(llvm::ArrayRef(op),
target, patterns, config);
4279 "expected top-level op to be isolated from above");
4282 "expected ops to have a common ancestor");
4291 for (
Operation *op : ops.drop_front()) {
4295 assert(commonAncestor &&
4296 "expected to find a common isolated from above ancestor");
4300 return commonAncestor;
4303LogicalResult mlir::applyAnalysisConversion(
4304 ArrayRef<Operation *> ops, ConversionTarget &
target,
4305 const FrozenRewritePatternSet &patterns, ConversionConfig config) {
4307 if (config.legalizableOps)
4308 assert(config.legalizableOps->empty() &&
"expected empty set");
4314 Operation *clonedAncestor = commonAncestor->
clone(mapping);
4318 inverseOperationMap[it.second] = it.first;
4321 SmallVector<Operation *> opsToConvert = llvm::map_to_vector(
4322 ops, [&](Operation *op) {
return mapping.
lookup(op); });
4324 OpConversionMode::Analysis);
4328 if (config.legalizableOps) {
4330 for (Operation *op : *config.legalizableOps)
4331 originalLegalizableOps.insert(inverseOperationMap[op]);
4332 *config.legalizableOps = std::move(originalLegalizableOps);
4336 clonedAncestor->
erase();
4341mlir::applyAnalysisConversion(Operation *op, ConversionTarget &
target,
4342 const FrozenRewritePatternSet &patterns,
4343 ConversionConfig config) {
4344 return applyAnalysisConversion(llvm::ArrayRef(op),
target, patterns, config);
static void setInsertionPointAfter(OpBuilder &b, Value value)
static Operation * getCommonDefiningOp(const ValueVector &values)
Return the operation that defines all values in the vector.
static LogicalResult applyConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config, OpConversionMode mode)
static T moveAndReset(T &obj)
Helper function that moves and returns the given object.
SmallVector< Value, 2 > ValueVector
A vector of SSA values, optimized for the most common case of one or two values.
static ConversionTarget::DynamicLegalityCallbackFn composeLegalityCallbacks(ConversionTarget::DynamicLegalityCallbackFn oldCallback, ConversionTarget::DynamicLegalityCallbackFn newCallback)
static bool isPureTypeConversion(const ValueVector &values)
A vector of values is a pure type conversion if all values are defined by the same operation and the ...
static LogicalResult legalizeUnresolvedMaterialization(RewriterBase &rewriter, UnrealizedConversionCastOp op, const UnresolvedMaterializationInfo &info)
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 void reconcileUnrealizedCastsImpl(RangeT castOps, function_ref< bool(UnrealizedConversionCastOp)> isCastOpOfInterestFn, SmallVectorImpl< UnrealizedConversionCastOp > *remainingCastOps)
Try to reconcile all given UnrealizedConversionCastOps and store the left-over ops in remainingCastOp...
static Operation * findCommonAncestor(ArrayRef< Operation * > ops)
Find a common IsolatedFromAbove ancestor of the given ops.
static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args)
A utility function to log a successful result for the given reason.
static void performReplaceValue(RewriterBase &rewriter, Value from, Value repl, function_ref< bool(OpOperand &)> functor=nullptr)
Replace all uses of from with repl.
static void reportNewIrLegalizationFatalError(const Pattern &pattern, const SetVector< Operation * > &newOps, const SetVector< Operation * > &modifiedOps)
Report a fatal error indicating that newly produced or modified IR could not be legalized.
static OpBuilder::InsertPoint computeInsertPoint(Value value)
Helper function that computes an insertion point where the given value is defined and can be used wit...
static const StringRef kPureTypeConversionMarker
Marker attribute for pure type conversions.
static SmallVector< Value > getReplacementValues(ConversionPatternRewriterImpl &impl, ValueRange fromRange, const SmallVector< SmallVector< Value > > &toRange, const TypeConverter *converter)
Given that fromRange is about to be replaced with toRange, compute replacement values with the types ...
static std::string diag(const llvm::Value &value)
static void rewrite(DataFlowSolver &solver, MLIRContext *context, MutableArrayRef< Region > initialRegions)
Rewrite the given regions using the computing analysis.
This is the type of Action that is dispatched when a conversion is applied.
tracing::ActionImpl< ApplyConversionAction > Base
static constexpr StringLiteral desc
ApplyConversionAction(ArrayRef< IRUnit > irUnits)
void print(raw_ostream &os) const override
static constexpr StringLiteral tag
This class represents an argument of a Block.
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()
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
RetT walk(FnT &&callback)
Walk all nested operations, blocks (including this block) or regions, depending on the type of callba...
BlockArgListType getArguments()
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
StringAttr getStringAttr(const Twine &bytes)
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.
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 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.
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.
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.
Operation * insert(Operation *op)
Insert the given operation at the current insertion point and return it.
This class represents an operand of an operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
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.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
type_range getTypes() const
void destroyOpProperties(PropertyRef properties) const
This hooks destroy the op properties.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
TypeID getOpPropertiesTypeID() const
Return the TypeID of the op properties.
Operation is the basic unit of execution within MLIR.
PropertyRef getPropertiesStorage()
Return a generic (but typed) reference to the property type storage.
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
void copyProperties(PropertyRef rhs)
Copy properties from an existing other properties object.
bool use_empty()
Returns true if this operation has no uses.
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.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Block * getBlock()
Returns the operation block that contains this operation.
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
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...
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
OperandRange operand_range
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
bool hasDiscardableAttr(StringRef name)
Return true if this operation has a discardable attribute with the provided name.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
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'.
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),...
result_range getResults()
Operation * clone(IRMapping &mapper, const CloneOptions &options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
MLIRContext * getContext()
Return the context this operation is associated with.
void setDiscardableAttrs(DictionaryAttr newAttrs)
Set the discardable attribute dictionary on this operation.
void erase()
Remove this operation from its parent block and delete it.
unsigned getNumResults()
Return the number of results held by this operation.
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...
StringRef getDebugName() const
Return a readable name for this pattern.
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
PDLPatternModule & getPDLPatterns()
Return the PDL patterns held in this list.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
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...
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.
virtual void cancelOpModification(Operation *op)
This method cancels a pending in-place modification.
virtual 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.
RewriterBase(MLIRContext *ctx, OpBuilder::Listener *listener=nullptr)
Initialize the builder.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
virtual void startOpModification(Operation *op)
This method is used to notify the rewriter that an in-place operation modification is about to happen...
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.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
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.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static WalkResult advance()
Operation * getOwner() const
Return the owner of this operand.
CRTP Implementation of an action.
ArrayRef< IRUnit > irUnits
Set of IR units (operations, regions, blocks, values) that are associated with this action.
Kind
An enumeration of the kinds of predicates.
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
llvm::SetVector< T, Vector, Set, N > SetVector
static void reconcileUnrealizedCasts(const llvm::MapVector< UnrealizedConversionCastOp, UnresolvedMaterializationInfo > &castOps, SmallVectorImpl< UnrealizedConversionCastOp > *remainingCastOps)
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref
This iterator enumerates elements according to their dominance relationship.
virtual void notifyBlockInserted(Block *block, Region *previous, Region::iterator previousIt)
Notify the listener that the specified block was inserted.
virtual void notifyOperationInserted(Operation *op, InsertPoint previous)
Notify the listener that the specified operation was inserted.
OperationConverter(MLIRContext *ctx, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, const ConversionConfig &config, OpConversionMode mode)
const ConversionTarget & getTarget()
LogicalResult legalizeOperations(ArrayRef< Operation * > ops, bool isRecursiveLegalization=false)
LogicalResult convert(Operation *op, bool isRecursiveLegalization=false)
Converts a single operation.
LogicalResult legalizeOperations(ArrayRef< Operation * > ops, Fn onFailure, bool isRecursiveLegalization=false)
Legalizes the given operations (and their nested operations) to the conversion target.
LogicalResult applyConversion(ArrayRef< Operation * > ops)
Applies the conversion to the given operations (and their nested operations).
virtual void notifyOperationModified(Operation *op)
Notify the listener that the specified operation was modified in-place.
virtual void notifyOperationErased(Operation *op)
Notify the listener that the specified operation is about to be erased.
virtual void notifyOperationReplaced(Operation *op, Operation *replacement)
Notify the listener that all uses of the specified operation's results are about to be replaced with ...
virtual void notifyBlockErased(Block *block)
Notify the listener that the specified block is about to be erased.
A rewriter that keeps track of erased ops and blocks.
SingleEraseRewriter(MLIRContext *context, std::function< void(Operation *)> opErasedCallback=nullptr)
bool wasErased(void *ptr) const
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).
llvm::impl::raw_ldbg_ostream os
A raw output stream used to prefix the debug log.
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.
SetVector< Operation * > patternNewOps
A set of operations that were created by the current pattern.
void replaceValueUses(Value from, ValueRange to, const TypeConverter *converter, function_ref< bool(OpOperand &)> functor=nullptr)
Replace the uses of the given value with the given values.
DenseSet< Block * > erasedBlocks
A set of erased blocks.
llvm::MapVector< UnrealizedConversionCastOp, UnresolvedMaterializationInfo > unresolvedMaterializations
A mapping for looking up metadata of unresolved materializations.
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.
ConversionPatternRewriterImpl(ConversionPatternRewriter &rewriter, const ConversionConfig &config, OperationConverter &opConverter)
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...
LogicalResult remapValues(StringRef valueDiagTag, std::optional< Location > inputLoc, ValueRange values, SmallVector< ValueVector > &remapped)
Remap the given values to those with potentially different types.
ValueRange buildUnresolvedMaterialization(MaterializationKind kind, OpBuilder::InsertPoint ip, Location loc, ValueVector valuesToMap, ValueRange inputs, TypeRange outputTypes, Type originalType, const TypeConverter *converter, bool isPureTypeConversion=true)
Build an unresolved materialization operation given a range of output types and a list of input opera...
DenseSet< UnrealizedConversionCastOp > patternMaterializations
A list of unresolved materializations that were created by the current pattern.
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.
Block * applySignatureConversion(Block *block, const TypeConverter *converter, TypeConverter::SignatureConversion &signatureConversion)
Apply the given signature conversion on the given block.
void inlineBlockBefore(Block *source, Block *dest, Block::iterator before)
Inline the source block into the destination block before the given iterator.
void replaceOp(Operation *op, SmallVector< SmallVector< Value > > &&newValues)
Replace the results of the given operation with the given values and erase the operation.
RewriterState getCurrentState()
Return the current state of the rewriter.
llvm::ScopedPrinter logger
A logger used to emit diagnostics during the conversion process.
ValueVector lookupOrNull(Value from, TypeRange desiredTypes={}) const
Lookup the given value within the map, or return an empty vector if the value is not mapped.
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.
ValueVector lookupOrDefault(Value from, TypeRange desiredTypes={}, bool skipPureTypeConversions=false) const
Lookup the most recently mapped values with the desired types in the mapping, taking into account onl...
bool isOpIgnored(Operation *op) const
Return "true" if the given operation is ignored, and does not need to be converted.
IRRewriter notifyingRewriter
A rewriter that notifies the listener (if any) about all IR modifications.
OperationConverter & opConverter
The operation converter to use for recursive legalization.
DenseSet< Value > replacedValues
A set of replaced values.
DenseSet< Operation * > erasedOps
A set of erased operations.
void eraseBlock(Block *block)
Erase the given block and its contents.
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).
SetVector< Operation * > patternModifiedOps
A set of operations that were modified by the current pattern.
const ConversionConfig & config
Dialect conversion configuration.
SetVector< Operation * > replacedOps
A set of operations that were replaced/erased.
ConversionPatternRewriter & rewriter
The rewriter that is used to perform the conversion.
const TypeConverter * currentTypeConverter
The current type converter, or nullptr if no type converter is currently active.
FailureOr< Block * > convertRegionTypes(Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion)
Convert the types of block arguments within the given region.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.