1//===- DataLayoutInterfaces.td - Data layout 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// Defines the interfaces for the data layout specification, operations to which
10// they can be attached, and types that are subject to data layout.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_DATALAYOUTINTERFACES
15#define MLIR_DATALAYOUTINTERFACES
16
17include "mlir/IR/OpBase.td"
18
19//===----------------------------------------------------------------------===//
20// Attribute interfaces
21//===----------------------------------------------------------------------===//
22
23def DataLayoutEntryInterface : AttrInterface<"DataLayoutEntryInterface"> {
24  let cppNamespace = "::mlir";
25
26  let description = [{
27    Attribute interface describing an entry in a data layout specification.
28
29    A data layout specification entry is a key-value pair. Its key is either a
30    type, when the entry is related to a type or a class of types, or an
31    identifier, when it is not. `DataLayoutEntryKey` is an alias allowing one
32    to use both key types. Its value is an arbitrary attribute that is
33    interpreted either by the type for type keys or by the dialect containing
34    the identifier for identifier keys. The interface provides a hook that
35    can be used by specific implementations to delegate the verification of
36    attribute fitness for a particular key to the relevant type or dialect.
37  }];
38
39  let methods = [
40    InterfaceMethod<
41      /*description=*/"Returns the key of the this layout entry.",
42      /*retTy=*/"::mlir::DataLayoutEntryKey",
43      /*methodName=*/"getKey",
44      /*args=*/(ins)
45    >,
46    InterfaceMethod<
47      /*description=*/"Returns the value of this layout entry.",
48      /*retTy=*/"::mlir::Attribute",
49      /*methodName=*/"getValue",
50      /*args=*/(ins)
51    >,
52    InterfaceMethod<
53      /*description=*/"Checks that the entry is well-formed, reports errors "
54                      "at the provided location.",
55      /*retTy=*/"::mlir::LogicalResult",
56      /*methodName=*/"verifyEntry",
57      /*args=*/(ins "::mlir::Location":$loc),
58      /*methodBody=*/"",
59      /*defaultImplementation=*/[{ return ::mlir::success(); }]
60    >
61  ];
62
63  let extraClassDeclaration = [{
64    /// Returns `true` if the key of this entry is a type.
65    bool isTypeEntry() {
66      return getKey().is<::mlir::Type>();
67    }
68  }];
69}
70
71def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
72  let cppNamespace = "::mlir";
73
74  let description = [{
75    Attribute interface describing a data layout specification.
76
77    A data layout specification is seen as a sequence of entries, each of which
78    is an attribute implementing the data layout entry interface. It assumes
79    a contiguous underlying storage for entries. The interface provides a hook
80    for implementations to verify the well-formedness of the specification,
81    with a default implementation that verifies the absence of entries with
82    duplicate keys and the well-formedness of each individual entry before
83    dispatching to the type or dialect the entry is associated with.
84
85    Data layout specifications may need to be combined in case they appear on
86    nested operations subject to layout, or to ensure the validity of layout
87    modification. Concrete specification attributes must implement the
88    corresponding hook.
89  }];
90  // The underlying storage being contiguous may be revised in the future, but
91  // care must be taken to avoid materializing or copying the entire list of
92  // entries.
93
94  let methods = [
95    InterfaceMethod<
96      /*description=*/"Combines the current layout with the given list of "
97                      "layouts, provided from the outermost (oldest) to the "
98                      "innermost (newest). Returns null on failure.",
99      /*retTy=*/"::mlir::DataLayoutSpecInterface",
100      /*methodName=*/"combineWith",
101      /*args=*/(ins "::llvm::ArrayRef<::mlir::DataLayoutSpecInterface>":$specs)
102    >,
103    InterfaceMethod<
104      /*description=*/"Returns the list of layout entries.",
105      /*retTy=*/"::mlir::DataLayoutEntryListRef",
106      /*methodName=*/"getEntries",
107      /*args=*/(ins)
108    >,
109    // Implementations may override this if they have an efficient lookup
110    // mechanism.
111    InterfaceMethod<
112      /*description=*/"Returns a copy of the entries related to a specific "
113                      "type class regardles of type parameters. ",
114      /*retTy=*/"::mlir::DataLayoutEntryList",
115      /*methodName=*/"getSpecForType",
116      /*args=*/(ins "::mlir::TypeID":$type),
117      /*methodBody=*/"",
118      /*defaultImplementation=*/[{
119        return ::mlir::detail::filterEntriesForType($_attr.getEntries(), type);
120      }]
121    >,
122    // Implementations may override this if they have an efficient lookup
123    // mechanism.
124    InterfaceMethod<
125      /*description=*/"Returns the entry related to the given identifier, if "
126                      "present.",
127      /*retTy=*/"::mlir::DataLayoutEntryInterface",
128      /*methodName=*/"getSpecForIdentifier",
129      /*args=*/(ins "::mlir::StringAttr":$identifier),
130      /*methodBody=*/"",
131      /*defaultImplementation=*/[{
132        return ::mlir::detail::filterEntryForIdentifier($_attr.getEntries(),
133                                                        identifier);
134      }]
135    >,
136    InterfaceMethod<
137      /*description=*/"Verifies the validity of the specification and reports "
138                      "any errors at the given location.",
139      /*retTy=*/"::mlir::LogicalResult",
140      /*methodName=*/"verifySpec",
141      /*args=*/(ins "::mlir::Location":$loc),
142      /*methodBody=*/"",
143      /*defaultImplementation=*/[{
144        return ::mlir::detail::verifyDataLayoutSpec($_attr, loc);
145      }]
146    >,
147  ];
148
149  let extraClassDeclaration = [{
150    /// Returns a copy of the entries related to the type specified as template
151    /// parameter.
152    template <typename Ty>
153    DataLayoutEntryList getSpecForType() {
154      return getSpecForType(TypeID::get<Ty>());
155    }
156
157    /// Populates the given maps with lists of entries grouped by the type or
158    /// identifier they are associated with. Users are not expected to call this
159    /// method directly.
160    void bucketEntriesByType(
161        ::llvm::DenseMap<::mlir::TypeID, ::mlir::DataLayoutEntryList> &types,
162        ::llvm::DenseMap<::mlir::StringAttr,
163                         ::mlir::DataLayoutEntryInterface> &ids);
164  }];
165}
166
167//===----------------------------------------------------------------------===//
168// Operation interface
169//===----------------------------------------------------------------------===//
170
171def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
172  let cppNamespace = "::mlir";
173
174  let description = [{
175    Interface for operations that can have a data layout specification attached.
176
177    The `DataLayout` object, which can be used for data layout queries, can be
178    constructed for such operations. The absence of a data layout specification
179    must be handled without failing.
180
181    Concrete operations must implement the hook returning the data layout
182    specification. They may optionally override the methods used in data layout
183    queries, default implementations of which provide predefined answers for
184    built-in types and dispatch to the type interface for all other types. These
185    methods must be idempotent, that is return the same result on repeated
186    queries with the same parameters. They are declared static and therefore
187    have no access to the operation or its attributes. Instead, they receive a
188    list of data layout entries relevant to the request. The entries are known
189    to have passed the spec and entry verifier.
190  }];
191
192  let methods = [
193    InterfaceMethod<
194      /*description=*/"Returns the data layout specification for this op, or "
195                      "null if it does not exist.",
196      /*retTy=*/"::mlir::DataLayoutSpecInterface",
197      /*methodName=*/"getDataLayoutSpec",
198      /*args=*/(ins)
199    >,
200    StaticInterfaceMethod<
201      /*description=*/"Returns the size of the given type computed using the "
202                      "relevant entries. The data layout object can be used "
203                      "for recursive queries.",
204      /*retTy=*/"unsigned",
205      /*methodName=*/"getTypeSize",
206      /*args=*/(ins "::mlir::Type":$type,
207                    "const ::mlir::DataLayout &":$dataLayout,
208                    "::mlir::DataLayoutEntryListRef":$params),
209      /*methodBody=*/"",
210      /*defaultImplementation=*/[{
211        unsigned bits = ConcreteOp::getTypeSizeInBits(type, dataLayout, params);
212        return ::llvm::divideCeil(bits, 8);
213      }]
214    >,
215    StaticInterfaceMethod<
216      /*description=*/"Returns the size of the given type in bits computed "
217                      "using the relevant entries. The data layout object can "
218                      "be used for recursive queries.",
219      /*retTy=*/"unsigned",
220      /*methodName=*/"getTypeSizeInBits",
221      /*args=*/(ins "::mlir::Type":$type,
222                    "const ::mlir::DataLayout &":$dataLayout,
223                    "::mlir::DataLayoutEntryListRef":$params),
224      /*methodBody=*/"",
225      /*defaultImplementation=*/[{
226        return ::mlir::detail::getDefaultTypeSizeInBits(type, dataLayout,
227                                                        params);
228      }]
229    >,
230    StaticInterfaceMethod<
231      /*description=*/"Returns the alignment required by the ABI for the given "
232                      "type computed using the relevant entries. The data "
233                      "layout object can be used for recursive queries.",
234      /*retTy=*/"unsigned",
235      /*methodName=*/"getTypeABIAlignment",
236      /*args=*/(ins "::mlir::Type":$type,
237                    "const ::mlir::DataLayout &":$dataLayout,
238                    "::mlir::DataLayoutEntryListRef":$params),
239      /*methodBody=*/"",
240      /*defaultImplementation=*/[{
241        return ::mlir::detail::getDefaultABIAlignment(type, dataLayout, params);
242      }]
243    >,
244    StaticInterfaceMethod<
245      /*description=*/"Returns the alignment preferred by the given type "
246                      "computed using the relevant entries. The data layout"
247                      "object can be used for recursive queries.",
248      /*retTy=*/"unsigned",
249      /*methodName=*/"getTypePreferredAlignment",
250      /*args=*/(ins "::mlir::Type":$type,
251                    "const ::mlir::DataLayout &":$dataLayout,
252                    "::mlir::DataLayoutEntryListRef":$params),
253      /*methodBody=*/"",
254      /*defaultImplementation=*/[{
255        return ::mlir::detail::getDefaultPreferredAlignment(type, dataLayout,
256                                                            params);
257      }]
258    >,
259  ];
260
261  let verify = [{ return ::mlir::detail::verifyDataLayoutOp($_op); }];
262}
263
264//===----------------------------------------------------------------------===//
265// Type interface
266//===----------------------------------------------------------------------===//
267
268def DataLayoutTypeInterface : TypeInterface<"DataLayoutTypeInterface"> {
269  let cppNamespace = "::mlir";
270
271  let description = [{
272    Interface for types subject to data layout.
273
274    Types willing to be supported by the data layout subsystem should implement
275    this interface by providing implementations of functions querying their
276    size, required and preferred alignment. Each of these functions accepts as
277    arguments a data layout object that can be used to perform recursive queries
278    in the same scope, and a list of data layout entries relevant to this type.
279    Specifically, the entries are those that have as key _any instance_ of the
280    same type class as the current type. For example, if IntegerType had
281    implemented this interface, it would have received the entries with keys i1,
282    i2, i8, etc. regardless of the bitwidth of this type. This mechanism allows
283    types to "interpolate" the results in a type-specific way instead of listing
284    all possible types in the specification.
285
286    The list of entries may be empty, in which case the type must provide a
287    reasonable default value. The entries in the list are known to have passed
288    the spec and the entry verifiers, as well as the type-specified verifier if
289    provided.
290
291    In case of nested layout specs or spec changes, the type can override a hook
292    indicating whether the outer (old) and the inner (new) spec are compatible.
293  }];
294
295  let methods = [
296    InterfaceMethod<
297      /*description=*/"Returns the size of this type in bytes.",
298      /*retTy=*/"unsigned",
299      /*methodName=*/"getTypeSize",
300      /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
301                    "::mlir::DataLayoutEntryListRef":$params),
302      /*methodBody=*/"",
303      /*defaultImplementation=*/[{
304        unsigned bits = $_type.getTypeSizeInBits(dataLayout, params);
305        return ::llvm::divideCeil(bits, 8);
306      }]
307    >,
308    InterfaceMethod<
309      /*description=*/"Returns the size of this type in bits.",
310      /*retTy=*/"unsigned",
311      /*methodName=*/"getTypeSizeInBits",
312      /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
313                    "::mlir::DataLayoutEntryListRef":$params)
314    >,
315    InterfaceMethod<
316      /*description=*/"Returns the ABI-required alignment for this type, "
317                      "in bytes",
318      /*retTy=*/"unsigned",
319      /*methodName=*/"getABIAlignment",
320      /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
321                    "::mlir::DataLayoutEntryListRef":$params)
322    >,
323    InterfaceMethod<
324      /*description=*/"Returns the preferred alignment for this type, "
325                      "in bytes.",
326      /*retTy=*/"unsigned",
327      /*methodName=*/"getPreferredAlignment",
328      /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
329                    "::mlir::DataLayoutEntryListRef":$params)
330    >,
331    InterfaceMethod<
332      /*desc=*/"Returns true if the two lists of entries are compatible, that "
333               "is, that `newLayout` spec entries can be nested in an op with "
334               "`oldLayout` spec entries.",
335      /*retTy=*/"bool",
336      /*methodName=*/"areCompatible",
337      /*args=*/(ins "::mlir::DataLayoutEntryListRef":$oldLayout,
338                    "::mlir::DataLayoutEntryListRef":$newLayout),
339      /*methodBody=*/"",
340      /*defaultImplementation=*/[{ return true; }]
341    >,
342    InterfaceMethod<
343      /*description=*/"Verifies that the given list of entries is valid for "
344                      "this type.",
345      /*retTy=*/"::mlir::LogicalResult",
346      /*methodName=*/"verifyEntries",
347      /*args=*/(ins "::mlir::DataLayoutEntryListRef":$entries,
348                    "::mlir::Location":$loc),
349      /*methodBody=*/"",
350      /*defaultImplementation=*/[{ return ::mlir::success(); }]
351    >,
352  ];
353}
354
355#endif // MLIR_DATALAYOUTINTERFACES
356