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
23namespace mlir {
24class DataLayout;
25class DataLayoutEntryInterface;
26using 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.
29using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>;
30using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>;
31class DataLayoutOpInterface;
32class DataLayoutSpecInterface;
33class ModuleOp;
34
35namespace detail {
36/// Default handler for the type size request. Computes results for built-in
37/// types and dispatches to the DataLayoutTypeInterface for other types.
38llvm::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.
44llvm::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.
50uint64_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.
56uint64_t
57getDefaultPreferredAlignment(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.
63std::optional<uint64_t>
64getDefaultIndexBitwidth(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.
69Attribute getDefaultEndianness(DataLayoutEntryInterface entry);
70
71/// Default handler for alloca memory space request. Dispatches to the
72/// DataLayoutInterface if specified, otherwise returns the default.
73Attribute getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry);
74
75/// Default handler for program memory space request. Dispatches to the
76/// DataLayoutInterface if specified, otherwise returns the default.
77Attribute getDefaultProgramMemorySpace(DataLayoutEntryInterface entry);
78
79/// Default handler for global memory space request. Dispatches to the
80/// DataLayoutInterface if specified, otherwise returns the default.
81Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry);
82
83/// Default handler for the stack alignment request. Dispatches to the
84/// DataLayoutInterface if specified, otherwise returns the default.
85uint64_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.
90DataLayoutEntryList 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.
95DataLayoutEntryInterface
96filterEntryForIdentifier(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.
102LogicalResult 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.
107LogicalResult 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.
111llvm::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
119namespace 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.
128class DataLayoutDialectInterface
129 : public DialectInterface::Base<DataLayoutDialectInterface> {
130public:
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.
173class DataLayout {
174public:
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
217private:
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

source code of mlir/include/mlir/Interfaces/DataLayoutInterfaces.h