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
24namespace llvm {
25class RecordKeeper;
26} // namespace llvm
27
28namespace mlir {
29namespace tblgen {
30class Constraint;
31class DagLeaf;
32
33// Format into a std::string
34template <typename... Parameters>
35std::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.
40class IfDefScope {
41public:
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
49private:
50 std::string name;
51 llvm::raw_ostream &os;
52};
53
54// A helper RAII class to emit nested namespaces for this op.
55class NamespaceEmitter {
56public:
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
71private:
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///
100class StaticVerifierFunctionEmitter {
101public:
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 &region, StringRef regionName,
162 /// unsigned regionIndex);
163 ///
164 /// The region name may be empty.
165 StringRef getRegionConstraintFn(const Constraint &constraint) const;
166
167private:
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.
218std::string escapeString(StringRef value);
219
220namespace detail {
221template <typename>
222struct stringifier {
223 template <typename T>
224 static std::string apply(T &&t) {
225 return std::string(std::forward<T>(t));
226 }
227};
228template <>
229struct stringifier<Twine> {
230 static std::string apply(const Twine &twine) { return twine.str(); }
231};
232template <typename OptionalT>
233struct 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.
241template <typename T>
242std::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

source code of mlir/include/mlir/TableGen/CodeGenHelpers.h