@@ -5991,13 +5991,93 @@ LogicalResult ConvertAtenOp<AtenIscloseOp>::matchAndRewriteImpl(
59915991 return success ();
59925992}
59935993
5994+ static LogicalResult
5995+ rewriteClampAsMinimumMaximumOp (Operation *op, TensorType resultType, Value self,
5996+ Value min, Value max,
5997+ ConversionPatternRewriter &rewriter) {
5998+ if (mlir::tosa::EqualizeRanks (rewriter, op->getLoc (), self, min).failed ())
5999+ return rewriter.notifyMatchFailure (op, " failed to equalize self and min" );
6000+
6001+ auto selfType = cast<RankedTensorType>(self.getType ());
6002+ auto minType = cast<RankedTensorType>(min.getType ());
6003+
6004+ self = tosa::tosaCastTensorToType (rewriter, self,
6005+ selfType.clone (resultType.getElementType ()))
6006+ .value ();
6007+ min = tosa::tosaCastTensorToType (rewriter, min,
6008+ minType.clone (resultType.getElementType ()))
6009+ .value ();
6010+
6011+ auto maxRank = cast<RankedTensorType>(self.getType ()).getRank ();
6012+ auto dynamicIntermediateType =
6013+ RankedTensorType::get (SmallVector<int64_t >(maxRank, ShapedType::kDynamic ),
6014+ resultType.getElementType ());
6015+
6016+ // max(xi, min_valuei)
6017+ // Use default NaN Propagation mode "PROPAGATE" for tosa.maximum
6018+ auto minThresholdCheck = tosa::CreateOpAndInfer<tosa::MaximumOp>(
6019+ rewriter, op->getLoc (), dynamicIntermediateType, self, min,
6020+ tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6021+ tosa::NanPropagationMode::PROPAGATE ));
6022+
6023+ Value tmp = minThresholdCheck.getResult ();
6024+
6025+ if (mlir::tosa::EqualizeRanks (rewriter, op->getLoc (), tmp, max).failed ())
6026+ return rewriter.notifyMatchFailure (
6027+ op, " failed to equalize intermediate and max" );
6028+
6029+ auto maxType = cast<RankedTensorType>(max.getType ());
6030+ max = tosa::tosaCastTensorToType (rewriter, max,
6031+ maxType.clone (resultType.getElementType ()))
6032+ .value ();
6033+
6034+ // yi = min(max(xi, min_valuei), max_valuei)
6035+ // Use default NaN Propagation mode "PROPAGATE" for tosa.minimum
6036+ auto result = tosa::CreateOpAndInfer<tosa::MinimumOp>(
6037+ rewriter, op->getLoc (), resultType, tmp, max,
6038+ tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6039+ tosa::NanPropagationMode::PROPAGATE ));
6040+
6041+ rewriter.replaceOp (op, result);
6042+ return success ();
6043+ }
6044+
6045+ static LogicalResult validateClampBoundsInValidRange (
6046+ ConversionPatternRewriter &rewriter, Operation *op, IntegerType intType,
6047+ std::optional<int64_t > minInt, std::optional<int64_t > maxInt) {
6048+ auto isOutOfRange = [&](int64_t value) {
6049+ switch (intType.getWidth ()) {
6050+ case 8 :
6051+ return value < std::numeric_limits<int8_t >::min () ||
6052+ value > std::numeric_limits<int8_t >::max ();
6053+ case 16 :
6054+ return value < std::numeric_limits<int16_t >::min () ||
6055+ value > std::numeric_limits<int16_t >::max ();
6056+ case 32 :
6057+ return value < std::numeric_limits<int32_t >::min () ||
6058+ value > std::numeric_limits<int32_t >::max ();
6059+ case 64 :
6060+ return false ;
6061+ default :
6062+ return true ;
6063+ }
6064+ };
6065+
6066+ if ((minInt && isOutOfRange (*minInt)) || (maxInt && isOutOfRange (*maxInt))) {
6067+ return rewriter.notifyMatchFailure (
6068+ op, " explicit clamp bound is not representable in result integer type" );
6069+ }
6070+
6071+ return success ();
6072+ }
6073+
59946074template <>
59956075LogicalResult ConvertAtenOp<AtenClampOp>::matchAndRewriteImpl(
59966076 AtenClampOp op, OpAdaptor adaptor,
59976077 ConversionPatternRewriter &rewriter) const {
5998-
6078+ auto self = adaptor. getSelf ();
59996079 // Not a tensor type.
6000- auto selfType = dyn_cast<TensorType>(adaptor. getSelf () .getType ());
6080+ auto selfType = dyn_cast<TensorType>(self .getType ());
60016081 if (!selfType)
60026082 return rewriter.notifyMatchFailure (
60036083 op, " only tensor types input are currently supported" );
@@ -6013,7 +6093,6 @@ LogicalResult ConvertAtenOp<AtenClampOp>::matchAndRewriteImpl(
60136093 return rewriter.notifyMatchFailure (
60146094 op, " only tensor types output are currently supported" );
60156095 auto outElemTy = outType.getElementType ();
6016- Value self = adaptor.getSelf ();
60176096 if (selfType != outType) {
60186097 auto castedSelf = tosa::tosaCastTensorToType (rewriter, self, outType);
60196098 if (!castedSelf)
@@ -6055,34 +6134,76 @@ LogicalResult ConvertAtenOp<AtenClampOp>::matchAndRewriteImpl(
60556134 }
60566135 }
60576136
6058- if (!isa<mlir::FloatType>(outElemTy)) {
6059- IntegerAttr minIntAttr, maxIntAttr;
6060- if (failed (tosa::getIntegerClampAttrs (rewriter, op, outElemTy, minInt,
6061- maxInt, minIntAttr, maxIntAttr))) {
6062- return failure ();
6063- }
6064-
6065- rewriter.replaceOpWithNewOp <tosa::ClampOp>(
6066- op, outType, self, minIntAttr, maxIntAttr,
6067- /* nan_mode=*/
6068- tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6069- tosa::NanPropagationMode::PROPAGATE ));
6070- } else {
6071- FloatAttr minFloatAttr, maxFloatAttr;
6072- if (failed (tosa::getFloatClampAttrs (rewriter, op, outElemTy, minFloat,
6073- maxFloat, minFloatAttr,
6074- maxFloatAttr))) {
6075- return failure ();
6076- }
6137+ return TypeSwitch<Type, LogicalResult>(outElemTy)
6138+ .Case <mlir::IntegerType>([&](auto intType) -> LogicalResult {
6139+ if (failed (validateClampBoundsInValidRange (rewriter, op, intType,
6140+ minInt, maxInt)))
6141+ return failure ();
60776142
6078- rewriter.replaceOpWithNewOp <tosa::ClampOp>(
6079- op, outType, self, minFloatAttr, maxFloatAttr,
6080- /* nan_mode=*/
6081- tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6082- tosa::NanPropagationMode::PROPAGATE ));
6083- }
6143+ IntegerAttr minIntAttr, maxIntAttr;
6144+ if (failed (tosa::getIntegerClampAttrs (rewriter, op, outElemTy, minInt,
6145+ maxInt, minIntAttr,
6146+ maxIntAttr))) {
6147+ return failure ();
6148+ }
6149+ // tosa.clamp does not support integer tensors wider than 16 bits.
6150+ //
6151+ // We use the following formula for 32-bit and 64-bit integers:
6152+ // yi = min(max(xi, min_valuei), max_valuei)
6153+ switch (intType.getWidth ()) {
6154+ case 8 :
6155+ case 16 :
6156+ if (minIntAttr.getInt () > maxIntAttr.getInt ())
6157+ minIntAttr = maxIntAttr;
6158+ rewriter.replaceOpWithNewOp <tosa::ClampOp>(
6159+ op, outType, self, minIntAttr, maxIntAttr,
6160+ /* nan_mode=*/
6161+ tosa::NanPropagationModeAttr::get (
6162+ rewriter.getContext (), tosa::NanPropagationMode::PROPAGATE ));
6163+ return success ();
6164+ case 32 : {
6165+ int32_t minValue = static_cast <int32_t >(minIntAttr.getInt ());
6166+ int32_t maxValue = static_cast <int32_t >(maxIntAttr.getInt ());
6167+ Value min =
6168+ tosa::getConstTensor<int32_t >(rewriter, op, minValue, {}).value ();
6169+ Value max =
6170+ tosa::getConstTensor<int32_t >(rewriter, op, maxValue, {}).value ();
6171+ return rewriteClampAsMinimumMaximumOp (op, outType, self, min, max,
6172+ rewriter);
6173+ }
6174+ case 64 : {
6175+ int64_t minValue = static_cast <int64_t >(minIntAttr.getInt ());
6176+ int64_t maxValue = static_cast <int64_t >(maxIntAttr.getInt ());
6177+ Value min =
6178+ tosa::getConstTensor<int64_t >(rewriter, op, minValue, {}).value ();
6179+ Value max =
6180+ tosa::getConstTensor<int64_t >(rewriter, op, maxValue, {}).value ();
6181+ return rewriteClampAsMinimumMaximumOp (op, outType, self, min, max,
6182+ rewriter);
6183+ }
6184+ default :
6185+ return rewriter.notifyMatchFailure (op, " Unsupported integer width" );
6186+ }
6187+ })
6188+ .Case <mlir::FloatType>([&](auto ) -> LogicalResult {
6189+ FloatAttr minFloatAttr, maxFloatAttr;
6190+ if (failed (tosa::getFloatClampAttrs (rewriter, op, outElemTy, minFloat,
6191+ maxFloat, minFloatAttr,
6192+ maxFloatAttr))) {
6193+ return failure ();
6194+ }
60846195
6085- return success ();
6196+ rewriter.replaceOpWithNewOp <tosa::ClampOp>(
6197+ op, outType, self, minFloatAttr, maxFloatAttr,
6198+ /* nan_mode=*/
6199+ tosa::NanPropagationModeAttr::get (
6200+ rewriter.getContext (), tosa::NanPropagationMode::PROPAGATE ));
6201+ return success ();
6202+ })
6203+ .Default ([&](Type) -> LogicalResult {
6204+ return rewriter.notifyMatchFailure (op,
6205+ " unsupported clamp element type" );
6206+ });
60866207}
60876208
60886209// Legalization for aten.clamp.Tensor
@@ -6106,6 +6227,8 @@ LogicalResult ConvertAtenOp<AtenClampTensorOp>::matchAndRewriteImpl(
61066227
61076228 auto resultType =
61086229 dyn_cast<TensorType>(typeConverter->convertType (op.getType ()));
6230+ if (!resultType)
6231+ return rewriter.notifyMatchFailure (op, " expected tensor result type" );
61096232
61106233 // Get min tensor. If None, there is no lower bound.
61116234 Value min;
@@ -6126,6 +6249,11 @@ LogicalResult ConvertAtenOp<AtenClampTensorOp>::matchAndRewriteImpl(
61266249 return tosa::getConstTensor<int8_t >(
61276250 rewriter, op, std::numeric_limits<int8_t >::min (), {})
61286251 .value ();
6252+ case 16 :
6253+ return tosa::getConstTensor<int16_t >(
6254+ rewriter, op, std::numeric_limits<int16_t >::min (),
6255+ {})
6256+ .value ();
61296257 case 32 :
61306258 return tosa::getConstTensor<int32_t >(
61316259 rewriter, op, std::numeric_limits<int32_t >::min (),
@@ -6160,6 +6288,11 @@ LogicalResult ConvertAtenOp<AtenClampTensorOp>::matchAndRewriteImpl(
61606288 return tosa::getConstTensor<int8_t >(
61616289 rewriter, op, std::numeric_limits<int8_t >::max (), {})
61626290 .value ();
6291+ case 16 :
6292+ return tosa::getConstTensor<int16_t >(
6293+ rewriter, op, std::numeric_limits<int16_t >::max (),
6294+ {})
6295+ .value ();
61636296 case 32 :
61646297 return tosa::getConstTensor<int32_t >(
61656298 rewriter, op, std::numeric_limits<int32_t >::max (),
@@ -6175,33 +6308,8 @@ LogicalResult ConvertAtenOp<AtenClampTensorOp>::matchAndRewriteImpl(
61756308 });
61766309 }
61776310
6178- if (mlir::tosa::EqualizeRanks (rewriter, op->getLoc (), self, min).failed () ||
6179- mlir::tosa::EqualizeRanks (rewriter, op->getLoc (), self, max).failed ())
6180- return rewriter.notifyMatchFailure (
6181- op, " Failed to equalize ranks among operands and result" );
6182-
6183- self = tosa::tosaCastTensorToType (rewriter, self, resultType).value ();
6184- min = tosa::tosaCastTensorToType (rewriter, min, resultType).value ();
6185- max = tosa::tosaCastTensorToType (rewriter, max, resultType).value ();
6186-
6187- // max(xi, min_valuei)
6188- // Use default NaN Propagation mode "PROPAGATE" for tosa.maximum
6189- auto minThresholdCheck = tosa::MaximumOp::create (
6190- rewriter, op->getLoc (), resultType, self, min,
6191- /* nan_mode=*/
6192- tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6193- tosa::NanPropagationMode::PROPAGATE ));
6194-
6195- // yi = min(max(xi, min_valuei), max_valuei)
6196- // Use default NaN Propagation mode "PROPAGATE" for tosa.minimum
6197- auto result = tosa::MinimumOp::create (
6198- rewriter, op->getLoc (), resultType, minThresholdCheck, max,
6199- /* nan_mode=*/
6200- tosa::NanPropagationModeAttr::get (rewriter.getContext (),
6201- tosa::NanPropagationMode::PROPAGATE ));
6202-
6203- rewriter.replaceOp (op, result);
6204- return success ();
6311+ return rewriteClampAsMinimumMaximumOp (op, resultType, self, min, max,
6312+ rewriter);
62056313}
62066314
62076315template <>
0 commit comments