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 
22 namespace mlir {
23 class DataLayout;
24 class DataLayoutEntryInterface;
25 using DataLayoutEntryKey = llvm::PointerUnion<Type, StringAttr>;
26 // Using explicit SmallVector size because we cannot infer the size from the
27 // forward declaration, and we need the typedef in the actual declaration.
28 using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>;
29 using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>;
30 class DataLayoutOpInterface;
31 class DataLayoutSpecInterface;
32 class ModuleOp;
33 
34 namespace detail {
35 /// Default handler for the type size request. Computes results for built-in
36 /// types and dispatches to the DataLayoutTypeInterface for other types.
37 unsigned getDefaultTypeSize(Type type, const DataLayout &dataLayout,
38                             DataLayoutEntryListRef params);
39 
40 /// Default handler for the type size in bits request. Computes results for
41 /// built-in types and dispatches to the DataLayoutTypeInterface for other
42 /// types.
43 unsigned getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout,
44                                   DataLayoutEntryListRef params);
45 
46 /// Default handler for the required alignemnt request. Computes results for
47 /// built-in types and dispatches to the DataLayoutTypeInterface for other
48 /// types.
49 unsigned getDefaultABIAlignment(Type type, const DataLayout &dataLayout,
50                                 ArrayRef<DataLayoutEntryInterface> params);
51 
52 /// Default handler for the preferred alignemnt request. Computes results for
53 /// built-in types and dispatches to the DataLayoutTypeInterface for other
54 /// types.
55 unsigned
56 getDefaultPreferredAlignment(Type type, const DataLayout &dataLayout,
57                              ArrayRef<DataLayoutEntryInterface> params);
58 
59 /// Given a list of data layout entries, returns a new list containing the
60 /// entries with keys having the given type ID, i.e. belonging to the same type
61 /// class.
62 DataLayoutEntryList filterEntriesForType(DataLayoutEntryListRef entries,
63                                          TypeID typeID);
64 
65 /// Given a list of data layout entries, returns the entry that has the given
66 /// identifier as key, if such an entry exists in the list.
67 DataLayoutEntryInterface
68 filterEntryForIdentifier(DataLayoutEntryListRef entries, StringAttr id);
69 
70 /// Verifies that the operation implementing the data layout interface, or a
71 /// module operation, is valid. This calls the verifier of the spec attribute
72 /// and checks if the layout is compatible with specs attached to the enclosing
73 /// operations.
74 LogicalResult verifyDataLayoutOp(Operation *op);
75 
76 /// Verifies that a data layout spec is valid. This dispatches to individual
77 /// entry verifiers, and then to the verifiers implemented by the relevant type
78 /// and dialect interfaces for type and identifier keys respectively.
79 LogicalResult verifyDataLayoutSpec(DataLayoutSpecInterface spec, Location loc);
80 } // namespace detail
81 } // namespace mlir
82 
83 #include "mlir/Interfaces/DataLayoutAttrInterface.h.inc"
84 #include "mlir/Interfaces/DataLayoutOpInterface.h.inc"
85 #include "mlir/Interfaces/DataLayoutTypeInterface.h.inc"
86 
87 namespace mlir {
88 
89 //===----------------------------------------------------------------------===//
90 // DataLayoutDialectInterface
91 //===----------------------------------------------------------------------===//
92 
93 /// An interface to be implemented by dialects that can have identifiers in the
94 /// data layout specification entries. Provides hooks for verifying the entry
95 /// validity and combining two entries.
96 class DataLayoutDialectInterface
97     : public DialectInterface::Base<DataLayoutDialectInterface> {
98 public:
DataLayoutDialectInterface(Dialect * dialect)99   DataLayoutDialectInterface(Dialect *dialect) : Base(dialect) {}
100 
101   /// Checks whether the given data layout entry is valid and reports any errors
102   /// at the provided location. Derived classes should override this.
verifyEntry(DataLayoutEntryInterface entry,Location loc)103   virtual LogicalResult verifyEntry(DataLayoutEntryInterface entry,
104                                     Location loc) const {
105     return success();
106   }
107 
108   /// Default implementation of entry combination that combines identical
109   /// entries and returns null otherwise.
110   static DataLayoutEntryInterface
defaultCombine(DataLayoutEntryInterface outer,DataLayoutEntryInterface inner)111   defaultCombine(DataLayoutEntryInterface outer,
112                  DataLayoutEntryInterface inner) {
113     if (!outer || outer == inner)
114       return inner;
115     return {};
116   }
117 
118   /// Combines two entries with identifiers that belong to this dialect. Returns
119   /// the combined entry or null if the entries are not compatible. Derived
120   /// classes likely need to reimplement this.
121   virtual DataLayoutEntryInterface
combine(DataLayoutEntryInterface outer,DataLayoutEntryInterface inner)122   combine(DataLayoutEntryInterface outer,
123           DataLayoutEntryInterface inner) const {
124     return defaultCombine(outer, inner);
125   }
126 };
127 
128 //===----------------------------------------------------------------------===//
129 // DataLayout
130 //===----------------------------------------------------------------------===//
131 
132 /// The main mechanism for performing data layout queries. Instances of this
133 /// class can be created for an operation implementing DataLayoutOpInterface.
134 /// Upon construction, a layout spec combining that of the given operation with
135 /// all its ancestors will be computed and used to handle further requests. For
136 /// efficiency, results to all requests will be cached in this object.
137 /// Therefore, if the data layout spec for the scoping operation, or any of the
138 /// enclosing operations, changes, the cache is no longer valid. The user is
139 /// responsible creating a new DataLayout object after any spec change. In debug
140 /// mode, the cache validity is being checked in every request.
141 class DataLayout {
142 public:
143   explicit DataLayout();
144   explicit DataLayout(DataLayoutOpInterface op);
145   explicit DataLayout(ModuleOp op);
146 
147   /// Returns the layout of the closest parent operation carrying layout info.
148   static DataLayout closest(Operation *op);
149 
150   /// Returns the size of the given type in the current scope.
151   unsigned getTypeSize(Type t) const;
152 
153   /// Returns the size in bits of the given type in the current scope.
154   unsigned getTypeSizeInBits(Type t) const;
155 
156   /// Returns the required alignment of the given type in the current scope.
157   unsigned getTypeABIAlignment(Type t) const;
158 
159   /// Returns the preferred of the given type in the current scope.
160   unsigned getTypePreferredAlignment(Type t) const;
161 
162 private:
163   /// Combined layout spec at the given scope.
164   const DataLayoutSpecInterface originalLayout;
165 
166 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
167   /// List of enclosing layout specs.
168   SmallVector<DataLayoutSpecInterface, 2> layoutStack;
169 #endif
170 
171   /// Asserts that the cache is still valid. Expensive in debug mode. No-op in
172   /// release mode.
173   void checkValid() const;
174 
175   /// Operation defining the scope of requests.
176   Operation *scope;
177 
178   /// Caches for individual requests.
179   mutable DenseMap<Type, unsigned> sizes;
180   mutable DenseMap<Type, unsigned> bitsizes;
181   mutable DenseMap<Type, unsigned> abiAlignments;
182   mutable DenseMap<Type, unsigned> preferredAlignments;
183 };
184 
185 } // namespace mlir
186 
187 #endif // MLIR_INTERFACES_DATALAYOUTINTERFACES_H
188