10 #include "mlir/Config/mlir-config.h"
19 #include "llvm/ADT/SmallPtrSet.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/SaveAndRestore.h"
23 #include "llvm/Support/ScopedPrinter.h"
29 #define DEBUG_TYPE "dialect-conversion"
32 template <
typename... Args>
33 static void logSuccess(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
36 os.startLine() <<
"} -> SUCCESS";
38 os.getOStream() <<
" : "
39 << llvm::formatv(fmt.data(), std::forward<Args>(args)...);
40 os.getOStream() <<
"\n";
45 template <
typename... Args>
46 static void logFailure(llvm::ScopedPrinter &os, StringRef fmt, Args &&...args) {
49 os.startLine() <<
"} -> FAILURE : "
50 << llvm::formatv(fmt.data(), std::forward<Args>(args)...)
60 if (
OpResult inputRes = dyn_cast<OpResult>(value))
61 insertPt = ++inputRes.getOwner()->getIterator();
68 assert(!vals.empty() &&
"expected at least one value");
71 for (
Value v : vals.drop_front()) {
85 assert(dom &&
"unable to find valid insertion point");
103 struct ValueVectorMapInfo {
106 static ::llvm::hash_code getHashValue(
const ValueVector &val) {
107 return ::llvm::hash_combine_range(val);
116 struct ConversionValueMapping {
119 bool isMappedTo(
Value value)
const {
return mappedTo.contains(value); }
138 template <
typename T>
139 struct IsValueVector : std::is_same<std::decay_t<T>, ValueVector> {};
142 template <
typename OldVal,
typename NewVal>
143 std::enable_if_t<IsValueVector<OldVal>::value && IsValueVector<NewVal>::value>
144 map(OldVal &&oldVal, NewVal &&newVal) {
148 assert(next != oldVal &&
"inserting cyclic mapping");
149 auto it = mapping.find(next);
150 if (it == mapping.end())
155 mappedTo.insert_range(newVal);
157 mapping[std::forward<OldVal>(oldVal)] = std::forward<NewVal>(newVal);
161 template <
typename OldVal,
typename NewVal>
162 std::enable_if_t<!IsValueVector<OldVal>::value ||
163 !IsValueVector<NewVal>::value>
164 map(OldVal &&oldVal, NewVal &&newVal) {
165 if constexpr (IsValueVector<OldVal>{}) {
166 map(std::forward<OldVal>(oldVal),
ValueVector{newVal});
167 }
else if constexpr (IsValueVector<NewVal>{}) {
168 map(
ValueVector{oldVal}, std::forward<NewVal>(newVal));
174 void map(
Value oldVal, SmallVector<Value> &&newVal) {
179 void erase(
const ValueVector &value) { mapping.erase(value); }
191 ConversionValueMapping::lookupOrDefault(
Value from,
200 desiredValue = current;
204 for (
Value v : current) {
205 auto it = mapping.find({v});
206 if (it != mapping.end()) {
207 llvm::append_range(next, it->second);
212 if (next != current) {
214 current = std::move(next);
226 auto it = mapping.find(current);
227 if (it == mapping.end()) {
231 current = it->second;
237 return !desiredValue.empty() ? std::move(desiredValue) : std::move(current);
242 ValueVector result = lookupOrDefault(from, desiredTypes);
255 struct RewriterState {
256 RewriterState(
unsigned numRewrites,
unsigned numIgnoredOperations,
257 unsigned numReplacedOps)
258 : numRewrites(numRewrites), numIgnoredOperations(numIgnoredOperations),
259 numReplacedOps(numReplacedOps) {}
262 unsigned numRewrites;
265 unsigned numIgnoredOperations;
268 unsigned numReplacedOps;
280 notifyIRErased(listener, op);
289 notifyIRErased(listener, b);
320 UnresolvedMaterialization
323 virtual ~IRRewrite() =
default;
326 virtual void rollback() = 0;
345 Kind getKind()
const {
return kind; }
347 static bool classof(
const IRRewrite *
rewrite) {
return true; }
351 :
kind(
kind), rewriterImpl(rewriterImpl) {}
360 class BlockRewrite :
public IRRewrite {
363 Block *getBlock()
const {
return block; }
365 static bool classof(
const IRRewrite *
rewrite) {
366 return rewrite->getKind() >= Kind::CreateBlock &&
367 rewrite->getKind() <= Kind::ReplaceBlockArg;
373 : IRRewrite(
kind, rewriterImpl), block(block) {}
382 class CreateBlockRewrite :
public BlockRewrite {
385 : BlockRewrite(
Kind::CreateBlock, rewriterImpl, block) {}
387 static bool classof(
const IRRewrite *
rewrite) {
388 return rewrite->getKind() == Kind::CreateBlock;
397 void rollback()
override {
400 auto &blockOps = block->getOperations();
401 while (!blockOps.empty())
402 blockOps.remove(blockOps.begin());
403 block->dropAllUses();
404 if (block->getParent())
415 class EraseBlockRewrite :
public BlockRewrite {
418 : BlockRewrite(
Kind::EraseBlock, rewriterImpl, block),
419 region(block->getParent()), insertBeforeBlock(block->getNextNode()) {}
421 static bool classof(
const IRRewrite *
rewrite) {
422 return rewrite->getKind() == Kind::EraseBlock;
425 ~EraseBlockRewrite()
override {
427 "rewrite was neither rolled back nor committed/cleaned up");
430 void rollback()
override {
433 assert(block &&
"expected block");
434 auto &blockList = region->getBlocks();
438 blockList.insert(before, block);
443 assert(block &&
"expected block");
447 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
448 notifyIRErased(listener, *block);
453 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(*block)))
455 assert(block->empty() &&
"expected empty block");
458 block->dropAllDefinedValueUses();
469 Block *insertBeforeBlock;
475 class InlineBlockRewrite :
public BlockRewrite {
479 : BlockRewrite(
Kind::InlineBlock, rewriterImpl, block),
480 sourceBlock(sourceBlock),
481 firstInlinedInst(sourceBlock->empty() ? nullptr
482 : &sourceBlock->front()),
483 lastInlinedInst(sourceBlock->empty() ? nullptr : &sourceBlock->back()) {
489 assert(!getConfig().listener &&
490 "InlineBlockRewrite not supported if listener is attached");
493 static bool classof(
const IRRewrite *
rewrite) {
494 return rewrite->getKind() == Kind::InlineBlock;
497 void rollback()
override {
500 if (firstInlinedInst) {
501 assert(lastInlinedInst &&
"expected operation");
521 class MoveBlockRewrite :
public BlockRewrite {
525 : BlockRewrite(
Kind::MoveBlock, rewriterImpl, block), region(region),
526 insertBeforeBlock(insertBeforeBlock) {}
528 static bool classof(
const IRRewrite *
rewrite) {
529 return rewrite->getKind() == Kind::MoveBlock;
542 void rollback()
override {
555 Block *insertBeforeBlock;
559 class BlockTypeConversionRewrite :
public BlockRewrite {
563 : BlockRewrite(
Kind::BlockTypeConversion, rewriterImpl, origBlock),
564 newBlock(newBlock) {}
566 static bool classof(
const IRRewrite *
rewrite) {
567 return rewrite->getKind() == Kind::BlockTypeConversion;
570 Block *getOrigBlock()
const {
return block; }
572 Block *getNewBlock()
const {
return newBlock; }
576 void rollback()
override;
586 class ReplaceBlockArgRewrite :
public BlockRewrite {
591 : BlockRewrite(
Kind::ReplaceBlockArg, rewriterImpl, block), arg(arg),
592 converter(converter) {}
594 static bool classof(
const IRRewrite *
rewrite) {
595 return rewrite->getKind() == Kind::ReplaceBlockArg;
600 void rollback()
override;
610 class OperationRewrite :
public IRRewrite {
613 Operation *getOperation()
const {
return op; }
615 static bool classof(
const IRRewrite *
rewrite) {
616 return rewrite->getKind() >= Kind::MoveOperation &&
617 rewrite->getKind() <= Kind::UnresolvedMaterialization;
623 : IRRewrite(
kind, rewriterImpl), op(op) {}
630 class MoveOperationRewrite :
public OperationRewrite {
634 : OperationRewrite(
Kind::MoveOperation, rewriterImpl, op), block(block),
635 insertBeforeOp(insertBeforeOp) {}
637 static bool classof(
const IRRewrite *
rewrite) {
638 return rewrite->getKind() == Kind::MoveOperation;
652 void rollback()
override {
670 class ModifyOperationRewrite :
public OperationRewrite {
674 : OperationRewrite(
Kind::ModifyOperation, rewriterImpl, op),
675 name(op->getName()), loc(op->getLoc()), attrs(op->getAttrDictionary()),
676 operands(op->operand_begin(), op->operand_end()),
677 successors(op->successor_begin(), op->successor_end()) {
682 name.initOpProperties(propCopy, prop);
686 static bool classof(
const IRRewrite *
rewrite) {
687 return rewrite->getKind() == Kind::ModifyOperation;
690 ~ModifyOperationRewrite()
override {
691 assert(!propertiesStorage &&
692 "rewrite was neither committed nor rolled back");
698 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
701 if (propertiesStorage) {
705 name.destroyOpProperties(propCopy);
706 operator delete(propertiesStorage);
707 propertiesStorage =
nullptr;
711 void rollback()
override {
717 if (propertiesStorage) {
720 name.destroyOpProperties(propCopy);
721 operator delete(propertiesStorage);
722 propertiesStorage =
nullptr;
729 DictionaryAttr attrs;
730 SmallVector<Value, 8> operands;
731 SmallVector<Block *, 2> successors;
732 void *propertiesStorage =
nullptr;
739 class ReplaceOperationRewrite :
public OperationRewrite {
743 : OperationRewrite(
Kind::ReplaceOperation, rewriterImpl, op),
744 converter(converter) {}
746 static bool classof(
const IRRewrite *
rewrite) {
747 return rewrite->getKind() == Kind::ReplaceOperation;
752 void rollback()
override;
762 class CreateOperationRewrite :
public OperationRewrite {
766 : OperationRewrite(
Kind::CreateOperation, rewriterImpl, op) {}
768 static bool classof(
const IRRewrite *
rewrite) {
769 return rewrite->getKind() == Kind::CreateOperation;
778 void rollback()
override;
782 enum MaterializationKind {
793 class UnresolvedMaterializationInfo {
795 UnresolvedMaterializationInfo() =
default;
796 UnresolvedMaterializationInfo(
const TypeConverter *converter,
797 MaterializationKind
kind,
Type originalType)
798 : converterAndKind(converter,
kind), originalType(originalType) {}
802 return converterAndKind.getPointer();
806 MaterializationKind getMaterializationKind()
const {
807 return converterAndKind.getInt();
811 Type getOriginalType()
const {
return originalType; }
816 llvm::PointerIntPair<const TypeConverter *, 2, MaterializationKind>
827 class UnresolvedMaterializationRewrite :
public OperationRewrite {
830 UnrealizedConversionCastOp op,
832 : OperationRewrite(
Kind::UnresolvedMaterialization, rewriterImpl, op),
833 mappedValues(std::move(mappedValues)) {}
835 static bool classof(
const IRRewrite *
rewrite) {
836 return rewrite->getKind() == Kind::UnresolvedMaterialization;
839 void rollback()
override;
841 UnrealizedConversionCastOp getOperation()
const {
842 return cast<UnrealizedConversionCastOp>(op);
852 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
855 template <
typename RewriteTy,
typename R>
856 static bool hasRewrite(R &&rewrites,
Operation *op) {
857 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
858 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
859 return rewriteTy && rewriteTy->getOperation() == op;
865 template <
typename RewriteTy,
typename R>
866 static bool hasRewrite(R &&rewrites,
Block *block) {
867 return any_of(std::forward<R>(rewrites), [&](
auto &
rewrite) {
868 auto *rewriteTy = dyn_cast<RewriteTy>(
rewrite.get());
869 return rewriteTy && rewriteTy->getBlock() == block;
889 RewriterState getCurrentState();
893 void applyRewrites();
898 void resetState(RewriterState state, StringRef patternName =
"");
902 template <
typename RewriteTy,
typename... Args>
905 std::make_unique<RewriteTy>(*
this, std::forward<Args>(args)...));
911 void undoRewrites(
unsigned numRewritesToKeep = 0, StringRef patternName =
"");
917 LogicalResult remapValues(StringRef valueDiagTag,
918 std::optional<Location> inputLoc,
945 Block *applySignatureConversion(
965 void eraseBlock(
Block *block);
989 UnrealizedConversionCastOp *castOp =
nullptr);
996 Value findOrBuildReplacementValue(
Value value,
1004 void notifyOperationInserted(
Operation *op,
1008 void notifyBlockInserted(
Block *block,
Region *previous,
1027 std::function<
void(
Operation *)> opErasedCallback =
nullptr)
1029 opErasedCallback(opErasedCallback) {}
1041 if (wasErased(block))
1043 assert(block->
empty() &&
"expected empty block");
1048 bool wasErased(
void *ptr)
const {
return erased.contains(ptr); }
1052 if (opErasedCallback)
1053 opErasedCallback(op);
1063 std::function<void(
Operation *)> opErasedCallback;
1123 llvm::ScopedPrinter logger{llvm::dbgs()};
1130 return rewriterImpl.
config;
1133 void BlockTypeConversionRewrite::commit(
RewriterBase &rewriter) {
1137 if (
auto *listener =
1138 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener()))
1139 for (
Operation *op : getNewBlock()->getUsers())
1143 void BlockTypeConversionRewrite::rollback() {
1144 getNewBlock()->replaceAllUsesWith(getOrigBlock());
1147 void ReplaceBlockArgRewrite::commit(
RewriterBase &rewriter) {
1152 if (isa<BlockArgument>(repl)) {
1160 Operation *replOp = cast<OpResult>(repl).getOwner();
1168 void ReplaceBlockArgRewrite::rollback() { rewriterImpl.
mapping.erase({arg}); }
1170 void ReplaceOperationRewrite::commit(
RewriterBase &rewriter) {
1172 dyn_cast_or_null<RewriterBase::Listener>(rewriter.
getListener());
1175 SmallVector<Value> replacements =
1177 return rewriterImpl.findOrBuildReplacementValue(result, converter);
1185 for (
auto [result, newValue] :
1186 llvm::zip_equal(op->
getResults(), replacements))
1192 if (getConfig().unlegalizedOps)
1193 getConfig().unlegalizedOps->erase(op);
1197 notifyIRErased(listener, *op);
1204 void ReplaceOperationRewrite::rollback() {
1206 rewriterImpl.
mapping.erase({result});
1209 void ReplaceOperationRewrite::cleanup(
RewriterBase &rewriter) {
1213 void CreateOperationRewrite::rollback() {
1215 while (!region.getBlocks().empty())
1216 region.getBlocks().remove(region.getBlocks().begin());
1222 void UnresolvedMaterializationRewrite::rollback() {
1223 if (!mappedValues.empty())
1224 rewriterImpl.
mapping.erase(mappedValues);
1234 for (
size_t i = 0; i <
rewrites.size(); ++i)
1240 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1244 rewrite->cleanup(eraseRewriter);
1256 StringRef patternName) {
1261 while (
ignoredOps.size() != state.numIgnoredOperations)
1264 while (
replacedOps.size() != state.numReplacedOps)
1269 StringRef patternName) {
1271 llvm::reverse(llvm::drop_begin(
rewrites, numRewritesToKeep))) {
1273 !isa<UnresolvedMaterializationRewrite>(
rewrite)) {
1275 llvm::report_fatal_error(
"pattern '" + patternName +
1276 "' rollback of IR modifications requested");
1280 rewrites.resize(numRewritesToKeep);
1284 StringRef valueDiagTag, std::optional<Location> inputLoc,
1287 remapped.reserve(llvm::size(values));
1290 Value operand = it.value();
1298 remapped.push_back(
mapping.lookupOrDefault(operand));
1306 diag <<
"unable to convert type for " << valueDiagTag <<
" #"
1307 << it.index() <<
", type was " << origType;
1312 if (legalTypes.empty()) {
1313 remapped.push_back({});
1322 remapped.push_back(std::move(repl));
1327 repl =
mapping.lookupOrDefault(operand);
1330 repl, repl, legalTypes,
1332 remapped.push_back(castValues);
1356 if (region->
empty())
1361 llvm::make_early_inc_range(llvm::drop_begin(*region, 1))) {
1363 std::optional<TypeConverter::SignatureConversion> conversion =
1373 if (entryConversion)
1376 std::optional<TypeConverter::SignatureConversion> conversion =
1388 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
1390 if (hasRewrite<BlockTypeConversionRewrite>(
rewrites, block))
1391 llvm::report_fatal_error(
"block was already converted");
1405 for (
unsigned i = 0; i < origArgCount; ++i) {
1407 if (!inputMap || inputMap->replacedWithValues())
1410 for (
unsigned j = 0;
j < inputMap->size; ++
j)
1411 newLocs[inputMap->inputNo +
j] = origLoc;
1418 convertedTypes, newLocs);
1428 appendRewrite<InlineBlockRewrite>(newBlock, block, newBlock->
end());
1431 while (!block->
empty())
1438 for (
unsigned i = 0; i != origArgCount; ++i) {
1442 std::optional<TypeConverter::SignatureConversion::InputMapping> inputMap =
1449 MaterializationKind::Source,
1453 origArgType,
Type(), converter)
1459 if (inputMap->replacedWithValues()) {
1461 assert(inputMap->size == 0 &&
1462 "invalid to provide a replacement value when the argument isn't "
1471 newBlock->
getArguments().slice(inputMap->inputNo, inputMap->size);
1475 appendRewrite<BlockTypeConversionRewrite>(block, newBlock);
1494 UnrealizedConversionCastOp *castOp) {
1495 assert((!originalType ||
kind == MaterializationKind::Target) &&
1496 "original type is valid only for target materializations");
1497 assert(
TypeRange(inputs) != outputTypes &&
1498 "materialization is not necessary");
1502 OpBuilder builder(outputTypes.front().getContext());
1505 UnrealizedConversionCastOp::create(builder, loc, outputTypes, inputs);
1506 if (!valuesToMap.empty())
1507 mapping.map(valuesToMap, convertOp.getResults());
1509 *castOp = convertOp;
1511 UnresolvedMaterializationInfo(converter,
kind, originalType);
1512 appendRewrite<UnresolvedMaterializationRewrite>(convertOp,
1513 std::move(valuesToMap));
1514 return convertOp.getResults();
1524 return repl.front();
1531 [&](
Operation *op) { return replacedOps.contains(op); }) &&
1538 repl =
mapping.lookupOrNull(value);
1572 logger.startLine() <<
"** Insert : '" << op->
getName() <<
"'(" << op
1576 "attempting to insert into a block within a replaced/erased op");
1578 if (!previous.
isSet()) {
1580 appendRewrite<CreateOperationRewrite>(op);
1587 appendRewrite<MoveOperationRewrite>(op, previous.
getBlock(), prevOp);
1593 assert(!
ignoredOps.contains(op) &&
"operation was already replaced");
1597 if (
auto castOp = dyn_cast<UnrealizedConversionCastOp>(op)) {
1602 "attempting to replace/erase an unresolved materialization");
1606 for (
auto [repl, result] : llvm::zip_equal(newValues, op->
getResults())) {
1621 mapping.map(
static_cast<Value>(result), std::move(repl));
1631 appendRewrite<ReplaceBlockArgRewrite>(from.
getOwner(), from, converter);
1637 "attempting to erase a block within a replaced/erased op");
1638 appendRewrite<EraseBlockRewrite>(block);
1653 "attempting to insert into a region within a replaced/erased op");
1658 logger.startLine() <<
"** Insert Block into : '" << parent->
getName()
1659 <<
"'(" << parent <<
")\n";
1662 <<
"** Insert Block into detached Region (nullptr parent op)'\n";
1670 appendRewrite<CreateBlockRewrite>(block);
1673 Block *prevBlock = previousIt == previous->
end() ? nullptr : &*previousIt;
1674 appendRewrite<MoveBlockRewrite>(block, previous, prevBlock);
1680 appendRewrite<InlineBlockRewrite>(dest, source, before);
1687 reasonCallback(
diag);
1688 logger.startLine() <<
"** Failure : " <<
diag.str() <<
"\n";
1698 ConversionPatternRewriter::ConversionPatternRewriter(
1702 setListener(
impl.get());
1708 assert(op && newOp &&
"expected non-null op");
1714 "incorrect # of replacement values");
1716 impl->logger.startLine()
1717 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1723 impl->replaceOp(op, std::move(newVals));
1729 "incorrect # of replacement values");
1731 impl->logger.startLine()
1732 <<
"** Replace : '" << op->
getName() <<
"'(" << op <<
")\n";
1734 impl->replaceOp(op, std::move(newValues));
1739 impl->logger.startLine()
1740 <<
"** Erase : '" << op->
getName() <<
"'(" << op <<
")\n";
1743 impl->replaceOp(op, std::move(nullRepls));
1747 impl->eraseBlock(block);
1754 "attempting to apply a signature conversion to a block within a "
1755 "replaced/erased op");
1756 return impl->applySignatureConversion(*
this, block, converter, conversion);
1763 "attempting to apply a signature conversion to a block within a "
1764 "replaced/erased op");
1765 return impl->convertRegionTypes(*
this, region, converter, entryConversion);
1771 impl->logger.startLine() <<
"** Replace Argument : '" << from <<
"'";
1773 impl->logger.getOStream() <<
" (in region of '" << parentOp->getName()
1774 <<
"' (" << parentOp <<
")\n";
1776 impl->logger.getOStream() <<
" (unlinked block)\n";
1779 impl->replaceUsesOfBlockArgument(from, to,
impl->currentTypeConverter);
1784 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, key,
1787 assert(remappedValues.front().size() == 1 &&
"1:N conversion not supported");
1788 return remappedValues.front().front();
1797 if (failed(
impl->remapValues(
"value", std::nullopt, *
this, keys,
1800 for (
const auto &values : remapped) {
1801 assert(values.size() == 1 &&
"1:N conversion not supported");
1802 results.push_back(values.front());
1812 "incorrect # of argument replacement values");
1814 "attempting to inline a block from a replaced/erased op");
1816 "attempting to inline a block into a replaced/erased op");
1817 auto opIgnored = [&](
Operation *op) {
return impl->isOpIgnored(op); };
1820 assert(llvm::all_of(source->
getUsers(), opIgnored) &&
1821 "expected 'source' to have no predecessors");
1830 bool fastPath = !
impl->config.listener;
1833 impl->inlineBlockBefore(source, dest, before);
1836 for (
auto it : llvm::zip(source->
getArguments(), argValues))
1837 replaceUsesOfBlockArgument(std::get<0>(it), std::get<1>(it));
1844 while (!source->
empty())
1845 moveOpBefore(&source->
front(), dest, before);
1853 assert(!
impl->wasOpReplaced(op) &&
1854 "attempting to modify a replaced/erased op");
1856 impl->pendingRootUpdates.insert(op);
1858 impl->appendRewrite<ModifyOperationRewrite>(op);
1862 assert(!
impl->wasOpReplaced(op) &&
1863 "attempting to modify a replaced/erased op");
1865 impl->patternModifiedOps.insert(op);
1870 assert(
impl->pendingRootUpdates.erase(op) &&
1871 "operation did not have a pending in-place update");
1877 assert(
impl->pendingRootUpdates.erase(op) &&
1878 "operation did not have a pending in-place update");
1881 auto it = llvm::find_if(
1882 llvm::reverse(
impl->rewrites), [&](std::unique_ptr<IRRewrite> &
rewrite) {
1883 auto *modifyRewrite = dyn_cast<ModifyOperationRewrite>(rewrite.get());
1884 return modifyRewrite && modifyRewrite->getOperation() == op;
1886 assert(it !=
impl->rewrites.rend() &&
"no root update started on op");
1888 int updateIdx = std::prev(
impl->rewrites.rend()) - it;
1889 impl->rewrites.erase(
impl->rewrites.begin() + updateIdx);
1903 oneToOneOperands.reserve(operands.size());
1905 if (operand.size() != 1)
1906 llvm::report_fatal_error(
"pattern '" + getDebugName() +
1907 "' does not support 1:N conversion");
1908 oneToOneOperands.push_back(operand.front());
1910 return oneToOneOperands;
1917 auto &rewriterImpl = dialectRewriter.getImpl();
1921 getTypeConverter());
1930 llvm::to_vector_of<ValueRange>(remapped);
1931 return matchAndRewrite(op, remappedAsRange, dialectRewriter);
1943 class OperationLegalizer {
1963 LogicalResult legalizeWithFold(
Operation *op,
1968 LogicalResult legalizeWithPattern(
Operation *op,
1985 legalizePatternBlockRewrites(
Operation *op,
2007 void buildLegalizationGraph(
2008 LegalizationPatterns &anyOpLegalizerPatterns,
2019 void computeLegalizationGraphBenefit(
2020 LegalizationPatterns &anyOpLegalizerPatterns,
2025 unsigned computeOpLegalizationDepth(
2032 unsigned applyCostModelToPatterns(
2058 LegalizationPatterns anyOpLegalizerPatterns;
2060 buildLegalizationGraph(anyOpLegalizerPatterns, legalizerPatterns);
2061 computeLegalizationGraphBenefit(anyOpLegalizerPatterns, legalizerPatterns);
2064 bool OperationLegalizer::isIllegal(
Operation *op)
const {
2065 return target.isIllegal(op);
2069 OperationLegalizer::legalize(
Operation *op,
2072 const char *logLineComment =
2073 "//===-------------------------------------------===//\n";
2082 logger.getOStream() <<
"\n";
2083 logger.startLine() << logLineComment;
2084 logger.startLine() <<
"Legalizing operation : ";
2089 logger.getOStream() <<
"'" << op->
getName() <<
"' ";
2090 logger.getOStream() <<
"(" << op <<
") {\n";
2095 op->print(logger.startLine(), OpPrintingFlags().printGenericOpForm());
2096 logger.getOStream() <<
"\n\n";
2102 logSuccess(logger,
"operation marked 'ignored' during conversion");
2103 logger.startLine() << logLineComment;
2109 if (
auto legalityInfo = target.isLegal(op)) {
2112 logger,
"operation marked legal by the target{0}",
2113 legalityInfo->isRecursivelyLegal
2114 ?
"; NOTE: operation is recursively legal; skipping internals"
2116 logger.startLine() << logLineComment;
2121 if (legalityInfo->isRecursivelyLegal) {
2134 if (succeeded(legalizeWithFold(op, rewriter))) {
2137 logger.startLine() << logLineComment;
2143 if (succeeded(legalizeWithPattern(op, rewriter))) {
2146 logger.startLine() << logLineComment;
2152 logFailure(logger,
"no matched legalization pattern");
2153 logger.startLine() << logLineComment;
2160 template <
typename T>
2162 T result = std::move(obj);
2168 OperationLegalizer::legalizeWithFold(
Operation *op,
2170 auto &rewriterImpl = rewriter.
getImpl();
2172 rewriterImpl.
logger.startLine() <<
"* Fold {\n";
2173 rewriterImpl.
logger.indent();
2179 SmallVector<Value, 2> replacementValues;
2180 SmallVector<Operation *, 2> newOps;
2182 if (failed(rewriter.
tryFold(op, replacementValues, &newOps))) {
2189 if (replacementValues.empty())
2190 return legalize(op, rewriter);
2194 if (failed(legalize(newOp, rewriter))) {
2196 "failed to legalize generated constant '{0}'",
2198 if (!
config.allowPatternRollback) {
2200 llvm::report_fatal_error(
2202 "' folder rollback of IR modifications requested");
2212 rewriter.
replaceOp(op, replacementValues);
2219 OperationLegalizer::legalizeWithPattern(
Operation *op,
2221 auto &rewriterImpl = rewriter.
getImpl();
2224 auto canApply = [&](
const Pattern &pattern) {
2225 bool canApply = canApplyPattern(op, pattern, rewriter);
2226 if (canApply &&
config.listener)
2227 config.listener->notifyPatternBegin(pattern, op);
2233 auto onFailure = [&](
const Pattern &pattern) {
2242 diag <<
"Failed to apply pattern \"" << pattern.getDebugName()
2249 config.listener->notifyPatternEnd(pattern, failure());
2250 rewriterImpl.
resetState(curState, pattern.getDebugName());
2251 appliedPatterns.erase(&pattern);
2256 auto onSuccess = [&](
const Pattern &pattern) {
2263 auto result = legalizePatternResult(op, pattern, rewriter, newOps,
2264 modifiedOps, insertedBlocks);
2265 appliedPatterns.erase(&pattern);
2266 if (failed(result)) {
2268 llvm::report_fatal_error(
"pattern '" + pattern.getDebugName() +
2269 "' produced IR that could not be legalized");
2270 rewriterImpl.
resetState(curState, pattern.getDebugName());
2273 config.listener->notifyPatternEnd(pattern, result);
2278 return applicator.matchAndRewrite(op, rewriter, canApply, onFailure,
2282 bool OperationLegalizer::canApplyPattern(
Operation *op,
const Pattern &pattern,
2285 auto &os = rewriter.
getImpl().logger;
2286 os.getOStream() <<
"\n";
2287 os.startLine() <<
"* Pattern : '" << op->
getName() <<
" -> (";
2289 os.getOStream() <<
")' {\n";
2296 !appliedPatterns.insert(&pattern).second) {
2304 LogicalResult OperationLegalizer::legalizePatternResult(
2310 assert(
impl.pendingRootUpdates.empty() &&
"dangling root updates");
2312 #if MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS
2314 auto newRewrites = llvm::drop_begin(
impl.rewrites, curState.numRewrites);
2315 auto replacedRoot = [&] {
2316 return hasRewrite<ReplaceOperationRewrite>(newRewrites, op);
2318 auto updatedRootInPlace = [&] {
2319 return hasRewrite<ModifyOperationRewrite>(newRewrites, op);
2321 if (!replacedRoot() && !updatedRootInPlace())
2322 llvm::report_fatal_error(
"expected pattern to replace the root operation");
2326 if (failed(legalizePatternBlockRewrites(op, rewriter,
impl, insertedBlocks,
2328 failed(legalizePatternRootUpdates(rewriter,
impl, modifiedOps)) ||
2329 failed(legalizePatternCreatedOperations(rewriter,
impl, newOps))) {
2333 LLVM_DEBUG(
logSuccess(
impl.logger,
"pattern applied successfully"));
2337 LogicalResult OperationLegalizer::legalizePatternBlockRewrites(
2346 for (
Block *block : insertedBlocks) {
2354 if (
auto *converter =
impl.regionToConverter.lookup(block->
getParent())) {
2355 std::optional<TypeConverter::SignatureConversion> conversion =
2356 converter->convertBlockSignature(block);
2358 LLVM_DEBUG(
logFailure(
impl.logger,
"failed to convert types of moved "
2362 impl.applySignatureConversion(rewriter, block, converter, *conversion);
2370 if (!newOps.count(parentOp) && alreadyLegalized.insert(parentOp).second) {
2371 if (failed(legalize(parentOp, rewriter))) {
2373 impl.logger,
"operation '{0}'({1}) became illegal after rewrite",
2374 parentOp->
getName(), parentOp));
2382 LogicalResult OperationLegalizer::legalizePatternCreatedOperations(
2386 if (failed(legalize(op, rewriter))) {
2388 "failed to legalize generated operation '{0}'({1})",
2396 LogicalResult OperationLegalizer::legalizePatternRootUpdates(
2400 if (failed(legalize(op, rewriter))) {
2402 impl.logger,
"failed to legalize operation updated in-place '{0}'",
2414 void OperationLegalizer::buildLegalizationGraph(
2415 LegalizationPatterns &anyOpLegalizerPatterns,
2426 applicator.walkAllPatterns([&](
const Pattern &pattern) {
2427 std::optional<OperationName> root = pattern.
getRootKind();
2433 anyOpLegalizerPatterns.push_back(&pattern);
2438 if (target.getOpAction(*root) == LegalizationAction::Legal)
2443 invalidPatterns[*root].insert(&pattern);
2445 parentOps[op].insert(*root);
2448 patternWorklist.insert(&pattern);
2456 if (!anyOpLegalizerPatterns.empty()) {
2457 for (
const Pattern *pattern : patternWorklist)
2458 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2462 while (!patternWorklist.empty()) {
2463 auto *pattern = patternWorklist.pop_back_val();
2467 std::optional<LegalizationAction> action = target.getOpAction(op);
2468 return !legalizerPatterns.count(op) &&
2469 (!action || action == LegalizationAction::Illegal);
2475 legalizerPatterns[*pattern->
getRootKind()].push_back(pattern);
2476 invalidPatterns[*pattern->
getRootKind()].erase(pattern);
2480 for (
auto op : parentOps[*pattern->
getRootKind()])
2481 patternWorklist.set_union(invalidPatterns[op]);
2485 void OperationLegalizer::computeLegalizationGraphBenefit(
2486 LegalizationPatterns &anyOpLegalizerPatterns,
2492 for (
auto &opIt : legalizerPatterns)
2493 if (!minOpPatternDepth.count(opIt.first))
2494 computeOpLegalizationDepth(opIt.first, minOpPatternDepth,
2500 if (!anyOpLegalizerPatterns.empty())
2501 applyCostModelToPatterns(anyOpLegalizerPatterns, minOpPatternDepth,
2507 applicator.applyCostModel([&](
const Pattern &pattern) {
2509 if (std::optional<OperationName> rootName = pattern.
getRootKind())
2510 orderedPatternList = legalizerPatterns[*rootName];
2512 orderedPatternList = anyOpLegalizerPatterns;
2515 auto *it = llvm::find(orderedPatternList, &pattern);
2516 if (it == orderedPatternList.end())
2520 return PatternBenefit(std::distance(it, orderedPatternList.end()));
2524 unsigned OperationLegalizer::computeOpLegalizationDepth(
2528 auto depthIt = minOpPatternDepth.find(op);
2529 if (depthIt != minOpPatternDepth.end())
2530 return depthIt->second;
2534 auto opPatternsIt = legalizerPatterns.find(op);
2535 if (opPatternsIt == legalizerPatterns.end() || opPatternsIt->second.empty())
2544 unsigned minDepth = applyCostModelToPatterns(
2545 opPatternsIt->second, minOpPatternDepth, legalizerPatterns);
2546 minOpPatternDepth[op] = minDepth;
2550 unsigned OperationLegalizer::applyCostModelToPatterns(
2557 SmallVector<std::pair<const Pattern *, unsigned>, 4> patternsByDepth;
2558 patternsByDepth.reserve(
patterns.size());
2562 unsigned generatedOpDepth = computeOpLegalizationDepth(
2563 generatedOp, minOpPatternDepth, legalizerPatterns);
2564 depth =
std::max(depth, generatedOpDepth + 1);
2566 patternsByDepth.emplace_back(pattern, depth);
2569 minDepth =
std::min(minDepth, depth);
2574 if (patternsByDepth.size() == 1)
2578 llvm::stable_sort(patternsByDepth,
2579 [](
const std::pair<const Pattern *, unsigned> &lhs,
2580 const std::pair<const Pattern *, unsigned> &rhs) {
2583 if (lhs.second != rhs.second)
2584 return lhs.second < rhs.second;
2587 auto lhsBenefit = lhs.first->getBenefit();
2588 auto rhsBenefit = rhs.first->getBenefit();
2589 return lhsBenefit > rhsBenefit;
2594 for (
auto &patternIt : patternsByDepth)
2595 patterns.push_back(patternIt.first);
2603 enum OpConversionMode {
2626 OpConversionMode mode)
2641 OperationLegalizer opLegalizer;
2644 OpConversionMode mode;
2651 if (failed(opLegalizer.legalize(op, rewriter))) {
2654 if (mode == OpConversionMode::Full)
2656 <<
"failed to legalize operation '" << op->
getName() <<
"'";
2660 if (mode == OpConversionMode::Partial) {
2661 if (opLegalizer.isIllegal(op))
2663 <<
"failed to legalize operation '" << op->
getName()
2664 <<
"' that was explicitly marked illegal";
2668 }
else if (mode == OpConversionMode::Analysis) {
2678 static LogicalResult
2680 UnrealizedConversionCastOp op,
2681 const UnresolvedMaterializationInfo &info) {
2682 assert(!op.use_empty() &&
2683 "expected that dead materializations have already been DCE'd");
2689 SmallVector<Value> newMaterialization;
2690 switch (info.getMaterializationKind()) {
2691 case MaterializationKind::Target:
2692 newMaterialization = converter->materializeTargetConversion(
2693 rewriter, op->getLoc(), op.getResultTypes(), inputOperands,
2694 info.getOriginalType());
2696 case MaterializationKind::Source:
2697 assert(op->getNumResults() == 1 &&
"expected single result");
2698 Value sourceMat = converter->materializeSourceConversion(
2699 rewriter, op->getLoc(), op.getResultTypes().front(), inputOperands);
2701 newMaterialization.push_back(sourceMat);
2704 if (!newMaterialization.empty()) {
2706 ValueRange newMaterializationRange(newMaterialization);
2707 assert(
TypeRange(newMaterializationRange) == op.getResultTypes() &&
2708 "materialization callback produced value of incorrect type");
2710 rewriter.
replaceOp(op, newMaterialization);
2716 <<
"failed to legalize unresolved materialization "
2718 << inputOperands.
getTypes() <<
") to ("
2719 << op.getResultTypes()
2720 <<
") that remained live after conversion";
2721 diag.attachNote(op->getUsers().begin()->getLoc())
2722 <<
"see existing live user here: " << *op->getUsers().begin();
2727 assert(!ops.empty() &&
"expected at least one operation");
2732 for (
auto *op : ops) {
2735 toConvert.push_back(op);
2738 auto legalityInfo = target.
isLegal(op);
2739 if (legalityInfo && legalityInfo->isRecursivelyLegal)
2749 for (
auto *op : toConvert) {
2750 if (failed(convert(rewriter, op))) {
2771 for (
auto it : materializations)
2772 allCastOps.push_back(it.first);
2783 for (UnrealizedConversionCastOp castOp : remainingCastOps) {
2784 auto it = materializations.find(castOp);
2785 assert(it != materializations.end() &&
"inconsistent state");
2808 auto enqueueOperands = [&](UnrealizedConversionCastOp castOp) {
2809 for (
Value v : castOp.getInputs())
2810 if (
auto inputCastOp = v.getDefiningOp<UnrealizedConversionCastOp>())
2811 worklist.insert(inputCastOp);
2818 [](UnrealizedConversionCastOp castOp) -> UnrealizedConversionCastOp {
2819 if (castOp.getInputs().empty())
2822 castOp.getInputs().front().getDefiningOp<UnrealizedConversionCastOp>();
2825 if (inputCastOp.getOutputs() != castOp.getInputs())
2831 while (!worklist.empty()) {
2832 UnrealizedConversionCastOp castOp = worklist.pop_back_val();
2833 if (castOp->use_empty()) {
2836 enqueueOperands(castOp);
2837 if (remainingCastOps)
2838 erasedOps.insert(castOp.getOperation());
2845 UnrealizedConversionCastOp nextCast = castOp;
2847 if (nextCast.getInputs().getTypes() == castOp.getResultTypes()) {
2851 enqueueOperands(castOp);
2852 castOp.replaceAllUsesWith(nextCast.getInputs());
2853 if (remainingCastOps)
2854 erasedOps.insert(castOp.getOperation());
2858 nextCast = getInputCast(nextCast);
2862 if (remainingCastOps)
2863 for (UnrealizedConversionCastOp op : castOps)
2864 if (!erasedOps.contains(op.getOperation()))
2865 remainingCastOps->push_back(op);
2874 assert(!types.empty() &&
"expected valid types");
2875 remapInput(origInputNo, argTypes.size(), types.size());
2880 assert(!types.empty() &&
2881 "1->0 type remappings don't need to be added explicitly");
2882 argTypes.append(types.begin(), types.end());
2886 unsigned newInputNo,
2887 unsigned newInputCount) {
2888 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2889 assert(newInputCount != 0 &&
"expected valid input count");
2890 remappedInputs[origInputNo] =
2891 InputMapping{newInputNo, newInputCount, {}};
2896 assert(!remappedInputs[origInputNo] &&
"input has already been remapped");
2904 assert(t &&
"expected non-null type");
2907 std::shared_lock<decltype(cacheMutex)> cacheReadLock(cacheMutex,
2910 cacheReadLock.lock();
2911 auto existingIt = cachedDirectConversions.find(t);
2912 if (existingIt != cachedDirectConversions.end()) {
2913 if (existingIt->second)
2914 results.push_back(existingIt->second);
2915 return success(existingIt->second !=
nullptr);
2917 auto multiIt = cachedMultiConversions.find(t);
2918 if (multiIt != cachedMultiConversions.end()) {
2919 results.append(multiIt->second.begin(), multiIt->second.end());
2925 size_t currentCount = results.size();
2927 std::unique_lock<decltype(cacheMutex)> cacheWriteLock(cacheMutex,
2930 for (
const ConversionCallbackFn &converter : llvm::reverse(conversions)) {
2931 if (std::optional<LogicalResult> result = converter(t, results)) {
2933 cacheWriteLock.lock();
2934 if (!succeeded(*result)) {
2935 assert(results.size() == currentCount &&
2936 "failed type conversion should not change results");
2937 cachedDirectConversions.try_emplace(t,
nullptr);
2940 auto newTypes =
ArrayRef<Type>(results).drop_front(currentCount);
2941 if (newTypes.size() == 1)
2942 cachedDirectConversions.try_emplace(t, newTypes.front());
2944 cachedMultiConversions.try_emplace(t, llvm::to_vector<2>(newTypes));
2947 assert(results.size() == currentCount &&
2948 "failed type conversion should not change results");
2961 return results.size() == 1 ? results.front() :
nullptr;
2967 for (
Type type : types)
2981 return llvm::all_of(*region, [
this](
Block &block) {
2987 return isLegal(llvm::concat<const Type>(ty.getInputs(), ty.getResults()));
2999 if (convertedTypes.empty())
3003 result.
addInputs(inputNo, convertedTypes);
3009 unsigned origInputOffset)
const {
3010 for (
unsigned i = 0, e = types.size(); i != e; ++i)
3019 for (
const SourceMaterializationCallbackFn &fn :
3020 llvm::reverse(sourceMaterializations))
3021 if (
Value result = fn(builder, resultType, inputs, loc))
3029 Type originalType)
const {
3031 builder, loc,
TypeRange(resultType), inputs, originalType);
3034 assert(result.size() == 1 &&
"expected single result");
3035 return result.front();
3040 Type originalType)
const {
3041 for (
const TargetMaterializationCallbackFn &fn :
3042 llvm::reverse(targetMaterializations)) {
3044 fn(builder, resultTypes, inputs, loc, originalType);
3048 "callback produced incorrect number of values or values with "
3055 std::optional<TypeConverter::SignatureConversion>
3059 return std::nullopt;
3082 return impl.getInt() == resultTag;
3086 return impl.getInt() == naTag;
3090 return impl.getInt() == abortTag;
3094 assert(hasResult() &&
"Cannot get result from N/A or abort");
3095 return impl.getPointer();
3098 std::optional<Attribute>
3100 for (
const TypeAttributeConversionCallbackFn &fn :
3101 llvm::reverse(typeAttributeConversions)) {
3106 return std::nullopt;
3108 return std::nullopt;
3118 FunctionType type = dyn_cast<FunctionType>(funcOp.getFunctionType());
3124 SmallVector<Type, 1> newResults;
3126 failed(typeConverter.
convertTypes(type.getResults(), newResults)) ||
3128 typeConverter, &result)))
3145 FunctionOpInterfaceSignatureConversion(StringRef functionLikeOpName,
3153 FunctionOpInterface funcOp = cast<FunctionOpInterface>(op);
3158 struct AnyFunctionOpInterfaceSignatureConversion
3170 FailureOr<Operation *>
3174 assert(op &&
"Invalid op");
3188 return rewriter.
create(newOp);
3194 patterns.add<FunctionOpInterfaceSignatureConversion>(
3195 functionLikeOpName,
patterns.getContext(), converter);
3200 patterns.add<AnyFunctionOpInterfaceSignatureConversion>(
3210 legalOperations[op].action = action;
3215 for (StringRef dialect : dialectNames)
3216 legalDialects[dialect] = action;
3220 -> std::optional<LegalizationAction> {
3221 std::optional<LegalizationInfo> info = getOpInfo(op);
3222 return info ? info->action : std::optional<LegalizationAction>();
3226 -> std::optional<LegalOpDetails> {
3227 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3229 return std::nullopt;
3232 auto isOpLegal = [&] {
3234 if (info->action == LegalizationAction::Dynamic) {
3235 std::optional<bool> result = info->legalityFn(op);
3241 return info->action == LegalizationAction::Legal;
3244 return std::nullopt;
3248 if (info->isRecursivelyLegal) {
3249 auto legalityFnIt = opRecursiveLegalityFns.find(op->
getName());
3250 if (legalityFnIt != opRecursiveLegalityFns.end()) {
3252 legalityFnIt->second(op).value_or(
true);
3257 return legalityDetails;
3261 std::optional<LegalizationInfo> info = getOpInfo(op->
getName());
3265 if (info->action == LegalizationAction::Dynamic) {
3266 std::optional<bool> result = info->legalityFn(op);
3273 return info->action == LegalizationAction::Illegal;
3282 auto chain = [oldCl = std::move(oldCallback), newCl = std::move(newCallback)](
3284 if (std::optional<bool> result = newCl(op))
3292 void ConversionTarget::setLegalityCallback(
3293 OperationName name,
const DynamicLegalityCallbackFn &callback) {
3294 assert(callback &&
"expected valid legality callback");
3295 auto *infoIt = legalOperations.find(name);
3296 assert(infoIt != legalOperations.end() &&
3297 infoIt->second.action == LegalizationAction::Dynamic &&
3298 "expected operation to already be marked as dynamically legal");
3299 infoIt->second.legalityFn =
3305 auto *infoIt = legalOperations.find(name);
3306 assert(infoIt != legalOperations.end() &&
3307 infoIt->second.action != LegalizationAction::Illegal &&
3308 "expected operation to already be marked as legal");
3309 infoIt->second.isRecursivelyLegal =
true;
3312 std::move(opRecursiveLegalityFns[name]), callback);
3314 opRecursiveLegalityFns.erase(name);
3317 void ConversionTarget::setLegalityCallback(
3319 assert(callback &&
"expected valid legality callback");
3320 for (StringRef dialect : dialects)
3322 std::move(dialectLegalityFns[dialect]), callback);
3325 void ConversionTarget::setLegalityCallback(
3326 const DynamicLegalityCallbackFn &callback) {
3327 assert(callback &&
"expected valid legality callback");
3332 -> std::optional<LegalizationInfo> {
3334 const auto *it = legalOperations.find(op);
3335 if (it != legalOperations.end())
3338 auto dialectIt = legalDialects.find(op.getDialectNamespace());
3339 if (dialectIt != legalDialects.end()) {
3340 DynamicLegalityCallbackFn callback;
3341 auto dialectFn = dialectLegalityFns.find(op.getDialectNamespace());
3342 if (dialectFn != dialectLegalityFns.end())
3343 callback = dialectFn->second;
3344 return LegalizationInfo{dialectIt->second,
false,
3348 if (unknownLegalityFn)
3349 return LegalizationInfo{LegalizationAction::Dynamic,
3350 false, unknownLegalityFn};
3351 return std::nullopt;
3354 #if MLIR_ENABLE_PDL_IN_PATTERNMATCH
3360 auto &rewriterImpl =
3366 auto &rewriterImpl =
3373 static FailureOr<SmallVector<Value>>
3375 SmallVector<Value> mappedValues;
3378 return std::move(mappedValues);
3382 patterns.getPDLPatterns().registerRewriteFunction(
3387 if (failed(results))
3389 return results->front();
3391 patterns.getPDLPatterns().registerRewriteFunction(
3396 patterns.getPDLPatterns().registerRewriteFunction(
3399 auto &rewriterImpl =
3403 if (
Type newType = converter->convertType(type))
3409 patterns.getPDLPatterns().registerRewriteFunction(
3412 TypeRange types) -> FailureOr<SmallVector<Type>> {
3413 auto &rewriterImpl =
3420 if (failed(converter->
convertTypes(types, remappedTypes)))
3422 return std::move(remappedTypes);
3437 static constexpr StringLiteral tag =
"apply-conversion";
3438 static constexpr StringLiteral desc =
3439 "Encapsulate the application of a dialect conversion";
3441 void print(raw_ostream &os)
const override { os << tag; }
3448 OpConversionMode mode) {
3452 LogicalResult status = success();
3453 SmallVector<IRUnit> irUnits(ops.begin(), ops.end());
3471 OpConversionMode::Partial);
3511 "expected top-level op to be isolated from above");
3514 "expected ops to have a common ancestor");
3523 for (
Operation *op : ops.drop_front()) {
3527 assert(commonAncestor &&
3528 "expected to find a common isolated from above ancestor");
3532 return commonAncestor;
3539 if (
config.legalizableOps)
3540 assert(
config.legalizableOps->empty() &&
"expected empty set");
3550 inverseOperationMap[it.second] = it.first;
3556 OpConversionMode::Analysis);
3560 if (
config.legalizableOps) {
3563 originalLegalizableOps.insert(inverseOperationMap[op]);
3564 *
config.legalizableOps = std::move(originalLegalizableOps);
3568 clonedAncestor->
erase();
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.
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 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 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::@1223::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.
This is the type of Action that is dispatched when a conversion is applied.
ApplyConversionAction(ArrayRef< IRUnit > irUnits)
void print(raw_ostream &os) const override
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()
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...
RetT walk(FnT &&callback)
Walk all nested operations, blocks (including this block) or regions, depending on the type of callba...
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, ValueRange to)
Replace all the uses of the block argument from with 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 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.
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.
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
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
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...
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.
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.
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.
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.
CRTP Implementation of an action.
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.
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.
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)
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).
void notifyOperationInserted(Operation *op, OpBuilder::InsertPoint previous) override
Notify the listener that the specified operation was inserted.
DenseMap< UnrealizedConversionCastOp, UnresolvedMaterializationInfo > unresolvedMaterializations
A mapping for looking up metadata of unresolved materializations.
Value findOrBuildReplacementValue(Value value, const TypeConverter *converter)
Find a replacement value for the given SSA value in the conversion value mapping.
void replaceUsesOfBlockArgument(BlockArgument from, ValueRange to, const TypeConverter *converter)
Replace the given block argument with the given values.
SetVector< Operation * > patternNewOps
A set of operations that were created by the current pattern.
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...
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.
void inlineBlockBefore(Block *source, Block *dest, Block::iterator before)
Inline the source block into the destination block before the given iterator.
RewriterState getCurrentState()
Return the current state of the rewriter.
llvm::ScopedPrinter logger
A logger used to emit diagnostics during the conversion process.
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.
void eraseBlock(Block *block)
Erase the given block and its contents.
SetVector< Block * > patternInsertedBlocks
A set of blocks that were inserted (newly-created blocks or moved blocks) by the current pattern.
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).
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.
const TypeConverter * currentTypeConverter
The current type converter, or nullptr if no type converter is currently active.
void replaceOp(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Replace the results of the given operation with the given values and erase the operation.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.