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);
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);
2240bool ConversionPatternRewriter::replaceUsesWithIf(
2242 bool *allUsesReplaced) {
2243 assert(!allUsesReplaced &&
2244 "allUsesReplaced is not supported in a dialect conversion");
2245 bool replaced =
false;
2246 impl->replaceValueUses(from, to, impl->currentTypeConverter,
2247 [&](OpOperand &operand) {
2248 bool replace = functor(operand);
2249 replaced |= replace;
2255Value ConversionPatternRewriter::getRemappedValue(Value key) {
2256 SmallVector<ValueVector> remappedValues;
2257 if (
failed(impl->remapValues(
"value", std::nullopt, key,
2260 assert(remappedValues.front().size() == 1 &&
"1:N conversion not supported");
2261 return remappedValues.front().front();
2265ConversionPatternRewriter::getRemappedValues(
ValueRange keys,
2266 SmallVectorImpl<Value> &results) {
2269 SmallVector<ValueVector> remapped;
2270 if (
failed(impl->remapValues(
"value", std::nullopt, keys,
2273 for (
const auto &values : remapped) {
2274 assert(values.size() == 1 &&
"1:N conversion not supported");
2275 results.push_back(values.front());
2280void ConversionPatternRewriter::inlineBlockBefore(
Block *source,
Block *dest,
2285 "incorrect # of argument replacement values");
2286 assert(!impl->wasOpReplaced(source->
getParentOp()) &&
2287 "attempting to inline a block from a replaced/erased op");
2288 assert(!impl->wasOpReplaced(dest->
getParentOp()) &&
2289 "attempting to inline a block into a replaced/erased op");
2290 auto opIgnored = [&](Operation *op) {
return impl->isOpIgnored(op); };
2293 assert(llvm::all_of(source->
getUsers(), opIgnored) &&
2294 "expected 'source' to have no predecessors");
2303 bool fastPath = !getConfig().listener;
2305 if (fastPath && impl->config.allowPatternRollback)
2306 impl->inlineBlockBefore(source, dest, before);
2309 for (
auto it : llvm::zip(source->
getArguments(), argValues))
2310 replaceAllUsesWith(std::get<0>(it), std::get<1>(it));
2317 while (!source->
empty())
2318 moveOpBefore(&source->
front(), dest, before);
2323 if (getInsertionBlock() == source)
2324 setInsertionPoint(dest, getInsertionPoint());
2330void ConversionPatternRewriter::startOpModification(Operation *op) {
2331 if (!impl->config.allowPatternRollback) {
2336 assert(!impl->wasOpReplaced(op) &&
2337 "attempting to modify a replaced/erased op");
2339 impl->pendingRootUpdates.insert(op);
2341 impl->appendRewrite<ModifyOperationRewrite>(op);
2344void ConversionPatternRewriter::finalizeOpModification(Operation *op) {
2345 impl->patternModifiedOps.insert(op);
2346 if (!impl->config.allowPatternRollback) {
2348 if (getConfig().listener)
2349 getConfig().listener->notifyOperationModified(op);
2356 assert(!impl->wasOpReplaced(op) &&
2357 "attempting to modify a replaced/erased op");
2358 assert(impl->pendingRootUpdates.erase(op) &&
2359 "operation did not have a pending in-place update");
2363void ConversionPatternRewriter::cancelOpModification(Operation *op) {
2364 if (!impl->config.allowPatternRollback) {
2369 assert(impl->pendingRootUpdates.erase(op) &&
2370 "operation did not have a pending in-place update");
2373 auto it = llvm::find_if(
2374 llvm::reverse(impl->rewrites), [&](std::unique_ptr<IRRewrite> &
rewrite) {
2375 auto *modifyRewrite = dyn_cast<ModifyOperationRewrite>(rewrite.get());
2376 return modifyRewrite && modifyRewrite->getOperation() == op;
2378 assert(it != impl->rewrites.rend() &&
"no root update started on op");
2380 int updateIdx = std::prev(impl->rewrites.rend()) - it;
2381 impl->rewrites.erase(impl->rewrites.begin() + updateIdx);
2384detail::ConversionPatternRewriterImpl &ConversionPatternRewriter::getImpl() {
2392FailureOr<SmallVector<Value>> ConversionPattern::getOneToOneAdaptorOperands(
2393 ArrayRef<ValueRange> operands)
const {
2394 SmallVector<Value> oneToOneOperands;
2395 oneToOneOperands.reserve(operands.size());
2397 if (operand.size() != 1)
2400 oneToOneOperands.push_back(operand.front());
2402 return std::move(oneToOneOperands);
2406ConversionPattern::matchAndRewrite(Operation *op,
2407 PatternRewriter &rewriter)
const {
2408 auto &dialectRewriter =
static_cast<ConversionPatternRewriter &
>(rewriter);
2409 auto &rewriterImpl = dialectRewriter.getImpl();
2413 getTypeConverter());
2416 SmallVector<ValueVector> remapped;
2421 SmallVector<ValueRange> remappedAsRange =
2422 llvm::to_vector_of<ValueRange>(remapped);
2423 return matchAndRewrite(op, remappedAsRange, dialectRewriter);
2432using LegalizationPatterns = SmallVector<const Pattern *, 1>;
2435class OperationLegalizer {
2437 using LegalizationAction = ConversionTarget::LegalizationAction;
2439 OperationLegalizer(ConversionPatternRewriter &rewriter,
2440 const ConversionTarget &targetInfo,
2441 const FrozenRewritePatternSet &patterns);
2444 bool isIllegal(Operation *op)
const;
2448 LogicalResult legalize(Operation *op);
2451 const ConversionTarget &getTarget() {
return target; }
2455 LogicalResult legalizeWithFold(Operation *op);
2459 LogicalResult legalizeWithPattern(Operation *op);
2463 bool canApplyPattern(Operation *op,
const Pattern &pattern);
2467 legalizePatternResult(Operation *op,
const Pattern &pattern,
2468 const RewriterState &curState,
2485 void buildLegalizationGraph(
2486 LegalizationPatterns &anyOpLegalizerPatterns,
2497 void computeLegalizationGraphBenefit(
2498 LegalizationPatterns &anyOpLegalizerPatterns,
2503 unsigned computeOpLegalizationDepth(
2510 unsigned applyCostModelToPatterns(
2511 LegalizationPatterns &patterns,
2516 SmallPtrSet<const Pattern *, 8> appliedPatterns;
2519 ConversionPatternRewriter &rewriter;
2522 const ConversionTarget &
target;
2525 PatternApplicator applicator;
2529OperationLegalizer::OperationLegalizer(ConversionPatternRewriter &rewriter,
2530 const ConversionTarget &targetInfo,
2531 const FrozenRewritePatternSet &patterns)
2532 : rewriter(rewriter),
target(targetInfo), applicator(patterns) {
2536 LegalizationPatterns anyOpLegalizerPatterns;
2538 buildLegalizationGraph(anyOpLegalizerPatterns, legalizerPatterns);
2539 computeLegalizationGraphBenefit(anyOpLegalizerPatterns, legalizerPatterns);
2542bool OperationLegalizer::isIllegal(Operation *op)
const {
2543 return target.isIllegal(op);
2546LogicalResult OperationLegalizer::legalize(Operation *op) {
2548 const char *logLineComment =
2549 "//===-------------------------------------------===//\n";
2551 auto &logger = rewriter.getImpl().logger;
2555 bool isIgnored = rewriter.getImpl().isOpIgnored(op);
2558 logger.getOStream() <<
"\n";
2559 logger.startLine() << logLineComment;
2560 logger.startLine() <<
"Legalizing operation : ";
2565 logger.getOStream() <<
"'" << op->
getName() <<
"' ";
2566 logger.getOStream() <<
"(" << op <<
") {\n";
2571 logger.startLine() << OpWithFlags(op,
2572 OpPrintingFlags().printGenericOpForm())
2579 logSuccess(logger,
"operation marked 'ignored' during conversion");
2580 logger.startLine() << logLineComment;
2586 if (
auto legalityInfo =
target.isLegal(op)) {
2589 logger,
"operation marked legal by the target{0}",
2590 legalityInfo->isRecursivelyLegal
2591 ?
"; NOTE: operation is recursively legal; skipping internals"
2593 logger.startLine() << logLineComment;
2598 if (legalityInfo->isRecursivelyLegal) {
2599 op->
walk([&](Operation *nested) {
2601 rewriter.getImpl().ignoredOps.
insert(nested);
2610 const ConversionConfig &config = rewriter.getConfig();
2611 if (config.foldingMode == DialectConversionFoldingMode::BeforePatterns) {
2612 if (succeeded(legalizeWithFold(op))) {
2615 logger.startLine() << logLineComment;
2622 if (succeeded(legalizeWithPattern(op))) {
2625 logger.startLine() << logLineComment;
2632 if (config.foldingMode == DialectConversionFoldingMode::AfterPatterns) {
2633 if (succeeded(legalizeWithFold(op))) {
2636 logger.startLine() << logLineComment;
2643 logFailure(logger,
"no matched legalization pattern");
2644 logger.startLine() << logLineComment;
2651template <
typename T>
2653 T
result = std::move(obj);
2658LogicalResult OperationLegalizer::legalizeWithFold(Operation *op) {
2659 auto &rewriterImpl = rewriter.getImpl();
2661 rewriterImpl.
logger.startLine() <<
"* Fold {\n";
2662 rewriterImpl.
logger.indent();
2667 llvm::scope_exit cleanup([&]() {
2677 SmallVector<Value, 2> replacementValues;
2678 SmallVector<Operation *, 2> newOps;
2681 if (
failed(rewriter.
tryFold(op, replacementValues, &newOps))) {
2690 if (replacementValues.empty())
2691 return legalize(op);
2694 rewriter.
replaceOp(op, replacementValues);
2697 for (Operation *newOp : newOps) {
2698 if (
failed(legalize(newOp))) {
2700 "failed to legalize generated constant '{0}'",
2702 if (!rewriter.getConfig().allowPatternRollback) {
2704 llvm::reportFatalInternalError(
2706 "' folder rollback of IR modifications requested");
2708 rewriterImpl.
resetState(curState, std::string(opName) +
" folder");
2723 auto newOpNames = llvm::map_range(
2725 auto modifiedOpNames = llvm::map_range(
2727 llvm::reportFatalInternalError(
"pattern '" + pattern.
getDebugName() +
2728 "' produced IR that could not be legalized. " +
2729 "new ops: {" + llvm::join(newOpNames,
", ") +
2730 "}, " +
"modified ops: {" +
2731 llvm::join(modifiedOpNames,
", ") +
"}");
2734LogicalResult OperationLegalizer::legalizeWithPattern(Operation *op) {
2735 auto &rewriterImpl = rewriter.getImpl();
2736 const ConversionConfig &config = rewriter.getConfig();
2738#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2740 std::optional<OperationFingerPrint> topLevelFingerPrint;
2741 if (!rewriterImpl.
config.allowPatternRollback) {
2748 topLevelFingerPrint = OperationFingerPrint(checkOp);
2754 rewriterImpl.
logger.startLine()
2755 <<
"WARNING: Multi-threadeding is enabled. Some dialect "
2756 "conversion expensive checks are skipped in multithreading "
2765 auto canApply = [&](
const Pattern &pattern) {
2766 bool canApply = canApplyPattern(op, pattern);
2767 if (canApply && config.listener)
2768 config.listener->notifyPatternBegin(pattern, op);
2774 auto onFailure = [&](
const Pattern &pattern) {
2776 if (!rewriterImpl.
config.allowPatternRollback) {
2783#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2785 if (checkOp && topLevelFingerPrint) {
2786 OperationFingerPrint fingerPrintAfterPattern(checkOp);
2787 if (fingerPrintAfterPattern != *topLevelFingerPrint)
2788 llvm::reportFatalInternalError(
2789 "pattern '" + pattern.getDebugName() +
2790 "' returned failure but IR did change");
2798 if (rewriterImpl.
config.notifyCallback) {
2800 diag <<
"Failed to apply pattern \"" << pattern.getDebugName()
2803 rewriterImpl.
config.notifyCallback(diag);
2806 if (config.listener)
2807 config.listener->notifyPatternEnd(pattern, failure());
2808 rewriterImpl.
resetState(curState, pattern.getDebugName());
2809 appliedPatterns.erase(&pattern);
2814 auto onSuccess = [&](
const Pattern &pattern) {
2816 if (!rewriterImpl.
config.allowPatternRollback) {
2830 legalizePatternResult(op, pattern, curState, newOps, modifiedOps);
2831 appliedPatterns.erase(&pattern);
2833 if (!rewriterImpl.
config.allowPatternRollback)
2835 rewriterImpl.
resetState(curState, pattern.getDebugName());
2837 if (config.listener)
2838 config.listener->notifyPatternEnd(pattern,
result);
2843 return applicator.matchAndRewrite(op, rewriter, canApply, onFailure,
2847bool OperationLegalizer::canApplyPattern(Operation *op,
2848 const Pattern &pattern) {
2850 auto &os = rewriter.getImpl().logger;
2851 os.getOStream() <<
"\n";
2852 os.startLine() <<
"* Pattern : '" << op->
getName() <<
" -> (";
2854 os.getOStream() <<
")' {\n";
2861 !appliedPatterns.insert(&pattern).second) {
2863 logFailure(rewriter.getImpl().logger,
"pattern was already applied"));
2869LogicalResult OperationLegalizer::legalizePatternResult(
2870 Operation *op,
const Pattern &pattern,
const RewriterState &curState,
2873 [[maybe_unused]]
auto &impl = rewriter.getImpl();
2874 assert(impl.pendingRootUpdates.empty() &&
"dangling root updates");
2876#if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2877 if (impl.config.allowPatternRollback) {
2879 auto newRewrites = llvm::drop_begin(impl.rewrites, curState.numRewrites);
2880 auto replacedRoot = [&] {
2881 return hasRewrite<ReplaceOperationRewrite>(newRewrites, op);
2883 auto updatedRootInPlace = [&] {
2884 return hasRewrite<ModifyOperationRewrite>(newRewrites, op);
2886 if (!replacedRoot() && !updatedRootInPlace())
2887 llvm::reportFatalInternalError(
2888 "expected pattern to replace the root operation "
2889 "or modify it in place");
2894 if (
failed(legalizePatternRootUpdates(modifiedOps)) ||
2895 failed(legalizePatternCreatedOperations(newOps))) {
2899 LLVM_DEBUG(
logSuccess(impl.logger,
"pattern applied successfully"));
2903LogicalResult OperationLegalizer::legalizePatternCreatedOperations(
2905 for (Operation *op : newOps) {
2906 if (
failed(legalize(op))) {
2907 LLVM_DEBUG(
logFailure(rewriter.getImpl().logger,
2908 "failed to legalize generated operation '{0}'({1})",
2916LogicalResult OperationLegalizer::legalizePatternRootUpdates(
2918 for (Operation *op : modifiedOps) {
2919 if (
failed(legalize(op))) {
2922 "failed to legalize operation updated in-place '{0}'",
2934void OperationLegalizer::buildLegalizationGraph(
2935 LegalizationPatterns &anyOpLegalizerPatterns,
2946 applicator.walkAllPatterns([&](
const Pattern &pattern) {
2947 std::optional<OperationName> root = pattern.
getRootKind();
2953 anyOpLegalizerPatterns.push_back(&pattern);
2958 if (
target.getOpAction(*root) == LegalizationAction::Legal)
2963 invalidPatterns[*root].insert(&pattern);
2965 parentOps[op].insert(*root);
2968 patternWorklist.insert(&pattern);
2976 if (!anyOpLegalizerPatterns.empty()) {
2977 for (
const Pattern *pattern : patternWorklist)
2978 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2982 while (!patternWorklist.empty()) {
2983 auto *pattern = patternWorklist.pop_back_val();
2987 std::optional<LegalizationAction> action = target.getOpAction(op);
2988 return !legalizerPatterns.count(op) &&
2989 (!action || action == LegalizationAction::Illegal);
2995 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2996 invalidPatterns[*pattern->
getRootKind()].erase(pattern);
3000 for (
auto op : parentOps[*pattern->
getRootKind()])
3001 patternWorklist.set_union(invalidPatterns[op]);
3005void OperationLegalizer::computeLegalizationGraphBenefit(
3006 LegalizationPatterns &anyOpLegalizerPatterns,
3012 for (
auto &opIt : legalizerPatterns)
3013 if (!minOpPatternDepth.count(opIt.first))
3014 computeOpLegalizationDepth(opIt.first, minOpPatternDepth,
3020 if (!anyOpLegalizerPatterns.empty())
3021 applyCostModelToPatterns(anyOpLegalizerPatterns, minOpPatternDepth,
3027 applicator.applyCostModel([&](
const Pattern &pattern) {
3028 ArrayRef<const Pattern *> orderedPatternList;
3029 if (std::optional<OperationName> rootName = pattern.
getRootKind())
3030 orderedPatternList = legalizerPatterns[*rootName];
3032 orderedPatternList = anyOpLegalizerPatterns;
3035 auto *it = llvm::find(orderedPatternList, &pattern);
3036 if (it == orderedPatternList.end())
3040 return PatternBenefit(std::distance(it, orderedPatternList.end()));
3044unsigned OperationLegalizer::computeOpLegalizationDepth(
3048 auto depthIt = minOpPatternDepth.find(op);
3049 if (depthIt != minOpPatternDepth.end())
3050 return depthIt->second;
3054 auto opPatternsIt = legalizerPatterns.find(op);
3055 if (opPatternsIt == legalizerPatterns.end() || opPatternsIt->second.empty())
3060 minOpPatternDepth.try_emplace(op, std::numeric_limits<unsigned>::max());
3064 unsigned minDepth = applyCostModelToPatterns(
3065 opPatternsIt->second, minOpPatternDepth, legalizerPatterns);
3066 minOpPatternDepth[op] = minDepth;
3070unsigned OperationLegalizer::applyCostModelToPatterns(
3071 LegalizationPatterns &patterns,
3074 unsigned minDepth = std::numeric_limits<unsigned>::max();
3077 SmallVector<std::pair<const Pattern *, unsigned>, 4> patternsByDepth;
3078 patternsByDepth.reserve(patterns.size());
3079 for (
const Pattern *pattern : patterns) {
3082 unsigned generatedOpDepth = computeOpLegalizationDepth(
3083 generatedOp, minOpPatternDepth, legalizerPatterns);
3084 depth = std::max(depth, generatedOpDepth + 1);
3086 patternsByDepth.emplace_back(pattern, depth);
3089 minDepth = std::min(minDepth, depth);
3094 if (patternsByDepth.size() == 1)
3098 llvm::stable_sort(patternsByDepth,
3099 [](
const std::pair<const Pattern *, unsigned> &
lhs,
3100 const std::pair<const Pattern *, unsigned> &
rhs) {
3103 if (
lhs.second !=
rhs.second)
3104 return lhs.second <
rhs.second;
3107 auto lhsBenefit =
lhs.first->getBenefit();
3108 auto rhsBenefit =
rhs.first->getBenefit();
3109 return lhsBenefit > rhsBenefit;
3114 for (
auto &patternIt : patternsByDepth)
3115 patterns.push_back(patternIt.first);
3129template <
typename RangeT>
3132 function_ref<
bool(UnrealizedConversionCastOp)> isCastOpOfInterestFn,
3141 [](UnrealizedConversionCastOp castOp) -> UnrealizedConversionCastOp {
3142 if (castOp.getInputs().empty())
3145 castOp.getInputs().front().getDefiningOp<UnrealizedConversionCastOp>();
3148 if (inputCastOp.getOutputs() != castOp.getInputs())
3154 while (!worklist.empty()) {
3155 UnrealizedConversionCastOp castOp = worklist.pop_back_val();
3159 UnrealizedConversionCastOp nextCast = castOp;
3161 if (nextCast.getInputs().getTypes() == castOp.getResultTypes()) {
3162 if (llvm::any_of(nextCast.getInputs(), [&](
Value v) {
3163 return v.getDefiningOp() == castOp;
3171 castOp.replaceAllUsesWith(nextCast.getInputs());
3174 nextCast = getInputCast(nextCast);
3184 auto markOpLive = [&](
Operation *rootOp) {
3186 worklist.push_back(rootOp);
3187 while (!worklist.empty()) {
3188 Operation *op = worklist.pop_back_val();
3189 if (liveOps.insert(op).second) {
3192 if (
auto castOp = v.
getDefiningOp<UnrealizedConversionCastOp>())
3193 if (isCastOpOfInterestFn(castOp))
3194 worklist.push_back(castOp);
3200 for (UnrealizedConversionCastOp op : castOps) {
3203 if (liveOps.contains(op.getOperation()))
3207 if (llvm::any_of(op->getUsers(), [&](
Operation *user) {
3208 auto castOp = dyn_cast<UnrealizedConversionCastOp>(user);
3209 return !castOp || !isCastOpOfInterestFn(castOp);
3215 for (UnrealizedConversionCastOp op : castOps) {
3216 if (liveOps.contains(op)) {
3218 if (remainingCastOps)
3219 remainingCastOps->push_back(op);
3230 ArrayRef<UnrealizedConversionCastOp> castOps,
3231 SmallVectorImpl<UnrealizedConversionCastOp> *remainingCastOps) {
3233 DenseSet<UnrealizedConversionCastOp> castOpSet;
3234 for (UnrealizedConversionCastOp op : castOps)
3235 castOpSet.insert(op);
3240 const DenseSet<UnrealizedConversionCastOp> &castOps,
3241 SmallVectorImpl<UnrealizedConversionCastOp> *remainingCastOps) {
3243 llvm::make_range(castOps.begin(), castOps.end()),
3244 [&](UnrealizedConversionCastOp castOp) {
3245 return castOps.contains(castOp);
3253 UnresolvedMaterializationInfo> &castOps,
3257 [&](UnrealizedConversionCastOp castOp) {
3258 return castOps.contains(castOp);
3275 const ConversionConfig &config,
3276 OpConversionMode mode)
3277 : rewriter(ctx, config, *this), opLegalizer(rewriter,
target, patterns),
3286 template <
typename Fn>
3288 bool isRecursiveLegalization =
false);
3290 bool isRecursiveLegalization =
false) {
3292 ops, [&]() {}, isRecursiveLegalization);
3300 LogicalResult convert(
Operation *op,
bool isRecursiveLegalization =
false);
3306 ConversionPatternRewriter rewriter;
3309 OperationLegalizer opLegalizer;
3312 OpConversionMode mode;
3317 bool isRecursiveLegalization) {
3318 const ConversionConfig &config = rewriter.getConfig();
3319 auto emitFailedToLegalizeDiag = [&](
bool wasExplicitlyIllegal) {
3321 <<
"failed to legalize operation '"
3323 if (wasExplicitlyIllegal)
3324 diag <<
" that was explicitly marked illegal";
3329 if (failed(opLegalizer.legalize(op))) {
3332 if (mode == OpConversionMode::Full) {
3333 if (!isRecursiveLegalization)
3334 emitFailedToLegalizeDiag(
false);
3340 if (mode == OpConversionMode::Partial) {
3341 if (opLegalizer.isIllegal(op)) {
3342 if (!isRecursiveLegalization)
3343 emitFailedToLegalizeDiag(
true);
3346 if (config.unlegalizedOps && !isRecursiveLegalization)
3347 config.unlegalizedOps->insert(op);
3349 }
else if (mode == OpConversionMode::Analysis) {
3353 if (config.legalizableOps && !isRecursiveLegalization)
3354 config.legalizableOps->insert(op);
3361 UnrealizedConversionCastOp op,
3362 const UnresolvedMaterializationInfo &info) {
3363 assert(!op.use_empty() &&
3364 "expected that dead materializations have already been DCE'd");
3371 switch (info.getMaterializationKind()) {
3372 case MaterializationKind::Target:
3373 newMaterialization = converter->materializeTargetConversion(
3374 rewriter, op->getLoc(), op.getResultTypes(), inputOperands,
3375 info.getOriginalType());
3377 case MaterializationKind::Source:
3378 assert(op->getNumResults() == 1 &&
"expected single result");
3379 Value sourceMat = converter->materializeSourceConversion(
3380 rewriter, op->getLoc(), op.getResultTypes().front(), inputOperands);
3382 newMaterialization.push_back(sourceMat);
3385 if (!newMaterialization.empty()) {
3387 ValueRange newMaterializationRange(newMaterialization);
3388 assert(
TypeRange(newMaterializationRange) == op.getResultTypes() &&
3389 "materialization callback produced value of incorrect type");
3391 rewriter.
replaceOp(op, newMaterialization);
3394 StringRef direction =
3395 info.getMaterializationKind() == MaterializationKind::Target ?
"target"
3399 <<
"failed to legalize unresolved " << direction
3400 <<
" materialization from (" << inputOperands.
getTypes() <<
") to ("
3401 << op.getResultTypes()
3402 <<
") that remained live after conversion (no matching callback)";
3403 diag.attachNote(op->getUsers().begin()->getLoc())
3404 <<
"see existing live user here: " << *op->getUsers().begin();
3410 <<
"failed to legalize unresolved materialization "
3412 << inputOperands.
getTypes() <<
") to (" << op.getResultTypes()
3413 <<
") that remained live after conversion (no type converter specified)";
3414 diag.attachNote(op->getUsers().begin()->getLoc())
3415 <<
"see existing live user here: " << *op->getUsers().begin();
3419template <
typename Fn>
3422 bool isRecursiveLegalization) {
3430 toConvert.push_back(op);
3433 auto legalityInfo =
target.isLegal(op);
3434 if (legalityInfo && legalityInfo->isRecursivelyLegal)
3440 if (failed(
convert(op, isRecursiveLegalization))) {
3449LogicalResult ConversionPatternRewriter::legalize(
Operation *op) {
3450 return impl->opConverter.legalizeOperations(op,
3454LogicalResult ConversionPatternRewriter::legalize(
Region *r) {
3470 std::optional<TypeConverter::SignatureConversion> conversion =
3471 converter->convertBlockSignature(&r->front());
3474 applySignatureConversion(&r->front(), *conversion, converter);
3479 return impl->opConverter.legalizeOperations(ops,
3489 if (rewriterImpl.
config.allowPatternRollback) {
3508 UnresolvedMaterializationInfo> &materializations =
3514 for (UnrealizedConversionCastOp castOp : remainingCastOps)
3518 if (rewriter.getConfig().buildMaterializations) {
3522 rewriter.getConfig().listener);
3523 for (UnrealizedConversionCastOp castOp : remainingCastOps) {
3524 auto it = materializations.find(castOp);
3525 assert(it != materializations.end() &&
"inconsistent state");
3539void TypeConverter::SignatureConversion::addInputs(
unsigned origInputNo,
3541 assert(!types.empty() &&
"expected valid types");
3542 remapInput(origInputNo, argTypes.size(), types.size());
3546void TypeConverter::SignatureConversion::addInputs(
ArrayRef<Type> types) {
3547 assert(!types.empty() &&
3548 "1->0 type remappings don't need to be added explicitly");
3549 argTypes.append(types.begin(), types.end());
3552void TypeConverter::SignatureConversion::remapInput(
unsigned origInputNo,
3553 unsigned newInputNo,
3554 unsigned newInputCount) {
3555 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
3556 assert(newInputCount != 0 &&
"expected valid input count");
3557 remappedInputs[origInputNo] =
3558 InputMapping{newInputNo, newInputCount, {}};
3561void TypeConverter::SignatureConversion::remapInput(
3562 unsigned origInputNo, ArrayRef<Value> replacements) {
3563 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
3564 remappedInputs[origInputNo] = InputMapping{
3566 SmallVector<Value, 1>(replacements.begin(), replacements.end())};
3577TypeConverter::convertTypeImpl(PointerUnion<Type, Value> typeOrValue,
3578 SmallVectorImpl<Type> &results)
const {
3579 assert(typeOrValue &&
"expected non-null type");
3580 Type t = (isa<Value>(typeOrValue)) ? cast<Value>(typeOrValue).getType()
3581 : cast<Type>(typeOrValue);
3583 std::shared_lock<
decltype(cacheMutex)> cacheReadLock(cacheMutex,
3586 cacheReadLock.lock();
3587 auto existingIt = cachedDirectConversions.find(t);
3588 if (existingIt != cachedDirectConversions.end()) {
3589 if (existingIt->second)
3590 results.push_back(existingIt->second);
3591 return success(existingIt->second !=
nullptr);
3593 auto multiIt = cachedMultiConversions.find(t);
3594 if (multiIt != cachedMultiConversions.end()) {
3595 results.append(multiIt->second.begin(), multiIt->second.end());
3601 size_t currentCount = results.size();
3605 auto isCacheable = [&](
int index) {
3606 int numberOfConversionsUntilContextAware =
3607 conversions.size() - 1 - contextAwareTypeConversionsIndex;
3608 return index < numberOfConversionsUntilContextAware;
3611 std::unique_lock<
decltype(cacheMutex)> cacheWriteLock(cacheMutex,
3614 for (
auto indexedConverter : llvm::enumerate(llvm::reverse(conversions))) {
3615 const ConversionCallbackFn &converter = indexedConverter.value();
3616 std::optional<LogicalResult>
result = converter(typeOrValue, results);
3618 assert(results.size() == currentCount &&
3619 "failed type conversion should not change results");
3622 if (!isCacheable(indexedConverter.index()))
3625 cacheWriteLock.lock();
3626 if (!succeeded(*
result)) {
3627 assert(results.size() == currentCount &&
3628 "failed type conversion should not change results");
3629 cachedDirectConversions.try_emplace(t,
nullptr);
3632 auto newTypes = ArrayRef<Type>(results).drop_front(currentCount);
3633 if (newTypes.size() == 1)
3634 cachedDirectConversions.try_emplace(t, newTypes.front());
3636 cachedMultiConversions.try_emplace(t, llvm::to_vector<2>(newTypes));
3642LogicalResult TypeConverter::convertType(Type t,
3643 SmallVectorImpl<Type> &results)
const {
3644 return convertTypeImpl(t, results);
3647LogicalResult TypeConverter::convertType(Value v,
3648 SmallVectorImpl<Type> &results)
const {
3649 return convertTypeImpl(v, results);
3652Type TypeConverter::convertType(Type t)
const {
3654 SmallVector<Type, 1> results;
3655 if (
failed(convertType(t, results)))
3659 return results.size() == 1 ? results.front() :
nullptr;
3662Type TypeConverter::convertType(Value v)
const {
3664 SmallVector<Type, 1> results;
3665 if (
failed(convertType(v, results)))
3669 return results.size() == 1 ? results.front() :
nullptr;
3673TypeConverter::convertTypes(
TypeRange types,
3674 SmallVectorImpl<Type> &results)
const {
3675 for (Type type : types)
3676 if (
failed(convertType(type, results)))
3682TypeConverter::convertTypes(
ValueRange values,
3683 SmallVectorImpl<Type> &results)
const {
3684 for (Value value : values)
3685 if (
failed(convertType(value, results)))
3690bool TypeConverter::isLegal(Type type)
const {
3691 return convertType(type) == type;
3694bool TypeConverter::isLegal(Value value)
const {
3695 return convertType(value) == value.
getType();
3698bool TypeConverter::isLegal(Operation *op)
const {
3702bool TypeConverter::isLegal(Region *region)
const {
3703 return llvm::all_of(
3707bool TypeConverter::isSignatureLegal(FunctionType ty)
const {
3708 if (!isLegal(ty.getInputs()))
3710 if (!isLegal(ty.getResults()))
3716TypeConverter::convertSignatureArg(
unsigned inputNo, Type type,
3717 SignatureConversion &
result)
const {
3719 SmallVector<Type, 1> convertedTypes;
3720 if (
failed(convertType(type, convertedTypes)))
3724 if (convertedTypes.empty())
3728 result.addInputs(inputNo, convertedTypes);
3732TypeConverter::convertSignatureArgs(
TypeRange types,
3733 SignatureConversion &
result,
3734 unsigned origInputOffset)
const {
3735 for (
unsigned i = 0, e = types.size(); i != e; ++i)
3736 if (
failed(convertSignatureArg(origInputOffset + i, types[i],
result)))
3741TypeConverter::convertSignatureArg(
unsigned inputNo, Value value,
3742 SignatureConversion &
result)
const {
3744 SmallVector<Type, 1> convertedTypes;
3745 if (
failed(convertType(value, convertedTypes)))
3749 if (convertedTypes.empty())
3753 result.addInputs(inputNo, convertedTypes);
3757TypeConverter::convertSignatureArgs(
ValueRange values,
3758 SignatureConversion &
result,
3759 unsigned origInputOffset)
const {
3760 for (
unsigned i = 0, e = values.size(); i != e; ++i)
3761 if (
failed(convertSignatureArg(origInputOffset + i, values[i],
result)))
3766Value TypeConverter::materializeSourceConversion(OpBuilder &builder,
3767 Location loc, Type resultType,
3769 for (
const SourceMaterializationCallbackFn &fn :
3770 llvm::reverse(sourceMaterializations))
3771 if (Value
result = fn(builder, resultType, inputs, loc))
3776Value TypeConverter::materializeTargetConversion(OpBuilder &builder,
3777 Location loc, Type resultType,
3779 Type originalType)
const {
3780 SmallVector<Value>
result = materializeTargetConversion(
3781 builder, loc,
TypeRange(resultType), inputs, originalType);
3784 assert(
result.size() == 1 &&
"expected single result");
3788SmallVector<Value> TypeConverter::materializeTargetConversion(
3790 Type originalType)
const {
3791 for (
const TargetMaterializationCallbackFn &fn :
3792 llvm::reverse(targetMaterializations)) {
3793 SmallVector<Value>
result =
3794 fn(builder, resultTypes, inputs, loc, originalType);
3798 "callback produced incorrect number of values or values with "
3805std::optional<TypeConverter::SignatureConversion>
3806TypeConverter::convertBlockSignature(
Block *block)
const {
3809 return std::nullopt;
3816TypeConverter::AttributeConversionResult
3817TypeConverter::AttributeConversionResult::result(Attribute attr) {
3818 return AttributeConversionResult(attr, resultTag);
3821TypeConverter::AttributeConversionResult
3822TypeConverter::AttributeConversionResult::na() {
3823 return AttributeConversionResult(
nullptr, naTag);
3826TypeConverter::AttributeConversionResult
3827TypeConverter::AttributeConversionResult::abort() {
3828 return AttributeConversionResult(
nullptr, abortTag);
3831bool TypeConverter::AttributeConversionResult::hasResult()
const {
3832 return impl.getInt() == resultTag;
3835bool TypeConverter::AttributeConversionResult::isNa()
const {
3836 return impl.getInt() == naTag;
3839bool TypeConverter::AttributeConversionResult::isAbort()
const {
3840 return impl.getInt() == abortTag;
3843Attribute TypeConverter::AttributeConversionResult::getResult()
const {
3844 assert(hasResult() &&
"Cannot get result from N/A or abort");
3845 return impl.getPointer();
3848std::optional<Attribute>
3849TypeConverter::convertTypeAttribute(Type type, Attribute attr)
const {
3850 for (
const TypeAttributeConversionCallbackFn &fn :
3851 llvm::reverse(typeAttributeConversions)) {
3852 AttributeConversionResult res = fn(type, attr);
3853 if (res.hasResult())
3854 return res.getResult();
3856 return std::nullopt;
3858 return std::nullopt;
3867 ConversionPatternRewriter &rewriter) {
3868 FunctionType type = dyn_cast<FunctionType>(funcOp.getFunctionType());
3873 TypeConverter::SignatureConversion funcConversion(type.getNumInputs());
3875 if (failed(typeConverter.convertSignatureArgs(type.getInputs(),
3877 failed(typeConverter.convertTypes(type.getResults(), newResults)))
3886 if (!funcOp.getFunctionBody().empty()) {
3887 Block *entryBlock = &funcOp.getFunctionBody().
front();
3889 unsigned numFuncTypeInputs = type.getNumInputs();
3890 TypeConverter::SignatureConversion blockConversion(numEntryBlockArgs);
3892 if (failed(typeConverter.convertSignatureArgs(type.getInputs(),
3897 for (
unsigned i = numFuncTypeInputs; i < numEntryBlockArgs; ++i)
3899 rewriter.applySignatureConversion(entryBlock, blockConversion,
3903 auto newType = FunctionType::get(
3904 rewriter.getContext(), funcConversion.getConvertedTypes(), newResults);
3906 rewriter.modifyOpInPlace(funcOp, [&] { funcOp.setType(newType); });
3915struct FunctionOpInterfaceSignatureConversion :
public ConversionPattern {
3916 FunctionOpInterfaceSignatureConversion(StringRef functionLikeOpName,
3918 const TypeConverter &converter,
3919 PatternBenefit benefit)
3920 : ConversionPattern(converter, functionLikeOpName, benefit, ctx) {}
3923 matchAndRewrite(Operation *op, ArrayRef<Value> ,
3924 ConversionPatternRewriter &rewriter)
const override {
3925 FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
3930struct AnyFunctionOpInterfaceSignatureConversion
3931 :
public OpInterfaceConversionPattern<FunctionOpInterface> {
3935 matchAndRewrite(FunctionOpInterface funcOp, ArrayRef<Value> ,
3936 ConversionPatternRewriter &rewriter)
const override {
3942FailureOr<Operation *>
3943mlir::convertOpResultTypes(Operation *op,
ValueRange operands,
3944 const TypeConverter &converter,
3945 ConversionPatternRewriter &rewriter) {
3946 assert(op &&
"Invalid op");
3947 Location loc = op->
getLoc();
3948 if (converter.isLegal(op))
3949 return rewriter.notifyMatchFailure(loc,
"op already legal");
3951 OperationState newOp(loc, op->
getName());
3952 newOp.addOperands(operands);
3954 SmallVector<Type> newResultTypes;
3956 return rewriter.notifyMatchFailure(loc,
"couldn't convert return types");
3958 newOp.addTypes(newResultTypes);
3961 return rewriter.create(newOp);
3964void mlir::populateFunctionOpInterfaceTypeConversionPattern(
3965 StringRef functionLikeOpName, RewritePatternSet &patterns,
3966 const TypeConverter &converter, PatternBenefit benefit) {
3967 patterns.
add<FunctionOpInterfaceSignatureConversion>(
3968 functionLikeOpName, patterns.
getContext(), converter, benefit);
3971void mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
3972 RewritePatternSet &patterns,
const TypeConverter &converter,
3973 PatternBenefit benefit) {
3974 patterns.
add<AnyFunctionOpInterfaceSignatureConversion>(
3982void ConversionTarget::setOpAction(OperationName op,
3983 LegalizationAction action) {
3984 legalOperations[op].action = action;
3987void ConversionTarget::setDialectAction(ArrayRef<StringRef> dialectNames,
3988 LegalizationAction action) {
3989 for (StringRef dialect : dialectNames)
3990 legalDialects[dialect] = action;
3993auto ConversionTarget::getOpAction(OperationName op)
const
3994 -> std::optional<LegalizationAction> {
3995 std::optional<LegalizationInfo> info = getOpInfo(op);
3996 return info ? info->action : std::optional<LegalizationAction>();
3999auto ConversionTarget::isLegal(Operation *op)
const
4000 -> std::optional<LegalOpDetails> {
4001 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
4003 return std::nullopt;
4006 auto isOpLegal = [&] {
4008 if (info->action == LegalizationAction::Dynamic) {
4009 std::optional<bool>
result = info->legalityFn(op);
4015 return info->action == LegalizationAction::Legal;
4018 return std::nullopt;
4021 LegalOpDetails legalityDetails;
4022 if (info->isRecursivelyLegal) {
4023 auto legalityFnIt = opRecursiveLegalityFns.find(op->
getName());
4024 if (legalityFnIt != opRecursiveLegalityFns.end()) {
4025 legalityDetails.isRecursivelyLegal =
4026 legalityFnIt->second(op).value_or(
true);
4028 legalityDetails.isRecursivelyLegal =
true;
4031 return legalityDetails;
4034bool ConversionTarget::isIllegal(Operation *op)
const {
4035 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
4039 if (info->action == LegalizationAction::Dynamic) {
4040 std::optional<bool>
result = info->legalityFn(op);
4047 return info->action == LegalizationAction::Illegal;
4051 ConversionTarget::DynamicLegalityCallbackFn oldCallback,
4052 ConversionTarget::DynamicLegalityCallbackFn newCallback) {
4056 auto chain = [oldCl = std::move(oldCallback), newCl = std::move(newCallback)](
4058 if (std::optional<bool>
result = newCl(op))
4066void ConversionTarget::setLegalityCallback(
4067 OperationName name,
const DynamicLegalityCallbackFn &callback) {
4068 assert(callback &&
"expected valid legality callback");
4069 auto *infoIt = legalOperations.find(name);
4070 assert(infoIt != legalOperations.end() &&
4071 infoIt->second.action == LegalizationAction::Dynamic &&
4072 "expected operation to already be marked as dynamically legal");
4073 infoIt->second.legalityFn =
4077void ConversionTarget::markOpRecursivelyLegal(
4078 OperationName name,
const DynamicLegalityCallbackFn &callback) {
4079 auto *infoIt = legalOperations.find(name);
4080 assert(infoIt != legalOperations.end() &&
4081 infoIt->second.action != LegalizationAction::Illegal &&
4082 "expected operation to already be marked as legal");
4083 infoIt->second.isRecursivelyLegal =
true;
4086 std::move(opRecursiveLegalityFns[name]), callback);
4088 opRecursiveLegalityFns.erase(name);
4091void ConversionTarget::setLegalityCallback(
4092 ArrayRef<StringRef> dialects,
const DynamicLegalityCallbackFn &callback) {
4093 assert(callback &&
"expected valid legality callback");
4094 for (StringRef dialect : dialects)
4096 std::move(dialectLegalityFns[dialect]), callback);
4099void ConversionTarget::setLegalityCallback(
4100 const DynamicLegalityCallbackFn &callback) {
4101 assert(callback &&
"expected valid legality callback");
4105auto ConversionTarget::getOpInfo(OperationName op)
const
4106 -> std::optional<LegalizationInfo> {
4108 const auto *it = legalOperations.find(op);
4109 if (it != legalOperations.end())
4112 auto dialectIt = legalDialects.find(op.getDialectNamespace());
4113 if (dialectIt != legalDialects.end()) {
4114 DynamicLegalityCallbackFn callback;
4115 auto dialectFn = dialectLegalityFns.find(op.getDialectNamespace());
4116 if (dialectFn != dialectLegalityFns.end())
4117 callback = dialectFn->second;
4118 return LegalizationInfo{dialectIt->second,
false,
4122 if (unknownLegalityFn)
4123 return LegalizationInfo{LegalizationAction::Dynamic,
4124 false, unknownLegalityFn};
4125 return std::nullopt;
4128#if MLIR_ENABLE_PDL_IN_PATTERNMATCH
4133void PDLConversionConfig::notifyRewriteBegin(PatternRewriter &rewriter) {
4134 auto &rewriterImpl =
4135 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4139void PDLConversionConfig::notifyRewriteEnd(PatternRewriter &rewriter) {
4140 auto &rewriterImpl =
4141 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4147static FailureOr<SmallVector<Value>>
4148pdllConvertValues(ConversionPatternRewriter &rewriter,
ValueRange values) {
4149 SmallVector<Value> mappedValues;
4150 if (
failed(rewriter.getRemappedValues(values, mappedValues)))
4152 return std::move(mappedValues);
4155void mlir::registerConversionPDLFunctions(RewritePatternSet &patterns) {
4158 [](PatternRewriter &rewriter, Value value) -> FailureOr<Value> {
4159 auto results = pdllConvertValues(
4160 static_cast<ConversionPatternRewriter &
>(rewriter), value);
4163 return results->front();
4166 "convertValues", [](PatternRewriter &rewriter,
ValueRange values) {
4167 return pdllConvertValues(
4168 static_cast<ConversionPatternRewriter &
>(rewriter), values);
4172 [](PatternRewriter &rewriter, Type type) -> FailureOr<Type> {
4173 auto &rewriterImpl =
4174 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4175 if (
const TypeConverter *converter =
4177 if (Type newType = converter->convertType(type))
4185 [](PatternRewriter &rewriter,
4186 TypeRange types) -> FailureOr<SmallVector<Type>> {
4187 auto &rewriterImpl =
4188 static_cast<ConversionPatternRewriter &
>(rewriter).getImpl();
4191 return SmallVector<Type>(types);
4193 SmallVector<Type> remappedTypes;
4194 if (
failed(converter->convertTypes(types, remappedTypes)))
4196 return std::move(remappedTypes);
4207class ApplyConversionAction
4208 :
public tracing::ActionImpl<ApplyConversionAction> {
4211 using Base = tracing::ActionImpl<ApplyConversionAction>;
4212 ApplyConversionAction(ArrayRef<IRUnit> irUnits) : Base(irUnits) {}
4213 static constexpr StringLiteral tag =
"apply-conversion";
4215 void print(raw_ostream &os)
const override { os << tag; }
4222 ConversionConfig config,
4223 OpConversionMode mode) {
4227 LogicalResult status =
success();
4232 patterns, config, mode);
4243LogicalResult mlir::applyPartialConversion(
4244 ArrayRef<Operation *> ops,
const ConversionTarget &
target,
4245 const FrozenRewritePatternSet &patterns, ConversionConfig config) {
4247 OpConversionMode::Partial);
4250mlir::applyPartialConversion(Operation *op,
const ConversionTarget &
target,
4251 const FrozenRewritePatternSet &patterns,
4252 ConversionConfig config) {
4253 return applyPartialConversion(llvm::ArrayRef(op),
target, patterns, config);
4260LogicalResult mlir::applyFullConversion(ArrayRef<Operation *> ops,
4261 const ConversionTarget &
target,
4262 const FrozenRewritePatternSet &patterns,
4263 ConversionConfig config) {
4266LogicalResult mlir::applyFullConversion(Operation *op,
4267 const ConversionTarget &
target,
4268 const FrozenRewritePatternSet &patterns,
4269 ConversionConfig config) {
4270 return applyFullConversion(llvm::ArrayRef(op),
target, patterns, config);
4287 "expected top-level op to be isolated from above");
4290 "expected ops to have a common ancestor");
4299 for (
Operation *op : ops.drop_front()) {
4303 assert(commonAncestor &&
4304 "expected to find a common isolated from above ancestor");
4308 return commonAncestor;
4311LogicalResult mlir::applyAnalysisConversion(
4312 ArrayRef<Operation *> ops, ConversionTarget &
target,
4313 const FrozenRewritePatternSet &patterns, ConversionConfig config) {
4315 if (config.legalizableOps)
4316 assert(config.legalizableOps->empty() &&
"expected empty set");
4322 Operation *clonedAncestor = commonAncestor->
clone(mapping);
4326 inverseOperationMap[it.second] = it.first;
4329 SmallVector<Operation *> opsToConvert = llvm::map_to_vector(
4330 ops, [&](Operation *op) {
return mapping.
lookup(op); });
4332 OpConversionMode::Analysis);
4336 if (config.legalizableOps) {
4338 for (Operation *op : *config.legalizableOps)
4339 originalLegalizableOps.insert(inverseOperationMap[op]);
4340 *config.legalizableOps = std::move(originalLegalizableOps);
4344 clonedAncestor->
erase();
4349mlir::applyAnalysisConversion(Operation *op, ConversionTarget &
target,
4350 const FrozenRewritePatternSet &patterns,
4351 ConversionConfig config) {
4352 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 void rewrite(DataFlowSolver &solver, MLIRContext *context, MutableArrayRef< Region > initialRegions)
Rewrite the given regions using the computing analysis.
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
static Value splice(OpBuilder &b, Location loc, ValueRange values, VectorType regTileType)
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.
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...
virtual bool 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.
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.
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.