| @@ -7,17 +7,15 @@ | |||||
| https://github.com/llvm/llvm-project.git | https://github.com/llvm/llvm-project.git | ||||
| git checkout -b mlir <a_working_commit_id> | git checkout -b mlir <a_working_commit_id> | ||||
| ``` | ``` | ||||
| Current working commit id is 7c15e0f64ccc79a53ed2db258f1cb58ec452a957: | |||||
| Current working commit id is 74e6030bcbcc8e628f9a99a424342a0c656456f9: | |||||
| ``` | ``` | ||||
| $ git log | $ git log | ||||
| commit 7c15e0f64ccc79a53ed2db258f1cb58ec452a957 (HEAD -> 01-26) | |||||
| Author: MaheshRavishankar <ravishankarm@google.com> | |||||
| Date: Tue Jan 26 23:21:33 2021 -0800 | |||||
| commit 74e6030bcbcc8e628f9a99a424342a0c656456f9 (HEAD -> main, origin/main, origin/HEAD) | |||||
| Author: Craig Topper <craig.topper@sifive.com> | |||||
| Date: Thu Mar 4 22:30:38 2021 -0800 | |||||
| [mlir][Linalg] Add canonicalization for init_tensor -> subtensor op. | |||||
| Differential Revision: https://reviews.llvm.org/D95305 | |||||
| [TargetLowering] Use HandleSDNodes to prevent nodes from being deleted by recursive calls in getNegatedExpression. | |||||
| ``` | ``` | ||||
| It is determined by query lastest git commit date of `tools/mlir` directory. | It is determined by query lastest git commit date of `tools/mlir` directory. | ||||
| @@ -139,7 +139,7 @@ bool ShapeAttr::hasStaticShape() const | |||||
| FuncAttr FuncAttr::get(mlir::MLIRContext* context, llvm::StringRef name, | FuncAttr FuncAttr::get(mlir::MLIRContext* context, llvm::StringRef name, | ||||
| DictionaryAttr attr) | DictionaryAttr attr) | ||||
| { | { | ||||
| auto symbol = SymbolRefAttr::get(name, context); | |||||
| auto symbol = SymbolRefAttr::get(context, name); | |||||
| return Base::get(context, symbol, attr); | return Base::get(context, symbol, attr); | ||||
| } | } | ||||
| @@ -178,8 +178,6 @@ Type TensorFlowDialect::parseType(DialectAsmParser& parser) const | |||||
| StringRef data; | StringRef data; | ||||
| if (parser.parseKeyword(&data)) return Type(); | if (parser.parseKeyword(&data)) return Type(); | ||||
| Location loc = parser.getEncodedSourceLoc(parser.getNameLoc()); | |||||
| #define HANDLE_TF_TYPE(tftype, enumerant, name) \ | #define HANDLE_TF_TYPE(tftype, enumerant, name) \ | ||||
| if (data == name) return tftype##Type::get(getContext()); | if (data == name) return tftype##Type::get(getContext()); | ||||
| // Custom TensorFlow types are handled separately at the end as they do partial | // Custom TensorFlow types are handled separately at the end as they do partial | ||||
| @@ -188,15 +186,25 @@ Type TensorFlowDialect::parseType(DialectAsmParser& parser) const | |||||
| // NOLINTNEXTLINE | // NOLINTNEXTLINE | ||||
| #include "tf_types.def" | #include "tf_types.def" | ||||
| if (data.startswith("resource")) return ParseResourceType(parser, loc); | |||||
| if (data.startswith("variant")) return ParseVariantType(parser, loc); | |||||
| return (emitError(loc, "unknown TensorFlow type: " + data), nullptr); | |||||
| llvm::SMLoc loc = parser.getNameLoc(); | |||||
| if (data.startswith("resource")) | |||||
| { | |||||
| Type ret = ParseResourceType(parser); | |||||
| if (!ret) parser.emitError(loc, "invalid resource type"); | |||||
| return ret; | |||||
| } | |||||
| if (data.startswith("variant")) | |||||
| { | |||||
| Type ret = ParseVariantType(parser); | |||||
| if (!ret) parser.emitError(loc, "invalid variant type"); | |||||
| return ret; | |||||
| } | |||||
| return (parser.emitError(loc, "unknown TensorFlow type: " + data), nullptr); | |||||
| } | } | ||||
| namespace { | namespace { | ||||
| template<typename TypeWithSubtype> | template<typename TypeWithSubtype> | ||||
| Type ParseTypeWithSubtype(MLIRContext* context, DialectAsmParser& parser, | |||||
| Location loc) | |||||
| Type ParseTypeWithSubtype(MLIRContext* context, DialectAsmParser& parser) | |||||
| { | { | ||||
| // Default type without inferred subtypes. | // Default type without inferred subtypes. | ||||
| if (failed(parser.parseOptionalLess())) return TypeWithSubtype::get(context); | if (failed(parser.parseOptionalLess())) return TypeWithSubtype::get(context); | ||||
| @@ -207,24 +215,31 @@ Type ParseTypeWithSubtype(MLIRContext* context, DialectAsmParser& parser, | |||||
| { | { | ||||
| TensorType tensor_ty; | TensorType tensor_ty; | ||||
| if (parser.parseType(tensor_ty)) return Type(); | if (parser.parseType(tensor_ty)) return Type(); | ||||
| // Each of the subtypes should be a valid TensorFlow type. | |||||
| // TODO(jpienaar): Remove duplication. | |||||
| if (!IsValidTFTensorType(tensor_ty)) | |||||
| { | |||||
| parser.emitError(parser.getNameLoc()) << "invalid subtype: " << tensor_ty; | |||||
| return Type(); | |||||
| } | |||||
| subtypes.push_back(tensor_ty); | subtypes.push_back(tensor_ty); | ||||
| } while (succeeded(parser.parseOptionalComma())); | } while (succeeded(parser.parseOptionalComma())); | ||||
| if (parser.parseGreater()) return Type(); | if (parser.parseGreater()) return Type(); | ||||
| return TypeWithSubtype::getChecked(subtypes, context, loc); | |||||
| return TypeWithSubtype::get(subtypes, context); | |||||
| } | } | ||||
| } // anonymous namespace | } // anonymous namespace | ||||
| Type TensorFlowDialect::ParseResourceType(DialectAsmParser& parser, | |||||
| Location loc) const | |||||
| Type TensorFlowDialect::ParseResourceType(DialectAsmParser& parser) const | |||||
| { | { | ||||
| return ParseTypeWithSubtype<ResourceType>(getContext(), parser, loc); | |||||
| return ParseTypeWithSubtype<ResourceType>(getContext(), parser); | |||||
| } | } | ||||
| Type TensorFlowDialect::ParseVariantType(DialectAsmParser& parser, | |||||
| Location loc) const | |||||
| Type TensorFlowDialect::ParseVariantType(DialectAsmParser& parser) const | |||||
| { | { | ||||
| return ParseTypeWithSubtype<VariantType>(getContext(), parser, loc); | |||||
| return ParseTypeWithSubtype<VariantType>(getContext(), parser); | |||||
| } | } | ||||
| Operation* TensorFlowDialect::materializeConstant(OpBuilder& builder, | Operation* TensorFlowDialect::materializeConstant(OpBuilder& builder, | ||||
| @@ -47,11 +47,11 @@ public: | |||||
| Type parseType(DialectAsmParser& parser) const override; | Type parseType(DialectAsmParser& parser) const override; | ||||
| // Parses resource type with potential subtypes. | // Parses resource type with potential subtypes. | ||||
| Type ParseResourceType(DialectAsmParser& parser, Location loc) const; | |||||
| Type ParseResourceType(DialectAsmParser& parser) const; | |||||
| // Parse and print variant type. It may have subtypes inferred using shape | // Parse and print variant type. It may have subtypes inferred using shape | ||||
| // inference. | // inference. | ||||
| Type ParseVariantType(DialectAsmParser& parser, Location loc) const; | |||||
| Type ParseVariantType(DialectAsmParser& parser) const; | |||||
| // Registered hook to materialize a constant operation from a given attribute | // Registered hook to materialize a constant operation from a given attribute | ||||
| // value with the desired resultant type. | // value with the desired resultant type. | ||||
| @@ -24,7 +24,6 @@ limitations under the License. | |||||
| include "mlir/IR/OpBase.td" | include "mlir/IR/OpBase.td" | ||||
| include "mlir/Interfaces/SideEffectInterfaces.td" | include "mlir/Interfaces/SideEffectInterfaces.td" | ||||
| //include "tf_op_interfaces.td" | |||||
| //===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
| // TensorFlow dialect definitions | // TensorFlow dialect definitions | ||||
| @@ -477,13 +476,13 @@ class TF_DerivedOperandTypeListAttr<int idx> : DerivedAttr< | |||||
| "return {mlir::OperandElementTypeIterator(values.begin()), " | "return {mlir::OperandElementTypeIterator(values.begin()), " | ||||
| "mlir::OperandElementTypeIterator(values.end())};", | "mlir::OperandElementTypeIterator(values.end())};", | ||||
| [{ | [{ | ||||
| ArrayAttr::get( | |||||
| ArrayAttr::get($_ctx, | |||||
| [&]() { | [&]() { | ||||
| llvm::SmallVector<Attribute, 4> ret; | llvm::SmallVector<Attribute, 4> ret; | ||||
| for (auto t : $_self) | for (auto t : $_self) | ||||
| ret.push_back(TypeAttr::get(t)); | ret.push_back(TypeAttr::get(t)); | ||||
| return ret; | return ret; | ||||
| }(), $_ctx) | |||||
| }()) | |||||
| }] | }] | ||||
| >; | >; | ||||
| @@ -497,13 +496,13 @@ class TF_DerivedOperandShapeListAttr<int idx> : DerivedAttr< | |||||
| "return {mlir::TF::OperandShapeIterator(values.begin()), " | "return {mlir::TF::OperandShapeIterator(values.begin()), " | ||||
| "mlir::TF::OperandShapeIterator(values.end())};", | "mlir::TF::OperandShapeIterator(values.end())};", | ||||
| [{ | [{ | ||||
| ArrayAttr::get( | |||||
| ArrayAttr::get($_ctx, | |||||
| [&](){ | [&](){ | ||||
| llvm::SmallVector<Attribute, 4> ret; | llvm::SmallVector<Attribute, 4> ret; | ||||
| for (auto shape : $_self) | for (auto shape : $_self) | ||||
| ret.push_back(mlir::TF::ShapeAttr::get($_ctx, shape)); | ret.push_back(mlir::TF::ShapeAttr::get($_ctx, shape)); | ||||
| return ret; | return ret; | ||||
| }(), $_ctx) | |||||
| }()) | |||||
| }] | }] | ||||
| >; | >; | ||||
| @@ -533,13 +532,13 @@ class TF_DerivedResultTypeListAttr<int idx> : DerivedAttr< | |||||
| "return {mlir::ResultElementTypeIterator(values.begin()), " | "return {mlir::ResultElementTypeIterator(values.begin()), " | ||||
| "mlir::ResultElementTypeIterator(values.end())};", | "mlir::ResultElementTypeIterator(values.end())};", | ||||
| [{ | [{ | ||||
| ArrayAttr::get( | |||||
| ArrayAttr::get($_ctx, | |||||
| [&]() { | [&]() { | ||||
| llvm::SmallVector<Attribute, 4> ret; | llvm::SmallVector<Attribute, 4> ret; | ||||
| for (auto t : $_self) | for (auto t : $_self) | ||||
| ret.push_back(TypeAttr::get(t)); | ret.push_back(TypeAttr::get(t)); | ||||
| return ret; | return ret; | ||||
| }(), $_ctx) | |||||
| }()) | |||||
| }] | }] | ||||
| >; | >; | ||||
| @@ -553,13 +552,13 @@ class TF_DerivedResultShapeListAttr<int idx> : DerivedAttr< | |||||
| "return {mlir::TF::ResultShapeIterator(values.begin()), " | "return {mlir::TF::ResultShapeIterator(values.begin()), " | ||||
| "mlir::TF::ResultShapeIterator(values.end())};", | "mlir::TF::ResultShapeIterator(values.end())};", | ||||
| [{ | [{ | ||||
| ArrayAttr::get( | |||||
| ArrayAttr::get($_ctx, | |||||
| [&](){ | [&](){ | ||||
| llvm::SmallVector<Attribute, 4> ret; | llvm::SmallVector<Attribute, 4> ret; | ||||
| for (auto shape : $_self) | for (auto shape : $_self) | ||||
| ret.push_back(mlir::TF::ShapeAttr::get($_ctx, shape)); | ret.push_back(mlir::TF::ShapeAttr::get($_ctx, shape)); | ||||
| return ret; | return ret; | ||||
| }(), $_ctx) | |||||
| }()) | |||||
| }] | }] | ||||
| >; | >; | ||||
| @@ -579,8 +578,8 @@ def TF_IntTypeAttr : TypeAttrBase<"IntegerType", "integer type"> { | |||||
| // Mixin class defining a builder for binary ops supporting broadcast | // Mixin class defining a builder for binary ops supporting broadcast | ||||
| // behavior. The result type has the same element type as both operands. | // behavior. The result type has the same element type as both operands. | ||||
| class WithBroadcastableBinOpBuilder { | class WithBroadcastableBinOpBuilder { | ||||
| list<OpBuilderDAG> builders = [ | |||||
| OpBuilderDAG<(ins "Value":$x, "Value":$y), | |||||
| list<OpBuilder> builders = [ | |||||
| OpBuilder<(ins "Value":$x, "Value":$y), | |||||
| [{ | [{ | ||||
| auto resultType = | auto resultType = | ||||
| OpTrait::util::getBroadcastedType(x.getType(), y.getType()); | OpTrait::util::getBroadcastedType(x.getType(), y.getType()); | ||||
| @@ -593,8 +592,8 @@ class WithBroadcastableBinOpBuilder { | |||||
| // Mixin class defining a builder for comparison ops supporting broadcast | // Mixin class defining a builder for comparison ops supporting broadcast | ||||
| // behavior. The result type has bool element type. | // behavior. The result type has bool element type. | ||||
| class WithBroadcastableCmpOpBuilder { | class WithBroadcastableCmpOpBuilder { | ||||
| list<OpBuilderDAG> builders = [ | |||||
| OpBuilderDAG<(ins "Value":$x, "Value":$y), | |||||
| list<OpBuilder> builders = [ | |||||
| OpBuilder<(ins "Value":$x, "Value":$y), | |||||
| [{ | [{ | ||||
| Type resultType; | Type resultType; | ||||
| if (x.getType().isa<UnrankedTensorType>() || | if (x.getType().isa<UnrankedTensorType>() || | ||||
| @@ -34,6 +34,7 @@ include "mlir/Interfaces/ControlFlowInterfaces.td" | |||||
| include "mlir/Interfaces/LoopLikeInterface.td" | include "mlir/Interfaces/LoopLikeInterface.td" | ||||
| include "mlir/Interfaces/SideEffectInterfaces.td" | include "mlir/Interfaces/SideEffectInterfaces.td" | ||||
| include "mlir/IR/OpBase.td" | include "mlir/IR/OpBase.td" | ||||
| include "mlir/IR/SymbolInterfaces.td" | |||||
| class TF_TensorListInitOp<string mnemonic> : TF_Op<mnemonic, [NoSideEffect]> { | class TF_TensorListInitOp<string mnemonic> : TF_Op<mnemonic, [NoSideEffect]> { | ||||
| let results = (outs | let results = (outs | ||||
| @@ -112,7 +113,6 @@ An n-way switch statement, implementing the following: | |||||
| TF_DerivedResultTypeListAttr Tout = TF_DerivedResultTypeListAttr<0>; | TF_DerivedResultTypeListAttr Tout = TF_DerivedResultTypeListAttr<0>; | ||||
| TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | ||||
| let verifier = [{ | let verifier = [{ | ||||
| return Verify(*this); | return Verify(*this); | ||||
| }]; | }]; | ||||
| @@ -179,7 +179,6 @@ An n-way switch statement, implementing the following: | |||||
| return Verify(*this); | return Verify(*this); | ||||
| }]; | }]; | ||||
| } | } | ||||
| // In MLIR, the TensorFlow tensor value is represented as an ElementsAttr, with | // In MLIR, the TensorFlow tensor value is represented as an ElementsAttr, with | ||||
| @@ -198,8 +197,8 @@ def TF_ConstOp : TF_Op<"Const", [ConstantLike, NoSideEffect]> { | |||||
| TF_DerivedResultTypeAttr dtype = TF_DerivedResultTypeAttr<0>; | TF_DerivedResultTypeAttr dtype = TF_DerivedResultTypeAttr<0>; | ||||
| let builders = [ | let builders = [ | ||||
| OpBuilderDAG<(ins "Attribute":$value)>, | |||||
| OpBuilderDAG<(ins "Type":$type, "Attribute":$value)>, | |||||
| OpBuilder<(ins "Attribute":$value)>, | |||||
| OpBuilder<(ins "Type":$type, "Attribute":$value)>, | |||||
| ]; | ]; | ||||
| } | } | ||||
| @@ -322,11 +321,6 @@ else_branch: A function that takes 'inputs' and returns a list of | |||||
| TF_DerivedResultTypeListAttr Tout = TF_DerivedResultTypeListAttr<0>; | TF_DerivedResultTypeListAttr Tout = TF_DerivedResultTypeListAttr<0>; | ||||
| TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | ||||
| let verifier = [{ | |||||
| return Verify(*this); | |||||
| }]; | |||||
| let extraClassDeclaration = [{ | let extraClassDeclaration = [{ | ||||
| // Get the then branch function. | // Get the then branch function. | ||||
| FuncOp then_function() { | FuncOp then_function() { | ||||
| @@ -381,7 +375,12 @@ else_branch: A region that computes the outputs of the op if cond = false. | |||||
| 0DTensorOf<[I1]>:$cond, | 0DTensorOf<[I1]>:$cond, | ||||
| // Used to map StatelessIf and If op defined in TensorFlow to a common op. | // Used to map StatelessIf and If op defined in TensorFlow to a common op. | ||||
| BoolAttr:$is_stateless | |||||
| BoolAttr:$is_stateless, | |||||
| // Used to maintain function name when round-tripping | |||||
| // between functional and regional control flow. This can be removed if | |||||
| // the runtime does not require globally unique then/else branch function names. | |||||
| OptionalAttr<StrAttr>:$_then_func_name, | |||||
| OptionalAttr<StrAttr>:$_else_func_name | |||||
| ); | ); | ||||
| let results = (outs | let results = (outs | ||||
| @@ -395,14 +394,13 @@ else_branch: A region that computes the outputs of the op if cond = false. | |||||
| }]; | }]; | ||||
| let builders = [ | let builders = [ | ||||
| OpBuilderDAG<(ins "TypeRange":$resultTypes, "ValueRange":$operands, | |||||
| OpBuilder<(ins "TypeRange":$resultTypes, "ValueRange":$operands, | |||||
| "llvm::ArrayRef<::mlir::NamedAttribute>":$attributes, | "llvm::ArrayRef<::mlir::NamedAttribute>":$attributes, | ||||
| "unsigned":$numRegions), | "unsigned":$numRegions), | ||||
| [{ | [{ | ||||
| assert(numRegions == 2u && "mismatched number of regions"); | assert(numRegions == 2u && "mismatched number of regions"); | ||||
| build($_builder, $_state, resultTypes, operands, attributes); | build($_builder, $_state, resultTypes, operands, attributes); | ||||
| }]>]; | }]>]; | ||||
| } | } | ||||
| def TF_LegacyCallOp : TF_Op<"LegacyCall", | def TF_LegacyCallOp : TF_Op<"LegacyCall", | ||||
| @@ -699,10 +697,6 @@ body: A function that takes a list of tensors and returns another | |||||
| TF_DerivedOperandTypeListAttr T = TF_DerivedOperandTypeListAttr<0>; | TF_DerivedOperandTypeListAttr T = TF_DerivedOperandTypeListAttr<0>; | ||||
| TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | TF_DerivedResultShapeListAttr output_shapes = TF_DerivedResultShapeListAttr<0>; | ||||
| let verifier = [{ | |||||
| return Verify(*this); | |||||
| }]; | |||||
| let extraClassDeclaration = [{ | let extraClassDeclaration = [{ | ||||
| // Get the condition function. | // Get the condition function. | ||||
| FuncOp cond_function() { | FuncOp cond_function() { | ||||
| @@ -776,7 +770,6 @@ def TF_WhileRegionOp : TF_Op<"WhileRegion", | |||||
| let regions = (region SizedRegion<1>:$cond, SizedRegion<1>:$body); | let regions = (region SizedRegion<1>:$cond, SizedRegion<1>:$body); | ||||
| let verifier = [{ return Verify(*this); }]; | let verifier = [{ return Verify(*this); }]; | ||||
| } | } | ||||
| def TF_TensorListReserveOp : TF_TensorListInitOp<"TensorListReserve"> { | def TF_TensorListReserveOp : TF_TensorListInitOp<"TensorListReserve"> { | ||||
| @@ -825,7 +818,7 @@ This operation holds the metadata common to operations of a `tpu.replicate()` co | |||||
| let results = (outs); | let results = (outs); | ||||
| } | } | ||||
| def TF_VarHandleOp : TF_Op<"VarHandleOp"> { | |||||
| def TF_VarHandleOp : TF_Op<"VarHandleOp", []> { | |||||
| let summary = "Creates a handle to a Variable resource from its name."; | let summary = "Creates a handle to a Variable resource from its name."; | ||||
| let description = [{ | let description = [{ | ||||
| @@ -967,6 +960,7 @@ An op which shards the input based on the given sharding attribute. | |||||
| let arguments = (ins | let arguments = (ins | ||||
| TF_Tensor:$input, | TF_Tensor:$input, | ||||
| DefaultValuedAttr<StrAttr, "">:$sharding, | |||||
| OptionalAttr<StrAttr>:$_XlaSharding | OptionalAttr<StrAttr>:$_XlaSharding | ||||
| ); | ); | ||||
| @@ -1168,12 +1162,11 @@ as true/false for a branch condition. | |||||
| TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | ||||
| let builders = [ | let builders = [ | ||||
| OpBuilderDAG<(ins "Value":$value), | |||||
| OpBuilder<(ins "Value":$value), | |||||
| [{ | [{ | ||||
| build($_builder, $_state, RankedTensorType::get({}, $_builder.getI1Type()), | build($_builder, $_state, RankedTensorType::get({}, $_builder.getI1Type()), | ||||
| value); | value); | ||||
| }]>]; | }]>]; | ||||
| } | } | ||||
| def TF_BesselI0eOp : TF_Op<"BesselI0e", [NoSideEffect, SameOperandsAndResultType]> { | def TF_BesselI0eOp : TF_Op<"BesselI0e", [NoSideEffect, SameOperandsAndResultType]> { | ||||
| @@ -1333,17 +1326,15 @@ def TF_AddV2Op : TF_Op<"AddV2", [Commutative, NoSideEffect, ResultsBroadcastable | |||||
| }]; | }]; | ||||
| let arguments = (ins | let arguments = (ins | ||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint32]>:$x, | |||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint32]>:$y | |||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint16, TF_Uint32, TF_Uint64]>:$x, | |||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint16, TF_Uint32, TF_Uint64]>:$y | |||||
| ); | ); | ||||
| let results = (outs | let results = (outs | ||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint32]>:$z | |||||
| TensorOf<[TF_Float, TF_SInt, TF_Complex, TF_Uint8, TF_Uint16, TF_Uint32, TF_Uint64]>:$z | |||||
| ); | ); | ||||
| TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | ||||
| } | } | ||||
| def TF_DivNoNanOp : TF_Op<"DivNoNan", [NoSideEffect, ResultsBroadcastableShape, TF_SameOperandsAndResultElementTypeResolveRef]>, | def TF_DivNoNanOp : TF_Op<"DivNoNan", [NoSideEffect, ResultsBroadcastableShape, TF_SameOperandsAndResultElementTypeResolveRef]>, | ||||
| @@ -1409,8 +1400,6 @@ If `x` and `y` are reals, this will return the floating-point division. | |||||
| ); | ); | ||||
| TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | ||||
| } | } | ||||
| def TF_AddOp : TF_Op<"Add", [NoSideEffect, ResultsBroadcastableShape, TF_LayoutAgnostic, TF_SameOperandsAndResultElementTypeResolveRef]>, | def TF_AddOp : TF_Op<"Add", [NoSideEffect, ResultsBroadcastableShape, TF_LayoutAgnostic, TF_SameOperandsAndResultElementTypeResolveRef]>, | ||||
| @@ -1436,7 +1425,6 @@ Both input and output have a range `(-inf, inf)`. | |||||
| ); | ); | ||||
| TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | TF_DerivedOperandTypeAttr T = TF_DerivedOperandTypeAttr<0>; | ||||
| } | } | ||||
| def TF_StatefulStandardNormalV2Op : TF_Op<"StatefulStandardNormalV2", []> { | def TF_StatefulStandardNormalV2Op : TF_Op<"StatefulStandardNormalV2", []> { | ||||
| @@ -1665,7 +1653,7 @@ event: A string containing a binary-encoded tf.Event proto. | |||||
| let results = (outs); | let results = (outs); | ||||
| } | } | ||||
| def TF_SummaryWriterOp : TF_Op<"SummaryWriter"> { | |||||
| def TF_SummaryWriterOp : TF_Op<"SummaryWriter", []> { | |||||
| let summary = "Returns a handle to be used to access a summary writer."; | let summary = "Returns a handle to be used to access a summary writer."; | ||||
| let description = [{ | let description = [{ | ||||
| @@ -230,7 +230,7 @@ ArrayRef<TensorType> TensorFlowTypeWithSubtype::GetSubtypes() | |||||
| // TODO(jpienaar): BroadcastCompatible and HasCompatibleElementTypes have | // TODO(jpienaar): BroadcastCompatible and HasCompatibleElementTypes have | ||||
| // similar structure that could be extracted into helper method. | // similar structure that could be extracted into helper method. | ||||
| bool BroadcastCompatible(ArrayRef<Type> lhs, ArrayRef<Type> rhs) | |||||
| bool BroadcastCompatible(TypeRange lhs, TypeRange rhs) | |||||
| { | { | ||||
| if (lhs.size() != rhs.size()) return false; | if (lhs.size() != rhs.size()) return false; | ||||
| for (auto types : llvm::zip(lhs, rhs)) | for (auto types : llvm::zip(lhs, rhs)) | ||||
| @@ -395,7 +395,7 @@ bool HasCompatibleElementTypes(Type lhs, Type rhs, | |||||
| return GetCastCompatibleType(lhs, rhs, may_ignore_ref_type_lhs) != nullptr; | return GetCastCompatibleType(lhs, rhs, may_ignore_ref_type_lhs) != nullptr; | ||||
| } | } | ||||
| bool AreCastCompatible(ArrayRef<Type> types) | |||||
| bool AreCastCompatible(TypeRange types) | |||||
| { | { | ||||
| Type common = types.front(); | Type common = types.front(); | ||||
| for (auto type : types.drop_front()) | for (auto type : types.drop_front()) | ||||
| @@ -407,7 +407,7 @@ bool AreCastCompatible(ArrayRef<Type> types) | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool ArraysAreCastCompatible(ArrayRef<Type> lhs, ArrayRef<Type> rhs) | |||||
| bool ArraysAreCastCompatible(TypeRange lhs, TypeRange rhs) | |||||
| { | { | ||||
| if (lhs.size() != rhs.size()) return false; | if (lhs.size() != rhs.size()) return false; | ||||
| for (auto pair : llvm::zip(lhs, rhs)) | for (auto pair : llvm::zip(lhs, rhs)) | ||||
| @@ -123,14 +123,14 @@ public: | |||||
| static TensorFlowType getChecked(Type type, MLIRContext* context, | static TensorFlowType getChecked(Type type, MLIRContext* context, | ||||
| Location loc) | Location loc) | ||||
| { | { | ||||
| if (failed(verifyConstructionInvariants(loc, type))) | |||||
| if (failed(verify(loc, type))) | |||||
| { | { | ||||
| return TensorFlowRefType(); | return TensorFlowRefType(); | ||||
| } | } | ||||
| return get(type); | return get(type); | ||||
| } | } | ||||
| static LogicalResult verifyConstructionInvariants(Location loc, Type type) | |||||
| static LogicalResult verify(Location loc, Type type) | |||||
| { | { | ||||
| // type should be a valid TensorFlow type. | // type should be a valid TensorFlow type. | ||||
| if (!IsValidTFTensorType(type)) | if (!IsValidTFTensorType(type)) | ||||
| @@ -237,21 +237,27 @@ public: | |||||
| { | { | ||||
| return Base::getChecked(loc, subtypes); | return Base::getChecked(loc, subtypes); | ||||
| } | } | ||||
| static Derived getChecked(function_ref<InFlightDiagnostic()> emitError, | |||||
| MLIRContext* context, | |||||
| ArrayRef<TensorType> subtypes) | |||||
| { | |||||
| return Base::getChecked(emitError, context, subtypes); | |||||
| } | |||||
| static Derived get(MLIRContext* context) | static Derived get(MLIRContext* context) | ||||
| { | { | ||||
| return get({}, context); | return get({}, context); | ||||
| } | } | ||||
| static LogicalResult verifyConstructionInvariants( | |||||
| Location loc, ArrayRef<TensorType> subtypes) | |||||
| static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError, | |||||
| ArrayRef<TensorType> subtypes) | |||||
| { | { | ||||
| // Each of the subtypes should be a valid TensorFlow type. | // Each of the subtypes should be a valid TensorFlow type. | ||||
| for (TensorType subtype : subtypes) | for (TensorType subtype : subtypes) | ||||
| { | { | ||||
| if (!IsValidTFTensorType(subtype)) | if (!IsValidTFTensorType(subtype)) | ||||
| { | { | ||||
| return emitError(loc) << "invalid " << Derived::getTypeName() | |||||
| return emitError() << "invalid " << Derived::getTypeName() | |||||
| << " subtype: " << subtype; | << " subtype: " << subtype; | ||||
| } | } | ||||
| } | } | ||||
| @@ -328,7 +334,7 @@ mlir::Type GetCastCompatibleType(mlir::Type a, mlir::Type b, | |||||
| bool may_ignore_ref_type_a); | bool may_ignore_ref_type_a); | ||||
| // Returns whether two arrays of Type are broadcast compatible. | // Returns whether two arrays of Type are broadcast compatible. | ||||
| bool BroadcastCompatible(ArrayRef<Type> lhs, ArrayRef<Type> rhs); | |||||
| bool BroadcastCompatible(TypeRange lhs, TypeRange rhs); | |||||
| // Returns whether the two elemental types are compatible. Shapes are compatible | // Returns whether the two elemental types are compatible. Shapes are compatible | ||||
| // if: | // if: | ||||
| @@ -346,11 +352,11 @@ bool HasCompatibleElementTypes(Type lhs, Type rhs, | |||||
| // another. In other words, a single run-time value is legal for both the types. | // another. In other words, a single run-time value is legal for both the types. | ||||
| // For example, tensor<*xf32>, tensor<?xf32> and tensor<3xf32> are cast | // For example, tensor<*xf32>, tensor<?xf32> and tensor<3xf32> are cast | ||||
| // compatible. | // compatible. | ||||
| bool AreCastCompatible(ArrayRef<Type> types); | |||||
| bool AreCastCompatible(TypeRange types); | |||||
| // Returns true if corresponding elements of lhs and rhs AreCastCompatible and | // Returns true if corresponding elements of lhs and rhs AreCastCompatible and | ||||
| // lhs and rhs are the same length. | // lhs and rhs are the same length. | ||||
| bool ArraysAreCastCompatible(ArrayRef<Type> lhs, ArrayRef<Type> rhs); | |||||
| bool ArraysAreCastCompatible(TypeRange lhs, TypeRange rhs); | |||||
| // If `ty` is a tensor type and its element type has subtypes, then returns a | // If `ty` is a tensor type and its element type has subtypes, then returns a | ||||
| // new type of same shape but dropped subtypes for the element type. | // new type of same shape but dropped subtypes for the element type. | ||||