diff --git a/tensorflow/compiler/mlir/lite/ir/tfl_ops.cc b/tensorflow/compiler/mlir/lite/ir/tfl_ops.cc index 3dcfe71770b..0c384ebf9f3 100644 --- a/tensorflow/compiler/mlir/lite/ir/tfl_ops.cc +++ b/tensorflow/compiler/mlir/lite/ir/tfl_ops.cc @@ -1966,9 +1966,9 @@ OpFoldResult TransposeOp::fold(ArrayRef operands) { } static LogicalResult Verify(TransposeOp op) { - auto input_type = op.x().getType().cast(); + auto input_type = op.input().getType().cast(); auto perm_type = op.perm().getType().cast(); - auto output_type = op.y().getType().cast(); + auto output_type = op.output().getType().cast(); if (input_type.hasStaticShape() && perm_type.hasStaticShape()) { if (perm_type.getNumElements() != input_type.getRank()) { return op.emitOpError( diff --git a/tensorflow/compiler/mlir/lite/ir/tfl_ops.td b/tensorflow/compiler/mlir/lite/ir/tfl_ops.td index 76c342bd10a..48bc68e5c95 100644 --- a/tensorflow/compiler/mlir/lite/ir/tfl_ops.td +++ b/tensorflow/compiler/mlir/lite/ir/tfl_ops.td @@ -161,7 +161,6 @@ class TFL_VariadicTensorOf allowedRuntimeTypes, Variadic>, TFL_RuntimeType>>; -def TFL_Uint8 : UI<8>; def TFL_Int32Or64 : SignlessIntOfWidths<[32, 64]>; def TFL_BoolTensor : TFL_TensorOf<[I1]>; @@ -294,21 +293,33 @@ class TFL_OperandHasRankRange : "getRank() <= " # y>]>>; def TFL_FloatNonNegative : AttrConstraint< - CPred<"!$_self.cast().getValue().isNegative()">, + CPred<"$_self.isa() && " + "!$_self.cast().getValue().isNegative()">, "whose value is non-negative">; def TFL_BoolTrue : AttrConstraint< - CPred<"$_self.cast().getValue()">, + CPred<"$_self.isa() && $_self.cast().getValue()">, "whose value is true">; def TFL_BoolFalse : AttrConstraint< - CPred<"!$_self.cast().getValue()">, + CPred<"$_self.isa() && !$_self.cast().getValue()">, "whose value is false">; class TFL_StringEqualsTo : AttrConstraint< CPred<"$_self.cast().getValue() == \"" # value # "\"">, "whose value equals to '" # value # "'">; +// Ensures the array attribute's size is within the given maximum size. +class TFL_ArrayMaxCount : AttrConstraint< + CPred<"$_self.isa() && $_self.cast().size() <= " # n>, + "whose size is at most " # n>; + +// Ensures the given integer attribute has the given value. +class TFL_IntEqualsTo : AttrConstraint< + CPred<"$_self.isa() && " + "$_self.cast().getInt() == " # n>, + "whose value is " # n>; + // This is a quantization-aware version of TCresVTEtIsSameAsOp class TFL_TCresVTEtIsSameAsOp : And<[ TCOpResIsShapedTypePred, @@ -472,7 +483,10 @@ an output element, this operation computes \\(y = |x|\\). def TFL_AddOp : TFL_Op<"add", [ TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 5>, - ResultsBroadcastableShape, NoSideEffect, Commutative, TFL_GpuTargetOp]> { + ResultsBroadcastableShape, + NoSideEffect, + Commutative, + TFL_GpuTargetOp]> { let summary = "Addition operator"; let description = [{ @@ -540,8 +554,14 @@ retained with length 1. let customOption = "ReducerOptions"; } -def TFL_TransposeConvOp: - TFL_Op<"transpose_conv", [NoSideEffect, TFL_GpuTargetOp]> { +def TFL_TransposeConvOp: TFL_Op<"transpose_conv", [ + NoSideEffect, + TFL_OperandHasRank<0, 1>, + TFL_OperandHasRank<1, 4>, + TFL_OperandHasRank<2, 4>, + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 2>>, + TFL_GpuTargetOp]> { let summary = "Transpose convolution operator"; let description = [{ @@ -549,16 +569,16 @@ def TFL_TransposeConvOp: }]; let arguments = (ins - TFL_1DTensorOf<[I32]>:$output_shape, - TFL_TensorOf<[F32, TFL_Uint8, QI8, QUI8]>:$weights, - TFL_TensorOf<[F32, TFL_Uint8, QI8, QUI8]>:$input, - TFL_TensorOfOrNone<[F32, QI32, QUI32]>:$bias, + TFL_I32Tensor:$output_shape, + TFL_TensorOf<[F32, QI8, QUI8]>:$weights, + TFL_TensorOf<[F32, QI8, QUI8]>:$input, + TFL_TensorOfOrNone<[F32, QI32]>:$bias, TFL_PaddingAttr:$padding, - I32Attr:$stride_h, - I32Attr:$stride_w + Confined:$stride_h, + Confined:$stride_w ); - let results = (outs AnyTensor:$output); + let results = (outs TFL_TensorOf<[F32, QI8, QUI8]>:$output); let hasOptions = 1; @@ -600,7 +620,7 @@ def TFL_ArgMaxOp : TFL_Op<"arg_max", [NoSideEffect]> { }]; let arguments = ( - ins TFL_TensorOf<[F32, I32, I8, TFL_Uint8, QI8, QUI8]>:$input, + ins TFL_TensorOf<[F32, I32, I8, UI8, QI8, QUI8]>:$input, TFL_I32OrI64Tensor:$dim ); @@ -630,7 +650,7 @@ def TFL_ArgMinOp : TFL_Op<"arg_min", [NoSideEffect]> { }]; let arguments = ( - ins TFL_TensorOf<[F32, I32, I8, TFL_Uint8, QI8, QUI8]>:$input, + ins TFL_TensorOf<[F32, I32, I8, UI8, QI8, QUI8]>:$input, TFL_I32OrI64Tensor:$dim ); @@ -677,14 +697,14 @@ def TFL_ConcatenationOp : TFL_Op<"concatenation", let arguments = ( ins TFL_VariadicTensorOf< - [F32, I64, I32, I16, I8, QI8, QUI8, TFL_Uint8]>:$values, + [F32, I64, I32, I16, I8, QI8, QUI8, UI8]>:$values, I32Attr:$axis, TFL_AFAttr:$fused_activation_function ); let results = (outs TFL_TensorOf< - [F32, I64, I32, I16, I8, QI8, QUI8, TFL_Uint8]>:$output + [F32, I64, I32, I16, I8, QI8, QUI8, UI8]>:$output ); let hasOptions = 1; @@ -748,7 +768,8 @@ def SparsityParameterAttr : StructAttr<"SparsityParameterAttr", TFL_Dialect, [ let storageType = [{ TFL::SparsityParameterAttr }]; } -def TFL_SparseConstOp : Op { let summary = "Sparse constant pseudo op."; @@ -959,12 +980,12 @@ def TFL_GatherNdOp : TFL_Op<"gather_nd", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I8, I64, I32, TFL_Uint8, TFL_Str]>:$params, + TFL_TensorOf<[F32, I8, I64, I32, UI8, TFL_Str]>:$params, TFL_I32OrI64Tensor:$indices ); let results = (outs - TFL_TensorOf<[F32, I8, I64, I32, TFL_Uint8, TFL_Str]>:$output + TFL_TensorOf<[F32, I8, I64, I32, UI8, TFL_Str]>:$output ); } @@ -983,12 +1004,12 @@ def TFL_ScatterNdOp : TFL_Op<"scatter_nd", [ let arguments = (ins TFL_TensorOf<[I32]>:$indices, - TFL_TensorOf<[F32, I8, I64, I32, TFL_Uint8]>:$updates, + TFL_TensorOf<[F32, I8, I64, I32, UI8]>:$updates, TFL_1DTensorOf<[I32]>:$shape ); let results = (outs - TFL_TensorOf<[F32, I8, I64, I32, TFL_Uint8]>:$output + TFL_TensorOf<[F32, I8, I64, I32, UI8]>:$output ); let verifier = [{ return Verify(*this); }]; @@ -1103,11 +1124,11 @@ def TFL_MatrixDiagOp : TFL_Op<"matrix_diag", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I8, I16, I32, I64, TFL_Uint8, QUI8, QI8, TFL_Quint8]>:$diagonal + TFL_TensorOf<[F32, I8, I16, I32, I64, UI8, QUI8, QI8, TFL_Quint8]>:$diagonal ); let results = (outs - TFL_TensorOf<[F32, I8, I16, I32, I64, TFL_Uint8, QUI8, QI8, TFL_Quint8]>:$output + TFL_TensorOf<[F32, I8, I16, I32, I64, UI8, QUI8, QI8, TFL_Quint8]>:$output ); let hasOptions = 0; @@ -1285,8 +1306,10 @@ def TFL_NotEqualOp : TFL_Op<"not_equal", [ } def TFL_DivOp : TFL_Op<"div", [ - // TODO(fengliuai): NoQuantizableResult is only correct for int8 - // quantization. update to handle Uint8 quantization. + // TODO(fengliuai): NoQuantizableResult is only correct for int8 + // quantization. update to handle Uint8 quantization. + BinaryOpSameElementTypeConstraint, + TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 5>, ResultsBroadcastableShape, NoSideEffect, NoQuantizableResult, @@ -1299,10 +1322,10 @@ def TFL_DivOp : TFL_Op<"div", [ let arguments = ( ins TFL_TensorOf<[F32, I32, QUI8]>:$lhs, - TFL_TensorOf<[F32, I32, TFL_Uint8]>:$rhs, + TFL_TensorOf<[F32, I32, QUI8]>:$rhs, TFL_AFAttr:$fused_activation_function); - let results = (outs TFL_TensorOf<[F32, I32, TFL_Uint8]>:$output); + let results = (outs TFL_TensorOf<[F32, I32, QUI8]>:$output); let builders = [TFL_FusedBroadcastableBinaryBuilder]; @@ -1345,10 +1368,10 @@ def TFL_EmbeddingLookupOp: TFL_Op<"embedding_lookup", let arguments = (ins TFL_TensorOf<[I32]>:$lookup, - TFL_TensorOf<[F32, I8, TFL_Uint8]>:$value + TFL_TensorOf<[F32, I8, UI8]>:$value ); - let results = (outs TFL_TensorOf<[F32, I8, TFL_Uint8]>:$output); + let results = (outs TFL_TensorOf<[F32, I8, UI8]>:$output); } def TFL_EqualOp: TFL_Op<"equal", [Commutative, ResultsBroadcastableShape, @@ -1364,8 +1387,8 @@ def TFL_EqualOp: TFL_Op<"equal", [Commutative, ResultsBroadcastableShape, let arguments = ( ins - TFL_TensorOf<[I1, F32, I32, I64, QI8, QUI8, TFL_Uint8, TFL_Str]>:$x, - TFL_TensorOf<[I1, F32, I32, I64, QI8, QUI8, TFL_Uint8, TFL_Str]>:$y + TFL_TensorOf<[I1, F32, I32, I64, QI8, QUI8, UI8, TFL_Str]>:$x, + TFL_TensorOf<[I1, F32, I32, I64, QI8, QUI8, UI8, TFL_Str]>:$y ); let results = (outs TFL_BoolTensor:$output); @@ -1445,7 +1468,7 @@ def TFL_SqueezeOp: TFL_Op<"squeeze", [NoSideEffect, Given a tensor `input`, this operation returns a tensor of the same type with all dimensions of size 1 removed. If you don't want to remove all size 1 dimensions, you can remove specific size 1 dimensions by specifying -`axis`. +`squeeze_dims`. For example: @@ -1464,7 +1487,7 @@ shape(squeeze(t, [2, 4])) ==> [1, 2, 3, 1] let arguments = (ins AnyTensor:$input, - DefaultValuedAttr:$squeeze_dims + Confined, [TFL_ArrayMaxCount<8>]>:$squeeze_dims ); let results = (outs @@ -1899,13 +1922,13 @@ def TFL_MeanOp : TFL_Op<"mean", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Uint8]>:$input, + TFL_TensorOf<[F32, I32, I64, QI8, QUI8, UI8]>:$input, TFL_TensorOf<[I32, I64]>:$axis, BoolAttr:$keep_dims ); let results = (outs - TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Uint8]>:$output); + TFL_TensorOf<[F32, I32, I64, QI8, QUI8, UI8]>:$output); let hasOptions = 1; let customOption = "ReducerOptions"; @@ -1998,7 +2021,11 @@ equivalent to setting: let hasCanonicalizer = 1; } -def TFL_SumOp: TFL_Op<"sum", [NoSideEffect]> { +def TFL_SumOp: TFL_Op<"sum", [ + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 0>>, + NoSideEffect]> { + let summary = "Sum operator"; let description = [{ @@ -2006,12 +2033,12 @@ def TFL_SumOp: TFL_Op<"sum", [NoSideEffect]> { }]; let arguments = (ins - AnyTensor:$input, + TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Quint8]>:$input, TFL_I32Tensor:$axes, BoolAttr:$keep_dims ); - let results = (outs AnyTensor); + let results = (outs TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Quint8]>:$output); let hasOptions = 1; let customOption = "ReducerOptions"; @@ -2113,12 +2140,13 @@ def TFL_MinimumOp : TFL_Op<"minimum", [ let hasOptions = 0; } -def TFL_MulOp : TFL_Op<"mul", [ResultsBroadcastableShape, - NoSideEffect, - Commutative, - BinaryOpSameElementTypeConstraint, - TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 5>, - TFL_GpuTargetOp]> { +def TFL_MulOp : TFL_Op<"mul", [ + ResultsBroadcastableShape, + NoSideEffect, + Commutative, + BinaryOpSameElementTypeConstraint, + TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 5>, + TFL_GpuTargetOp]> { let summary = "Multiplication operator"; let description = [{ @@ -2611,7 +2639,7 @@ def TFL_SelectOp : TFL_Op<"select", [ NoSideEffect, PredOpTrait<"operands have same element type", TCopVTEtIsSameAs<1, 2>>, PredOpTrait<"operands and result have same element type", - TCresVTEtIsSameAsOp<0, 1>>]> { + TFL_TCresVTEtIsSameAsOp<0, 1>>]> { let summary = "Select operator"; let description = [{ @@ -2647,7 +2675,7 @@ def TFL_SelectV2Op : TFL_Op<"select_v2", [ TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<1, 2, 4>, PredOpTrait<"operands have same element type", TCopVTEtIsSameAs<1, 2>>, PredOpTrait<"operands and result have same element type", - TCresVTEtIsSameAsOp<0, 1>>]> { + TFL_TCresVTEtIsSameAsOp<0, 1>>]> { let summary = "SelectV2 operator"; let description = [{ @@ -2760,7 +2788,11 @@ def TFL_SquareOp: TFL_Op<"square", [ let hasFolder = 1; } -def TFL_SubOp : TFL_Op<"sub", [ResultsBroadcastableShape, NoSideEffect]> { +def TFL_SubOp : TFL_Op<"sub", [ + ResultsBroadcastableShape, + BinaryOpSameElementTypeConstraint, + TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 5>, + NoSideEffect]> { let summary = "Subtraction operator"; let description = [{ @@ -2768,11 +2800,11 @@ def TFL_SubOp : TFL_Op<"sub", [ResultsBroadcastableShape, NoSideEffect]> { }]; let arguments = ( - ins AnyTensor:$lhs, - AnyTensor:$rhs, + ins TFL_TensorOf<[F32, I32, QI8, QUI8, QI16]>:$lhs, + TFL_TensorOf<[F32, I32, QI8, QUI8, QI16]>:$rhs, TFL_AFAttr:$fused_activation_function); - let results = (outs AnyTensor:$output); + let results = (outs TFL_TensorOf<[F32, I32, QI8, QUI8, QI16]>:$output); let hasFolder = 1; @@ -2788,6 +2820,8 @@ def TFL_SubOp : TFL_Op<"sub", [ResultsBroadcastableShape, NoSideEffect]> { // TODO(jpienaar): Expand the kernel implementation to support all types besides // I32 and F32. def TFL_SquaredDifferenceOp : TFL_Op<"squared_difference", [ + TFL_BinaryOperandsHaveSameShapesOrBroadcastableShape<0, 1, 4>, + SameOperandsAndResultElementType, ResultsBroadcastableShape, NoSideEffect, NoQuantizableResult, @@ -2799,10 +2833,10 @@ def TFL_SquaredDifferenceOp : TFL_Op<"squared_difference", [ }]; let arguments = ( - ins AnyTensor:$lhs, - AnyTensor:$rhs); + ins TFL_TensorOf<[F32, I32]>:$lhs, + TFL_TensorOf<[F32, I32]>:$rhs); - let results = (outs AnyTensor:$output); + let results = (outs TFL_TensorOf<[F32, I32]>:$output); let builders = [TFL_BroadcastableBinaryBuilder]; @@ -2814,6 +2848,8 @@ def TFL_SquaredDifferenceOp : TFL_Op<"squared_difference", [ def TFL_TanhOp: TFL_Op<"tanh", [ NoSideEffect, SameOperandsAndResultShape, + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 0>>, // central_value = min_value / 2 + (max_value - 1) / 2 + 1 // zero_point = central_value // scale = 1. / (central_value - min_value) @@ -2826,9 +2862,9 @@ def TFL_TanhOp: TFL_Op<"tanh", [ Computes element-wise Hyperbolic tangent of input }]; - let arguments = (ins TFL_TensorOf<[F32, I16, I8, QI8, QUI8, QI16, QUI16, TFL_Uint8]>:$x); + let arguments = (ins TFL_TensorOf<[F32, QI8, QUI8, QI16, TFL_Quint8]>:$input); - let results = (outs TFL_TensorOf<[F32, I16, I8, QI8, QUI8, QI16, QUI16, TFL_Uint8]>:$y); + let results = (outs TFL_TensorOf<[F32, QI8, QUI8, QI16, TFL_Quint8]>:$output); // This builder doesn't work with quantized type, so it can only be used by // non-quantization tablegen patterns. Currently, it is used by the @@ -2842,9 +2878,11 @@ def TFL_TanhOp: TFL_Op<"tanh", [ ]; } -def TFL_TileOp: TFL_Op<"tile", [NoSideEffect, SameOperandsAndResultsScale, - PredOpTrait<"resultant element type needs to match first operand type", - TFL_TCresVTEtIsSameAsOp<0,0>>]> { +def TFL_TileOp: TFL_Op<"tile", [ + NoSideEffect, + SameOperandsAndResultsScale, + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 0>>]> { let summary = "Tile operator."; let description = [{ Constructs a tensor by tiling a given tensor. @@ -2857,11 +2895,11 @@ def TFL_TileOp: TFL_Op<"tile", [NoSideEffect, SameOperandsAndResultsScale, }]; let arguments = (ins - TFL_TensorOf<[F32, I1, I32, I64, TFL_Uint8, QUI8, TFL_Str]>:$input, + TFL_TensorOf<[F32, I1, I32, I64, UI8, QUI8, TFL_Str]>:$input, TFL_I32OrI64Tensor:$multiples); let results = (outs - TFL_TensorOf<[F32, I1, I32, I64, TFL_Uint8, QUI8, TFL_Str]>:$output); + TFL_TensorOf<[F32, I1, I32, I64, UI8, QUI8, TFL_Str]>:$output); let hasOptions = 0; } @@ -2869,9 +2907,13 @@ def TFL_TileOp: TFL_Op<"tile", [NoSideEffect, SameOperandsAndResultsScale, // TODO(jpienaar): Maybe make it accept any single element tensor as `k`. // TODO(jpienaar): Check that input has one or more dimensions. // TODO(jpienaar): Check that k is less or equal the internal dimension -def TFL_TopKV2Op: TFL_Op<"topk_v2", [NoSideEffect, TFL_OperandHasRank<1,0>, +def TFL_TopKV2Op: TFL_Op<"topk_v2", [ + NoSideEffect, + TFL_OperandHasRankAtLeast<0, 1>, + TFL_OperandHasRank<1, 0>, PredOpTrait<"result and input element type match", - TCresVTEtIsSameAsOp<0,0>>, SameOperandsAndResultsScale]> { + TFL_TCresVTEtIsSameAsOp<0,0>>, + SameOperandsAndResultsScale]> { let summary = "TopK operator"; let description = [{ @@ -2881,11 +2923,11 @@ def TFL_TopKV2Op: TFL_Op<"topk_v2", [NoSideEffect, TFL_OperandHasRank<1,0>, }]; let arguments = (ins - TFL_TensorOf<[F32, I8, I32, I64, TFL_Uint8, QI8, QUI8]>:$input, + TFL_TensorOf<[F32, I8, I32, I64, UI8, QI8, QUI8]>:$input, TFL_I32Tensor:$k); let results = (outs - TFL_TensorOf<[F32, I8, I32, I64, TFL_Uint8, QI8, QUI8]>:$values, + TFL_TensorOf<[F32, I8, I32, I64, UI8, QI8, QUI8]>:$values, TFL_I32Tensor:$indices); let builders = [OpBuilder<"OpBuilder &builder, OperationState &result, " @@ -2895,29 +2937,27 @@ def TFL_TopKV2Op: TFL_Op<"topk_v2", [NoSideEffect, TFL_OperandHasRank<1,0>, let hasOptions = 1; } -def TFL_TransposeOp : TFL_Op<"transpose", - [NoSideEffect, - TFL_OperandHasRank<1,1>, - // TODO(jpienaar): these are only true dynamically, change so that it works - // with unknowns. - // TFL_OperandRankEquals1DimOfOperand<0, 1>, - PredOpTrait<"input and output must have same element type", - TCresVTEtIsSameAsOp<0, 0>>, - SameOperandsAndResultsScale, - TFL_GpuTargetOp]> { +def TFL_TransposeOp : TFL_Op<"transpose", [ + NoSideEffect, + TFL_OperandHasRankAtMost<0, 5>, + TFL_OperandHasRank<1, 1>, + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 0>>, + SameOperandsAndResultsScale, + TFL_GpuTargetOp]> { let summary = "Transpose operator"; let description = [{ Returns the Transpose of x }]; - let arguments = ( - ins AnyTensor:$x, + let arguments = (ins + TFL_TensorOf<[I32, F32, I8, UI8, QI8, QUI8, TFL_Quint8, I1, I64]>:$input, TFL_TensorOf<[I32]>:$perm ); let results = (outs - AnyTensor:$y + TFL_TensorOf<[I32, F32, I8, UI8, QI8, QUI8, TFL_Quint8, I1, I64]>:$output ); let verifier = [{ return Verify(*this); }]; @@ -2925,7 +2965,10 @@ def TFL_TransposeOp : TFL_Op<"transpose", let hasFolder = 1; } -def TFL_UnpackOp : TFL_Op<"unpack", [NoSideEffect, SameOperandsAndResultsScale]> { +def TFL_UnpackOp : TFL_Op<"unpack", [ + NoSideEffect, + SameOperandsAndResultElementType, + SameOperandsAndResultsScale]> { let summary = "Unpacks a tensor along a dimension into multiple tensors"; let description = [{ @@ -2946,14 +2989,14 @@ def TFL_UnpackOp : TFL_Op<"unpack", [NoSideEffect, SameOperandsAndResultsScale]> }]; let arguments = (ins - TFL_TensorOf<[F32, I1, I8, I32, QI8, QUI8]>:$input, + TFL_TensorOf<[F32, I1, I8, UI8, I32, QI8, QUI8, I16, QI16]>:$input, I32Attr:$num, I32Attr:$axis ); let results = (outs - TFL_VariadicTensorOf<[F32, I1, I8, I32, QI8, QUI8]>:$outputs + TFL_VariadicTensorOf<[F32, I1, I8, UI8, I32, QI8, QUI8, I16, QI16]>:$outputs ); let verifier = [{ return Verify(*this); }]; @@ -2961,16 +3004,19 @@ def TFL_UnpackOp : TFL_Op<"unpack", [NoSideEffect, SameOperandsAndResultsScale]> let hasOptions = 1; } -def TFL_ZerosLikeOp: TFL_Op<"zeros_like", [NoSideEffect]> { +def TFL_ZerosLikeOp: TFL_Op<"zeros_like", [ + PredOpTrait<"input and output must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 0>>, + NoSideEffect]> { let summary = "ZerosLike operator"; let description = [{ Returns a tensor of zeros with the same shape and type as the input tensor. }]; - let arguments = (ins AnyTensor:$input); + let arguments = (ins TFL_TensorOf<[I64, I32, F32]>:$input); - let results = (outs AnyTensor:$output); + let results = (outs TFL_TensorOf<[I64, I32, F32]>:$output); let hasOptions = 1; } @@ -3006,7 +3052,7 @@ def TFL_SpaceToBatchNdOp: TFL_Op<"space_to_batch_nd", [ SameOperandsAndResultsScale, TFL_OperandHasRankRange<0, 3, 4>, PredOpTrait<"input and output must have same element type", - TCresVTEtIsSameAsOp<0, 0>> + TFL_TCresVTEtIsSameAsOp<0, 0>> ]> { let summary = "SpaceToBatchNd operator"; @@ -3029,7 +3075,8 @@ def TFL_SpaceToDepthOp: TFL_Op<"space_to_depth", [ NoSideEffect, SameOperandsAndResultsScale, PredOpTrait<"input and output must have same element type", - TCresVTEtIsSameAsOp<0, 0>>, + TFL_TCresVTEtIsSameAsOp<0, 0>>, + TFL_OperandHasRankAtMost<0, 4>, TFL_GpuTargetOp ]> { let summary = "SpaceToDepth operator"; @@ -3042,12 +3089,12 @@ def TFL_SpaceToDepthOp: TFL_Op<"space_to_depth", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I8, I32, I64, TFL_Uint8, QUI8]>:$input, - I32Attr:$block_size + TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Quint8]>:$input, + Confined:$block_size ); let results = (outs - TFL_TensorOf<[F32, I8, I32, I64, TFL_Uint8, QUI8]>:$output + TFL_TensorOf<[F32, I32, I64, QI8, QUI8, TFL_Quint8]>:$output ); let hasOptions = 1; @@ -3072,12 +3119,12 @@ def TFL_DepthToSpaceOp: TFL_Op<"depth_to_space", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I8, I32, I64, TFL_Quint8, TFL_Uint8, UI8, QI8, QUI8]>:$input, + TFL_TensorOf<[F32, I8, I32, I64, TFL_Quint8, UI8, QI8, QUI8]>:$input, Confined:$block_size ); let results = (outs - TFL_TensorOf<[F32, I8, I32, I64, TFL_Quint8, TFL_Uint8, UI8, QI8, QUI8]>:$output + TFL_TensorOf<[F32, I8, I32, I64, TFL_Quint8, UI8, QI8, QUI8]>:$output ); let hasOptions = 1; @@ -3097,12 +3144,12 @@ def TFL_SplitOp : TFL_Op<"split", [ let arguments = (ins TFL_TensorOf<[I32]>:$split_dim, - TFL_TensorOf<[F32, I16, I32, I64, QI8, QUI8, QI16]>:$value, + TFL_TensorOf<[F32, I16, I32, I64, I8, UI8, QI8, QUI8, QI16]>:$value, Confined:$num_splits ); let results = (outs - TFL_VariadicTensorOf<[F32, I16, I32, I64, QI8, QUI8, QI16]>:$outputs + TFL_VariadicTensorOf<[F32, I16, I32, I64, I8, UI8, QI8, QUI8, QI16]>:$outputs ); let verifier = [{ return Verify(*this); }]; @@ -3120,14 +3167,14 @@ def TFL_SplitVOp : TFL_Op<"split_v", [NoSideEffect, SameOperandsAndResultsScale] }]; let arguments = (ins - TFL_TensorOf<[F32, I16, I32, I64, QI8, QUI8, QI16]>:$value, + TFL_TensorOf<[F32, I16, I32, I64, I8, UI8, QI8, QUI8, QI16]>:$value, TFL_1DTensorOf<[I32], [I32]>:$size_splits, TFL_0DTensorOf<[I32], [I32]>:$split_dim, Confined:$num_splits ); let results = (outs - TFL_VariadicTensorOf<[F32, I16, I32, I64, QI8, QUI8, QI16]>:$outputs + TFL_VariadicTensorOf<[F32, I16, I32, I64, I8, UI8, QI8, QUI8, QI16]>:$outputs ); let verifier = [{ return Verify(*this); }]; @@ -3189,7 +3236,15 @@ def TFL_ResizeNearestNeighborOp : TFL_Op<"resize_nearest_neighbor", [ let hasOptions = 1; } -def TFL_SparseToDenseOp : TFL_Op<"sparse_to_dense", [NoSideEffect]> { +def TFL_SparseToDenseOp : TFL_Op<"sparse_to_dense", [ + NoSideEffect, + PredOpTrait<"sparse_values and dense must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 2>>, + PredOpTrait<"default_value and dense must have same element type", + TFL_TCresVTEtIsSameAsOp<0, 3>>, + TFL_OperandHasRankAtMost<0, 2>, + TFL_OperandHasRankAtMost<1, 1>, + TFL_OperandHasRankAtMost<2, 1>]> { let summary = "Converts a sparse representation into a dense tensor."; let description = [{ @@ -3217,21 +3272,24 @@ are checked during execution. let arguments = (ins TFL_I32OrI64Tensor:$sparse_indices, TFL_I32OrI64Tensor:$output_shape, - TFL_TensorOf<[I32, I64, I8, TFL_Uint8, F32]>:$sparse_values, - TFL_TensorOf<[I32, I64, I8, TFL_Uint8, F32]>:$default_value + TFL_TensorOf<[I32, I64, I8, QI8, UI8, QUI8, TFL_Quint8, F32]>:$sparse_values, + TFL_TensorOf<[I32, I64, I8, QI8, UI8, QUI8, TFL_Quint8, F32]>:$default_value ); let results = (outs - TFL_TensorOf<[I32, I64, I8, TFL_Uint8, F32]>:$dense + TFL_TensorOf<[I32, I64, I8, QI8, UI8, QUI8, TFL_Quint8, F32]>:$dense ); } -def TFL_StridedSliceOp: TFL_Op<"strided_slice", - [ +def TFL_StridedSliceOp: TFL_Op<"strided_slice", [ NoSideEffect, PredOpTrait<"input and output must have same element type", TFL_TCresVTEtIsSameAsOp<0, 0>>, SameOperandsAndResultsScale, + TFL_OperandHasRankAtMost<0, 5>, + TFL_OperandHasRank<1, 1>, + TFL_OperandHasRank<2, 1>, + TFL_OperandHasRank<3, 1>, TFL_GpuTargetOp ]> { let summary = "StridedSlice Op"; @@ -3241,20 +3299,20 @@ def TFL_StridedSliceOp: TFL_Op<"strided_slice", }]; let arguments = (ins - TFL_TensorOf<[F32, I32, I64, I8, QI8, QUI8, I1, TFL_Quint8, TFL_Uint8]>:$input, - TFL_TensorOf<[I32]>:$begin, - TFL_TensorOf<[I32]>:$end, - TFL_TensorOf<[I32]>:$strides, + TFL_TensorOf<[F32, I32, I64, I8, UI8, QI8, QUI8, I1, I16, QI16, TFL_Quint8]>:$input, + TFL_I32Tensor:$begin, + TFL_I32Tensor:$end, + TFL_I32Tensor:$strides, I32Attr:$begin_mask, I32Attr:$end_mask, - I32Attr:$ellipsis_mask, - I32Attr:$new_axis_mask, + Confined]>:$ellipsis_mask, + Confined]>:$new_axis_mask, I32Attr:$shrink_axis_mask ); let results = (outs - TFL_TensorOf<[F32, I32, I64, I8, QI8, QUI8, I1, TFL_Quint8, TFL_Uint8]>:$output + TFL_TensorOf<[F32, I32, I64, I8, UI8, QI8, QUI8, I1, I16, QI16, TFL_Quint8]>:$output ); let hasOptions = 1; @@ -3269,17 +3327,16 @@ def TFL_CastOp : TFL_Op<"cast", [ }]; let arguments = (ins - TFL_TensorOf<[F32, I1, I32, I64, TFL_Quint8, TFL_Uint8, Complex>]>:$input + TFL_TensorOf<[F32, I1, I32, I64, TFL_Quint8, UI8, Complex>]>:$input ); - let results = (outs TFL_TensorOf<[F32, I1, I32, I64, TFL_Quint8, TFL_Uint8, Complex>]>:$output); + let results = (outs TFL_TensorOf<[F32, I1, I32, I64, TFL_Quint8, UI8, Complex>]>:$output); // TFLite's cast op does not utilize CastOptions, instead derives types // from the TfLiteTensors. let hasOptions = 0; } - def TFL_MirrorPadOp: TFL_Op<"mirror_pad", [ NoSideEffect, TFL_OperandHasRank<1, 2>, TFL_GpuTargetOp]> { let summary = "MirrorPad Operator. Pads a tensor with mirrored values."; @@ -3315,24 +3372,25 @@ def TFL_MirrorPadOp: TFL_Op<"mirror_pad", [ let hasOptions = 1; } -def TFL_UniqueOp: TFL_Op<"unique", [NoSideEffect]> { +def TFL_UniqueOp: TFL_Op<"unique", [ + TFL_OperandHasRank<0, 1>, + NoSideEffect]> { let summary = "Unique Op."; let description = [{ - This operation returns a tensor `y` containing all of the unique elements of `x` -sorted in the same order that they occur in `x`. This operation also returns a -tensor `idx` the same size as `x` that contains the index of each value of `x` -in the unique output `y`. In other words: + This operation returns a tensor `output` containing all of the unique elements +of `input` sorted in the same order that they occur in `input`. This operation +also returns a tensor `idx` the same size as `x` that contains the index of each +value of `input` in the unique output `output`. In other words: }]; let arguments = (ins - // TODO: add uint8 support after quantize support. - TFL_TensorOf<[I8, I16, I32, I64, F32]>:$input + TFL_TensorOf<[I8, QI8, UI8, QUI8, I16, QI16, I32, I64, F32]>:$input ); let results = (outs - TFL_TensorOf<[I8, I16, I32, I64, F32]>:$output, - TFL_TensorOf<[I32, I64]>:$idx + TFL_TensorOf<[I8, QI8, UI8, QUI8, I16, QI16, I32, I64, F32]>:$output, + TFL_I32OrI64Tensor:$idx ); DerivedTFLiteTypeAttr idx_out_type = DerivedTFLiteTypeAttr<[{ @@ -3432,7 +3490,7 @@ def TFL_SparseQConstOp : Op:$output); let builders = [OpBuilder< "OpBuilder &, OperationState &state, TypeAttr qtype, " @@ -4076,7 +4134,7 @@ def TFL_NumericVerifyOp : Op>, + TFL_TCresVTEtIsSameAsOp<0, 0>>, TFL_StatefulOp]> { let summary = "Single value decomposition filter operator"; @@ -4150,8 +4208,8 @@ def TFL_YieldOp : Op { } def TFL_WhileOp : Op, - SingleBlockImplicitTerminator<"YieldOp">]> { + DeclareOpInterfaceMethods, + SingleBlockImplicitTerminator<"YieldOp">]> { let summary = [{While loop}]; let description = [{ diff --git a/tensorflow/compiler/mlir/lite/transforms/load_quantization_recipe.cc b/tensorflow/compiler/mlir/lite/transforms/load_quantization_recipe.cc index 307a45639c5..5cb659fa318 100644 --- a/tensorflow/compiler/mlir/lite/transforms/load_quantization_recipe.cc +++ b/tensorflow/compiler/mlir/lite/transforms/load_quantization_recipe.cc @@ -184,7 +184,7 @@ void LoadQuantizationRecipe::LoadForLSTMOp(LSTMOp lstm, OpBuilder* builder) { auto new_cell_tanh = builder->create(loc, int16, new_cell); auto hidden_state = builder->create( - loc, int16, new_cell_tanh.y(), output_gate->getResult(0), none_af); + loc, int16, new_cell_tanh.output(), output_gate->getResult(0), none_af); auto act = builder->create( loc, int8, hidden_state.output(), lstm.projection_weights(), lstm.projection_bias(), none_af, fc_format, keep_dims); diff --git a/tensorflow/compiler/mlir/lite/transforms/optimize.cc b/tensorflow/compiler/mlir/lite/transforms/optimize.cc index c1c646c6dff..30ae4b81f4f 100644 --- a/tensorflow/compiler/mlir/lite/transforms/optimize.cc +++ b/tensorflow/compiler/mlir/lite/transforms/optimize.cc @@ -663,8 +663,8 @@ struct ConvertTrivialTransposeOpToReshapeOp LogicalResult matchAndRewrite(TFL::TransposeOp transpose_op, PatternRewriter &rewriter) const override { - auto input_type = transpose_op.x().getType().cast(); - auto output_type = transpose_op.y().getType().cast(); + auto input_type = transpose_op.input().getType().cast(); + auto output_type = transpose_op.output().getType().cast(); // It's possible to know if the transformation is safe only if the input // & output shapes are fully known and permutation is a constant. if (!input_type.hasStaticShape() || !output_type.hasStaticShape()) @@ -713,7 +713,8 @@ struct ConvertTrivialTransposeOpToReshapeOp auto new_shape = rewriter.create(loc, new_shape_attr); rewriter.replaceOpWithNewOp( - transpose_op, transpose_op.y().getType(), transpose_op.x(), new_shape); + transpose_op, transpose_op.output().getType(), transpose_op.input(), + new_shape); return success(); }