1 | // |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | // |
6 | //===----------------------------------------------------------------------===// |
7 | // |
8 | // This file defines common utilities for generating C++ from tablegen |
9 | // structures. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef MLIR_TABLEGEN_CODEGENHELPERS_H |
14 | #define MLIR_TABLEGEN_CODEGENHELPERS_H |
15 | |
16 | #include "mlir/TableGen/Constraint.h" |
17 | #include "mlir/TableGen/Dialect.h" |
18 | #include "mlir/TableGen/Format.h" |
19 | #include "llvm/ADT/DenseMap.h" |
20 | #include "llvm/ADT/MapVector.h" |
21 | #include "llvm/ADT/StringExtras.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | |
24 | namespace llvm { |
25 | class RecordKeeper; |
26 | } // namespace llvm |
27 | |
28 | namespace mlir { |
29 | namespace tblgen { |
30 | class Constraint; |
31 | class DagLeaf; |
32 | |
33 | // Format into a std::string |
34 | template <typename... Parameters> |
35 | std::string strfmt(const char *fmt, Parameters &&...parameters) { |
36 | return llvm::formatv(fmt, std::forward<Parameters>(parameters)...).str(); |
37 | } |
38 | |
39 | // Simple RAII helper for defining ifdef-undef-endif scopes. |
40 | class IfDefScope { |
41 | public: |
42 | IfDefScope(llvm::StringRef name, llvm::raw_ostream &os) |
43 | : name(name.str()), os(os) { |
44 | os << "#ifdef " << name << "\n" |
45 | << "#undef " << name << "\n\n" ; |
46 | } |
47 | ~IfDefScope() { os << "\n#endif // " << name << "\n\n" ; } |
48 | |
49 | private: |
50 | std::string name; |
51 | llvm::raw_ostream &os; |
52 | }; |
53 | |
54 | // A helper RAII class to emit nested namespaces for this op. |
55 | class NamespaceEmitter { |
56 | public: |
57 | NamespaceEmitter(raw_ostream &os, const Dialect &dialect) : os(os) { |
58 | if (!dialect) |
59 | return; |
60 | emitNamespaceStarts(os, cppNamespace: dialect.getCppNamespace()); |
61 | } |
62 | NamespaceEmitter(raw_ostream &os, StringRef cppNamespace) : os(os) { |
63 | emitNamespaceStarts(os, cppNamespace); |
64 | } |
65 | |
66 | ~NamespaceEmitter() { |
67 | for (StringRef ns : llvm::reverse(C&: namespaces)) |
68 | os << "} // namespace " << ns << "\n" ; |
69 | } |
70 | |
71 | private: |
72 | void emitNamespaceStarts(raw_ostream &os, StringRef cppNamespace) { |
73 | llvm::SplitString(Source: cppNamespace, OutFragments&: namespaces, Delimiters: "::" ); |
74 | for (StringRef ns : namespaces) |
75 | os << "namespace " << ns << " {\n" ; |
76 | } |
77 | raw_ostream &os; |
78 | SmallVector<StringRef, 2> namespaces; |
79 | }; |
80 | |
81 | /// This class deduplicates shared operation verification code by emitting |
82 | /// static functions alongside the op definitions. These methods are local to |
83 | /// the definition file, and are invoked within the operation verify methods. |
84 | /// An example is shown below: |
85 | /// |
86 | /// static LogicalResult localVerify(...) |
87 | /// |
88 | /// LogicalResult OpA::verify(...) { |
89 | /// if (failed(localVerify(...))) |
90 | /// return failure(); |
91 | /// ... |
92 | /// } |
93 | /// |
94 | /// LogicalResult OpB::verify(...) { |
95 | /// if (failed(localVerify(...))) |
96 | /// return failure(); |
97 | /// ... |
98 | /// } |
99 | /// |
100 | class StaticVerifierFunctionEmitter { |
101 | public: |
102 | StaticVerifierFunctionEmitter(raw_ostream &os, |
103 | const llvm::RecordKeeper &records); |
104 | |
105 | /// Collect and unique all compatible type, attribute, successor, and region |
106 | /// constraints from the operations in the file and emit them at the top of |
107 | /// the generated file. |
108 | /// |
109 | /// Constraints that do not meet the restriction that they can only reference |
110 | /// `$_self` and `$_op` are not uniqued. |
111 | void emitOpConstraints(ArrayRef<llvm::Record *> opDefs, bool emitDecl); |
112 | |
113 | /// Unique all compatible type and attribute constraints from a pattern file |
114 | /// and emit them at the top of the generated file. |
115 | /// |
116 | /// Constraints that do not meet the restriction that they can only reference |
117 | /// `$_self`, `$_op`, and `$_builder` are not uniqued. |
118 | void emitPatternConstraints(const ArrayRef<DagLeaf> constraints); |
119 | |
120 | /// Get the name of the static function used for the given type constraint. |
121 | /// These functions are used for operand and result constraints and have the |
122 | /// form: |
123 | /// |
124 | /// LogicalResult(Operation *op, Type type, StringRef valueKind, |
125 | /// unsigned valueIndex); |
126 | /// |
127 | /// Pattern constraints have the form: |
128 | /// |
129 | /// LogicalResult(PatternRewriter &rewriter, Operation *op, Type type, |
130 | /// StringRef failureStr); |
131 | /// |
132 | StringRef getTypeConstraintFn(const Constraint &constraint) const; |
133 | |
134 | /// Get the name of the static function used for the given attribute |
135 | /// constraint. These functions are in the form: |
136 | /// |
137 | /// LogicalResult(Operation *op, Attribute attr, StringRef attrName); |
138 | /// |
139 | /// If a uniqued constraint was not found, this function returns std::nullopt. |
140 | /// The uniqued constraints cannot be used in the context of an OpAdaptor. |
141 | /// |
142 | /// Pattern constraints have the form: |
143 | /// |
144 | /// LogicalResult(PatternRewriter &rewriter, Operation *op, Attribute attr, |
145 | /// StringRef failureStr); |
146 | /// |
147 | std::optional<StringRef> |
148 | getAttrConstraintFn(const Constraint &constraint) const; |
149 | |
150 | /// Get the name of the static function used for the given successor |
151 | /// constraint. These functions are in the form: |
152 | /// |
153 | /// LogicalResult(Operation *op, Block *successor, StringRef successorName, |
154 | /// unsigned successorIndex); |
155 | /// |
156 | StringRef getSuccessorConstraintFn(const Constraint &constraint) const; |
157 | |
158 | /// Get the name of the static function used for the given region constraint. |
159 | /// These functions are in the form: |
160 | /// |
161 | /// LogicalResult(Operation *op, Region ®ion, StringRef regionName, |
162 | /// unsigned regionIndex); |
163 | /// |
164 | /// The region name may be empty. |
165 | StringRef getRegionConstraintFn(const Constraint &constraint) const; |
166 | |
167 | private: |
168 | /// Emit static type constraint functions. |
169 | void emitTypeConstraints(); |
170 | /// Emit static attribute constraint functions. |
171 | void emitAttrConstraints(); |
172 | /// Emit static successor constraint functions. |
173 | void emitSuccessorConstraints(); |
174 | /// Emit static region constraint functions. |
175 | void emitRegionConstraints(); |
176 | |
177 | /// Emit pattern constraints. |
178 | void emitPatternConstraints(); |
179 | |
180 | /// Collect and unique all the constraints used by operations. |
181 | void collectOpConstraints(ArrayRef<llvm::Record *> opDefs); |
182 | /// Collect and unique all pattern constraints. |
183 | void collectPatternConstraints(ArrayRef<DagLeaf> constraints); |
184 | |
185 | /// The output stream. |
186 | raw_ostream &os; |
187 | |
188 | /// A unique label for the file currently being generated. This is used to |
189 | /// ensure that the static functions have a unique name. |
190 | std::string uniqueOutputLabel; |
191 | |
192 | /// Use a MapVector to ensure that functions are generated deterministically. |
193 | using ConstraintMap = llvm::MapVector<Constraint, std::string, |
194 | llvm::DenseMap<Constraint, unsigned>>; |
195 | |
196 | /// A generic function to emit constraints |
197 | void emitConstraints(const ConstraintMap &constraints, StringRef selfName, |
198 | const char *codeTemplate); |
199 | |
200 | /// Assign a unique name to a unique constraint. |
201 | std::string getUniqueName(StringRef kind, unsigned index); |
202 | /// Unique a constraint in the map. |
203 | void collectConstraint(ConstraintMap &map, StringRef kind, |
204 | Constraint constraint); |
205 | |
206 | /// The set of type constraints used for operand and result verification in |
207 | /// the current file. |
208 | ConstraintMap typeConstraints; |
209 | /// The set of attribute constraints used in the current file. |
210 | ConstraintMap attrConstraints; |
211 | /// The set of successor constraints used in the current file. |
212 | ConstraintMap successorConstraints; |
213 | /// The set of region constraints used in the current file. |
214 | ConstraintMap regionConstraints; |
215 | }; |
216 | |
217 | /// Escape a string using C++ encoding. E.g. foo"bar -> foo\x22bar. |
218 | std::string escapeString(StringRef value); |
219 | |
220 | namespace detail { |
221 | template <typename> |
222 | struct stringifier { |
223 | template <typename T> |
224 | static std::string apply(T &&t) { |
225 | return std::string(std::forward<T>(t)); |
226 | } |
227 | }; |
228 | template <> |
229 | struct stringifier<Twine> { |
230 | static std::string apply(const Twine &twine) { return twine.str(); } |
231 | }; |
232 | template <typename OptionalT> |
233 | struct stringifier<std::optional<OptionalT>> { |
234 | static std::string apply(std::optional<OptionalT> optional) { |
235 | return optional ? stringifier<OptionalT>::apply(*optional) : std::string(); |
236 | } |
237 | }; |
238 | } // namespace detail |
239 | |
240 | /// Generically convert a value to a std::string. |
241 | template <typename T> |
242 | std::string stringify(T &&t) { |
243 | return detail::stringifier<std::remove_reference_t<std::remove_const_t<T>>>:: |
244 | apply(std::forward<T>(t)); |
245 | } |
246 | |
247 | } // namespace tblgen |
248 | } // namespace mlir |
249 | |
250 | #endif // MLIR_TABLEGEN_CODEGENHELPERS_H |
251 | |