diff --git a/mlir/include/mlir/IR/BuiltinTypes.h b/mlir/include/mlir/IR/BuiltinTypes.h --- a/mlir/include/mlir/IR/BuiltinTypes.h +++ b/mlir/include/mlir/IR/BuiltinTypes.h @@ -29,119 +29,15 @@ namespace detail { struct BaseMemRefTypeStorage; -struct ComplexTypeStorage; -struct FunctionTypeStorage; -struct IntegerTypeStorage; struct MemRefTypeStorage; -struct OpaqueTypeStorage; struct RankedTensorTypeStorage; struct ShapedTypeStorage; -struct TupleTypeStorage; struct UnrankedMemRefTypeStorage; struct UnrankedTensorTypeStorage; struct VectorTypeStorage; } // namespace detail -//===----------------------------------------------------------------------===// -// ComplexType -//===----------------------------------------------------------------------===// - -/// The 'complex' type represents a complex number with a parameterized element -/// type, which is composed of a real and imaginary value of that element type. -/// -/// The element must be a floating point or integer scalar type. -/// -class ComplexType - : public Type::TypeBase { -public: - using Base::Base; - - /// Get or create a ComplexType with the provided element type. - static ComplexType get(Type elementType); - - /// Get or create a ComplexType with the provided element type. This emits - /// and error at the specified location and returns null if the element type - /// isn't supported. - static ComplexType getChecked(Location location, Type elementType); - - /// Verify the construction of an integer type. - static LogicalResult verifyConstructionInvariants(Location loc, - Type elementType); - - Type getElementType(); -}; - -//===----------------------------------------------------------------------===// -// IntegerType -//===----------------------------------------------------------------------===// - -/// Integer types can have arbitrary bitwidth up to a large fixed limit. -class IntegerType - : public Type::TypeBase { -public: - using Base::Base; - - /// Signedness semantics. - enum SignednessSemantics : uint32_t { - Signless, /// No signedness semantics - Signed, /// Signed integer - Unsigned, /// Unsigned integer - }; - - /// Get or create a new IntegerType of the given width within the context. - /// The created IntegerType is signless (i.e., no signedness semantics). - /// Assume the width is within the allowed range and assert on failures. Use - /// getChecked to handle failures gracefully. - static IntegerType get(MLIRContext *context, unsigned width); - - /// Get or create a new IntegerType of the given width within the context. - /// The created IntegerType has signedness semantics as indicated via - /// `signedness`. Assume the width is within the allowed range and assert on - /// failures. Use getChecked to handle failures gracefully. - static IntegerType get(MLIRContext *context, unsigned width, - SignednessSemantics signedness); - - /// Get or create a new IntegerType of the given width within the context, - /// defined at the given, potentially unknown, location. The created - /// IntegerType is signless (i.e., no signedness semantics). If the width is - /// outside the allowed range, emit errors and return a null type. - static IntegerType getChecked(Location location, unsigned width); - - /// Get or create a new IntegerType of the given width within the context, - /// defined at the given, potentially unknown, location. The created - /// IntegerType has signedness semantics as indicated via `signedness`. If the - /// width is outside the allowed range, emit errors and return a null type. - static IntegerType getChecked(Location location, unsigned width, - SignednessSemantics signedness); - - /// Verify the construction of an integer type. - static LogicalResult - verifyConstructionInvariants(Location loc, unsigned width, - SignednessSemantics signedness); - - /// Return the bitwidth of this integer type. - unsigned getWidth() const; - - /// Return the signedness semantics of this integer type. - SignednessSemantics getSignedness() const; - - /// Return true if this is a signless integer type. - bool isSignless() const { return getSignedness() == Signless; } - /// Return true if this is a signed integer type. - bool isSigned() const { return getSignedness() == Signed; } - /// Return true if this is an unsigned integer type. - bool isUnsigned() const { return getSignedness() == Unsigned; } - - /// Get or create a new IntegerType with the same signedness as `this` and a - /// bitwidth scaled by `scale`. - /// Return null if the scaled element type cannot be represented. - IntegerType scaleElementBitwidth(unsigned scale); - - /// Integer representation maximal bitwidth. - static constexpr unsigned kMaxWidth = (1 << 24) - 1; // Aligned with LLVM -}; - //===----------------------------------------------------------------------===// // FloatType //===----------------------------------------------------------------------===// @@ -170,68 +66,6 @@ const llvm::fltSemantics &getFloatSemantics(); }; -//===----------------------------------------------------------------------===// -// FunctionType -//===----------------------------------------------------------------------===// - -/// Function types map from a list of inputs to a list of results. -class FunctionType - : public Type::TypeBase { -public: - using Base::Base; - - static FunctionType get(MLIRContext *context, TypeRange inputs, - TypeRange results); - - /// Input types. - unsigned getNumInputs() const; - Type getInput(unsigned i) const { return getInputs()[i]; } - ArrayRef getInputs() const; - - /// Result types. - unsigned getNumResults() const; - Type getResult(unsigned i) const { return getResults()[i]; } - ArrayRef getResults() const; - - /// Returns a new function type without the specified arguments and results. - FunctionType getWithoutArgsAndResults(ArrayRef argIndices, - ArrayRef resultIndices); -}; - -//===----------------------------------------------------------------------===// -// OpaqueType -//===----------------------------------------------------------------------===// - -/// Opaque types represent types of non-registered dialects. These are types -/// represented in their raw string form, and can only usefully be tested for -/// type equality. -class OpaqueType - : public Type::TypeBase { -public: - using Base::Base; - - /// Get or create a new OpaqueType with the provided dialect and string data. - static OpaqueType get(MLIRContext *context, Identifier dialect, - StringRef typeData); - - /// Get or create a new OpaqueType with the provided dialect and string data. - /// If the given identifier is not a valid namespace for a dialect, then a - /// null type is returned. - static OpaqueType getChecked(Location location, Identifier dialect, - StringRef typeData); - - /// Returns the dialect namespace of the opaque type. - Identifier getDialectNamespace() const; - - /// Returns the raw type data of the opaque type. - StringRef getTypeData() const; - - /// Verify the construction of an opaque type. - static LogicalResult verifyConstructionInvariants(Location loc, - Identifier dialect, - StringRef typeData); -}; - //===----------------------------------------------------------------------===// // ShapedType //===----------------------------------------------------------------------===// @@ -444,9 +278,7 @@ using ShapedType::ShapedType; /// Return true if the specified element type is ok in a memref. - static bool isValidElementType(Type type) { - return type.isIntOrIndexOrFloat() || type.isa(); - } + static bool isValidElementType(Type type); /// Methods for support type inquiry through isa, cast, and dyn_cast. static bool classof(Type type); @@ -584,51 +416,6 @@ ArrayRef getShape() const { return llvm::None; } }; - -//===----------------------------------------------------------------------===// -// TupleType -//===----------------------------------------------------------------------===// - -/// Tuple types represent a collection of other types. Note: This type merely -/// provides a common mechanism for representing tuples in MLIR. It is up to -/// dialect authors to provides operations for manipulating them, e.g. -/// extract_tuple_element. When possible, users should prefer multi-result -/// operations in the place of tuples. -class TupleType - : public Type::TypeBase { -public: - using Base::Base; - - /// Get or create a new TupleType with the provided element types. Assumes the - /// arguments define a well-formed type. - static TupleType get(MLIRContext *context, TypeRange elementTypes); - - /// Get or create an empty tuple type. - static TupleType get(MLIRContext *context); - - /// Return the elements types for this tuple. - ArrayRef getTypes() const; - - /// Accumulate the types contained in this tuple and tuples nested within it. - /// Note that this only flattens nested tuples, not any other container type, - /// e.g. a tuple, tuple>> is flattened to - /// (i32, tensor, f32, i64) - void getFlattenedTypes(SmallVectorImpl &types); - - /// Return the number of held types. - size_t size() const; - - /// Iterate over the held elements. - using iterator = ArrayRef::iterator; - iterator begin() const { return getTypes().begin(); } - iterator end() const { return getTypes().end(); } - - /// Return the element type at index 'index'. - Type getType(size_t index) const { - assert(index < size() && "invalid index for tuple type"); - return getTypes()[index]; - } -}; } // end namespace mlir //===----------------------------------------------------------------------===// @@ -647,6 +434,10 @@ return type.isa(); } +inline bool BaseMemRefType::isValidElementType(Type type) { + return type.isIntOrIndexOrFloat() || type.isa(); +} + inline bool FloatType::classof(Type type) { return type.isa(); } diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td --- a/mlir/include/mlir/IR/BuiltinTypes.td +++ b/mlir/include/mlir/IR/BuiltinTypes.td @@ -25,6 +25,42 @@ let mnemonic = ?; } +//===----------------------------------------------------------------------===// +// ComplexType +//===----------------------------------------------------------------------===// + +def Builtin_Complex : Builtin_Type<"Complex"> { + let summary = "Complex number with a parameterized element type"; + let description = [{ + Syntax: + + ``` + complex-type ::= `complex` `<` type `>` + ``` + + The value of `complex` type represents a complex number with a parameterized + element type, which is composed of a real and imaginary value of that + element type. The element must be a floating point or integer scalar type. + + Examples: + + ```mlir + complex + complex + ``` + }]; + let parameters = (ins "Type":$elementType); + let builders = [ + TypeBuilderWithInferredContext<(ins "Type":$elementType), [{ + return Base::get(elementType.getContext(), elementType); + }], [{ + return Base::getChecked($_loc, elementType); + }]> + ]; + let skipDefaultBuilders = 1; + let genVerifyInvariantsDecl = 1; +} + //===----------------------------------------------------------------------===// // FloatType //===----------------------------------------------------------------------===// @@ -65,6 +101,48 @@ let summary = "64-bit floating-point type"; } +//===----------------------------------------------------------------------===// +// FunctionType +//===----------------------------------------------------------------------===// + +def Builtin_Function : Builtin_Type<"Function"> { + let summary = "Map from a list of inputs to a list of results"; + let description = [{ + Syntax: + + ``` + // Function types may have multiple results. + function-result-type ::= type-list-parens | non-function-type + function-type ::= type-list-parens `->` function-result-type + ``` + + The function type can be thought of as a function signature. It consists of + a list of formal parameter types and a list of formal result types. + ``` + }]; + let parameters = (ins "ArrayRef":$inputs, "ArrayRef":$results); + let builders = [ + TypeBuilder<(ins CArg<"TypeRange">:$inputs, CArg<"TypeRange">:$results), [{ + return Base::get($_ctxt, inputs, results); + }]> + ]; + let skipDefaultBuilders = 1; + let genStorageClass = 0; + let extraClassDeclaration = [{ + /// Input types. + unsigned getNumInputs() const; + Type getInput(unsigned i) const { return getInputs()[i]; } + + /// Result types. + unsigned getNumResults() const; + Type getResult(unsigned i) const { return getResults()[i]; } + + /// Returns a new function type without the specified arguments and results. + FunctionType getWithoutArgsAndResults(ArrayRef argIndices, + ArrayRef resultIndices); + }]; +} + //===----------------------------------------------------------------------===// // IndexType //===----------------------------------------------------------------------===// @@ -96,6 +174,70 @@ }]; } +//===----------------------------------------------------------------------===// +// IntegerType +//===----------------------------------------------------------------------===// + +def Builtin_Integer : Builtin_Type<"Integer"> { + let summary = "Integer type with arbitrary precision up to a fixed limit"; + let description = [{ + Syntax: + + ``` + // Sized integers like i1, i4, i8, i16, i32. + signed-integer-type ::= `si` [1-9][0-9]* + unsigned-integer-type ::= `ui` [1-9][0-9]* + signless-integer-type ::= `i` [1-9][0-9]* + integer-type ::= signed-integer-type | + unsigned-integer-type | + signless-integer-type + ``` + + Integer types have a designated bit width and may optionally have signedness + semantics. + + **Rationale:** low precision integers (like `i2`, `i4` etc) are useful for + low-precision inference chips, and arbitrary precision integers are useful + for hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller + than a 16 bit one). + }]; + let parameters = (ins "unsigned":$width, "SignednessSemantics":$signedness); + let builders = [ + TypeBuilder<(ins "unsigned":$width, + CArg<"SignednessSemantics", "Signless">:$signedness)> + ]; + + // IntegerType uses a special storage class that compacts parameters to save + // memory. + let genStorageClass = 0; + let skipDefaultBuilders = 1; + let genVerifyInvariantsDecl = 1; + let extraClassDeclaration = [{ + /// Signedness semantics. + enum SignednessSemantics : uint32_t { + Signless, /// No signedness semantics + Signed, /// Signed integer + Unsigned, /// Unsigned integer + }; + + /// Return true if this is a signless integer type. + bool isSignless() const { return getSignedness() == Signless; } + /// Return true if this is a signed integer type. + bool isSigned() const { return getSignedness() == Signed; } + /// Return true if this is an unsigned integer type. + bool isUnsigned() const { return getSignedness() == Unsigned; } + + /// Get or create a new IntegerType with the same signedness as `this` and a + /// bitwidth scaled by `scale`. + /// Return null if the scaled element type cannot be represented. + IntegerType scaleElementBitwidth(unsigned scale); + + /// Integer representation maximal bitwidth. + /// Note: This is aligned with the maximum width of llvm::IntegerType. + static constexpr unsigned kMaxWidth = (1 << 24) - 1; + }]; +} + //===----------------------------------------------------------------------===// // NoneType //===----------------------------------------------------------------------===// @@ -111,4 +253,102 @@ }]; } +//===----------------------------------------------------------------------===// +// OpaqueType +//===----------------------------------------------------------------------===// + +def Builtin_Opaque : Builtin_Type<"Opaque"> { + let summary = "Type of a non-registered dialect"; + let description = [{ + Syntax: + + ``` + opaque-type ::= `opaque` `<` type `>` + ``` + + Opaque types represent types of non-registered dialects. These are types + represented in their raw string form, and can only usefully be tested for + type equality. + + Examples: + + ```mlir + opaque<"llvm", "struct<(i32, float)>"> + opaque<"pdl", "value"> + ``` + }]; + let parameters = (ins + "Identifier":$dialectNamespace, + StringRefParameter<"">:$typeData + ); + let genVerifyInvariantsDecl = 1; +} + +//===----------------------------------------------------------------------===// +// TupleType +//===----------------------------------------------------------------------===// + +def Builtin_Tuple : Builtin_Type<"Tuple"> { + let summary = "Fixed-sized collection of other types"; + let description = [{ + Syntax: + + ``` + tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>` + ``` + + The value of `tuple` type represents a fixed-size collection of elements, + where each element may be of a different type. + + **Rationale:** Though this type is first class in the type system, MLIR + provides no standard operations for operating on `tuple` types + ([rationale](Rationale/Rationale.md#tuple-types)). + + Examples: + + ```mlir + // Empty tuple. + tuple<> + + // Single element + tuple + + // Many elements. + tuple, i5> + ``` + }]; + let parameters = (ins "ArrayRef":$types); + let builders = [ + TypeBuilder<(ins "TypeRange":$elementTypes), [{ + return Base::get($_ctxt, elementTypes); + }]>, + TypeBuilder<(ins), [{ + return Base::get($_ctxt, TypeRange()); + }]> + ]; + let skipDefaultBuilders = 1; + let genStorageClass = 0; + let extraClassDeclaration = [{ + /// Accumulate the types contained in this tuple and tuples nested within + /// it. Note that this only flattens nested tuples, not any other container + /// type, e.g. a tuple, tuple>> is + /// flattened to (i32, tensor, f32, i64) + void getFlattenedTypes(SmallVectorImpl &types); + + /// Return the number of held types. + size_t size() const; + + /// Iterate over the held elements. + using iterator = ArrayRef::iterator; + iterator begin() const { return getTypes().begin(); } + iterator end() const { return getTypes().end(); } + + /// Return the element type at index 'index'. + Type getType(size_t index) const { + assert(index < size() && "invalid index for tuple type"); + return getTypes()[index]; + } + }]; +} + #endif // BUILTIN_TYPES diff --git a/mlir/lib/IR/BuiltinTypes.cpp b/mlir/lib/IR/BuiltinTypes.cpp --- a/mlir/lib/IR/BuiltinTypes.cpp +++ b/mlir/lib/IR/BuiltinTypes.cpp @@ -31,14 +31,6 @@ /// ComplexType //===----------------------------------------------------------------------===// -ComplexType ComplexType::get(Type elementType) { - return Base::get(elementType.getContext(), elementType); -} - -ComplexType ComplexType::getChecked(Location location, Type elementType) { - return Base::getChecked(location, elementType); -} - /// Verify the construction of an integer type. LogicalResult ComplexType::verifyConstructionInvariants(Location loc, Type elementType) { @@ -47,8 +39,6 @@ return success(); } -Type ComplexType::getElementType() { return getImpl()->elementType; } - //===----------------------------------------------------------------------===// // Integer Type //===----------------------------------------------------------------------===// @@ -126,11 +116,6 @@ // FunctionType //===----------------------------------------------------------------------===// -FunctionType FunctionType::get(MLIRContext *context, TypeRange inputs, - TypeRange results) { - return Base::get(context, inputs, results); -} - unsigned FunctionType::getNumInputs() const { return getImpl()->numInputs; } ArrayRef FunctionType::getInputs() const { @@ -189,24 +174,6 @@ // OpaqueType //===----------------------------------------------------------------------===// -OpaqueType OpaqueType::get(MLIRContext *context, Identifier dialect, - StringRef typeData) { - return Base::get(context, dialect, typeData); -} - -OpaqueType OpaqueType::getChecked(Location location, Identifier dialect, - StringRef typeData) { - return Base::getChecked(location, dialect, typeData); -} - -/// Returns the dialect namespace of the opaque type. -Identifier OpaqueType::getDialectNamespace() const { - return getImpl()->dialectNamespace; -} - -/// Returns the raw type data of the opaque type. -StringRef OpaqueType::getTypeData() const { return getImpl()->typeData; } - /// Verify the construction of an opaque type. LogicalResult OpaqueType::verifyConstructionInvariants(Location loc, Identifier dialect, @@ -693,15 +660,6 @@ /// TupleType //===----------------------------------------------------------------------===// -/// Get or create a new TupleType with the provided element types. Assumes the -/// arguments define a well-formed type. -TupleType TupleType::get(MLIRContext *context, TypeRange elementTypes) { - return Base::get(context, elementTypes); -} - -/// Get or create an empty tuple type. -TupleType TupleType::get(MLIRContext *context) { return get(context, {}); } - /// Return the elements types for this tuple. ArrayRef TupleType::getTypes() const { return getImpl()->getTypes(); } @@ -721,6 +679,10 @@ /// Return the number of element types. size_t TupleType::size() const { return getImpl()->size(); } +//===----------------------------------------------------------------------===// +// Type Utilities +//===----------------------------------------------------------------------===// + AffineMap mlir::makeStridedLinearLayoutMap(ArrayRef strides, int64_t offset, MLIRContext *context) { diff --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp --- a/mlir/lib/IR/MLIRContext.cpp +++ b/mlir/lib/IR/MLIRContext.cpp @@ -772,10 +772,6 @@ } } -IntegerType IntegerType::get(MLIRContext *context, unsigned width) { - return get(context, width, IntegerType::Signless); -} - IntegerType IntegerType::get(MLIRContext *context, unsigned width, IntegerType::SignednessSemantics signedness) { if (auto cached = getCachedIntegerType(width, signedness, context)) @@ -783,10 +779,6 @@ return Base::get(context, width, signedness); } -IntegerType IntegerType::getChecked(Location location, unsigned width) { - return getChecked(location, width, IntegerType::Signless); -} - IntegerType IntegerType::getChecked(Location location, unsigned width, SignednessSemantics signedness) { if (auto cached = diff --git a/mlir/lib/IR/TypeDetail.h b/mlir/lib/IR/TypeDetail.h --- a/mlir/lib/IR/TypeDetail.h +++ b/mlir/lib/IR/TypeDetail.h @@ -27,31 +27,6 @@ namespace detail { -/// Opaque Type Storage and Uniquing. -struct OpaqueTypeStorage : public TypeStorage { - OpaqueTypeStorage(Identifier dialectNamespace, StringRef typeData) - : dialectNamespace(dialectNamespace), typeData(typeData) {} - - /// The hash key used for uniquing. - using KeyTy = std::pair; - bool operator==(const KeyTy &key) const { - return key == KeyTy(dialectNamespace, typeData); - } - - static OpaqueTypeStorage *construct(TypeStorageAllocator &allocator, - const KeyTy &key) { - StringRef tyData = allocator.copyInto(key.second); - return new (allocator.allocate()) - OpaqueTypeStorage(key.first, tyData); - } - - // The dialect namespace. - Identifier dialectNamespace; - - // The parser type data for this opaque type. - StringRef typeData; -}; - /// Integer Type Storage and Uniquing. struct IntegerTypeStorage : public TypeStorage { IntegerTypeStorage(unsigned width, @@ -290,24 +265,6 @@ } }; -/// Complex Type Storage. -struct ComplexTypeStorage : public TypeStorage { - ComplexTypeStorage(Type elementType) : elementType(elementType) {} - - /// The hash key used for uniquing. - using KeyTy = Type; - bool operator==(const KeyTy &key) const { return key == elementType; } - - /// Construction. - static ComplexTypeStorage *construct(TypeStorageAllocator &allocator, - Type elementType) { - return new (allocator.allocate()) - ComplexTypeStorage(elementType); - } - - Type elementType; -}; - /// A type representing a collection of other types. struct TupleTypeStorage final : public TypeStorage,