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