20 #include "llvm/ADT/APInt.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/MathExtras.h"
26 #define GEN_PASS_DEF_ARITHEMULATEWIDEINT
27 #include "mlir/Dialect/Arith/Transforms/Passes.h.inc"
40 static std::pair<APInt, APInt>
getHalves(
const APInt &value,
41 unsigned newBitWidth) {
42 APInt low = value.extractBits(newBitWidth, 0);
43 APInt high = value.extractBits(newBitWidth, newBitWidth);
44 return {std::move(low), std::move(high)};
53 if (type.getShape().size() == 1)
54 return type.getElementType();
56 auto newShape = to_vector(type.getShape());
70 assert(lastOffset < shape.back() &&
"Offset out of bounds");
73 if (shape.size() == 1)
74 return rewriter.
create<vector::ExtractOp>(loc, input, lastOffset);
77 offsets.back() = lastOffset;
78 auto sizes = llvm::to_vector(shape);
82 return rewriter.
create<vector::ExtractStridedSliceOp>(loc, input, offsets,
88 static std::pair<Value, Value>
99 auto vecTy = dyn_cast<VectorType>(input.
getType());
105 assert(shape.size() >= 2 &&
"Expected vector with at list two dims");
106 assert(shape.back() == 1 &&
"Expected the last vector dim to be x1");
108 auto newVecTy =
VectorType::get(shape.drop_back(), vecTy.getElementType());
109 return rewriter.
create<vector::ShapeCastOp>(loc, newVecTy, input);
116 auto vecTy = dyn_cast<VectorType>(input.
getType());
121 auto newShape = llvm::to_vector(vecTy.getShape());
122 newShape.push_back(1);
124 return rewriter.
create<vector::ShapeCastOp>(loc, newTy, input);
132 int64_t lastOffset) {
134 assert(lastOffset < shape.back() &&
"Offset out of bounds");
137 if (isa<IntegerType>(source.
getType()))
138 return rewriter.
create<vector::InsertOp>(loc, source, dest, lastOffset);
141 offsets.back() = lastOffset;
143 return rewriter.
create<vector::InsertStridedSliceOp>(loc, source, dest,
154 Location loc, VectorType resultType,
158 assert(!resultShape.empty() &&
"Result expected to have dimensions");
159 assert(resultShape.back() ==
static_cast<int64_t
>(resultComponents.size()) &&
160 "Wrong number of result components");
178 matchAndRewrite(arith::ConstantOp op, OpAdaptor,
180 Type oldType = op.getType();
181 auto newType = getTypeConverter()->convertType<VectorType>(oldType);
184 op, llvm::formatv(
"unsupported type: {0}", op.getType()));
186 unsigned newBitWidth = newType.getElementTypeBitWidth();
189 if (
auto intAttr = dyn_cast<IntegerAttr>(oldValue)) {
190 auto [low, high] =
getHalves(intAttr.getValue(), newBitWidth);
196 if (
auto splatAttr = dyn_cast<SplatElementsAttr>(oldValue)) {
198 getHalves(splatAttr.getSplatValue<APInt>(), newBitWidth);
199 int64_t numSplatElems = splatAttr.getNumElements();
201 values.reserve(numSplatElems * 2);
202 for (int64_t i = 0; i < numSplatElems; ++i) {
203 values.push_back(low);
204 values.push_back(high);
212 if (
auto elemsAttr = dyn_cast<DenseElementsAttr>(oldValue)) {
213 int64_t numElems = elemsAttr.getNumElements();
215 values.reserve(numElems * 2);
216 for (
const APInt &origVal : elemsAttr.getValues<APInt>()) {
217 auto [low, high] =
getHalves(origVal, newBitWidth);
218 values.push_back(std::move(low));
219 values.push_back(std::move(high));
228 "unhandled constant attribute");
240 matchAndRewrite(arith::AddIOp op, OpAdaptor adaptor,
243 auto newTy = getTypeConverter()->convertType<VectorType>(op.getType());
246 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
250 auto [lhsElem0, lhsElem1] =
252 auto [rhsElem0, rhsElem1] =
256 rewriter.
create<arith::AddUIExtendedOp>(loc, lhsElem0, rhsElem0);
258 rewriter.
create<arith::ExtUIOp>(loc, newElemTy, lowSum.getOverflow());
260 Value high0 = rewriter.
create<arith::AddIOp>(loc, overflowVal, lhsElem1);
261 Value high = rewriter.
create<arith::AddIOp>(loc, high0, rhsElem1);
275 template <
typename BinaryOp>
281 matchAndRewrite(BinaryOp op, OpAdaptor adaptor,
284 auto newTy = this->getTypeConverter()->template convertType<VectorType>(
288 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
290 auto [lhsElem0, lhsElem1] =
292 auto [rhsElem0, rhsElem1] =
295 Value resElem0 = rewriter.
create<BinaryOp>(loc, lhsElem0, rhsElem0);
296 Value resElem1 = rewriter.
create<BinaryOp>(loc, lhsElem1, rhsElem1);
310 static arith::CmpIPredicate toUnsignedPredicate(arith::CmpIPredicate pred) {
311 using P = arith::CmpIPredicate;
330 matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
334 getTypeConverter()->convertType<VectorType>(op.getLhs().getType());
337 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
339 arith::CmpIPredicate highPred = adaptor.getPredicate();
340 arith::CmpIPredicate lowPred = toUnsignedPredicate(highPred);
342 auto [lhsElem0, lhsElem1] =
344 auto [rhsElem0, rhsElem1] =
348 rewriter.
create<arith::CmpIOp>(loc, lowPred, lhsElem0, rhsElem0);
350 rewriter.
create<arith::CmpIOp>(loc, highPred, lhsElem1, rhsElem1);
354 case arith::CmpIPredicate::eq: {
355 cmpResult = rewriter.
create<arith::AndIOp>(loc, lowCmp, highCmp);
358 case arith::CmpIPredicate::ne: {
359 cmpResult = rewriter.
create<arith::OrIOp>(loc, lowCmp, highCmp);
365 loc, arith::CmpIPredicate::eq, lhsElem1, rhsElem1);
367 rewriter.
create<arith::SelectOp>(loc, highEq, lowCmp, highCmp);
372 assert(cmpResult &&
"Unhandled case");
386 matchAndRewrite(arith::MulIOp op, OpAdaptor adaptor,
389 auto newTy = getTypeConverter()->convertType<VectorType>(op.getType());
392 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
394 auto [lhsElem0, lhsElem1] =
396 auto [rhsElem0, rhsElem1] =
403 rewriter.
create<arith::MulUIExtendedOp>(loc, lhsElem0, rhsElem0);
404 Value mulLowHi = rewriter.
create<arith::MulIOp>(loc, lhsElem0, rhsElem1);
405 Value mulHiLow = rewriter.
create<arith::MulIOp>(loc, lhsElem1, rhsElem0);
407 Value resLow = mulLowLow.getLow();
409 rewriter.
create<arith::AddIOp>(loc, mulLowLow.getHigh(), mulLowHi);
410 resHi = rewriter.
create<arith::AddIOp>(loc, resHi, mulHiLow);
427 matchAndRewrite(arith::ExtSIOp op, OpAdaptor adaptor,
430 auto newTy = getTypeConverter()->convertType<VectorType>(op.getType());
433 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
442 loc, newResultComponentTy, newOperand);
443 Value operandZeroCst =
446 loc, arith::CmpIPredicate::slt, extended, operandZeroCst);
448 rewriter.
create<arith::ExtSIOp>(loc, newResultComponentTy, signBit);
465 matchAndRewrite(arith::ExtUIOp op, OpAdaptor adaptor,
468 auto newTy = getTypeConverter()->convertType<VectorType>(op.getType());
471 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
479 loc, newResultComponentTy, newOperand);
491 template <
typename SourceOp, arith::CmpIPredicate CmpPred>
496 matchAndRewrite(SourceOp op,
typename SourceOp::Adaptor adaptor,
500 Type oldTy = op.getType();
501 auto newTy = dyn_cast_or_null<VectorType>(
502 this->getTypeConverter()->convertType(oldTy));
505 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
510 rewriter.
create<arith::CmpIOp>(loc, CmpPred, op.getLhs(), op.getRhs());
521 static bool isIndexOrIndexVector(
Type type) {
522 if (isa<IndexType>(type))
525 if (
auto vectorTy = dyn_cast<VectorType>(type))
526 if (isa<IndexType>(vectorTy.getElementType()))
532 template <
typename CastOp>
537 matchAndRewrite(CastOp op,
typename CastOp::Adaptor adaptor,
539 Type resultType = op.getType();
540 if (!isIndexOrIndexVector(resultType))
544 Type inType = op.getIn().getType();
546 this->getTypeConverter()->template convertType<VectorType>(inType);
549 loc, llvm::formatv(
"unsupported type: {0}", inType));
559 template <
typename CastOp,
typename ExtensionOp>
564 matchAndRewrite(CastOp op,
typename CastOp::Adaptor adaptor,
566 Type inType = op.getIn().getType();
567 if (!isIndexOrIndexVector(inType))
571 auto *typeConverter =
572 this->
template getTypeConverter<arith::WideIntEmulationConverter>();
574 Type resultType = op.getType();
575 auto newTy = typeConverter->template convertType<VectorType>(resultType);
578 loc, llvm::formatv(
"unsupported type: {0}", resultType));
582 rewriter.
getIntegerType(typeConverter->getMaxTargetIntBitWidth());
583 if (
auto vecTy = dyn_cast<VectorType>(resultType))
588 Value underlyingVal =
589 rewriter.
create<CastOp>(loc, narrowTy, adaptor.getIn());
603 matchAndRewrite(arith::SelectOp op, OpAdaptor adaptor,
606 auto newTy = getTypeConverter()->convertType<VectorType>(op.getType());
609 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
611 auto [trueElem0, trueElem1] =
613 auto [falseElem0, falseElem1] =
618 rewriter.
create<arith::SelectOp>(loc, cond, trueElem0, falseElem0);
620 rewriter.
create<arith::SelectOp>(loc, cond, trueElem1, falseElem1);
636 matchAndRewrite(arith::ShLIOp op, OpAdaptor adaptor,
640 Type oldTy = op.getType();
641 auto newTy = getTypeConverter()->convertType<VectorType>(oldTy);
644 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
648 unsigned newBitWidth = newTy.getElementTypeBitWidth();
650 auto [lhsElem0, lhsElem1] =
682 Value illegalElemShift = rewriter.
create<arith::CmpIOp>(
683 loc, arith::CmpIPredicate::uge, rhsElem0, elemBitWidth);
686 rewriter.
create<arith::ShLIOp>(loc, lhsElem0, rhsElem0);
687 Value resElem0 = rewriter.
create<arith::SelectOp>(loc, illegalElemShift,
688 zeroCst, shiftedElem0);
690 Value cappedShiftAmount = rewriter.
create<arith::SelectOp>(
691 loc, illegalElemShift, elemBitWidth, rhsElem0);
692 Value rightShiftAmount =
693 rewriter.
create<arith::SubIOp>(loc, elemBitWidth, cappedShiftAmount);
695 rewriter.
create<arith::ShRUIOp>(loc, lhsElem0, rightShiftAmount);
696 Value overshotShiftAmount =
697 rewriter.
create<arith::SubIOp>(loc, rhsElem0, elemBitWidth);
699 rewriter.
create<arith::ShLIOp>(loc, lhsElem0, overshotShiftAmount);
702 rewriter.
create<arith::ShLIOp>(loc, lhsElem1, rhsElem0);
703 Value resElem1High = rewriter.
create<arith::SelectOp>(
704 loc, illegalElemShift, zeroCst, shiftedElem1);
705 Value resElem1Low = rewriter.
create<arith::SelectOp>(
706 loc, illegalElemShift, shiftedLeft, shiftedRight);
708 rewriter.
create<arith::OrIOp>(loc, resElem1Low, resElem1High);
725 matchAndRewrite(arith::ShRUIOp op, OpAdaptor adaptor,
729 Type oldTy = op.getType();
730 auto newTy = getTypeConverter()->convertType<VectorType>(oldTy);
733 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
737 unsigned newBitWidth = newTy.getElementTypeBitWidth();
739 auto [lhsElem0, lhsElem1] =
771 Value illegalElemShift = rewriter.
create<arith::CmpIOp>(
772 loc, arith::CmpIPredicate::uge, rhsElem0, elemBitWidth);
775 rewriter.
create<arith::ShRUIOp>(loc, lhsElem0, rhsElem0);
776 Value resElem0Low = rewriter.
create<arith::SelectOp>(loc, illegalElemShift,
777 zeroCst, shiftedElem0);
779 rewriter.
create<arith::ShRUIOp>(loc, lhsElem1, rhsElem0);
780 Value resElem1 = rewriter.
create<arith::SelectOp>(loc, illegalElemShift,
781 zeroCst, shiftedElem1);
783 Value cappedShiftAmount = rewriter.
create<arith::SelectOp>(
784 loc, illegalElemShift, elemBitWidth, rhsElem0);
785 Value leftShiftAmount =
786 rewriter.
create<arith::SubIOp>(loc, elemBitWidth, cappedShiftAmount);
788 rewriter.
create<arith::ShLIOp>(loc, lhsElem1, leftShiftAmount);
789 Value overshotShiftAmount =
790 rewriter.
create<arith::SubIOp>(loc, rhsElem0, elemBitWidth);
792 rewriter.
create<arith::ShRUIOp>(loc, lhsElem1, overshotShiftAmount);
794 Value resElem0High = rewriter.
create<arith::SelectOp>(
795 loc, illegalElemShift, shiftedRight, shiftedLeft);
797 rewriter.
create<arith::OrIOp>(loc, resElem0Low, resElem0High);
814 matchAndRewrite(arith::ShRSIOp op, OpAdaptor adaptor,
818 Type oldTy = op.getType();
819 auto newTy = getTypeConverter()->convertType<VectorType>(oldTy);
822 loc, llvm::formatv(
"unsupported type: {0}", op.getType()));
828 int64_t origBitwidth = newTy.getElementTypeBitWidth() * 2;
835 loc, arith::CmpIPredicate::slt, lhsElem1, elemZero);
841 Value allSign = rewriter.
create<arith::ExtSIOp>(loc, oldTy, signBit);
844 Value numNonSignExtBits =
845 rewriter.
create<arith::SubIOp>(loc, maxShift, rhsElem0);
848 rewriter.
create<arith::ExtUIOp>(loc, oldTy, numNonSignExtBits);
850 rewriter.
create<arith::ShLIOp>(loc, allSign, numNonSignExtBits);
854 rewriter.
create<arith::ShRUIOp>(loc, op.getLhs(), op.getRhs());
855 Value shrsi = rewriter.
create<arith::OrIOp>(loc, shrui, signBits);
859 Value isNoop = rewriter.
create<arith::CmpIOp>(loc, arith::CmpIPredicate::eq,
877 matchAndRewrite(arith::SIToFPOp op, OpAdaptor adaptor,
881 Value in = op.getIn();
883 auto newTy = getTypeConverter()->convertType<VectorType>(oldTy);
886 loc, llvm::formatv(
"unsupported type: {0}", oldTy));
892 rewriter, loc, oldTy, APInt::getAllOnes(oldBitWidth));
900 Value isNeg = rewriter.
create<arith::CmpIOp>(loc, arith::CmpIPredicate::slt,
902 Value bitwiseNeg = rewriter.
create<arith::XOrIOp>(loc, in, allOnesCst);
903 Value neg = rewriter.
create<arith::AddIOp>(loc, bitwiseNeg, oneCst);
904 Value abs = rewriter.
create<arith::SelectOp>(loc, isNeg, neg, in);
906 Value absResult = rewriter.
create<arith::UIToFPOp>(loc, op.getType(),
abs);
907 Value negResult = rewriter.
create<arith::NegFOp>(loc, absResult);
922 matchAndRewrite(arith::UIToFPOp op, OpAdaptor adaptor,
926 Type oldTy = op.getIn().getType();
927 auto newTy = getTypeConverter()->convertType<VectorType>(oldTy);
930 loc, llvm::formatv(
"unsupported type: {0}", oldTy));
931 unsigned newBitWidth = newTy.getElementTypeBitWidth();
954 loc, arith::CmpIPredicate::eq, hiInt, zeroCst);
956 Type resultTy = op.getType();
958 Value lowFp = rewriter.
create<arith::UIToFPOp>(loc, resultTy, lowInt);
959 Value hiFp = rewriter.
create<arith::UIToFPOp>(loc, resultTy, hiInt);
961 int64_t pow2Int = int64_t(1) << newBitWidth;
963 rewriter.
getFloatAttr(resultElemTy,
static_cast<double>(pow2Int));
964 if (
auto vecTy = dyn_cast<VectorType>(resultTy))
967 Value pow2Val = rewriter.
create<arith::ConstantOp>(loc, resultTy, pow2Attr);
969 Value hiVal = rewriter.
create<arith::MulFOp>(loc, hiFp, pow2Val);
970 Value result = rewriter.
create<arith::AddFOp>(loc, lowFp, hiVal);
985 matchAndRewrite(arith::TruncIOp op, OpAdaptor adaptor,
990 if (!getTypeConverter()->isLegal(op.getType()))
992 loc, llvm::formatv(
"unsupported truncation result type: {0}",
1000 rewriter.
createOrFold<arith::TruncIOp>(loc, op.getType(), extracted);
1014 matchAndRewrite(vector::PrintOp op, OpAdaptor adaptor,
1025 struct EmulateWideIntPass final
1026 : arith::impl::ArithEmulateWideIntBase<EmulateWideIntPass> {
1027 using ArithEmulateWideIntBase::ArithEmulateWideIntBase;
1029 void runOnOperation()
override {
1030 if (!llvm::isPowerOf2_32(widestIntSupported) || widestIntSupported < 2) {
1031 signalPassFailure();
1038 arith::WideIntEmulationConverter typeConverter(widestIntSupported);
1040 target.addDynamicallyLegalOp<func::FuncOp>([&typeConverter](
Operation *op) {
1041 return typeConverter.isLegal(cast<func::FuncOp>(op).getFunctionType());
1043 auto opLegalCallback = [&typeConverter](
Operation *op) {
1044 return typeConverter.isLegal(op);
1046 target.addDynamicallyLegalOp<func::CallOp, func::ReturnOp>(opLegalCallback);
1048 .addDynamicallyLegalDialect<arith::ArithDialect, vector::VectorDialect>(
1055 signalPassFailure();
1065 unsigned widestIntSupportedByTarget)
1066 : maxIntWidth(widestIntSupportedByTarget) {
1067 assert(llvm::isPowerOf2_32(widestIntSupportedByTarget) &&
1068 "Only power-of-two integers with are supported");
1069 assert(widestIntSupportedByTarget >= 2 &&
"Integer type too narrow");
1075 addConversion([
this](IntegerType ty) -> std::optional<Type> {
1076 unsigned width = ty.getWidth();
1077 if (width <= maxIntWidth)
1081 if (width == 2 * maxIntWidth)
1088 addConversion([
this](VectorType ty) -> std::optional<Type> {
1089 auto intTy = dyn_cast<IntegerType>(ty.getElementType());
1093 unsigned width = intTy.getWidth();
1094 if (width <= maxIntWidth)
1098 if (width == 2 * maxIntWidth) {
1099 auto newShape = to_vector(ty.getShape());
1100 newShape.push_back(2);
1109 addConversion([
this](FunctionType ty) -> std::optional<Type> {
1128 populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(patterns,
1136 ConvertConstant, ConvertCmpI, ConvertSelect, ConvertVectorPrint,
1138 ConvertAddI, ConvertMulI, ConvertShLI, ConvertShRSI, ConvertShRUI,
1139 ConvertMaxMin<arith::MaxUIOp, arith::CmpIPredicate::ugt>,
1140 ConvertMaxMin<arith::MaxSIOp, arith::CmpIPredicate::sgt>,
1141 ConvertMaxMin<arith::MinUIOp, arith::CmpIPredicate::ult>,
1142 ConvertMaxMin<arith::MinSIOp, arith::CmpIPredicate::slt>,
1144 ConvertBitwiseBinary<arith::AndIOp>, ConvertBitwiseBinary<arith::OrIOp>,
1145 ConvertBitwiseBinary<arith::XOrIOp>,
1147 ConvertExtSI, ConvertExtUI, ConvertTruncI,
1149 ConvertIndexCastIntToIndex<arith::IndexCastOp>,
1150 ConvertIndexCastIntToIndex<arith::IndexCastUIOp>,
1151 ConvertIndexCastIndexToInt<arith::IndexCastOp, arith::ExtSIOp>,
1152 ConvertIndexCastIndexToInt<arith::IndexCastUIOp, arith::ExtUIOp>,
1153 ConvertSIToFP, ConvertUIToFP>(typeConverter, patterns.
getContext());
Attributes are known-constant values of operations.
FloatAttr getFloatAttr(Type type, double value)
IntegerType getIntegerType(unsigned width)
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.
This class describes a specific conversion target.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
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 createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
typename SourceOp::Adaptor OpAdaptor
OpConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
Operation is the basic unit of execution within MLIR.
MLIRContext * getContext()
Return the context this operation is associated with.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
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,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
void addConversion(FnT &&callback)
Register a conversion function.
LogicalResult convertTypes(TypeRange types, SmallVectorImpl< Type > &results) const
Convert the given set of types, filling 'results' as necessary.
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.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Converts integer types that are too wide for the target by splitting them in two halves and thus turn...
WideIntEmulationConverter(unsigned widestIntSupportedByTarget)
void populateArithWideIntEmulationPatterns(const WideIntEmulationConverter &typeConverter, RewritePatternSet &patterns)
Adds patterns to emulate wide Arith and Function ops over integer types into supported ones.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Fraction abs(const Fraction &f)
Include the generated interface declarations.
Value createScalarOrSplatConstant(OpBuilder &builder, Location loc, Type type, const APInt &value)
Create a constant of type type at location loc whose value is value (an APInt or APFloat whose type m...
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
void populateCallOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to convert the operand and result types of a CallOp with the ...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void populateReturnOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to rewrite return ops to use operands that have been legalize...
LogicalResult applyPartialConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Below we define several entry points for operation conversion.