10 #include "mlir/Config/mlir-config.h"
19 #include "llvm/ADT/ScopeExit.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/SmallPtrSet.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/FormatVariadic.h"
24 #include "llvm/Support/SaveAndRestore.h"
25 #include "llvm/Support/ScopedPrinter.h"
31 #define DEBUG_TYPE "dialect-conversion"
34 template <
typename... Args>
35 static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
38 os.startLine() <<
"} -> SUCCESS";
40 os.getOStream() <<
" : "
41 << llvm::formatv(fmt.data(), std::forward<Args>(args)...);
42 os.getOStream() <<
"\n";
47 template <
typename... Args>
48 static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
51 os.startLine() <<
"} -> FAILURE : "
52 << llvm::formatv(fmt.data(), std::forward<Args>(args)...)
62 if (
OpResult inputRes = dyn_cast<OpResult>(value))
63 insertPt = ++inputRes.getOwner()->getIterator();
70 assert(!vals.empty() &&
"expected at least one value");
73 for (
Value v : vals.drop_front()) {
87 assert(dom &&
"unable to find valid insertion point");
105 struct ValueVectorMapInfo {
108 static ::llvm::hash_code getHashValue(
const ValueVector &val) {
109 return ::llvm::hash_combine_range(val);
118 struct ConversionValueMapping {
121 bool isMappedTo(
Value value)
const {
return mappedTo.contains(value); }
140 template <
typename T>
141 struct IsValueVector : std::is_same<std::decay_t<T>, ValueVector> {};
144 template <
typename OldVal,
typename NewVal>
145 std::enable_if_t<IsValueVector<OldVal>::value && IsValueVector<NewVal>::value>
146 map(OldVal &&oldVal, NewVal &&newVal) {
150 assert(next != oldVal &&
"inserting cyclic mapping");
151 auto it = mapping.find(next);
152 if (it == mapping.end())
157 mappedTo.insert_range(newVal);
159 mapping[std::forward<OldVal>(oldVal)] = std::forward<NewVal>(newVal);
163 template <
typename OldVal,
typename NewVal>
164 std::enable_if_t<!IsValueVector<OldVal>::value ||
165 !IsValueVector<NewVal>::value>
166 map(OldVal &&oldVal, NewVal &&newVal) {
167 if constexpr (IsValueVector<OldVal>{}) {
168 map(std::forward<OldVal>(oldVal),
ValueVector{newVal});
169 }
else if constexpr (IsValueVector<NewVal>{}) {
170 map(
ValueVector{oldVal}, std::forward<NewVal>(newVal));
176 void map(
Value oldVal, SmallVector<Value> &&newVal) {
181 void erase(
const ValueVector &value) { mapping.erase(value); }
193 ConversionValueMapping::lookupOrDefault(
Value from,
202 desiredValue = current;
206 for (
Value v : current) {
207 auto it = mapping.find({v});
208 if (it != mapping.end()) {
209 llvm::append_range(next, it->second);
214 if (next != current) {
216 current = std::move(next);
228 auto it = mapping.find(current);
229 if (it == mapping.end()) {
233 current = it->second;
239 return !desiredValue.empty() ? std::move(desiredValue) : std::move(current);
244 ValueVector result = lookupOrDefault(from, desiredTypes);
257 struct RewriterState {
258 RewriterState(
unsigned numRewrites,
unsigned numIgnoredOperations,
259 unsigned numReplacedOps)
260 : numRewrites(numRewrites), numIgnoredOperations(numIgnoredOperations),
261 numReplacedOps(numReplacedOps) {}
264 unsigned numRewrites;
267 unsigned numIgnoredOperations;
270 unsigned numReplacedOps;
302 UnresolvedMaterialization
305 virtual ~IRRewrite() =
default;
308 virtual void rollback() = 0;
327 Kind getKind()
const {
return kind; }
329 static bool classof(
const IRRewrite *
rewrite) {
return true; }
333 :
kind(
kind), rewriterImpl(rewriterImpl) {}
342 class BlockRewrite :
public IRRewrite {
345 Block *getBlock()
const {
return block; }
347 static bool classof(
const IRRewrite *
rewrite) {
348 return rewrite->getKind() >= Kind::CreateBlock &&
349 rewrite->getKind() <= Kind::ReplaceBlockArg;
355 : IRRewrite(
kind, rewriterImpl), block(block) {}
364 class CreateBlockRewrite :
public BlockRewrite {
367 : BlockRewrite(Kind::CreateBlock, rewriterImpl, block) {}
369 static bool classof(
const IRRewrite *
rewrite) {
370 return rewrite->getKind() == Kind::CreateBlock;
376 listener->notifyBlockInserted(block, {}, {});
379 void rollback()
override {
383 while (!blockOps.empty())
384 blockOps.remove(blockOps.begin());
397 class EraseBlockRewrite :
public BlockRewrite {
400 : BlockRewrite(Kind::EraseBlock, rewriterImpl, block),
401 region(block->
getParent()), insertBeforeBlock(block->getNextNode()) {}
403 static bool classof(
const IRRewrite *
rewrite) {
404 return rewrite->getKind() == Kind::EraseBlock;
407 ~EraseBlockRewrite()
override {
409 "rewrite was neither rolled back nor committed/cleaned up");
412 void rollback()
override {
415 assert(block &&
"expected block");
416 auto &blockList = region->getBlocks();
420 blockList.insert(before, block);
426 assert(block &&
"expected block");
427 assert(block->
empty() &&
"expected empty block");
431 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
432 listener->notifyBlockErased(block);
448 Block *insertBeforeBlock;
454 class InlineBlockRewrite :
public BlockRewrite {
458 : BlockRewrite(Kind::InlineBlock, rewriterImpl, block),
459 sourceBlock(sourceBlock),
460 firstInlinedInst(sourceBlock->
empty() ?
nullptr
461 : &sourceBlock->
front()),
462 lastInlinedInst(sourceBlock->
empty() ?
nullptr : &sourceBlock->
back()) {
468 assert(!getConfig().listener &&
469 "InlineBlockRewrite not supported if listener is attached");
472 static bool classof(
const IRRewrite *
rewrite) {
473 return rewrite->getKind() == Kind::InlineBlock;
476 void rollback()
override {
479 if (firstInlinedInst) {
480 assert(lastInlinedInst &&
"expected operation");
500 class MoveBlockRewrite :
public BlockRewrite {
504 : BlockRewrite(Kind::MoveBlock, rewriterImpl, block), region(region),
505 insertBeforeBlock(insertBeforeBlock) {}
507 static bool classof(
const IRRewrite *
rewrite) {
508 return rewrite->getKind() == Kind::MoveBlock;
516 listener->notifyBlockInserted(block, region,
521 void rollback()
override {
534 Block *insertBeforeBlock;
538 class BlockTypeConversionRewrite :
public BlockRewrite {
542 : BlockRewrite(Kind::BlockTypeConversion, rewriterImpl, origBlock),
543 newBlock(newBlock) {}
545 static bool classof(
const IRRewrite *
rewrite) {
546 return rewrite->getKind() == Kind::BlockTypeConversion;
549 Block *getOrigBlock()
const {
return block; }
551 Block *getNewBlock()
const {
return newBlock; }
555 void rollback()
override;
565 class ReplaceBlockArgRewrite :
public BlockRewrite {
570 : BlockRewrite(Kind::ReplaceBlockArg, rewriterImpl, block), arg(arg),
571 converter(converter) {}
573 static bool classof(
const IRRewrite *
rewrite) {
574 return rewrite->getKind() == Kind::ReplaceBlockArg;
579 void rollback()
override;
589 class OperationRewrite :
public IRRewrite {
592 Operation *getOperation()
const {
return op; }
594 static bool classof(
const IRRewrite *
rewrite) {
595 return rewrite->getKind() >= Kind::MoveOperation &&
596 rewrite->getKind() <= Kind::UnresolvedMaterialization;
602 : IRRewrite(
kind, rewriterImpl), op(op) {}
609 class MoveOperationRewrite :
public OperationRewrite {
613 : OperationRewrite(Kind::MoveOperation, rewriterImpl, op), block(block),
614 insertBeforeOp(insertBeforeOp) {}
616 static bool classof(
const IRRewrite *
rewrite) {
617 return rewrite->getKind() == Kind::MoveOperation;
625 listener->notifyOperationInserted(
631 void rollback()
override {
649 class ModifyOperationRewrite :
public OperationRewrite {
653 : OperationRewrite(Kind::ModifyOperation, rewriterImpl, op),
661 name.initOpProperties(propCopy, prop);
665 static bool classof(
const IRRewrite *
rewrite) {
666 return rewrite->getKind() == Kind::ModifyOperation;
669 ~ModifyOperationRewrite()
override {
670 assert(!propertiesStorage &&
671 "rewrite was neither committed nor rolled back");
677 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
678 listener->notifyOperationModified(op);
680 if (propertiesStorage) {
684 name.destroyOpProperties(propCopy);
685 operator delete(propertiesStorage);
686 propertiesStorage =
nullptr;
690 void rollback()
override {
696 if (propertiesStorage) {
699 name.destroyOpProperties(propCopy);
700 operator delete(propertiesStorage);
701 propertiesStorage =
nullptr;
708 DictionaryAttr attrs;
711 void *propertiesStorage =
nullptr;
718 class ReplaceOperationRewrite :
public OperationRewrite {
722 : OperationRewrite(Kind::ReplaceOperation, rewriterImpl, op),
723 converter(converter) {}
725 static bool classof(
const IRRewrite *
rewrite) {
726 return rewrite->getKind() == Kind::ReplaceOperation;
731 void rollback()
override;
741 class CreateOperationRewrite :
public OperationRewrite {
745 : OperationRewrite(Kind::CreateOperation, rewriterImpl, op) {}
747 static bool classof(
const IRRewrite *
rewrite) {
748 return rewrite->getKind() == Kind::CreateOperation;
754 listener->notifyOperationInserted(op, {});
757 void rollback()
override;
761 enum MaterializationKind {
774 class UnresolvedMaterializationRewrite :
public OperationRewrite {
777 UnrealizedConversionCastOp op,
779 MaterializationKind
kind,
Type originalType,
782 static bool classof(
const IRRewrite *
rewrite) {
783 return rewrite->getKind() == Kind::UnresolvedMaterialization;
786 void rollback()
override;
788 UnrealizedConversionCastOp getOperation()
const {
789 return cast<UnrealizedConversionCastOp>(op);
794 return converterAndKind.getPointer();
798 MaterializationKind getMaterializationKind()
const {
799 return converterAndKind.getInt();
803 Type getOriginalType()
const {
return originalType; }
808 llvm::PointerIntPair<const TypeConverter *, 2, MaterializationKind>
821 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
824 template <
typename RewriteTy,
typename R>
825 static bool hasRewrite(R &&rewrites,
Operation *op) {
826 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
827 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
828 return rewriteTy && rewriteTy->getOperation() == op;
834 template <
typename RewriteTy,
typename R>
835 static bool hasRewrite(R &&rewrites,
Block *block) {
836 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
837 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
838 return rewriteTy && rewriteTy->getBlock() == block;
858 RewriterState getCurrentState();
862 void applyRewrites();
867 void resetState(RewriterState state, StringRef patternName =
"");
871 template <
typename RewriteTy,
typename... Args>
874 std::make_unique<RewriteTy>(*
this, std::forward<Args>(args)...));
880 void undoRewrites(
unsigned numRewritesToKeep = 0, StringRef patternName =
"");
886 LogicalResult remapValues(StringRef valueDiagTag,
887 std::optional<Location> inputLoc,
914 Block *applySignatureConversion(
937 UnrealizedConversionCastOp *castOp =
nullptr);
944 Value findOrBuildReplacementValue(
Value value,
952 void notifyOperationInserted(
Operation *op,
960 void notifyBlockIsBeingErased(
Block *block);
963 void notifyBlockInserted(
Block *block,
Region *previous,
967 void notifyBlockBeingInlined(
Block *block,
Block *srcBlock,
986 std::function<
void(
Operation *)> opErasedCallback =
nullptr)
988 opErasedCallback(opErasedCallback) {}
1000 if (wasErased(block))
1002 assert(block->
empty() &&
"expected empty block");
1007 bool wasErased(
void *ptr)
const {
return erased.contains(ptr); }
1011 if (opErasedCallback)
1012 opErasedCallback(op);
1022 std::function<void(
Operation *)> opErasedCallback;
1073 llvm::ScopedPrinter logger{llvm::dbgs()};
1080 return rewriterImpl.config;
1083 void BlockTypeConversionRewrite::commit(
RewriterBase &rewriter) {
1087 if (
auto *listener =
1088 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
1089 for (
Operation *op : getNewBlock()->getUsers())
1090 listener->notifyOperationModified(op);
1093 void BlockTypeConversionRewrite::rollback() {
1094 getNewBlock()->replaceAllUsesWith(getOrigBlock());
1097 void ReplaceBlockArgRewrite::commit(
RewriterBase &rewriter) {
1098 Value repl = rewriterImpl.findOrBuildReplacementValue(arg, converter);
1102 if (isa<BlockArgument>(repl)) {
1110 Operation *replOp = cast<OpResult>(repl).getOwner();
1118 void ReplaceBlockArgRewrite::rollback() { rewriterImpl.mapping.erase({arg}); }
1120 void ReplaceOperationRewrite::commit(
RewriterBase &rewriter) {
1122 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener());
1125 SmallVector<Value> replacements =
1127 return rewriterImpl.findOrBuildReplacementValue(result, converter);
1132 listener->notifyOperationReplaced(op, replacements);
1135 for (
auto [result, newValue] :
1136 llvm::zip_equal(op->
getResults(), replacements))
1142 if (getConfig().unlegalizedOps)
1143 getConfig().unlegalizedOps->erase(op);
1149 [&](
Operation *op) { listener->notifyOperationErased(op); });
1157 void ReplaceOperationRewrite::rollback() {
1159 rewriterImpl.mapping.erase({result});
1162 void ReplaceOperationRewrite::cleanup(
RewriterBase &rewriter) {
1166 void CreateOperationRewrite::rollback() {
1168 while (!region.getBlocks().empty())
1169 region.getBlocks().remove(region.getBlocks().begin());
1175 UnresolvedMaterializationRewrite::UnresolvedMaterializationRewrite(
1179 : OperationRewrite(
Kind::UnresolvedMaterialization, rewriterImpl, op),
1180 converterAndKind(converter,
kind), originalType(originalType),
1181 mappedValues(std::move(mappedValues)) {
1182 assert((!originalType || kind == MaterializationKind::Target) &&
1183 "original type is valid only for target materializations");
1187 void UnresolvedMaterializationRewrite::rollback() {
1188 if (!mappedValues.empty())
1189 rewriterImpl.
mapping.erase(mappedValues);
1199 for (
size_t i = 0; i <
rewrites.size(); ++i)
1205 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1209 rewrite->cleanup(eraseRewriter);
1221 StringRef patternName) {
1226 while (
ignoredOps.size() != state.numIgnoredOperations)
1229 while (
replacedOps.size() != state.numReplacedOps)
1234 StringRef patternName) {
1236 llvm::reverse(llvm::drop_begin(
rewrites, numRewritesToKeep))) {
1238 !isa<UnresolvedMaterializationRewrite>(
rewrite)) {
1240 llvm::report_fatal_error(
"pattern '" + patternName +
1241 "' rollback of IR modifications requested");
1245 rewrites.resize(numRewritesToKeep);
1249 StringRef valueDiagTag, std::optional<Location> inputLoc,
1252 remapped.reserve(llvm::size(values));
1255 Value operand = it.value();
1263 remapped.push_back(
mapping.lookupOrDefault(operand));
1271 diag <<
"unable to convert type for " << valueDiagTag <<
" #"
1272 << it.index() <<
", type was " << origType;
1277 if (legalTypes.empty()) {
1278 remapped.push_back({});
1287 remapped.push_back(std::move(repl));
1292 repl =
mapping.lookupOrDefault(operand);
1295 repl, repl, legalTypes,
1297 remapped.push_back(castValues);
1321 if (region->
empty())
1326 llvm::make_early_inc_range(llvm::drop_begin(*region, 1))) {
1328 std::optional<TypeConverter::SignatureConversion> conversion =
1338 if (entryConversion)
1341 std::optional<TypeConverter::SignatureConversion> conversion =
1353 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1355 if (hasRewrite<BlockTypeConversionRewrite>(
rewrites, block))
1356 llvm::report_fatal_error(
"block was already converted");
1370 for (
unsigned i = 0; i < origArgCount; ++i) {
1372 if (!inputMap || inputMap->replacedWithValues())
1375 for (
unsigned j = 0;
j < inputMap->size; ++
j)
1376 newLocs[inputMap->inputNo +
j] = origLoc;
1383 convertedTypes, newLocs);
1393 appendRewrite<InlineBlockRewrite>(newBlock, block, newBlock->
end());
1396 while (!block->
empty())
1403 for (
unsigned i = 0; i != origArgCount; ++i) {
1407 std::optional<TypeConverter::SignatureConversion::InputMapping> inputMap =
1413 MaterializationKind::Source,
1416 origArgType,
Type(), converter);
1417 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1421 if (inputMap->replacedWithValues()) {
1423 assert(inputMap->size == 0 &&
1424 "invalid to provide a replacement value when the argument isn't "
1426 mapping.map(origArg, inputMap->replacementValues);
1427 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1433 newBlock->
getArguments().slice(inputMap->inputNo, inputMap->size);
1434 ValueVector replArgVals = llvm::to_vector_of<Value, 1>(replArgs);
1435 mapping.map(origArg, std::move(replArgVals));
1436 appendRewrite<ReplaceBlockArgRewrite>(block, origArg, converter);
1439 appendRewrite<BlockTypeConversionRewrite>(block, newBlock);
1458 UnrealizedConversionCastOp *castOp) {
1459 assert((!originalType ||
kind == MaterializationKind::Target) &&
1460 "original type is valid only for target materializations");
1461 assert(
TypeRange(inputs) != outputTypes &&
1462 "materialization is not necessary");
1466 OpBuilder builder(outputTypes.front().getContext());
1469 builder.
create<UnrealizedConversionCastOp>(loc, outputTypes, inputs);
1470 if (!valuesToMap.empty())
1471 mapping.map(valuesToMap, convertOp.getResults());
1473 *castOp = convertOp;
1474 appendRewrite<UnresolvedMaterializationRewrite>(
1475 convertOp, converter,
kind, originalType, std::move(valuesToMap));
1476 return convertOp.getResults();
1486 return repl.front();
1493 [&](
Operation *op) { return replacedOps.contains(op); }) &&
1500 repl =
mapping.lookupOrNull(value);
1534 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
1538 "attempting to insert into a block within a replaced/erased op");
1540 if (!previous.
isSet()) {
1542 appendRewrite<CreateOperationRewrite>(op);
1548 appendRewrite<MoveOperationRewrite>(op, previous.
getBlock(), prevOp);
1554 assert(!
ignoredOps.contains(op) &&
"operation was already replaced");
1558 bool isUnresolvedMaterialization =
false;
1559 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1561 isUnresolvedMaterialization =
true;
1564 for (
auto [repl, result] : llvm::zip_equal(newValues, op->
getResults())) {
1567 if (isUnresolvedMaterialization) {
1587 assert(!isUnresolvedMaterialization &&
1588 "attempting to replace an unresolved materialization");
1594 mapping.map(
static_cast<Value>(result), std::move(repl));
1603 appendRewrite<EraseBlockRewrite>(block);
1609 "attempting to insert into a region within a replaced/erased op");
1614 logger.startLine() <<
"** Insert Block into : '" << parent->
getName()
1615 <<
"'(" << parent <<
")\n";
1618 <<
"** Insert Block into detached Region (nullptr parent op)'\n";
1624 appendRewrite<CreateBlockRewrite>(block);
1627 Block *prevBlock = previousIt == previous->
end() ? nullptr : &*previousIt;
1628 appendRewrite<MoveBlockRewrite>(block, previous, prevBlock);
1633 appendRewrite<InlineBlockRewrite>(block, srcBlock, before);
1640 reasonCallback(
diag);
1641 logger.startLine() <<
"** Failure : " <<
diag.str() <<
"\n";
1651 ConversionPatternRewriter::ConversionPatternRewriter(
1655 setListener(
impl.get());
1661 assert(op && newOp &&
"expected non-null op");
1667 "incorrect # of replacement values");
1669 impl->logger.startLine()
1670 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1676 impl->notifyOpReplaced(op, std::move(newVals));
1682 "incorrect # of replacement values");
1684 impl->logger.startLine()
1685 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1687 impl->notifyOpReplaced(op, std::move(newValues));
1692 impl->logger.startLine()
1693 <<
"** Erase : '" << op->
getName() <<
"'(" << op <<
")\n";
1696 impl->notifyOpReplaced(op, std::move(nullRepls));
1701 "attempting to erase a block within a replaced/erased op");
1711 impl->notifyBlockIsBeingErased(block);
1719 "attempting to apply a signature conversion to a block within a "
1720 "replaced/erased op");
1721 return impl->applySignatureConversion(*
this, block, converter, conversion);
1728 "attempting to apply a signature conversion to a block within a "
1729 "replaced/erased op");
1730 return impl->convertRegionTypes(*
this, region, converter, entryConversion);
1736 impl->logger.startLine() <<
"** Replace Argument : '" << from <<
"'";
1738 impl->logger.getOStream() <<
" (in region of '" << parentOp->getName()
1739 <<
"' (" << parentOp <<
")\n";
1741 impl->logger.getOStream() <<
" (unlinked block)\n";
1744 impl->appendRewrite<ReplaceBlockArgRewrite>(from.
getOwner(), from,
1745 impl->currentTypeConverter);
1746 impl->mapping.map(from, to);
1751 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, key,
1754 assert(remappedValues.front().size() == 1 &&
"1:N conversion not supported");
1755 return remappedValues.front().front();
1764 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, keys,
1767 for (
const auto &values : remapped) {
1768 assert(values.size() == 1 &&
"1:N conversion not supported");
1769 results.push_back(values.front());
1779 "incorrect # of argument replacement values");
1781 "attempting to inline a block from a replaced/erased op");
1783 "attempting to inline a block into a replaced/erased op");
1784 auto opIgnored = [&](
Operation *op) {
return impl->isOpIgnored(op); };
1787 assert(llvm::all_of(source->
getUsers(), opIgnored) &&
1788 "expected 'source' to have no predecessors");
1797 bool fastPath = !
impl->config.listener;
1800 impl->notifyBlockBeingInlined(dest, source, before);
1803 for (
auto it : llvm::zip(source->
getArguments(), argValues))
1804 replaceUsesOfBlockArgument(std::get<0>(it), std::get<1>(it));
1811 while (!source->
empty())
1812 moveOpBefore(&source->
front(), dest, before);
1820 assert(!
impl->wasOpReplaced(op) &&
1821 "attempting to modify a replaced/erased op");
1823 impl->pendingRootUpdates.insert(op);
1825 impl->appendRewrite<ModifyOperationRewrite>(op);
1829 assert(!
impl->wasOpReplaced(op) &&
1830 "attempting to modify a replaced/erased op");
1835 assert(
impl->pendingRootUpdates.erase(op) &&
1836 "operation did not have a pending in-place update");
1842 assert(
impl->pendingRootUpdates.erase(op) &&
1843 "operation did not have a pending in-place update");
1846 auto it = llvm::find_if(
1847 llvm::reverse(
impl->rewrites), [&](std::unique_ptr<IRRewrite> &
rewrite) {
1848 auto *modifyRewrite = dyn_cast<ModifyOperationRewrite>(rewrite.get());
1849 return modifyRewrite && modifyRewrite->getOperation() == op;
1851 assert(it !=
impl->rewrites.rend() &&
"no root update started on op");
1853 int updateIdx = std::prev(
impl->rewrites.rend()) - it;
1854 impl->rewrites.erase(
impl->rewrites.begin() + updateIdx);
1868 oneToOneOperands.reserve(operands.size());
1870 if (operand.size() != 1)
1871 llvm::report_fatal_error(
"pattern '" + getDebugName() +
1872 "' does not support 1:N conversion");
1873 oneToOneOperands.push_back(operand.front());
1875 return oneToOneOperands;
1882 auto &rewriterImpl = dialectRewriter.getImpl();
1886 getTypeConverter());
1895 llvm::to_vector_of<ValueRange>(remapped);
1896 return matchAndRewrite(op, remappedAsRange, dialectRewriter);
1908 class OperationLegalizer {
1928 LogicalResult legalizeWithFold(
Operation *op,
1933 LogicalResult legalizeWithPattern(
Operation *op,
1944 RewriterState &curState);
1948 legalizePatternBlockRewrites(
Operation *op,
1951 RewriterState &state, RewriterState &newState);
1952 LogicalResult legalizePatternCreatedOperations(
1954 RewriterState &state, RewriterState &newState);
1957 RewriterState &state,
1958 RewriterState &newState);
1968 void buildLegalizationGraph(
1969 LegalizationPatterns &anyOpLegalizerPatterns,
1980 void computeLegalizationGraphBenefit(
1981 LegalizationPatterns &anyOpLegalizerPatterns,
1986 unsigned computeOpLegalizationDepth(
1993 unsigned applyCostModelToPatterns(
2019 LegalizationPatterns anyOpLegalizerPatterns;
2021 buildLegalizationGraph(anyOpLegalizerPatterns, legalizerPatterns);
2022 computeLegalizationGraphBenefit(anyOpLegalizerPatterns, legalizerPatterns);
2025 bool OperationLegalizer::isIllegal(
Operation *op)
const {
2026 return target.isIllegal(op);
2030 OperationLegalizer::legalize(
Operation *op,
2033 const char *logLineComment =
2034 "//===-------------------------------------------===//\n";
2039 logger.getOStream() <<
"\n";
2040 logger.startLine() << logLineComment;
2041 logger.startLine() <<
"Legalizing operation : '" << op->
getName() <<
"'("
2047 op->print(logger.startLine(), OpPrintingFlags().printGenericOpForm());
2048 logger.getOStream() <<
"\n\n";
2053 if (
auto legalityInfo = target.isLegal(op)) {
2056 logger,
"operation marked legal by the target{0}",
2057 legalityInfo->isRecursivelyLegal
2058 ?
"; NOTE: operation is recursively legal; skipping internals"
2060 logger.startLine() << logLineComment;
2065 if (legalityInfo->isRecursivelyLegal) {
2078 logSuccess(logger,
"operation marked 'ignored' during conversion");
2079 logger.startLine() << logLineComment;
2087 if (succeeded(legalizeWithFold(op, rewriter))) {
2090 logger.startLine() << logLineComment;
2096 if (succeeded(legalizeWithPattern(op, rewriter))) {
2099 logger.startLine() << logLineComment;
2105 logFailure(logger,
"no matched legalization pattern");
2106 logger.startLine() << logLineComment;
2112 OperationLegalizer::legalizeWithFold(
Operation *op,
2114 auto &rewriterImpl = rewriter.
getImpl();
2116 rewriterImpl.
logger.startLine() <<
"* Fold {\n";
2117 rewriterImpl.
logger.indent();
2122 SmallVector<Value, 2> replacementValues;
2123 SmallVector<Operation *, 2> newOps;
2125 if (failed(rewriter.
tryFold(op, replacementValues, &newOps))) {
2132 if (replacementValues.empty())
2133 return legalize(op, rewriter);
2137 if (failed(legalize(newOp, rewriter))) {
2139 "failed to legalize generated constant '{0}'",
2149 rewriter.
replaceOp(op, replacementValues);
2156 OperationLegalizer::legalizeWithPattern(
Operation *op,
2158 auto &rewriterImpl = rewriter.
getImpl();
2161 auto canApply = [&](
const Pattern &pattern) {
2162 bool canApply = canApplyPattern(op, pattern, rewriter);
2163 if (canApply &&
config.listener)
2164 config.listener->notifyPatternBegin(pattern, op);
2170 auto onFailure = [&](
const Pattern &pattern) {
2176 diag <<
"Failed to apply pattern \"" << pattern.getDebugName()
2183 config.listener->notifyPatternEnd(pattern, failure());
2184 rewriterImpl.
resetState(curState, pattern.getDebugName());
2185 appliedPatterns.erase(&pattern);
2190 auto onSuccess = [&](
const Pattern &pattern) {
2192 auto result = legalizePatternResult(op, pattern, rewriter, curState);
2193 appliedPatterns.erase(&pattern);
2194 if (failed(result)) {
2197 << pattern.getDebugName()
2198 <<
"' produced IR that could not be legalized";
2199 rewriterImpl.
resetState(curState, pattern.getDebugName());
2202 config.listener->notifyPatternEnd(pattern, result);
2207 return applicator.matchAndRewrite(op, rewriter, canApply, onFailure,
2211 bool OperationLegalizer::canApplyPattern(
Operation *op,
const Pattern &pattern,
2214 auto &os = rewriter.
getImpl().logger;
2215 os.getOStream() <<
"\n";
2216 os.startLine() <<
"* Pattern : '" << op->
getName() <<
" -> (";
2218 os.getOStream() <<
")' {\n";
2225 !appliedPatterns.insert(&pattern).second) {
2234 OperationLegalizer::legalizePatternResult(
Operation *op,
const Pattern &pattern,
2236 RewriterState &curState) {
2238 assert(
impl.pendingRootUpdates.empty() &&
"dangling root updates");
2240 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2242 auto newRewrites = llvm::drop_begin(
impl.rewrites, curState.numRewrites);
2243 auto replacedRoot = [&] {
2244 return hasRewrite<ReplaceOperationRewrite>(newRewrites, op);
2246 auto updatedRootInPlace = [&] {
2247 return hasRewrite<ModifyOperationRewrite>(newRewrites, op);
2249 if (!replacedRoot() && !updatedRootInPlace())
2250 llvm::report_fatal_error(
"expected pattern to replace the root operation");
2254 RewriterState newState =
impl.getCurrentState();
2255 if (failed(legalizePatternBlockRewrites(op, rewriter,
impl, curState,
2257 failed(legalizePatternRootUpdates(rewriter,
impl, curState, newState)) ||
2258 failed(legalizePatternCreatedOperations(rewriter,
impl, curState,
2263 LLVM_DEBUG(
logSuccess(
impl.logger,
"pattern applied successfully"));
2267 LogicalResult OperationLegalizer::legalizePatternBlockRewrites(
2270 RewriterState &newState) {
2275 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2276 BlockRewrite *
rewrite = dyn_cast<BlockRewrite>(
impl.rewrites[i].get());
2280 if (isa<BlockTypeConversionRewrite, EraseBlockRewrite,
2281 ReplaceBlockArgRewrite>(
rewrite))
2290 if (
auto *converter =
impl.regionToConverter.lookup(block->
getParent())) {
2291 std::optional<TypeConverter::SignatureConversion> conversion =
2294 LLVM_DEBUG(
logFailure(
impl.logger,
"failed to convert types of moved "
2298 impl.applySignatureConversion(rewriter, block, converter, *conversion);
2306 if (operationsToIgnore.empty()) {
2307 for (
unsigned i = state.numRewrites, e =
impl.rewrites.size(); i != e;
2310 dyn_cast<CreateOperationRewrite>(
impl.rewrites[i].get());
2313 operationsToIgnore.insert(createOp->getOperation());
2318 if (operationsToIgnore.insert(parentOp).second &&
2319 failed(legalize(parentOp, rewriter))) {
2321 "operation '{0}'({1}) became illegal after rewrite",
2322 parentOp->
getName(), parentOp));
2329 LogicalResult OperationLegalizer::legalizePatternCreatedOperations(
2331 RewriterState &state, RewriterState &newState) {
2332 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2333 auto *createOp = dyn_cast<CreateOperationRewrite>(
impl.rewrites[i].get());
2336 Operation *op = createOp->getOperation();
2337 if (failed(legalize(op, rewriter))) {
2339 "failed to legalize generated operation '{0}'({1})",
2347 LogicalResult OperationLegalizer::legalizePatternRootUpdates(
2349 RewriterState &state, RewriterState &newState) {
2350 for (
int i = state.numRewrites, e = newState.numRewrites; i != e; ++i) {
2351 auto *
rewrite = dyn_cast<ModifyOperationRewrite>(
impl.rewrites[i].get());
2355 if (failed(legalize(op, rewriter))) {
2357 impl.logger,
"failed to legalize operation updated in-place '{0}'",
2369 void OperationLegalizer::buildLegalizationGraph(
2370 LegalizationPatterns &anyOpLegalizerPatterns,
2381 applicator.walkAllPatterns([&](
const Pattern &pattern) {
2382 std::optional<OperationName> root = pattern.
getRootKind();
2388 anyOpLegalizerPatterns.push_back(&pattern);
2393 if (target.getOpAction(*root) == LegalizationAction::Legal)
2398 invalidPatterns[*root].insert(&pattern);
2400 parentOps[op].insert(*root);
2403 patternWorklist.insert(&pattern);
2411 if (!anyOpLegalizerPatterns.empty()) {
2412 for (
const Pattern *pattern : patternWorklist)
2413 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2417 while (!patternWorklist.empty()) {
2418 auto *pattern = patternWorklist.pop_back_val();
2422 std::optional<LegalizationAction> action = target.getOpAction(op);
2423 return !legalizerPatterns.count(op) &&
2424 (!action || action == LegalizationAction::Illegal);
2430 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2431 invalidPatterns[*pattern->
getRootKind()].erase(pattern);
2435 for (
auto op : parentOps[*pattern->
getRootKind()])
2436 patternWorklist.set_union(invalidPatterns[op]);
2440 void OperationLegalizer::computeLegalizationGraphBenefit(
2441 LegalizationPatterns &anyOpLegalizerPatterns,
2447 for (
auto &opIt : legalizerPatterns)
2448 if (!minOpPatternDepth.count(opIt.first))
2449 computeOpLegalizationDepth(opIt.first, minOpPatternDepth,
2455 if (!anyOpLegalizerPatterns.empty())
2456 applyCostModelToPatterns(anyOpLegalizerPatterns, minOpPatternDepth,
2462 applicator.applyCostModel([&](
const Pattern &pattern) {
2464 if (std::optional<OperationName> rootName = pattern.
getRootKind())
2465 orderedPatternList = legalizerPatterns[*rootName];
2467 orderedPatternList = anyOpLegalizerPatterns;
2470 auto *it = llvm::find(orderedPatternList, &pattern);
2471 if (it == orderedPatternList.end())
2475 return PatternBenefit(std::distance(it, orderedPatternList.end()));
2479 unsigned OperationLegalizer::computeOpLegalizationDepth(
2483 auto depthIt = minOpPatternDepth.find(op);
2484 if (depthIt != minOpPatternDepth.end())
2485 return depthIt->second;
2489 auto opPatternsIt = legalizerPatterns.find(op);
2490 if (opPatternsIt == legalizerPatterns.end() || opPatternsIt->second.empty())
2499 unsigned minDepth = applyCostModelToPatterns(
2500 opPatternsIt->second, minOpPatternDepth, legalizerPatterns);
2501 minOpPatternDepth[op] = minDepth;
2505 unsigned OperationLegalizer::applyCostModelToPatterns(
2512 SmallVector<std::pair<const Pattern *, unsigned>, 4> patternsByDepth;
2513 patternsByDepth.reserve(
patterns.size());
2517 unsigned generatedOpDepth = computeOpLegalizationDepth(
2518 generatedOp, minOpPatternDepth, legalizerPatterns);
2519 depth =
std::max(depth, generatedOpDepth + 1);
2521 patternsByDepth.emplace_back(pattern, depth);
2524 minDepth =
std::min(minDepth, depth);
2529 if (patternsByDepth.size() == 1)
2533 llvm::stable_sort(patternsByDepth,
2534 [](
const std::pair<const Pattern *, unsigned> &lhs,
2535 const std::pair<const Pattern *, unsigned> &rhs) {
2538 if (lhs.second != rhs.second)
2539 return lhs.second < rhs.second;
2542 auto lhsBenefit = lhs.first->getBenefit();
2543 auto rhsBenefit = rhs.first->getBenefit();
2544 return lhsBenefit > rhsBenefit;
2549 for (
auto &patternIt : patternsByDepth)
2550 patterns.push_back(patternIt.first);
2558 enum OpConversionMode {
2581 OpConversionMode mode)
2596 OperationLegalizer opLegalizer;
2599 OpConversionMode mode;
2606 if (failed(opLegalizer.legalize(op, rewriter))) {
2609 if (mode == OpConversionMode::Full)
2611 <<
"failed to legalize operation '" << op->
getName() <<
"'";
2615 if (mode == OpConversionMode::Partial) {
2616 if (opLegalizer.isIllegal(op))
2618 <<
"failed to legalize operation '" << op->
getName()
2619 <<
"' that was explicitly marked illegal";
2623 }
else if (mode == OpConversionMode::Analysis) {
2633 static LogicalResult
2635 UnresolvedMaterializationRewrite *
rewrite) {
2636 UnrealizedConversionCastOp op =
rewrite->getOperation();
2637 assert(!op.use_empty() &&
2638 "expected that dead materializations have already been DCE'd");
2644 SmallVector<Value> newMaterialization;
2645 switch (
rewrite->getMaterializationKind()) {
2646 case MaterializationKind::Target:
2648 rewriter, op->getLoc(), op.getResultTypes(), inputOperands,
2651 case MaterializationKind::Source:
2652 assert(op->getNumResults() == 1 &&
"expected single result");
2654 rewriter, op->getLoc(), op.getResultTypes().front(), inputOperands);
2656 newMaterialization.push_back(sourceMat);
2659 if (!newMaterialization.empty()) {
2661 ValueRange newMaterializationRange(newMaterialization);
2662 assert(
TypeRange(newMaterializationRange) == op.getResultTypes() &&
2663 "materialization callback produced value of incorrect type");
2665 rewriter.
replaceOp(op, newMaterialization);
2671 <<
"failed to legalize unresolved materialization "
2673 << inputOperands.
getTypes() <<
") to ("
2674 << op.getResultTypes()
2675 <<
") that remained live after conversion";
2676 diag.attachNote(op->getUsers().begin()->getLoc())
2677 <<
"see existing live user here: " << *op->getUsers().begin();
2688 for (
auto *op : ops) {
2691 toConvert.push_back(op);
2694 auto legalityInfo = target.
isLegal(op);
2695 if (legalityInfo && legalityInfo->isRecursivelyLegal)
2705 for (
auto *op : toConvert) {
2706 if (failed(convert(rewriter, op))) {
2727 for (
auto it : materializations)
2728 allCastOps.push_back(it.first);
2739 for (UnrealizedConversionCastOp castOp : remainingCastOps) {
2740 auto it = materializations.find(castOp);
2741 assert(it != materializations.end() &&
"inconsistent state");
2763 auto enqueueOperands = [&](UnrealizedConversionCastOp castOp) {
2764 for (
Value v : castOp.getInputs())
2765 if (
auto inputCastOp = v.getDefiningOp<UnrealizedConversionCastOp>())
2766 worklist.insert(inputCastOp);
2773 [](UnrealizedConversionCastOp castOp) -> UnrealizedConversionCastOp {
2774 if (castOp.getInputs().empty())
2777 castOp.getInputs().front().getDefiningOp<UnrealizedConversionCastOp>();
2780 if (inputCastOp.getOutputs() != castOp.getInputs())
2786 while (!worklist.empty()) {
2787 UnrealizedConversionCastOp castOp = worklist.pop_back_val();
2788 if (castOp->use_empty()) {
2791 enqueueOperands(castOp);
2792 if (remainingCastOps)
2793 erasedOps.insert(castOp.getOperation());
2800 UnrealizedConversionCastOp nextCast = castOp;
2802 if (nextCast.getInputs().getTypes() == castOp.getResultTypes()) {
2806 enqueueOperands(castOp);
2807 castOp.replaceAllUsesWith(nextCast.getInputs());
2808 if (remainingCastOps)
2809 erasedOps.insert(castOp.getOperation());
2813 nextCast = getInputCast(nextCast);
2817 if (remainingCastOps)
2818 for (UnrealizedConversionCastOp op : castOps)
2819 if (!erasedOps.contains(op.getOperation()))
2820 remainingCastOps->push_back(op);
2829 assert(!types.empty() &&
"expected valid types");
2830 remapInput(origInputNo, argTypes.size(), types.size());
2835 assert(!types.empty() &&
2836 "1->0 type remappings don't need to be added explicitly");
2837 argTypes.append(types.begin(), types.end());
2841 unsigned newInputNo,
2842 unsigned newInputCount) {
2843 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2844 assert(newInputCount != 0 &&
"expected valid input count");
2845 remappedInputs[origInputNo] =
2846 InputMapping{newInputNo, newInputCount, {}};
2851 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2859 assert(t &&
"expected non-null type");
2862 std::shared_lock<decltype(cacheMutex)> cacheReadLock(cacheMutex,
2865 cacheReadLock.lock();
2866 auto existingIt = cachedDirectConversions.find(t);
2867 if (existingIt != cachedDirectConversions.end()) {
2868 if (existingIt->second)
2869 results.push_back(existingIt->second);
2870 return success(existingIt->second !=
nullptr);
2872 auto multiIt = cachedMultiConversions.find(t);
2873 if (multiIt != cachedMultiConversions.end()) {
2874 results.append(multiIt->second.begin(), multiIt->second.end());
2880 size_t currentCount = results.size();
2882 std::unique_lock<decltype(cacheMutex)> cacheWriteLock(cacheMutex,
2885 for (
const ConversionCallbackFn &converter : llvm::reverse(conversions)) {
2886 if (std::optional<LogicalResult> result = converter(t, results)) {
2888 cacheWriteLock.lock();
2889 if (!succeeded(*result)) {
2890 assert(results.size() == currentCount &&
2891 "failed type conversion should not change results");
2892 cachedDirectConversions.try_emplace(t,
nullptr);
2895 auto newTypes =
ArrayRef<Type>(results).drop_front(currentCount);
2896 if (newTypes.size() == 1)
2897 cachedDirectConversions.try_emplace(t, newTypes.front());
2899 cachedMultiConversions.try_emplace(t, llvm::to_vector<2>(newTypes));
2902 assert(results.size() == currentCount &&
2903 "failed type conversion should not change results");
2916 return results.size() == 1 ? results.front() :
nullptr;
2922 for (
Type type : types)
2936 return llvm::all_of(*region, [
this](
Block &block) {
2942 return isLegal(llvm::concat<const Type>(ty.getInputs(), ty.getResults()));
2954 if (convertedTypes.empty())
2958 result.
addInputs(inputNo, convertedTypes);
2964 unsigned origInputOffset)
const {
2965 for (
unsigned i = 0, e = types.size(); i != e; ++i)
2974 for (
const SourceMaterializationCallbackFn &fn :
2975 llvm::reverse(sourceMaterializations))
2976 if (
Value result = fn(builder, resultType, inputs, loc))
2984 Type originalType)
const {
2986 builder, loc,
TypeRange(resultType), inputs, originalType);
2989 assert(result.size() == 1 &&
"expected single result");
2990 return result.front();
2995 Type originalType)
const {
2996 for (
const TargetMaterializationCallbackFn &fn :
2997 llvm::reverse(targetMaterializations)) {
2999 fn(builder, resultTypes, inputs, loc, originalType);
3003 "callback produced incorrect number of values or values with "
3010 std::optional<TypeConverter::SignatureConversion>
3014 return std::nullopt;
3037 return impl.getInt() == resultTag;
3041 return impl.getInt() == naTag;
3045 return impl.getInt() == abortTag;
3049 assert(hasResult() &&
"Cannot get result from N/A or abort");
3050 return impl.getPointer();
3053 std::optional<Attribute>
3055 for (
const TypeAttributeConversionCallbackFn &fn :
3056 llvm::reverse(typeAttributeConversions)) {
3061 return std::nullopt;
3063 return std::nullopt;
3073 FunctionType type = dyn_cast<FunctionType>(funcOp.getFunctionType());
3079 SmallVector<Type, 1> newResults;
3081 failed(typeConverter.
convertTypes(type.getResults(), newResults)) ||
3083 typeConverter, &result)))
3100 FunctionOpInterfaceSignatureConversion(StringRef functionLikeOpName,
3108 FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
3113 struct AnyFunctionOpInterfaceSignatureConversion
3125 FailureOr<Operation *>
3129 assert(op &&
"Invalid op");
3143 return rewriter.
create(newOp);
3149 patterns.add<FunctionOpInterfaceSignatureConversion>(
3150 functionLikeOpName,
patterns.getContext(), converter);
3155 patterns.add<AnyFunctionOpInterfaceSignatureConversion>(
3165 legalOperations[op].action = action;
3170 for (StringRef dialect : dialectNames)
3171 legalDialects[dialect] = action;
3175 -> std::optional<LegalizationAction> {
3176 std::optional<LegalizationInfo> info = getOpInfo(op);
3177 return info ? info->action : std::optional<LegalizationAction>();
3181 -> std::optional<LegalOpDetails> {
3182 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3184 return std::nullopt;
3187 auto isOpLegal = [&] {
3189 if (info->action == LegalizationAction::Dynamic) {
3190 std::optional<bool> result = info->legalityFn(op);
3196 return info->action == LegalizationAction::Legal;
3199 return std::nullopt;
3203 if (info->isRecursivelyLegal) {
3204 auto legalityFnIt = opRecursiveLegalityFns.find(op->
getName());
3205 if (legalityFnIt != opRecursiveLegalityFns.end()) {
3207 legalityFnIt->second(op).value_or(
true);
3212 return legalityDetails;
3216 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3220 if (info->action == LegalizationAction::Dynamic) {
3221 std::optional<bool> result = info->legalityFn(op);
3228 return info->action == LegalizationAction::Illegal;
3237 auto chain = [oldCl = std::move(oldCallback), newCl = std::move(newCallback)](
3239 if (std::optional<bool> result = newCl(op))
3247 void ConversionTarget::setLegalityCallback(
3248 OperationName name,
const DynamicLegalityCallbackFn &callback) {
3249 assert(callback &&
"expected valid legality callback");
3250 auto *infoIt = legalOperations.find(name);
3251 assert(infoIt != legalOperations.end() &&
3252 infoIt->second.action == LegalizationAction::Dynamic &&
3253 "expected operation to already be marked as dynamically legal");
3254 infoIt->second.legalityFn =
3260 auto *infoIt = legalOperations.find(name);
3261 assert(infoIt != legalOperations.end() &&
3262 infoIt->second.action != LegalizationAction::Illegal &&
3263 "expected operation to already be marked as legal");
3264 infoIt->second.isRecursivelyLegal =
true;
3267 std::move(opRecursiveLegalityFns[name]), callback);
3269 opRecursiveLegalityFns.erase(name);
3272 void ConversionTarget::setLegalityCallback(
3274 assert(callback &&
"expected valid legality callback");
3275 for (StringRef dialect : dialects)
3277 std::move(dialectLegalityFns[dialect]), callback);
3280 void ConversionTarget::setLegalityCallback(
3281 const DynamicLegalityCallbackFn &callback) {
3282 assert(callback &&
"expected valid legality callback");
3287 -> std::optional<LegalizationInfo> {
3289 const auto *it = legalOperations.find(op);
3290 if (it != legalOperations.end())
3293 auto dialectIt = legalDialects.find(op.getDialectNamespace());
3294 if (dialectIt != legalDialects.end()) {
3295 DynamicLegalityCallbackFn callback;
3296 auto dialectFn = dialectLegalityFns.find(op.getDialectNamespace());
3297 if (dialectFn != dialectLegalityFns.end())
3298 callback = dialectFn->second;
3299 return LegalizationInfo{dialectIt->second,
false,
3303 if (unknownLegalityFn)
3304 return LegalizationInfo{LegalizationAction::Dynamic,
3305 false, unknownLegalityFn};
3306 return std::nullopt;
3309 #if MLIR_ENABLE_PDL_IN_PATTERNMATCH
3315 auto &rewriterImpl =
3321 auto &rewriterImpl =
3328 static FailureOr<SmallVector<Value>>
3330 SmallVector<Value> mappedValues;
3333 return std::move(mappedValues);
3337 patterns.getPDLPatterns().registerRewriteFunction(
3342 if (failed(results))
3344 return results->front();
3346 patterns.getPDLPatterns().registerRewriteFunction(
3351 patterns.getPDLPatterns().registerRewriteFunction(
3354 auto &rewriterImpl =
3364 patterns.getPDLPatterns().registerRewriteFunction(
3367 TypeRange types) -> FailureOr<SmallVector<Type>> {
3368 auto &rewriterImpl =
3375 if (failed(converter->
convertTypes(types, remappedTypes)))
3377 return std::move(remappedTypes);
3394 OpConversionMode::Partial);
3413 OpConversionMode::Full);
3437 "expected top-level op to be isolated from above");
3440 "expected ops to have a common ancestor");
3449 for (
Operation *op : ops.drop_front()) {
3453 assert(commonAncestor &&
3454 "expected to find a common isolated from above ancestor");
3458 return commonAncestor;
3465 if (
config.legalizableOps)
3466 assert(
config.legalizableOps->empty() &&
"expected empty set");
3476 inverseOperationMap[it.second] = it.first;
3482 OpConversionMode::Analysis);
3483 LogicalResult status = opConverter.convertOperations(opsToConvert);
3487 if (
config.legalizableOps) {
3490 originalLegalizableOps.insert(inverseOperationMap[op]);
3491 *
config.legalizableOps = std::move(originalLegalizableOps);
3495 clonedAncestor->
erase();
static ConversionTarget::DynamicLegalityCallbackFn composeLegalityCallbacks(ConversionTarget::DynamicLegalityCallbackFn oldCallback, ConversionTarget::DynamicLegalityCallbackFn newCallback)
static FailureOr< SmallVector< Value > > pdllConvertValues(ConversionPatternRewriter &rewriter, ValueRange values)
Remap the given value using the rewriter and the type converter in the provided config.
static LogicalResult convertFuncOpTypes(FunctionOpInterface funcOp, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args)
A utility function to log a failure result for the given reason.
static LogicalResult legalizeUnresolvedMaterialization(RewriterBase &rewriter, UnresolvedMaterializationRewrite *rewrite)
static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args)
A utility function to log a successful result for the given reason.
SmallVector< Value, 1 > ValueVector
A vector of SSA values, optimized for the most common case of a single value.
static Operation * findCommonAncestor(ArrayRef< Operation * > ops)
Find a common IsolatedFromAbove ancestor of the given ops.
static OpBuilder::InsertPoint computeInsertPoint(Value value)
Helper function that computes an insertion point where the given value is defined and can be used wit...
union mlir::linalg::@1205::ArityGroupAndKind::Kind kind
static std::string diag(const llvm::Value &value)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void rewrite(DataFlowSolver &solver, MLIRContext *context, MutableArrayRef< Region > initialRegions)
Rewrite the given regions using the computing analysis.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block * getOwner() const
Returns the block that owns this argument.
Location getLoc() const
Return the location for this argument.
Block represents an ordered list of Operations.
OpListType::iterator iterator
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
void erase()
Unlink this Block from its parent region and delete it.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
OpListType & getOperations()
BlockArgListType getArguments()
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
MLIRContext * getContext() const
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
LogicalResult getRemappedValues(ValueRange keys, SmallVectorImpl< Value > &results)
Return the converted values that replace 'keys' with types defined by the type converter of the curre...
FailureOr< Block * > convertRegionTypes(Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion=nullptr)
Apply a signature conversion to each block in the given region.
void replaceOpWithMultiple(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Replace the given operation with the new value ranges.
Block * applySignatureConversion(Block *block, TypeConverter::SignatureConversion &conversion, const TypeConverter *converter=nullptr)
Apply a signature conversion to given block.
void startOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
detail::ConversionPatternRewriterImpl & getImpl()
Return a reference to the internal implementation.
void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={}) override
PatternRewriter hook for inlining the ops of a block into another block.
void eraseBlock(Block *block) override
PatternRewriter hook for erase all operations in a block.
void cancelOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
Value getRemappedValue(Value key)
Return the converted value of 'key' with a type defined by the type converter of the currently execut...
void finalizeOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void replaceUsesOfBlockArgument(BlockArgument from, Value to)
Replace all the uses of the block argument from with value to.
~ConversionPatternRewriter() override
Base class for the conversion patterns.
SmallVector< Value > getOneToOneAdaptorOperands(ArrayRef< ValueRange > operands) const
Given an array of value ranges, which are the inputs to a 1:N adaptor, try to extract the single valu...
virtual LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const
Hook for derived classes to implement combined matching and rewriting.
This class describes a specific conversion target.
void setDialectAction(ArrayRef< StringRef > dialectNames, LegalizationAction action)
Register a legality action for the given dialects.
void setOpAction(OperationName op, LegalizationAction action)
Register a legality action for the given operation.
std::optional< LegalOpDetails > isLegal(Operation *op) const
If the given operation instance is legal on this target, a structure containing legality information ...
std::optional< LegalizationAction > getOpAction(OperationName op) const
Get the legality action for the given operation.
LegalizationAction
This enumeration corresponds to the specific action to take when considering an operation legal for t...
void markOpRecursivelyLegal(OperationName name, const DynamicLegalityCallbackFn &callback)
Mark an operation, that must have either been set as Legal or DynamicallyLegal, as being recursively ...
std::function< std::optional< bool >(Operation *)> DynamicLegalityCallbackFn
The signature of the callback used to determine if an operation is dynamically legal on the target.
bool isIllegal(Operation *op) const
Returns true is operation instance is illegal on this target.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This is a utility class for mapping one set of IR entities to another.
const DenseMap< Operation *, Operation * > & getOperationMap() const
Return the held operation mapping.
auto lookup(T from) const
Lookup a mapped value within the map.
user_range getUsers() const
Returns a range of all users.
void dropAllUses()
Drop all uses of this object from their respective owners.
void replaceAllUsesWith(ValueT &&newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
This class represents a diagnostic that is inflight and set to be reported.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
This class represents a saved insertion point.
Block::iterator getPoint() const
bool isSet() const
Returns true if this insert point is set.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
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 * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
OpInterfaceConversionPattern is a wrapper around ConversionPattern that allows for matching and rewri...
OpInterfaceConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
This class represents an operand of an operation.
This is a value defined by a result of an operation.
This class provides the API for ops that are known to be isolated from above.
Simple wrapper around a void* in order to express generically how to pass in op properties through AP...
This class implements the operand iterators for the Operation class.
type_range getTypes() const
Operation is the basic unit of execution within MLIR.
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
void dropAllUses()
Drop all uses of results of this operation.
void setAttrs(DictionaryAttr newAttrs)
Set the attributes from a dictionary on this operation.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
operand_iterator operand_begin()
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
operand_iterator operand_end()
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
void setSuccessor(Block *block, unsigned index)
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
result_range getResults()
int getPropertiesStorageSize() const
Returns the properties storage size.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
succ_iterator successor_end()
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
void erase()
Remove this operation from its parent block and delete it.
void copyProperties(OpaqueProperties rhs)
Copy properties from an existing other properties object.
succ_iterator successor_begin()
unsigned getNumResults()
Return the number of results held by this operation.
void notifyRewriteEnd(PatternRewriter &rewriter) final
void notifyRewriteBegin(PatternRewriter &rewriter) final
Hooks that are invoked at the beginning and end of a rewrite of a matched pattern.
This class manages the application of a group of rewrite patterns, with a user-provided cost model.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
static PatternBenefit impossibleToMatch()
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class contains all of the data related to a pattern, but does not contain any methods or logic f...
bool hasBoundedRewriteRecursion() const
Returns true if this pattern is known to result in recursive application, i.e.
std::optional< OperationName > getRootKind() const
Return the root node that this pattern matches.
ArrayRef< OperationName > getGeneratedOps() const
Return a list of operations that may be generated when rewriting an operation instance with this patt...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Operation * getParentOp()
Return the parent operation this region is attached to.
BlockListType & getBlocks()
BlockListType::iterator iterator
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
virtual void eraseBlock(Block *block)
This method erases all operations in a block.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
virtual void finalizeOpModification(Operation *op)
This method is used to signal the end of an in-place modification of the given operation.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void replaceUsesWithIf(Value from, Value to, function_ref< bool(OpOperand &)> functor, bool *allUsesReplaced=nullptr)
Find uses of from and replace them with to if the functor returns true.
void moveOpBefore(Operation *op, Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
The general result of a type attribute conversion callback, allowing for early termination.
Attribute getResult() const
static AttributeConversionResult abort()
static AttributeConversionResult na()
static AttributeConversionResult result(Attribute attr)
This class provides all of the information necessary to convert a type signature.
void addInputs(unsigned origInputNo, ArrayRef< Type > types)
Remap an input of the original signature with a new set of types.
std::optional< InputMapping > getInputMapping(unsigned input) const
Get the input mapping for the given argument.
ArrayRef< Type > getConvertedTypes() const
Return the argument types for the new signature.
void remapInput(unsigned origInputNo, ArrayRef< Value > replacements)
Remap an input of the original signature to replacements values.
std::optional< Attribute > convertTypeAttribute(Type type, Attribute attr) const
Convert an attribute present attr from within the type type using the registered conversion functions...
Value materializeSourceConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs) const
Materialize a conversion from a set of types into one result type by generating a cast sequence of so...
bool isLegal(Type type) const
Return true if the given type is legal for this type converter, i.e.
LogicalResult convertSignatureArgs(TypeRange types, SignatureConversion &result, unsigned origInputOffset=0) const
LogicalResult convertSignatureArg(unsigned inputNo, Type type, SignatureConversion &result) const
This method allows for converting a specific argument of a signature.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
std::optional< SignatureConversion > convertBlockSignature(Block *block) const
This function converts the type signature of the given block, by invoking 'convertSignatureArg' for e...
LogicalResult convertTypes(TypeRange types, SmallVectorImpl< Type > &results) const
Convert the given set of types, filling 'results' as necessary.
bool isSignatureLegal(FunctionType ty) const
Return true if the inputs and outputs of the given function type are legal.
Value materializeTargetConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs, Type originalType={}) const
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Block * getParentBlock()
Return the Block in which this Value is defined.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
static WalkResult advance()
Operation * getOwner() const
Return the owner of this operand.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
@ Full
Documents are synced by always sending the full content of the document.
Kind
An enumeration of the kinds of predicates.
Include the generated interface declarations.
void populateFunctionOpInterfaceTypeConversionPattern(StringRef functionLikeOpName, RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to convert the signature of a FunctionOpInterface op with the...
void populateAnyFunctionOpInterfaceTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
const FrozenRewritePatternSet GreedyRewriteConfig config
LogicalResult applyFullConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply a complete conversion on the given operations, and all nested operations.
FailureOr< Operation * > convertOpResultTypes(Operation *op, ValueRange operands, const TypeConverter &converter, ConversionPatternRewriter &rewriter)
Generic utility to convert op result types according to type converter without knowing exact op type.
const FrozenRewritePatternSet & patterns
LogicalResult applyAnalysisConversion(ArrayRef< Operation * > ops, ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply an analysis conversion on the given operations, and all nested operations.
void reconcileUnrealizedCasts(ArrayRef< UnrealizedConversionCastOp > castOps, SmallVectorImpl< UnrealizedConversionCastOp > *remainingCastOps=nullptr)
Try to reconcile all given UnrealizedConversionCastOps and store the left-over ops in remainingCastOp...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void registerConversionPDLFunctions(RewritePatternSet &patterns)
Register the dialect conversion PDL functions with the given pattern set.
LogicalResult applyPartialConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Below we define several entry points for operation conversion.
Dialect conversion configuration.
bool allowPatternRollback
If set to "true", pattern rollback is allowed.
RewriterBase::Listener * listener
An optional listener that is notified about all IR modifications in case dialect conversion succeeds.
function_ref< void(Diagnostic &)> notifyCallback
An optional callback used to notify about match failure diagnostics during the conversion.
DenseSet< Operation * > * legalizableOps
Analysis conversion only.
DenseSet< Operation * > * unlegalizedOps
Partial conversion only.
bool buildMaterializations
If set to "true", the dialect conversion attempts to build source/target materializations through the...
A structure containing additional information describing a specific legal operation instance.
bool isRecursivelyLegal
A flag that indicates if this operation is 'recursively' legal.
This iterator enumerates elements according to their dominance relationship.
LogicalResult convertOperations(ArrayRef< Operation * > ops)
Converts the given operations to the conversion target.
OperationConverter(const ConversionTarget &target, const FrozenRewritePatternSet &patterns, const ConversionConfig &config, OpConversionMode mode)
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addTypes(ArrayRef< Type > newTypes)
A rewriter that keeps track of erased ops and blocks.
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).
void notifyOperationInserted(Operation *op, OpBuilder::InsertPoint previous) override
Notify the listener that the specified operation was inserted.
Value findOrBuildReplacementValue(Value value, const TypeConverter *converter)
Find a replacement value for the given SSA value in the conversion value mapping.
ConversionPatternRewriterImpl(MLIRContext *ctx, const ConversionConfig &config)
DenseMap< Region *, const TypeConverter * > regionToConverter
A mapping of regions to type converters that should be used when converting the arguments of blocks w...
bool wasOpReplaced(Operation *op) const
Return "true" if the given operation was replaced or erased.
void notifyBlockInserted(Block *block, Region *previous, Region::iterator previousIt) override
Notifies that a block was inserted.
void undoRewrites(unsigned numRewritesToKeep=0, StringRef patternName="")
Undo the rewrites (motions, splits) one by one in reverse order until "numRewritesToKeep" rewrites re...
DenseMap< UnrealizedConversionCastOp, UnresolvedMaterializationRewrite * > unresolvedMaterializations
A mapping of all unresolved materializations (UnrealizedConversionCastOp) to the corresponding rewrit...
LogicalResult remapValues(StringRef valueDiagTag, std::optional< Location > inputLoc, PatternRewriter &rewriter, ValueRange values, SmallVector< ValueVector > &remapped)
Remap the given values to those with potentially different types.
Block * applySignatureConversion(ConversionPatternRewriter &rewriter, Block *block, const TypeConverter *converter, TypeConverter::SignatureConversion &signatureConversion)
Apply the given signature conversion on the given block.
FailureOr< Block * > convertRegionTypes(ConversionPatternRewriter &rewriter, Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion)
Convert the types of block arguments within the given region.
void resetState(RewriterState state, StringRef patternName="")
Reset the state of the rewriter to a previously saved point.
ConversionValueMapping mapping
void applyRewrites()
Apply all requested operation rewrites.
RewriterState getCurrentState()
Return the current state of the rewriter.
llvm::ScopedPrinter logger
A logger used to emit diagnostics during the conversion process.
void notifyBlockBeingInlined(Block *block, Block *srcBlock, Block::iterator before)
Notifies that a block is being inlined into another block.
void appendRewrite(Args &&...args)
Append a rewrite.
SmallPtrSet< Operation *, 1 > pendingRootUpdates
A set of operations that have pending updates.
void notifyMatchFailure(Location loc, function_ref< void(Diagnostic &)> reasonCallback) override
Notifies that a pattern match failed for the given reason.
MLIRContext * context
MLIR context.
bool isOpIgnored(Operation *op) const
Return "true" if the given operation is ignored, and does not need to be converted.
ValueRange buildUnresolvedMaterialization(MaterializationKind kind, OpBuilder::InsertPoint ip, Location loc, ValueVector valuesToMap, ValueRange inputs, TypeRange outputTypes, Type originalType, const TypeConverter *converter, UnrealizedConversionCastOp *castOp=nullptr)
Build an unresolved materialization operation given a range of output types and a list of input opera...
SetVector< Operation * > ignoredOps
A set of operations that should no longer be considered for legalization.
SmallVector< std::unique_ptr< IRRewrite > > rewrites
Ordered list of block operations (creations, splits, motions).
const ConversionConfig & config
Dialect conversion configuration.
void notifyOpReplaced(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Notifies that an op is about to be replaced with the given values.
SetVector< Operation * > replacedOps
A set of operations that were replaced/erased.
void notifyBlockIsBeingErased(Block *block)
Notifies that a block is about to be erased.
const TypeConverter * currentTypeConverter
The current type converter, or nullptr if no type converter is currently active.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.