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, 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(namespaces)) 68 os << "} // namespace " << ns << "\n"; 69 } 70 71 private: 72 void emitNamespaceStarts(raw_ostream &os, StringRef cppNamespace) { 73 llvm::SplitString(cppNamespace, namespaces, "::"); 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 /// Create a constraint uniquer with a unique prefix derived from the record 103 /// keeper with an optional tag. 104 StaticVerifierFunctionEmitter(raw_ostream &os, 105 const llvm::RecordKeeper &records, 106 StringRef tag = ""); 107 108 /// Collect and unique all the constraints used by operations. 109 void collectOpConstraints(ArrayRef<const llvm::Record *> opDefs); 110 111 /// Collect and unique all compatible type, attribute, successor, and region 112 /// constraints from the operations in the file and emit them at the top of 113 /// the generated file. 114 /// 115 /// Constraints that do not meet the restriction that they can only reference 116 /// `$_self` and `$_op` are not uniqued. 117 void emitOpConstraints(ArrayRef<const llvm::Record *> opDefs); 118 119 /// Unique all compatible type and attribute constraints from a pattern file 120 /// and emit them at the top of the generated file. 121 /// 122 /// Constraints that do not meet the restriction that they can only reference 123 /// `$_self`, `$_op`, and `$_builder` are not uniqued. 124 void emitPatternConstraints(const ArrayRef<DagLeaf> constraints); 125 126 /// Get the name of the static function used for the given type constraint. 127 /// These functions are used for operand and result constraints and have the 128 /// form: 129 /// 130 /// LogicalResult(Operation *op, Type type, StringRef valueKind, 131 /// unsigned valueIndex); 132 /// 133 /// Pattern constraints have the form: 134 /// 135 /// LogicalResult(PatternRewriter &rewriter, Operation *op, Type type, 136 /// StringRef failureStr); 137 /// 138 StringRef getTypeConstraintFn(const Constraint &constraint) const; 139 140 /// Get the name of the static function used for the given attribute 141 /// constraint. These functions are in the form: 142 /// 143 /// LogicalResult(Operation *op, Attribute attr, StringRef attrName); 144 /// 145 /// If a uniqued constraint was not found, this function returns std::nullopt. 146 /// The uniqued constraints cannot be used in the context of an OpAdaptor. 147 /// 148 /// Pattern constraints have the form: 149 /// 150 /// LogicalResult(PatternRewriter &rewriter, Operation *op, Attribute attr, 151 /// StringRef failureStr); 152 /// 153 std::optional<StringRef> 154 getAttrConstraintFn(const Constraint &constraint) const; 155 156 /// Get the name of the static function used for the given successor 157 /// constraint. These functions are in the form: 158 /// 159 /// LogicalResult(Operation *op, Block *successor, StringRef successorName, 160 /// unsigned successorIndex); 161 /// 162 StringRef getSuccessorConstraintFn(const Constraint &constraint) const; 163 164 /// Get the name of the static function used for the given region constraint. 165 /// These functions are in the form: 166 /// 167 /// LogicalResult(Operation *op, Region ®ion, StringRef regionName, 168 /// unsigned regionIndex); 169 /// 170 /// The region name may be empty. 171 StringRef getRegionConstraintFn(const Constraint &constraint) const; 172 173 private: 174 /// Emit static type constraint functions. 175 void emitTypeConstraints(); 176 /// Emit static attribute constraint functions. 177 void emitAttrConstraints(); 178 /// Emit static successor constraint functions. 179 void emitSuccessorConstraints(); 180 /// Emit static region constraint functions. 181 void emitRegionConstraints(); 182 183 /// Emit pattern constraints. 184 void emitPatternConstraints(); 185 186 /// Collect and unique all pattern constraints. 187 void collectPatternConstraints(ArrayRef<DagLeaf> constraints); 188 189 /// The output stream. 190 raw_ostream &os; 191 192 /// A unique label for the file currently being generated. This is used to 193 /// ensure that the static functions have a unique name. 194 std::string uniqueOutputLabel; 195 196 /// Use a MapVector to ensure that functions are generated deterministically. 197 using ConstraintMap = llvm::MapVector<Constraint, std::string, 198 llvm::DenseMap<Constraint, unsigned>>; 199 200 /// A generic function to emit constraints 201 void emitConstraints(const ConstraintMap &constraints, StringRef selfName, 202 const char *codeTemplate); 203 204 /// Assign a unique name to a unique constraint. 205 std::string getUniqueName(StringRef kind, unsigned index); 206 /// Unique a constraint in the map. 207 void collectConstraint(ConstraintMap &map, StringRef kind, 208 Constraint constraint); 209 210 /// The set of type constraints used for operand and result verification in 211 /// the current file. 212 ConstraintMap typeConstraints; 213 /// The set of attribute constraints used in the current file. 214 ConstraintMap attrConstraints; 215 /// The set of successor constraints used in the current file. 216 ConstraintMap successorConstraints; 217 /// The set of region constraints used in the current file. 218 ConstraintMap regionConstraints; 219 }; 220 221 /// Escape a string using C++ encoding. E.g. foo"bar -> foo\x22bar. 222 std::string escapeString(StringRef value); 223 224 namespace detail { 225 template <typename> 226 struct stringifier { 227 template <typename T> 228 static std::string apply(T &&t) { 229 return std::string(std::forward<T>(t)); 230 } 231 }; 232 template <> 233 struct stringifier<Twine> { 234 static std::string apply(const Twine &twine) { return twine.str(); } 235 }; 236 template <typename OptionalT> 237 struct stringifier<std::optional<OptionalT>> { 238 static std::string apply(std::optional<OptionalT> optional) { 239 return optional ? stringifier<OptionalT>::apply(*optional) : std::string(); 240 } 241 }; 242 } // namespace detail 243 244 /// Generically convert a value to a std::string. 245 template <typename T> 246 std::string stringify(T &&t) { 247 return detail::stringifier<std::remove_reference_t<std::remove_const_t<T>>>:: 248 apply(std::forward<T>(t)); 249 } 250 251 } // namespace tblgen 252 } // namespace mlir 253 254 #endif // MLIR_TABLEGEN_CODEGENHELPERS_H 255