1 | //===- DataLayoutInterfaces.h - Data Layout Interface Decls -----*- C++ -*-===// |
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, types subject to data layout and dialects containing |
11 | // data layout entries. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef MLIR_INTERFACES_DATALAYOUTINTERFACES_H |
16 | #define MLIR_INTERFACES_DATALAYOUTINTERFACES_H |
17 | |
18 | #include "mlir/IR/DialectInterface.h" |
19 | #include "mlir/IR/OpDefinition.h" |
20 | #include "llvm/ADT/DenseMap.h" |
21 | #include "llvm/Support/TypeSize.h" |
22 | |
23 | namespace mlir { |
24 | class DataLayout; |
25 | class DataLayoutEntryInterface; |
26 | using DataLayoutEntryKey = llvm::PointerUnion<Type, StringAttr>; |
27 | // Using explicit SmallVector size because we cannot infer the size from the |
28 | // forward declaration, and we need the typedef in the actual declaration. |
29 | using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>; |
30 | using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>; |
31 | class DataLayoutOpInterface; |
32 | class DataLayoutSpecInterface; |
33 | class ModuleOp; |
34 | |
35 | namespace detail { |
36 | /// Default handler for the type size request. Computes results for built-in |
37 | /// types and dispatches to the DataLayoutTypeInterface for other types. |
38 | llvm::TypeSize getDefaultTypeSize(Type type, const DataLayout &dataLayout, |
39 | DataLayoutEntryListRef params); |
40 | |
41 | /// Default handler for the type size in bits request. Computes results for |
42 | /// built-in types and dispatches to the DataLayoutTypeInterface for other |
43 | /// types. |
44 | llvm::TypeSize getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout, |
45 | DataLayoutEntryListRef params); |
46 | |
47 | /// Default handler for the required alignment request. Computes results for |
48 | /// built-in types and dispatches to the DataLayoutTypeInterface for other |
49 | /// types. |
50 | uint64_t getDefaultABIAlignment(Type type, const DataLayout &dataLayout, |
51 | ArrayRef<DataLayoutEntryInterface> params); |
52 | |
53 | /// Default handler for the preferred alignment request. Computes results for |
54 | /// built-in types and dispatches to the DataLayoutTypeInterface for other |
55 | /// types. |
56 | uint64_t |
57 | getDefaultPreferredAlignment(Type type, const DataLayout &dataLayout, |
58 | ArrayRef<DataLayoutEntryInterface> params); |
59 | |
60 | /// Default handler for the index bitwidth request. Computes the result for |
61 | /// the built-in index type and dispatches to the DataLayoutTypeInterface for |
62 | /// other types. |
63 | std::optional<uint64_t> |
64 | getDefaultIndexBitwidth(Type type, const DataLayout &dataLayout, |
65 | ArrayRef<DataLayoutEntryInterface> params); |
66 | |
67 | /// Default handler for endianness request. Dispatches to the |
68 | /// DataLayoutInterface if specified, otherwise returns the default. |
69 | Attribute getDefaultEndianness(DataLayoutEntryInterface entry); |
70 | |
71 | /// Default handler for alloca memory space request. Dispatches to the |
72 | /// DataLayoutInterface if specified, otherwise returns the default. |
73 | Attribute getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry); |
74 | |
75 | /// Default handler for program memory space request. Dispatches to the |
76 | /// DataLayoutInterface if specified, otherwise returns the default. |
77 | Attribute getDefaultProgramMemorySpace(DataLayoutEntryInterface entry); |
78 | |
79 | /// Default handler for global memory space request. Dispatches to the |
80 | /// DataLayoutInterface if specified, otherwise returns the default. |
81 | Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry); |
82 | |
83 | /// Default handler for the stack alignment request. Dispatches to the |
84 | /// DataLayoutInterface if specified, otherwise returns the default. |
85 | uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry); |
86 | |
87 | /// Given a list of data layout entries, returns a new list containing the |
88 | /// entries with keys having the given type ID, i.e. belonging to the same type |
89 | /// class. |
90 | DataLayoutEntryList filterEntriesForType(DataLayoutEntryListRef entries, |
91 | TypeID typeID); |
92 | |
93 | /// Given a list of data layout entries, returns the entry that has the given |
94 | /// identifier as key, if such an entry exists in the list. |
95 | DataLayoutEntryInterface |
96 | filterEntryForIdentifier(DataLayoutEntryListRef entries, StringAttr id); |
97 | |
98 | /// Verifies that the operation implementing the data layout interface, or a |
99 | /// module operation, is valid. This calls the verifier of the spec attribute |
100 | /// and checks if the layout is compatible with specs attached to the enclosing |
101 | /// operations. |
102 | LogicalResult verifyDataLayoutOp(Operation *op); |
103 | |
104 | /// Verifies that a data layout spec is valid. This dispatches to individual |
105 | /// entry verifiers, and then to the verifiers implemented by the relevant type |
106 | /// and dialect interfaces for type and identifier keys respectively. |
107 | LogicalResult verifyDataLayoutSpec(DataLayoutSpecInterface spec, Location loc); |
108 | |
109 | /// Divides the known min value of the numerator by the denominator and rounds |
110 | /// the result up to the next integer. Preserves the scalable flag. |
111 | llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator); |
112 | } // namespace detail |
113 | } // namespace mlir |
114 | |
115 | #include "mlir/Interfaces/DataLayoutAttrInterface.h.inc" |
116 | #include "mlir/Interfaces/DataLayoutOpInterface.h.inc" |
117 | #include "mlir/Interfaces/DataLayoutTypeInterface.h.inc" |
118 | |
119 | namespace mlir { |
120 | |
121 | //===----------------------------------------------------------------------===// |
122 | // DataLayoutDialectInterface |
123 | //===----------------------------------------------------------------------===// |
124 | |
125 | /// An interface to be implemented by dialects that can have identifiers in the |
126 | /// data layout specification entries. Provides hooks for verifying the entry |
127 | /// validity and combining two entries. |
128 | class DataLayoutDialectInterface |
129 | : public DialectInterface::Base<DataLayoutDialectInterface> { |
130 | public: |
131 | DataLayoutDialectInterface(Dialect *dialect) : Base(dialect) {} |
132 | |
133 | /// Checks whether the given data layout entry is valid and reports any errors |
134 | /// at the provided location. Derived classes should override this. |
135 | virtual LogicalResult verifyEntry(DataLayoutEntryInterface entry, |
136 | Location loc) const { |
137 | return success(); |
138 | } |
139 | |
140 | /// Default implementation of entry combination that combines identical |
141 | /// entries and returns null otherwise. |
142 | static DataLayoutEntryInterface |
143 | defaultCombine(DataLayoutEntryInterface outer, |
144 | DataLayoutEntryInterface inner) { |
145 | if (!outer || outer == inner) |
146 | return inner; |
147 | return {}; |
148 | } |
149 | |
150 | /// Combines two entries with identifiers that belong to this dialect. Returns |
151 | /// the combined entry or null if the entries are not compatible. Derived |
152 | /// classes likely need to reimplement this. |
153 | virtual DataLayoutEntryInterface |
154 | combine(DataLayoutEntryInterface outer, |
155 | DataLayoutEntryInterface inner) const { |
156 | return defaultCombine(outer, inner); |
157 | } |
158 | }; |
159 | |
160 | //===----------------------------------------------------------------------===// |
161 | // DataLayout |
162 | //===----------------------------------------------------------------------===// |
163 | |
164 | /// The main mechanism for performing data layout queries. Instances of this |
165 | /// class can be created for an operation implementing DataLayoutOpInterface. |
166 | /// Upon construction, a layout spec combining that of the given operation with |
167 | /// all its ancestors will be computed and used to handle further requests. For |
168 | /// efficiency, results to all requests will be cached in this object. |
169 | /// Therefore, if the data layout spec for the scoping operation, or any of the |
170 | /// enclosing operations, changes, the cache is no longer valid. The user is |
171 | /// responsible creating a new DataLayout object after any spec change. In debug |
172 | /// mode, the cache validity is being checked in every request. |
173 | class DataLayout { |
174 | public: |
175 | explicit DataLayout(); |
176 | explicit DataLayout(DataLayoutOpInterface op); |
177 | explicit DataLayout(ModuleOp op); |
178 | |
179 | /// Returns the layout of the closest parent operation carrying layout info. |
180 | static DataLayout closest(Operation *op); |
181 | |
182 | /// Returns the size of the given type in the current scope. |
183 | llvm::TypeSize getTypeSize(Type t) const; |
184 | |
185 | /// Returns the size in bits of the given type in the current scope. |
186 | llvm::TypeSize getTypeSizeInBits(Type t) const; |
187 | |
188 | /// Returns the required alignment of the given type in the current scope. |
189 | uint64_t getTypeABIAlignment(Type t) const; |
190 | |
191 | /// Returns the preferred of the given type in the current scope. |
192 | uint64_t getTypePreferredAlignment(Type t) const; |
193 | |
194 | /// Returns the bitwidth that should be used when performing index |
195 | /// computations for the given pointer-like type in the current scope. If the |
196 | /// type is not a pointer-like type, it returns std::nullopt. |
197 | std::optional<uint64_t> getTypeIndexBitwidth(Type t) const; |
198 | |
199 | /// Returns the specified endianness. |
200 | Attribute getEndianness() const; |
201 | |
202 | /// Returns the memory space used for AllocaOps. |
203 | Attribute getAllocaMemorySpace() const; |
204 | |
205 | /// Returns the memory space used for program memory operations. |
206 | Attribute getProgramMemorySpace() const; |
207 | |
208 | /// Returns the memory space used for global operations. |
209 | Attribute getGlobalMemorySpace() const; |
210 | |
211 | /// Returns the natural alignment of the stack in bits. Alignment promotion of |
212 | /// stack variables should be limited to the natural stack alignment to |
213 | /// prevent dynamic stack alignment. Returns zero if the stack alignment is |
214 | /// unspecified. |
215 | uint64_t getStackAlignment() const; |
216 | |
217 | private: |
218 | /// Combined layout spec at the given scope. |
219 | const DataLayoutSpecInterface originalLayout; |
220 | |
221 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
222 | /// List of enclosing layout specs. |
223 | SmallVector<DataLayoutSpecInterface, 2> layoutStack; |
224 | #endif |
225 | |
226 | /// Asserts that the cache is still valid. Expensive in debug mode. No-op in |
227 | /// release mode. |
228 | void checkValid() const; |
229 | |
230 | /// Operation defining the scope of requests. |
231 | Operation *scope; |
232 | |
233 | /// Caches for individual requests. |
234 | mutable DenseMap<Type, llvm::TypeSize> sizes; |
235 | mutable DenseMap<Type, llvm::TypeSize> bitsizes; |
236 | mutable DenseMap<Type, uint64_t> abiAlignments; |
237 | mutable DenseMap<Type, uint64_t> preferredAlignments; |
238 | mutable DenseMap<Type, std::optional<uint64_t>> indexBitwidths; |
239 | |
240 | /// Cache for the endianness. |
241 | mutable std::optional<Attribute> endianness; |
242 | /// Cache for alloca, global, and program memory spaces. |
243 | mutable std::optional<Attribute> allocaMemorySpace; |
244 | mutable std::optional<Attribute> programMemorySpace; |
245 | mutable std::optional<Attribute> globalMemorySpace; |
246 | |
247 | /// Cache for stack alignment. |
248 | mutable std::optional<uint64_t> stackAlignment; |
249 | }; |
250 | |
251 | } // namespace mlir |
252 | |
253 | #endif // MLIR_INTERFACES_DATALAYOUTINTERFACES_H |
254 | |