xref: /llvm-project/mlir/include/mlir/IR/BuiltinTypeInterfaces.td (revision f023da12d12635f5fba436e825cbfc999e28e623)
1//===- BuiltinTypeInterfaces.td - Builtin type interfaces --*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains definitions for type interfaces that closely interact with
10// attributes, types, and operations in the builtin dialect.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_IR_BUILTINTYPEINTERFACES_TD_
15#define MLIR_IR_BUILTINTYPEINTERFACES_TD_
16
17include "mlir/IR/OpBase.td"
18
19def FloatTypeInterface : TypeInterface<"FloatType"> {
20  let cppNamespace = "::mlir";
21  let description = [{
22    This type interface should be implemented by all floating-point types. It
23    defines the LLVM APFloat semantics and provides a few helper functions.
24  }];
25
26  let methods = [
27    InterfaceMethod<
28      /*desc=*/[{
29        Returns the APFloat semantics for this floating-point type.
30      }],
31      /*retTy=*/"const ::llvm::fltSemantics &",
32      /*methodName=*/"getFloatSemantics",
33      /*args=*/(ins)
34    >,
35    InterfaceMethod<
36      /*desc=*/[{
37        Returns a float type with bitwidth scaled by `scale`. Returns a "null"
38        float type if the scaled element type cannot be represented.
39      }],
40      /*retTy=*/"::mlir::FloatType",
41      /*methodName=*/"scaleElementBitwidth",
42      /*args=*/(ins "unsigned":$scale),
43      /*methodBody=*/"",
44      /*defaultImplementation=*/"return ::mlir::FloatType();"
45    >
46  ];
47
48  let extraClassDeclaration = [{
49    /// Return the bitwidth of this float type.
50    unsigned getWidth();
51
52    /// Return the width of the mantissa of this type.
53    /// The width includes the integer bit.
54    unsigned getFPMantissaWidth();
55  }];
56}
57
58//===----------------------------------------------------------------------===//
59// MemRefElementTypeInterface
60//===----------------------------------------------------------------------===//
61
62def MemRefElementTypeInterface : TypeInterface<"MemRefElementTypeInterface"> {
63  let cppNamespace = "::mlir";
64  let description = [{
65    Indication that this type can be used as element in memref types.
66
67    Implementing this interface establishes a contract between this type and the
68    memref type indicating that this type can be used as element of ranked or
69    unranked memrefs. The type is expected to:
70
71      - model an entity stored in memory;
72      - have non-zero size.
73
74    For example, scalar values such as integers can implement this interface,
75    but indicator types such as `void` or `unit` should not.
76
77    The interface currently has no methods and is used by types to opt into
78    being memref elements. This may change in the future, in particular to
79    require types to provide their size or alignment given a data layout.
80  }];
81}
82
83//===----------------------------------------------------------------------===//
84// ShapedType
85//===----------------------------------------------------------------------===//
86
87def ShapedTypeInterface : TypeInterface<"ShapedType"> {
88  let cppNamespace = "::mlir";
89  let description = [{
90    This interface provides a common API for interacting with multi-dimensional
91    container types. These types contain a shape and an element type.
92
93    A shape is a list of sizes corresponding to the dimensions of the container.
94    If the number of dimensions in the shape is unknown, the shape is "unranked".
95    If the number of dimensions is known, the shape "ranked". The sizes of the
96    dimensions of the shape must be positive, or kDynamic (in which case the
97    size of the dimension is dynamic, or not statically known).
98  }];
99  let methods = [
100    InterfaceMethod<[{
101      Returns a clone of this type with the given shape and element type.
102
103      If no shape is provided, the shape of this type is used. In that case, if
104      this type is unranked, so is the resulting type.
105
106      If a shape is provided, the resulting type is always ranked, even if this
107      type is unranked.
108    }],
109    "::mlir::ShapedType", "cloneWith", (ins
110      "::std::optional<::llvm::ArrayRef<int64_t>>":$shape,
111      "::mlir::Type":$elementType
112    )>,
113
114    InterfaceMethod<[{
115      Returns the element type of this shaped type.
116    }],
117    "::mlir::Type", "getElementType">,
118
119    InterfaceMethod<[{
120      Returns if this type is ranked, i.e. it has a known number of dimensions.
121    }],
122    "bool", "hasRank">,
123
124    InterfaceMethod<[{
125      Returns the shape of this type if it is ranked, otherwise asserts.
126    }],
127    "::llvm::ArrayRef<int64_t>", "getShape">,
128  ];
129
130  let extraClassDeclaration = [{
131    static constexpr int64_t kDynamic =
132        std::numeric_limits<int64_t>::min();
133
134    /// Whether the given dimension size indicates a dynamic dimension.
135    static constexpr bool isDynamic(int64_t dValue) {
136      return dValue == kDynamic;
137    }
138
139    /// Whether the given shape has any size that indicates a dynamic dimension.
140    static bool isDynamicShape(ArrayRef<int64_t> dSizes) {
141      return any_of(dSizes, [](int64_t dSize) { return isDynamic(dSize); });
142    }
143
144    /// Return the number of elements present in the given shape.
145    static int64_t getNumElements(ArrayRef<int64_t> shape);
146
147    /// Return a clone of this type with the given new shape and element type.
148    /// The returned type is ranked, even if this type is unranked.
149    auto clone(::llvm::ArrayRef<int64_t> shape, Type elementType) {
150      return cloneWith(shape, elementType);
151    }
152
153    /// Return a clone of this type with the given new shape. The returned type
154    /// is ranked, even if this type is unranked.
155    auto clone(::llvm::ArrayRef<int64_t> shape) {
156      return cloneWith(shape, getElementType());
157    }
158  }];
159
160  let extraSharedClassDeclaration = [{
161    /// Return a clone of this type with the given new element type. The
162    /// returned type is ranked if and only if this type is ranked. In that
163    /// case, the returned type has the same shape as this type.
164    auto clone(::mlir::Type elementType) {
165      return $_type.cloneWith(/*shape=*/std::nullopt, elementType);
166    }
167
168    /// If an element type is an integer or a float, return its width. Otherwise,
169    /// abort.
170    unsigned getElementTypeBitWidth() const {
171      return $_type.getElementType().getIntOrFloatBitWidth();
172    }
173
174    /// If this is a ranked type, return the rank. Otherwise, abort.
175    int64_t getRank() const {
176      assert($_type.hasRank() && "cannot query rank of unranked shaped type");
177      return $_type.getShape().size();
178    }
179
180    /// If it has static shape, return the number of elements. Otherwise, abort.
181    int64_t getNumElements() const {
182      assert(hasStaticShape() && "cannot get element count of dynamic shaped type");
183      return ::mlir::ShapedType::getNumElements($_type.getShape());
184    }
185
186    /// Returns true if this dimension has a dynamic size (for ranked types);
187    /// aborts for unranked types.
188    bool isDynamicDim(unsigned idx) const {
189      assert(idx < getRank() && "invalid index for shaped type");
190      return ::mlir::ShapedType::isDynamic($_type.getShape()[idx]);
191    }
192
193    /// Returns if this type has a static shape, i.e. if the type is ranked and
194    /// all dimensions have known size (>= 0).
195    bool hasStaticShape() const {
196      return $_type.hasRank() &&
197             !::mlir::ShapedType::isDynamicShape($_type.getShape());
198    }
199
200    /// Returns if this type has a static shape and the shape is equal to
201    /// `shape` return true.
202    bool hasStaticShape(::llvm::ArrayRef<int64_t> shape) const {
203      return hasStaticShape() && $_type.getShape() == shape;
204    }
205
206    /// If this is a ranked type, return the number of dimensions with dynamic
207    /// size. Otherwise, abort.
208    size_t getNumDynamicDims() const {
209      return llvm::count_if($_type.getShape(), ::mlir::ShapedType::isDynamic);
210    }
211
212    /// If this is ranked type, return the size of the specified dimension.
213    /// Otherwise, abort.
214    int64_t getDimSize(unsigned idx) const {
215      assert(idx < getRank() && "invalid index for shaped type");
216      return $_type.getShape()[idx];
217    }
218
219    /// Returns the position of the dynamic dimension relative to just the dynamic
220    /// dimensions, given its `index` within the shape.
221    unsigned getDynamicDimIndex(unsigned index) const {
222      assert(index < getRank() && "invalid index");
223      assert(::mlir::ShapedType::isDynamic(getDimSize(index)) && "invalid index");
224      return llvm::count_if($_type.getShape().take_front(index),
225                            ::mlir::ShapedType::isDynamic);
226    }
227  }];
228}
229
230#endif // MLIR_IR_BUILTINTYPEINTERFACES_TD_
231