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(),
577template <
typename OpTy>
578class ConvertArgMaxMinOpWithBoundsChecking :
public OpConversionPattern<OpTy> {
579 using OpConversionPattern<OpTy>::OpConversionPattern;
582 matchAndRewrite(OpTy op,
typename OpTy::Adaptor adaptor,
583 ConversionPatternRewriter &rewriter)
const final {
584 const int32_t axis = op.getAxis();
585 const auto inputType = dyn_cast<ShapedType>(adaptor.getInput().getType());
586 if (!inputType || !inputType.isStaticDim(axis))
587 return rewriter.notifyMatchFailure(
588 op,
"Requires a static axis dimension for bounds checking.");
589 const int64_t axisDim = inputType.getDimSize(axis);
590 if (axisDim >= std::numeric_limits<int32_t>::max())
591 return rewriter.notifyMatchFailure(
592 op,
"Axis dimension is too large to narrow safely.");
594 const Type resultType = op.getOutput().getType();
595 const Type newResultType =
596 this->getTypeConverter()->convertType(resultType);
597 rewriter.replaceOpWithNewOp<OpTy>(op, newResultType, adaptor.getInput(),
603template <TosaNarrowKind Kind>
604class ConvertClampOpWithBoundsChecking
605 :
public OpConversionPattern<tosa::ClampOp> {
606 static_assert(
Kind == TosaNarrowKind::Int64ToInt32,
607 "Clamp bounds checking only supported for integer narrowing");
608 using OpConversionPattern<tosa::ClampOp>::OpConversionPattern;
611 matchAndRewrite(tosa::ClampOp op,
typename tosa::ClampOp::Adaptor adaptor,
612 ConversionPatternRewriter &rewriter)
const final {
613 auto minAttr = dyn_cast<IntegerAttr>(op.getMinValAttr());
614 auto maxAttr = dyn_cast<IntegerAttr>(op.getMaxValAttr());
615 if (!minAttr || !maxAttr)
616 return rewriter.notifyMatchFailure(
617 op,
"Clamp attributes must be integer constants.");
619 const int64_t
min = minAttr.getInt();
620 const int64_t
max = maxAttr.getInt();
621 if (
min < std::numeric_limits<int32_t>::min() ||
622 max > std::numeric_limits<int32_t>::max())
623 return rewriter.notifyMatchFailure(
624 op,
"Clamp bounds exceed int32 range. Narrowing may lose data.");
626 const Type resultType = op.getOutput().getType();
627 const Type newResultType =
628 this->getTypeConverter()->convertType(resultType);
629 const auto newResultShaped = dyn_cast<ShapedType>(newResultType);
630 if (!newResultShaped)
632 const auto newElementType =
633 dyn_cast<IntegerType>(newResultShaped.getElementType());
637 const IntegerAttr newMinAttr = IntegerAttr::get(newElementType,
min);
638 const IntegerAttr newMaxAttr = IntegerAttr::get(newElementType,
max);
640 rewriter.replaceOpWithNewOp<tosa::ClampOp>(op, newResultType,
641 adaptor.getInput(), newMinAttr,
642 newMaxAttr, op.getNanModeAttr());
649template <TosaNarrowKind Kind>
650LogicalResult runTosaNarrowing(
Operation *op,
bool aggressiveRewrite,
651 bool convertFunctionBoundaries,
652 bool convertAccumulatorType =
false) {
654 const bool allowLossyConversion = aggressiveRewrite;
657 typeConverter.addConversion([](
Type type) ->
Type {
return type; });
659 typeConverter.addConversion(
660 [](IntegerType type) ->
Type {
return convertInteger<Kind>(type); });
661 typeConverter.addConversion(
662 [](FloatType type) ->
Type {
return convertFloat<Kind>(type); });
663 typeConverter.addConversion([&typeConverter](RankedTensorType type) ->
Type {
664 Type elementType = type.getElementType();
665 if (!isSourceElement<Kind>(elementType))
667 Type converted = typeConverter.convertType(elementType);
668 if (!converted || converted == elementType)
670 return RankedTensorType::get(type.getShape(), converted,
673 typeConverter.addConversion(
674 [&typeConverter](UnrankedTensorType type) ->
Type {
675 Type elementType = type.getElementType();
676 if (!isSourceElement<Kind>(elementType))
678 Type converted = typeConverter.convertType(elementType);
679 if (!converted || converted == elementType)
681 return UnrankedTensorType::get(converted);
684 const auto materializeCast = [](
OpBuilder &builder,
Type resultType,
686 if (inputs.size() != 1)
688 return tosa::CastOp::create(
689 builder, loc, resultType, inputs.front(),
691 .isUnsignedInteger());
693 typeConverter.addSourceMaterialization(materializeCast);
694 typeConverter.addTargetMaterialization(materializeCast);
696 typeConverter.addTypeAttributeConversion(
697 [&typeConverter, allowLossyConversion](ShapedType type,
698 DenseResourceElementsAttr attr)
699 -> TypeConverter::AttributeConversionResult {
701 type, attr, typeConverter, allowLossyConversion);
703 return TypeConverter::AttributeConversionResult::abort();
704 return TypeConverter::AttributeConversionResult::result(
708 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
709 typeConverter.addTypeAttributeConversion(
710 [allowLossyConversion](IntegerType , IntegerAttr attribute)
711 -> TypeConverter::AttributeConversionResult {
712 FailureOr<Attribute> converted =
713 tryConvertScalarAttribute<Kind>(attribute, allowLossyConversion);
715 return TypeConverter::AttributeConversionResult::abort();
716 return TypeConverter::AttributeConversionResult::result(
719 typeConverter.addTypeAttributeConversion(
720 [&typeConverter, allowLossyConversion](ShapedType type,
722 -> TypeConverter::AttributeConversionResult {
723 FailureOr<Attribute> converted = convertDenseIntElementsAttr<Kind>(
724 type, attr, typeConverter, allowLossyConversion);
726 return TypeConverter::AttributeConversionResult::abort();
727 return TypeConverter::AttributeConversionResult::result(
730 }
else if constexpr (Kind == TosaNarrowKind::Float64ToFloat32 ||
731 Kind == TosaNarrowKind::Float32ToFloat16) {
732 typeConverter.addTypeAttributeConversion(
733 [allowLossyConversion](FloatType , FloatAttr attribute)
734 -> TypeConverter::AttributeConversionResult {
735 FailureOr<Attribute> converted =
736 tryConvertScalarAttribute<Kind>(attribute, allowLossyConversion);
738 return TypeConverter::AttributeConversionResult::abort();
739 return TypeConverter::AttributeConversionResult::result(
742 typeConverter.addTypeAttributeConversion(
743 [&typeConverter, allowLossyConversion](ShapedType type,
745 -> TypeConverter::AttributeConversionResult {
746 FailureOr<Attribute> converted = convertDenseFPElementsAttr<Kind>(
747 type, attr, typeConverter, allowLossyConversion);
749 return TypeConverter::AttributeConversionResult::abort();
750 return TypeConverter::AttributeConversionResult::result(
755 auto hasLegalTypes = [&typeConverter](
Operation *op) {
761 target.addDynamicallyLegalDialect<tosa::TosaDialect>([&](
Operation *op) {
762 if (!hasLegalTypes(op))
764 if (!convertAccumulatorType)
766 const auto accumulatorType = op->
getAttrOfType<TypeAttr>(
"acc_type");
767 return !accumulatorType ||
768 !typeNeedsConversion<Kind>(accumulatorType.getValue());
770 if (convertFunctionBoundaries) {
771 target.addDynamicallyLegalOp<func::FuncOp>(
772 [&typeConverter](func::FuncOp op) {
773 return typeConverter.isSignatureLegal(op.getFunctionType()) &&
774 typeConverter.isLegal(&op.getBody());
776 target.addDynamicallyLegalOp<func::ReturnOp>([](func::ReturnOp op) {
777 const FunctionType funcType =
782 target.addDynamicallyLegalOp<func::FuncOp>(
783 [](func::FuncOp) {
return true; });
784 target.addDynamicallyLegalOp<func::ReturnOp>(
785 [](func::ReturnOp) {
return true; });
787 target.markUnknownOpDynamicallyLegal(hasLegalTypes);
790 if (convertFunctionBoundaries) {
791 populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(
792 patterns, typeConverter);
795 if (convertAccumulatorType && !aggressiveRewrite)
796 patterns.add<ConvertAccumulatorTypeOp<Kind>>(typeConverter, context);
797 if (aggressiveRewrite) {
798 patterns.add<ConvertGenericOp<Kind>>(
799 typeConverter, context, allowLossyConversion, convertAccumulatorType);
801 if constexpr (Kind == TosaNarrowKind::Int64ToInt32) {
802 patterns.add<ConvertArgMaxMinOpWithBoundsChecking<tosa::ArgMaxOp>>(
803 typeConverter, context);
804 patterns.add<ConvertArgMaxMinOpWithBoundsChecking<tosa::ArgMinOp>>(
805 typeConverter, context);
806 patterns.add<ConvertClampOpWithBoundsChecking<Kind>>(typeConverter,
809 patterns.add<ConvertTypedOp<tosa::ConstOp, Kind>>(typeConverter, context);
810 patterns.add<ConvertTypedOp<tosa::ConcatOp, Kind>>(typeConverter, context);
811 patterns.add<ConvertTypedOp<tosa::PadOp, Kind>>(typeConverter, context);
812 patterns.add<ConvertTypedOp<tosa::ReshapeOp, Kind>>(typeConverter, context);
813 patterns.add<ConvertTypedOp<tosa::ReverseOp, Kind>>(typeConverter, context);
814 patterns.add<ConvertTypedOp<tosa::SliceOp, Kind>>(typeConverter, context);
815 patterns.add<ConvertTypedOp<tosa::TileOp, Kind>>(typeConverter, context);
816 patterns.add<ConvertTypedOp<tosa::TransposeOp, Kind>>(typeConverter,
818 patterns.add<ConvertTypedOp<tosa::IdentityOp, Kind>>(typeConverter,
820 patterns.add<ConvertCastOpWithBoundsChecking<Kind>>(typeConverter, context);
821 patterns.add<ConvertTypedOp<tosa::IfOp, Kind>>(typeConverter, context);
822 patterns.add<ConvertTypedOp<tosa::WhileOp, Kind>>(typeConverter, context);
823 patterns.add<ConvertTypedOp<tosa::YieldOp, Kind>>(typeConverter, context);
826 if (
failed(applyFullConversion(op,
target, std::move(patterns))))
835struct TosaNarrowI64ToI32
836 :
public tosa::impl::TosaNarrowI64ToI32PassBase<TosaNarrowI64ToI32> {
837 using Base = tosa::impl::TosaNarrowI64ToI32PassBase<TosaNarrowI64ToI32>;
839 TosaNarrowI64ToI32() =
default;
841 explicit TosaNarrowI64ToI32(
const TosaNarrowI64ToI32PassOptions &
options) {
842 this->aggressiveRewrite =
options.aggressiveRewrite;
843 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
846 void runOnOperation()
override {
847 if (
failed(runTosaNarrowing<TosaNarrowKind::Int64ToInt32>(
848 getOperation(), this->aggressiveRewrite,
849 this->convertFunctionBoundaries)))
854struct TosaNarrowF64ToF32
855 :
public tosa::impl::TosaNarrowF64ToF32PassBase<TosaNarrowF64ToF32> {
856 using Base = tosa::impl::TosaNarrowF64ToF32PassBase<TosaNarrowF64ToF32>;
858 TosaNarrowF64ToF32() =
default;
860 explicit TosaNarrowF64ToF32(
const TosaNarrowF64ToF32PassOptions &
options) {
861 this->aggressiveRewrite =
options.aggressiveRewrite;
862 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
865 void runOnOperation()
override {
866 if (
failed(runTosaNarrowing<TosaNarrowKind::Float64ToFloat32>(
867 getOperation(), this->aggressiveRewrite,
868 this->convertFunctionBoundaries)))
873struct TosaNarrowF32ToF16
874 :
public tosa::impl::TosaNarrowF32ToF16PassBase<TosaNarrowF32ToF16> {
875 TosaNarrowF32ToF16() =
default;
877 explicit TosaNarrowF32ToF16(
const TosaNarrowF32ToF16PassOptions &
options) {
878 this->aggressiveRewrite =
options.aggressiveRewrite;
879 this->convertFunctionBoundaries =
options.convertFunctionBoundaries;
880 this->convertAccumulatorType =
options.convertAccumulatorType;
883 void runOnOperation()
override {
884 if (
failed(runTosaNarrowing<TosaNarrowKind::Float32ToFloat16>(
885 getOperation(), this->aggressiveRewrite,
886 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.
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.
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.
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.