16#include "llvm/ADT/APFloat.h"
34#define GEN_PASS_DEF_TOSANARROWI64TOI32PASS
35#define GEN_PASS_DEF_TOSANARROWF64TOF32PASS
36#define GEN_PASS_DEF_TOSANARROWF32TOF16PASS
37#include "mlir/Dialect/Tosa/Transforms/Passes.h.inc"
47enum class TosaNarrowKind { Int64ToInt32, Float64ToFloat32, Float32ToFloat16 };
53template <TosaNarrowKind Kind>
54bool isSourceInteger(IntegerType type) {
55 if constexpr (Kind == TosaNarrowKind::Int64ToInt32)
56 return type.isInteger(64);
60template <TosaNarrowKind Kind>
61bool isSourceFloat(FloatType type) {
62 if constexpr (Kind == TosaNarrowKind::Float64ToFloat32)
64 if constexpr (Kind == TosaNarrowKind::Float32ToFloat16)
69template <TosaNarrowKind Kind>
70Type convertInteger(IntegerType type) {
71 if (!isSourceInteger<Kind>(type))
73 if constexpr (Kind == TosaNarrowKind::Int64ToInt32)
74 return IntegerType::get(type.getContext(), 32);
78template <TosaNarrowKind Kind>
79Type convertFloat(FloatType type) {
80 if (!isSourceFloat<Kind>(type))
82 if constexpr (Kind == TosaNarrowKind::Float64ToFloat32)
83 return Float32Type::get(type.getContext());
84 if constexpr (Kind == TosaNarrowKind::Float32ToFloat16)
85 return Float16Type::get(type.getContext());
89template <TosaNarrowKind Kind>
90bool isSourceElement(
Type type) {
91 if (
auto intTy = dyn_cast<IntegerType>(type))
92 return isSourceInteger<Kind>(intTy);
93 if (
auto floatTy = dyn_cast<FloatType>(type))
94 return isSourceFloat<Kind>(floatTy);
98template <TosaNarrowKind Kind>
99bool typeNeedsConversion(
Type type) {
100 if (
auto shaped = dyn_cast<ShapedType>(type))
101 return isSourceElement<Kind>(shaped.getElementType());
102 return isSourceElement<Kind>(type);
105FailureOr<APInt> convertIntegerConstant(IntegerType targetType,
107 bool allowLossyConversion) {
108 const unsigned targetWidth = targetType.getWidth();
109 if (!allowLossyConversion && !value.isSignedIntN(targetWidth))
112 if (allowLossyConversion)
113 return value.truncSSat(targetWidth);
114 return value.sextOrTrunc(targetWidth);
117FailureOr<APFloat> convertFloatConstant(FloatType targetType,
118 const APFloat &value,
119 bool allowLossyConversion) {
120 APFloat converted(value);
121 bool losesInfo =
false;
122 converted.convert(targetType.getFloatSemantics(),
123 APFloat::rmNearestTiesToEven, &losesInfo);
124 if (!allowLossyConversion && losesInfo)
131template <TosaNarrowKind Kind>
132FailureOr<Attribute> tryConvertScalarAttribute(
Attribute attribute,
133 bool allowLossyConversion) {
134 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
135 if (
const auto intAttr = dyn_cast<IntegerAttr>(attribute)) {
136 if (
const auto intType = dyn_cast<IntegerType>(intAttr.getType());
137 intType && isSourceInteger<Kind>(intType)) {
138 const auto convertedType =
139 cast<IntegerType>(convertInteger<Kind>(intType));
140 FailureOr<APInt> convertedValue = convertIntegerConstant(
141 convertedType, intAttr.getValue(), allowLossyConversion);
142 if (
failed(convertedValue))
144 return IntegerAttr::get(convertedType, convertedValue.value());
147 }
else if constexpr (Kind == TosaNarrowKind::Float64ToFloat32 ||
148 Kind == TosaNarrowKind::Float32ToFloat16) {
149 if (
const auto floatAttr = dyn_cast<FloatAttr>(attribute)) {
150 if (
const auto floatType = dyn_cast<FloatType>(floatAttr.getType());
151 floatType && isSourceFloat<Kind>(floatType)) {
152 const auto convertedType =
153 cast<FloatType>(convertFloat<Kind>(floatType));
154 FailureOr<APFloat> convertedValue = convertFloatConstant(
155 convertedType, floatAttr.getValue(), allowLossyConversion);
156 if (
failed(convertedValue))
158 return FloatAttr::get(convertedType, convertedValue.value());
166template <TosaNarrowKind Kind>
170 bool allowLossyConversion) {
171 if constexpr (Kind != TosaNarrowKind::Int64ToInt32)
174 const auto oldElementType = dyn_cast<IntegerType>(type.getElementType());
175 if (!oldElementType || !isSourceInteger<Kind>(oldElementType))
179 dyn_cast_or_null<ShapedType>(typeConverter.convertType(type));
183 const auto newElementType = dyn_cast<IntegerType>(newType.getElementType());
187 if (!allowLossyConversion) {
188 for (APInt value : attr.getValues<APInt>())
189 if (
failed(convertIntegerConstant(newElementType, value,
195 attr.
mapValues(newElementType, [&](
const APInt &value) -> APInt {
196 return convertIntegerConstant(newElementType, value,
200 return convertedAttr;
203template <TosaNarrowKind Kind>
207 bool allowLossyConversion) {
208 if constexpr (Kind != TosaNarrowKind::Float64ToFloat32 &&
209 Kind != TosaNarrowKind::Float32ToFloat16)
212 const auto oldElementType = dyn_cast<FloatType>(type.getElementType());
213 if (!oldElementType || !isSourceFloat<Kind>(oldElementType))
217 dyn_cast_or_null<ShapedType>(typeConverter.convertType(type));
221 const auto newElementType = dyn_cast<FloatType>(newType.getElementType());
225 if (!allowLossyConversion) {
226 for (APFloat value : attr.getValues<APFloat>())
227 if (
failed(convertFloatConstant(newElementType, value,
233 attr.
mapValues(newElementType, [&](
const APFloat &value) -> APInt {
234 APFloat converted = convertFloatConstant(newElementType, value,
239 return converted.bitcastToAPInt();
241 return convertedAttr;
244template <TosaNarrowKind Kind>
246 ShapedType type, DenseResourceElementsAttr attr,
247 const TypeConverter &typeConverter,
bool allowLossyConversion) {
248 static_assert(Kind == TosaNarrowKind::Int64ToInt32 ||
249 Kind == TosaNarrowKind::Float64ToFloat32 ||
250 Kind == TosaNarrowKind::Float32ToFloat16);
251 using From = std::conditional_t<
252 Kind == TosaNarrowKind::Int64ToInt32,
int64_t,
253 std::conditional_t<Kind == TosaNarrowKind::Float64ToFloat32, double,
255 using To = std::conditional_t<
256 Kind == TosaNarrowKind::Int64ToInt32, int32_t,
257 std::conditional_t<Kind == TosaNarrowKind::Float64ToFloat32, float,
260 if (Kind == TosaNarrowKind::Int64ToInt32 &&
261 !isa<DenseI64ResourceElementsAttr>(attr)) {
265 if (Kind == TosaNarrowKind::Float64ToFloat32 &&
266 !isa<DenseF64ResourceElementsAttr>(attr)) {
270 if (Kind == TosaNarrowKind::Float32ToFloat16 &&
271 !isa<DenseF32ResourceElementsAttr>(attr)) {
276 dyn_cast_or_null<ShapedType>(typeConverter.convertType(type));
280 const auto newElementType = dyn_cast<FloatType>(newType.getElementType());
282 auto narrow = [&](From value) -> FailureOr<To> {
283 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
284 From clamped = std::clamp<From>(value, std::numeric_limits<To>::min(),
285 std::numeric_limits<To>::max());
286 if (!allowLossyConversion && clamped != value)
288 return static_cast<To
>(clamped);
289 }
else if constexpr (Kind == TosaNarrowKind::Float64ToFloat32) {
290 To converted =
static_cast<To
>(value);
291 if (!allowLossyConversion && converted != value)
295 FailureOr<APFloat> converted = convertFloatConstant(
296 newElementType, APFloat(value), allowLossyConversion);
301 return static_cast<To
>(converted->bitcastToAPInt().getZExtValue());
305 const std::optional<ArrayRef<From>> values =
312 newValues.reserve(values->size());
313 for (From value : *values) {
314 FailureOr<To> convertedValue = narrow(value);
315 if (
failed(convertedValue))
317 newValues.push_back(*convertedValue);
323 auto resourceManager =
325 resourceManager.getBlobManager().update(attr.getRawHandle().getKey(),
328 return DenseResourceElementsAttr::get(newType, attr.getRawHandle());
331template <TosaNarrowKind Kind,
typename AttrT>
333convertAttributeWithTypeConverter(AttrT attr,
Type type,
335 if (!typeNeedsConversion<Kind>(type))
338 const std::optional<Attribute> convertedAttribute =
339 typeConverter->convertTypeAttribute(type, attr);
340 if (!convertedAttribute)
343 return convertedAttribute.value();
348template <TosaNarrowKind Kind>
350verifyCastDoesNotLosePrecision(
Operation *op, ShapedType inputType,
351 ShapedType resultType,
352 ConversionPatternRewriter &rewriter) {
353 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
354 const auto elementInputIntType =
355 dyn_cast<IntegerType>(inputType.getElementType());
356 const auto elementResultIntType =
357 dyn_cast<IntegerType>(resultType.getElementType());
358 if (elementInputIntType && elementResultIntType &&
359 elementInputIntType.getWidth() > elementResultIntType.getWidth())
360 return rewriter.notifyMatchFailure(
361 op,
"Narrowing cast may lead to data loss.");
362 }
else if constexpr (Kind == TosaNarrowKind::Float64ToFloat32 ||
363 Kind == TosaNarrowKind::Float32ToFloat16) {
364 const auto elementInputFloatType =
365 dyn_cast<FloatType>(inputType.getElementType());
366 const auto elementResultFloatType =
367 dyn_cast<FloatType>(resultType.getElementType());
368 if (elementInputFloatType && elementResultFloatType &&
369 elementInputFloatType.getIntOrFloatBitWidth() >
370 elementResultFloatType.getIntOrFloatBitWidth())
371 return rewriter.notifyMatchFailure(
372 op,
"Narrowing cast may lead to data loss.");
384template <TosaNarrowKind Kind>
386 ConversionPatternRewriter &rewriter,
388 bool allowLossyConversion,
389 bool convertAccumulatorType =
false) {
400 sourceAttrs.append(name, attr);
403 const Attribute attribute = namedAttribute.getValue();
405 if (isa<IntegerAttr>(attribute) || isa<FloatAttr>(attribute)) {
406 FailureOr<Attribute> convertedAttr =
407 tryConvertScalarAttribute<Kind>(attribute, allowLossyConversion);
408 if (
failed(convertedAttr))
409 return rewriter.notifyMatchFailure(
410 op,
"Scalar attribute narrowing would lose precision; enable "
411 "aggressive rewrite to override.");
412 state.addAttribute(namedAttribute.getName(), convertedAttr.value());
416 if (
const auto typeAttr = dyn_cast<TypeAttr>(attribute)) {
417 if (!convertAccumulatorType &&
418 namedAttribute.getName().getValue() ==
"acc_type") {
419 state.addAttribute(namedAttribute.getName(), attribute);
422 if (!typeNeedsConversion<Kind>(typeAttr.getValue())) {
423 state.addAttribute(namedAttribute.getName(), attribute);
426 Type convertedType = typeConverter->convertType(typeAttr.getValue());
428 return rewriter.notifyMatchFailure(op,
429 "Failed to convert type attribute.");
430 state.addAttribute(namedAttribute.getName(),
431 TypeAttr::get(convertedType));
435 if (
const auto denseElementsAttr = dyn_cast<DenseElementsAttr>(attribute)) {
436 FailureOr<Attribute> convertedAttr =
437 convertAttributeWithTypeConverter<Kind>(
438 denseElementsAttr, denseElementsAttr.getType(), typeConverter);
439 if (
failed(convertedAttr))
440 return rewriter.notifyMatchFailure(
441 op,
"Failed to convert dense elements attribute without precision "
442 "loss; enable aggressive rewrite to override.");
443 state.addAttribute(namedAttribute.getName(), convertedAttr.value());
447 if (
const auto denseResourceElementsAttr =
448 dyn_cast<DenseResourceElementsAttr>(attribute)) {
449 FailureOr<Attribute> convertedAttr =
450 convertAttributeWithTypeConverter<Kind>(
451 denseResourceElementsAttr, denseResourceElementsAttr.getType(),
453 if (
failed(convertedAttr))
454 return rewriter.notifyMatchFailure(
455 op,
"Failed to convert dense resource elements attribute without "
456 "precision loss; enable aggressive rewrite to override.");
457 state.addAttribute(namedAttribute.getName(), convertedAttr.value());
461 state.addAttribute(namedAttribute.getName(), attribute);
465 if (
failed(rewriter.convertRegionTypes(®ion, *typeConverter)))
467 Region *newRegion = state.addRegion();
468 rewriter.inlineRegionBefore(region, *newRegion, newRegion->
begin());
471 Operation *newOp = rewriter.create(state);
476template <TosaNarrowKind Kind>
479 ConvertGenericOp(TypeConverter &typeConverter, MLIRContext *context,
480 bool allowLossyConversion,
bool convertAccumulatorType)
481 : ConversionPattern(typeConverter, MatchAnyOpTypeTag{}, 0, context),
482 allowLossyConversion(allowLossyConversion),
483 convertAccumulatorType(convertAccumulatorType) {}
486 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
487 ConversionPatternRewriter &rewriter)
const final {
488 if (!isa<tosa::TosaOp>(op))
489 return rewriter.notifyMatchFailure(
491 "Support for operations other than TOSA has not been implemented.");
493 return convertGenericOp<Kind>(op, operands, rewriter, typeConverter,
494 allowLossyConversion, convertAccumulatorType);
498 const bool allowLossyConversion;
499 const bool convertAccumulatorType;
502template <TosaNarrowKind Kind>
505 ConvertAccumulatorTypeOp(TypeConverter &typeConverter, MLIRContext *context)
506 : ConversionPattern(typeConverter, MatchAnyOpTypeTag{}, 1, context) {}
509 matchAndRewrite(Operation *op, ArrayRef<Value> ,
510 ConversionPatternRewriter &rewriter)
const final {
511 if (!isa<tosa::TosaOp>(op))
514 const auto accumulatorType = op->
getAttrOfType<TypeAttr>(
"acc_type");
515 if (!accumulatorType ||
516 !typeNeedsConversion<Kind>(accumulatorType.getValue()))
519 Type convertedType = typeConverter->convertType(accumulatorType.getValue());
523 rewriter.modifyOpInPlace(
524 op, [&] { op->
setAttr(
"acc_type", TypeAttr::get(convertedType)); });
529template <
typename OpTy, TosaNarrowKind Kind>
530class ConvertTypedOp :
public OpConversionPattern<OpTy> {
532 ConvertTypedOp(TypeConverter &typeConverter, MLIRContext *context)
533 : OpConversionPattern<OpTy>(typeConverter, context) {}
536 matchAndRewrite(OpTy op,
typename OpTy::Adaptor adaptor,
537 ConversionPatternRewriter &rewriter)
const final {
538 return convertGenericOp<Kind>(op, adaptor.getOperands(), rewriter,
539 this->getTypeConverter(),
549template <TosaNarrowKind Kind>
550class ConvertCastOpWithBoundsChecking
551 :
public OpConversionPattern<tosa::CastOp> {
552 using OpConversionPattern<tosa::CastOp>::OpConversionPattern;
555 matchAndRewrite(tosa::CastOp op,
typename tosa::CastOp::Adaptor adaptor,
556 ConversionPatternRewriter &rewriter)
const final {
557 const auto inputType = dyn_cast<ShapedType>(adaptor.getInput().getType());
559 if (!inputType || !resultType)
562 const TypeConverter *typeConverter = this->getTypeConverter();
563 if (
failed(verifyCastDoesNotLosePrecision<Kind>(op, inputType, resultType,
567 rewriter.replaceOpWithNewOp<tosa::CastOp>(
568 op,
TypeRange{typeConverter->convertType(resultType)},
569 ValueRange{adaptor.getInput()}, op.getProperties(),
576class ConvertArgMaxOpWithBoundsChecking
577 :
public OpConversionPattern<tosa::ArgMaxOp> {
578 using OpConversionPattern::OpConversionPattern;
581 matchAndRewrite(tosa::ArgMaxOp op,
typename tosa::ArgMaxOp::Adaptor adaptor,
582 ConversionPatternRewriter &rewriter)
const final {
583 const int32_t axis = op.getAxis();
584 const auto inputType = dyn_cast<ShapedType>(adaptor.getInput().getType());
585 if (!inputType || !inputType.isStaticDim(axis))
586 return rewriter.notifyMatchFailure(
587 op,
"Requires a static axis dimension for bounds checking.");
588 const int64_t axisDim = inputType.getDimSize(axis);
589 if (axisDim >= std::numeric_limits<int32_t>::max())
590 return rewriter.notifyMatchFailure(
591 op,
"Axis dimension is too large to narrow safely.");
593 const Type resultType = op.getOutput().getType();
594 const Type newResultType =
595 this->getTypeConverter()->convertType(resultType);
596 rewriter.replaceOpWithNewOp<tosa::ArgMaxOp>(op, newResultType,
597 adaptor.getInput(), axis);
602template <TosaNarrowKind Kind>
603class ConvertClampOpWithBoundsChecking
604 :
public OpConversionPattern<tosa::ClampOp> {
605 static_assert(
Kind == TosaNarrowKind::Int64ToInt32,
606 "Clamp bounds checking only supported for integer narrowing");
607 using OpConversionPattern<tosa::ClampOp>::OpConversionPattern;
610 matchAndRewrite(tosa::ClampOp op,
typename tosa::ClampOp::Adaptor adaptor,
611 ConversionPatternRewriter &rewriter)
const final {
612 auto minAttr = dyn_cast<IntegerAttr>(op.getMinValAttr());
613 auto maxAttr = dyn_cast<IntegerAttr>(op.getMaxValAttr());
614 if (!minAttr || !maxAttr)
615 return rewriter.notifyMatchFailure(
616 op,
"Clamp attributes must be integer constants.");
618 const int64_t
min = minAttr.getInt();
619 const int64_t
max = maxAttr.getInt();
620 if (
min < std::numeric_limits<int32_t>::min() ||
621 max > std::numeric_limits<int32_t>::max())
622 return rewriter.notifyMatchFailure(
623 op,
"Clamp bounds exceed int32 range. Narrowing may lose data.");
625 const Type resultType = op.getOutput().getType();
626 const Type newResultType =
627 this->getTypeConverter()->convertType(resultType);
628 const auto newResultShaped = dyn_cast<ShapedType>(newResultType);
629 if (!newResultShaped)
631 const auto newElementType =
632 dyn_cast<IntegerType>(newResultShaped.getElementType());
636 const IntegerAttr newMinAttr = IntegerAttr::get(newElementType,
min);
637 const IntegerAttr newMaxAttr = IntegerAttr::get(newElementType,
max);
639 rewriter.replaceOpWithNewOp<tosa::ClampOp>(op, newResultType,
640 adaptor.getInput(), newMinAttr,
641 newMaxAttr, op.getNanModeAttr());
648template <TosaNarrowKind Kind>
649LogicalResult runTosaNarrowing(
Operation *op,
bool aggressiveRewrite,
650 bool convertFunctionBoundaries,
651 bool convertAccumulatorType =
false) {
653 const bool allowLossyConversion = aggressiveRewrite;
656 typeConverter.addConversion([](
Type type) ->
Type {
return type; });
658 typeConverter.addConversion(
659 [](IntegerType type) ->
Type {
return convertInteger<Kind>(type); });
660 typeConverter.addConversion(
661 [](FloatType type) ->
Type {
return convertFloat<Kind>(type); });
662 typeConverter.addConversion([&typeConverter](RankedTensorType type) ->
Type {
663 Type elementType = type.getElementType();
664 if (!isSourceElement<Kind>(elementType))
666 Type converted = typeConverter.convertType(elementType);
667 if (!converted || converted == elementType)
669 return RankedTensorType::get(type.getShape(), converted,
672 typeConverter.addConversion(
673 [&typeConverter](UnrankedTensorType type) ->
Type {
674 Type elementType = type.getElementType();
675 if (!isSourceElement<Kind>(elementType))
677 Type converted = typeConverter.convertType(elementType);
678 if (!converted || converted == elementType)
680 return UnrankedTensorType::get(converted);
683 const auto materializeCast = [](
OpBuilder &builder,
Type resultType,
685 if (inputs.size() != 1)
687 return tosa::CastOp::create(
688 builder, loc, resultType, inputs.front(),
690 .isUnsignedInteger());
692 typeConverter.addSourceMaterialization(materializeCast);
693 typeConverter.addTargetMaterialization(materializeCast);
695 typeConverter.addTypeAttributeConversion(
696 [&typeConverter, allowLossyConversion](ShapedType type,
697 DenseResourceElementsAttr attr)
698 -> TypeConverter::AttributeConversionResult {
700 type, attr, typeConverter, allowLossyConversion);
702 return TypeConverter::AttributeConversionResult::abort();
703 return TypeConverter::AttributeConversionResult::result(
707 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
708 typeConverter.addTypeAttributeConversion(
709 [allowLossyConversion](IntegerType , IntegerAttr attribute)
710 -> TypeConverter::AttributeConversionResult {
711 FailureOr<Attribute> converted =
712 tryConvertScalarAttribute<Kind>(attribute, allowLossyConversion);
714 return TypeConverter::AttributeConversionResult::abort();
715 return TypeConverter::AttributeConversionResult::result(
718 typeConverter.addTypeAttributeConversion(
719 [&typeConverter, allowLossyConversion](ShapedType type,
721 -> TypeConverter::AttributeConversionResult {
722 FailureOr<Attribute> converted = convertDenseIntElementsAttr<Kind>(
723 type, attr, typeConverter, allowLossyConversion);
725 return TypeConverter::AttributeConversionResult::abort();
726 return TypeConverter::AttributeConversionResult::result(
729 }
else if constexpr (Kind == TosaNarrowKind::Float64ToFloat32 ||
730 Kind == TosaNarrowKind::Float32ToFloat16) {
731 typeConverter.addTypeAttributeConversion(
732 [allowLossyConversion](FloatType , FloatAttr attribute)
733 -> TypeConverter::AttributeConversionResult {
734 FailureOr<Attribute> converted =
735 tryConvertScalarAttribute<Kind>(attribute, allowLossyConversion);
737 return TypeConverter::AttributeConversionResult::abort();
738 return TypeConverter::AttributeConversionResult::result(
741 typeConverter.addTypeAttributeConversion(
742 [&typeConverter, allowLossyConversion](ShapedType type,
744 -> TypeConverter::AttributeConversionResult {
745 FailureOr<Attribute> converted = convertDenseFPElementsAttr<Kind>(
746 type, attr, typeConverter, allowLossyConversion);
748 return TypeConverter::AttributeConversionResult::abort();
749 return TypeConverter::AttributeConversionResult::result(
755 target.addDynamicallyLegalDialect<tosa::TosaDialect>(
756 [&typeConverter, convertAccumulatorType](
Operation *op) {
760 if (!convertAccumulatorType)
762 const auto accumulatorType = op->
getAttrOfType<TypeAttr>(
"acc_type");
763 return !accumulatorType ||
764 !typeNeedsConversion<Kind>(accumulatorType.getValue());
766 if (convertFunctionBoundaries) {
767 target.addDynamicallyLegalOp<func::FuncOp>(
768 [&typeConverter](func::FuncOp op) {
769 return typeConverter.isSignatureLegal(op.getFunctionType()) &&
770 typeConverter.isLegal(&op.getBody());
772 target.addDynamicallyLegalOp<func::ReturnOp>([](func::ReturnOp op) {
773 const FunctionType funcType =
778 target.addDynamicallyLegalOp<func::FuncOp>(
779 [](func::FuncOp) {
return true; });
780 target.addDynamicallyLegalOp<func::ReturnOp>(
781 [](func::ReturnOp) {
return true; });
785 if (convertFunctionBoundaries) {
786 populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(
787 patterns, typeConverter);
790 if (convertAccumulatorType && !aggressiveRewrite)
791 patterns.add<ConvertAccumulatorTypeOp<Kind>>(typeConverter, context);
792 if (aggressiveRewrite) {
793 patterns.add<ConvertGenericOp<Kind>>(
794 typeConverter, context, allowLossyConversion, convertAccumulatorType);
796 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
797 patterns.add<ConvertArgMaxOpWithBoundsChecking>(typeConverter, context);
798 patterns.add<ConvertClampOpWithBoundsChecking<Kind>>(typeConverter,
801 patterns.add<ConvertTypedOp<tosa::ConstOp, Kind>>(typeConverter, context);
802 patterns.add<ConvertTypedOp<tosa::ConcatOp, Kind>>(typeConverter, context);
803 patterns.add<ConvertTypedOp<tosa::PadOp, Kind>>(typeConverter, context);
804 patterns.add<ConvertTypedOp<tosa::ReshapeOp, Kind>>(typeConverter, context);
805 patterns.add<ConvertTypedOp<tosa::ReverseOp, Kind>>(typeConverter, context);
806 patterns.add<ConvertTypedOp<tosa::SliceOp, Kind>>(typeConverter, context);
807 patterns.add<ConvertTypedOp<tosa::TileOp, Kind>>(typeConverter, context);
808 patterns.add<ConvertTypedOp<tosa::TransposeOp, Kind>>(typeConverter,
810 patterns.add<ConvertTypedOp<tosa::IdentityOp, Kind>>(typeConverter,
812 patterns.add<ConvertCastOpWithBoundsChecking<Kind>>(typeConverter, context);
813 patterns.add<ConvertTypedOp<tosa::IfOp, Kind>>(typeConverter, context);
814 patterns.add<ConvertTypedOp<tosa::WhileOp, Kind>>(typeConverter, context);
815 patterns.add<ConvertTypedOp<tosa::YieldOp, Kind>>(typeConverter, context);
818 if (failed(applyFullConversion(op,
target, std::move(patterns))))
827struct TosaNarrowI64ToI32
831 TosaNarrowI64ToI32() =
default;
834 this->aggressiveRewrite =
options.aggressiveRewrite;
835 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
839 if (failed(runTosaNarrowing<TosaNarrowKind::Int64ToInt32>(
841 this->convertFunctionBoundaries)))
846struct TosaNarrowF64ToF32
850 TosaNarrowF64ToF32() =
default;
853 this->aggressiveRewrite =
options.aggressiveRewrite;
854 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
857 void runOnOperation()
override {
858 if (failed(runTosaNarrowing<TosaNarrowKind::Float64ToFloat32>(
860 this->convertFunctionBoundaries)))
865struct TosaNarrowF32ToF16
867 TosaNarrowF32ToF16() =
default;
870 this->aggressiveRewrite =
options.aggressiveRewrite;
871 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
872 this->convertAccumulatorType =
options.convertAccumulatorType;
875 void runOnOperation()
override {
876 if (failed(runTosaNarrowing<TosaNarrowKind::Float32ToFloat16>(
877 getOperation(), this->aggressiveRewrite,
878 this->convertFunctionBoundaries, this->convertAccumulatorType)))
static llvm::Constant * convertDenseResourceElementsAttr(Location loc, DenseResourceElementsAttr denseResourceAttr, llvm::Type *llvmType, const ModuleTranslation &moduleTranslation)
Convert a dense resource elements attribute to an LLVM IR constant using its raw data storage if poss...
static llvm::ManagedStatic< PassManagerOptions > options
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
This class represents a processed binary blob of data.
Attributes are known-constant values of operations.
An attribute that represents a reference to a dense float vector or tensor object.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APFloat &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
An attribute that represents a reference to a dense integer vector or tensor object.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
static AsmResourceBlob allocateAndCopyInferAlign(ArrayRef< T > data, bool dataIsMutable=true)
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.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
NamedAttribute represents a combination of a name and an Attribute value.
This class helps build Operations.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
void walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) const
Visit the inherent attributes stored in the properties of op.
func::FuncOp getOperation()
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
operand_type_range getOperandTypes()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
result_type_range getResultTypes()
SuccessorRange getSuccessors()
result_range getResults()
MLIRContext * getContext()
Return the context this operation is associated with.
virtual void runOnOperation()=0
The polymorphic API that runs the pass over the currently held operation.
void signalPassFailure()
Signal that some invariant was broken when running.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
TosaNarrowF32ToF16PassBase Base
Kind
An enumeration of the kinds of predicates.
Type getStorageElementTypeOrSelf(Type type)
std::optional< ArrayRef< T > > tryGetDenseResourceValues(ElementsAttr attr)
Include the generated interface declarations.
void populateReturnOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter, PatternBenefit benefit=1)
Add a pattern to the given pattern list to rewrite return ops to use operands that have been legalize...
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
This represents an operation in an abstracted form, suitable for use with the builder APIs.