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 &region, 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