MLIR 22.0.0git
CodeGenHelpers.cpp
Go to the documentation of this file.
1//===- CodeGenHelpers.cpp - MLIR op definitions generator ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// OpDefinitionsGen uses the description of operations to generate C++
10// definitions for ops.
11//
12//===----------------------------------------------------------------------===//
13
17#include "llvm/Support/FormatVariadic.h"
18#include "llvm/Support/Path.h"
19#include "llvm/TableGen/CodeGenHelpers.h"
20#include "llvm/TableGen/Record.h"
21
22using namespace llvm;
23using namespace mlir;
24using namespace mlir::tblgen;
25
26/// Generate a unique label based on the current file name to prevent name
27/// collisions if multiple generated files are included at once.
28static std::string getUniqueOutputLabel(const RecordKeeper &records,
29 StringRef tag) {
30 // Use the input file name when generating a unique name.
31 StringRef inputFilename = records.getInputFilename();
32
33 // Drop all but the base filename.
34 StringRef nameRef = sys::path::filename(inputFilename);
35 nameRef.consume_back(".td");
36
37 // Sanitize any invalid characters.
38 std::string uniqueName(tag);
39 for (char c : nameRef) {
40 if (isAlnum(c) || c == '_')
41 uniqueName.push_back(c);
42 else
43 uniqueName.append(utohexstr((unsigned char)c));
44 }
45 return uniqueName;
46}
47
49 raw_ostream &os, const RecordKeeper &records, StringRef tag)
50 : os(os), uniqueOutputLabel(getUniqueOutputLabel(records, tag)) {}
51
53 emitTypeConstraints();
54 emitAttrConstraints();
55 emitPropConstraints();
56 emitSuccessorConstraints();
57 emitRegionConstraints();
58}
59
61 const ArrayRef<DagLeaf> constraints) {
62 collectPatternConstraints(constraints);
64}
65
66//===----------------------------------------------------------------------===//
67// Constraint Getters
68//===----------------------------------------------------------------------===//
69
71 const Constraint &constraint) const {
72 const auto *it = typeConstraints.find(constraint);
73 assert(it != typeConstraints.end() && "expected to find a type constraint");
74 return it->second;
75}
76
77// Find a uniqued attribute constraint. Since not all attribute constraints can
78// be uniqued, return std::nullopt if one was not found.
80 const Constraint &constraint) const {
81 const auto *it = attrConstraints.find(constraint);
82 return it == attrConstraints.end() ? std::optional<StringRef>()
83 : StringRef(it->second);
84}
85
86// Find a uniqued property constraint. Since not all property constraints can
87// be uniqued, return std::nullopt if one was not found.
89 const Constraint &constraint) const {
90 const auto *it = propConstraints.find(constraint);
91 return it == propConstraints.end() ? std::optional<StringRef>()
92 : StringRef(it->second);
93}
94
96 const Constraint &constraint) const {
97 const auto *it = successorConstraints.find(constraint);
98 assert(it != successorConstraints.end() &&
99 "expected to find a sucessor constraint");
100 return it->second;
101}
102
104 const Constraint &constraint) const {
105 const auto *it = regionConstraints.find(constraint);
106 assert(it != regionConstraints.end() &&
107 "expected to find a region constraint");
108 return it->second;
109}
110
111//===----------------------------------------------------------------------===//
112// Constraint Emission
113//===----------------------------------------------------------------------===//
114
115/// Code templates for emitting type, attribute, successor, and region
116/// constraints. Each of these templates require the following arguments:
117///
118/// {0}: The unique constraint name.
119/// {1}: The constraint code.
120/// {2}: The constraint description.
121
122/// Code for a type constraint. These may be called on the type of either
123/// operands or results.
124static const char *const typeConstraintCode = R"(
125static ::llvm::LogicalResult {0}(
126 ::mlir::Operation *op, ::mlir::Type type, ::llvm::StringRef valueKind,
127 unsigned valueIndex) {
128 if (!({1})) {
129 return op->emitOpError(valueKind) << " #" << valueIndex
130 << " must be {2}, but got " << type;
131 }
132 return ::mlir::success();
133}
134)";
135
136/// Code for an attribute constraint. These may be called from ops only.
137/// Attribute constraints cannot reference anything other than `$_self` and
138/// `$_op`.
139///
140/// TODO: Unique constraints for adaptors. However, most Adaptor::verify
141/// functions are stripped anyways.
142static const char *const attrConstraintCode = R"(
143static ::llvm::LogicalResult {0}(
144 ::mlir::Attribute attr, ::llvm::StringRef attrName, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) {{
145 if (attr && !({1}))
146 return emitError() << "attribute '" << attrName
147 << "' failed to satisfy constraint: {2}";
148 return ::mlir::success();
149}
150static ::llvm::LogicalResult {0}(
151 ::mlir::Operation *op, ::mlir::Attribute attr, ::llvm::StringRef attrName) {{
152 return {0}(attr, attrName, [op]() {{
153 return op->emitOpError();
154 });
155}
156)";
157
158/// Code for a property constraint. These may be called from ops only.
159/// Property constraints cannot reference anything other than `$_self` and
160/// `$_op`. {3} is the interface type of the property.
161static const char *const propConstraintCode = R"(
162 static ::llvm::LogicalResult {0}(
163 {3} prop, ::llvm::StringRef propName, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) {{
164 if (!({1}))
165 return emitError() << "property '" << propName
166 << "' failed to satisfy constraint: {2}";
167 return ::mlir::success();
168 }
169 static ::llvm::LogicalResult {0}(
170 ::mlir::Operation *op, {3} prop, ::llvm::StringRef propName) {{
171 return {0}(prop, propName, [op]() {{
172 return op->emitOpError();
173 });
174 }
175 )";
176
177/// Code for a successor constraint.
178static const char *const successorConstraintCode = R"(
179static ::llvm::LogicalResult {0}(
180 ::mlir::Operation *op, ::mlir::Block *successor,
181 ::llvm::StringRef successorName, unsigned successorIndex) {
182 if (!({1})) {
183 return op->emitOpError("successor #") << successorIndex << " ('"
184 << successorName << ")' failed to verify constraint: {2}";
185 }
186 return ::mlir::success();
187}
188)";
189
190/// Code for a region constraint. Callers will need to pass in the region's name
191/// for emitting an error message.
192static const char *const regionConstraintCode = R"(
193static ::llvm::LogicalResult {0}(
194 ::mlir::Operation *op, ::mlir::Region &region, ::llvm::StringRef regionName,
195 unsigned regionIndex) {
196 if (!({1})) {
197 return op->emitOpError("region #") << regionIndex
198 << (regionName.empty() ? " " : " ('" + regionName + "') ")
199 << "failed to verify constraint: {2}";
200 }
201 return ::mlir::success();
202}
203)";
204
205/// Code for a pattern type or attribute constraint.
206///
207/// {0}: name of function
208/// {1}: Condition template
209/// {2}: Constraint summary
210/// {3}: "::mlir::Type type" or "::mlirAttribute attr" or "propType prop".
211/// Can be "T prop" for generic property constraints.
212static const char *const patternConstraintCode = R"(
213static ::llvm::LogicalResult {0}(
214 ::mlir::PatternRewriter &rewriter, ::mlir::Operation *op, {3},
215 ::llvm::StringRef failureStr) {
216 if (!({1})) {
217 return rewriter.notifyMatchFailure(op, [&](::mlir::Diagnostic &diag) {
218 diag << failureStr << ": {2}";
219 });
220 }
221 return ::mlir::success();
222}
223)";
224
225void StaticVerifierFunctionEmitter::emitConstraints(
226 const ConstraintMap &constraints, StringRef selfName,
227 const char *const codeTemplate) {
228 FmtContext ctx;
229 ctx.addSubst("_op", "*op").withSelf(selfName);
230 for (auto &it : constraints) {
231 os << formatv(codeTemplate, it.second,
232 tgfmt(it.first.getConditionTemplate(), &ctx),
233 escapeString(it.first.getSummary()));
234 }
235}
236
237void StaticVerifierFunctionEmitter::emitTypeConstraints() {
238 emitConstraints(typeConstraints, "type", typeConstraintCode);
239}
240
241void StaticVerifierFunctionEmitter::emitAttrConstraints() {
242 emitConstraints(attrConstraints, "attr", attrConstraintCode);
243}
244
245/// Unlike with the other helpers, this one has to substitute in the interface
246/// type of the property, so we can't just use the generic function.
247void StaticVerifierFunctionEmitter::emitPropConstraints() {
248 FmtContext ctx;
249 ctx.addSubst("_op", "*op").withSelf("prop");
250 for (auto &it : propConstraints) {
251 auto propConstraint = cast<PropConstraint>(it.first);
252 os << formatv(propConstraintCode, it.second,
253 tgfmt(propConstraint.getConditionTemplate(), &ctx),
254 escapeString(it.first.getSummary()),
255 propConstraint.getInterfaceType());
256 }
257}
258
259void StaticVerifierFunctionEmitter::emitSuccessorConstraints() {
260 emitConstraints(successorConstraints, "successor", successorConstraintCode);
261}
262
263void StaticVerifierFunctionEmitter::emitRegionConstraints() {
264 emitConstraints(regionConstraints, "region", regionConstraintCode);
265}
266
268 FmtContext ctx;
269 ctx.addSubst("_op", "*op").withBuilder("rewriter").withSelf("type");
270 for (auto &it : typeConstraints) {
271 os << formatv(patternConstraintCode, it.second,
272 tgfmt(it.first.getConditionTemplate(), &ctx),
273 escapeString(it.first.getSummary()), "::mlir::Type type");
274 }
275 ctx.withSelf("attr");
276 for (auto &it : attrConstraints) {
277 os << formatv(patternConstraintCode, it.second,
278 tgfmt(it.first.getConditionTemplate(), &ctx),
279 escapeString(it.first.getSummary()),
280 "::mlir::Attribute attr");
281 }
282 ctx.withSelf("prop");
283 for (auto &it : propConstraints) {
284 PropConstraint propConstraint = cast<PropConstraint>(it.first);
285 StringRef interfaceType = propConstraint.getInterfaceType();
286 // Constraints that are generic over multiple interface types are
287 // templatized under the assumption that they'll be used correctly.
288 if (interfaceType.empty()) {
289 interfaceType = "T";
290 os << "template <typename T>";
291 }
292 os << formatv(patternConstraintCode, it.second,
293 tgfmt(propConstraint.getConditionTemplate(), &ctx),
294 escapeString(propConstraint.getSummary()),
295 Twine(interfaceType) + " prop");
296 }
297}
298
299//===----------------------------------------------------------------------===//
300// Constraint Uniquing
301//===----------------------------------------------------------------------===//
302
303/// An attribute constraint that references anything other than itself and the
304/// current op cannot be generically extracted into a function. Most
305/// prohibitive are operands and results, which require calls to
306/// `getODSOperands` or `getODSResults`. Attribute references are tricky too
307/// because ops use cached identifiers.
309 FmtContext ctx;
310 auto test = tgfmt(attr.getConditionTemplate(),
311 &ctx.withSelf("attr").addSubst("_op", "*op"))
312 .str();
313 return !StringRef(test).contains("<no-subst-found>");
314}
315
316/// A property constraint that references anything other than itself and the
317/// current op cannot be generically extracted into a function, just as with
318/// canUnequePropConstraint(). Additionally, property constraints without
319/// an interface type specified can't be uniqued, and ones that are a literal
320/// "true" shouldn't be constrained.
322 FmtContext ctx;
323 auto test = tgfmt(prop.getConditionTemplate(),
324 &ctx.withSelf("prop").addSubst("_op", "*op"))
325 .str();
326 return !StringRef(test).contains("<no-subst-found>") && test != "true" &&
327 !prop.getInterfaceType().empty();
328}
329
330std::string StaticVerifierFunctionEmitter::getUniqueName(StringRef kind,
331 unsigned index) {
332 return ("__mlir_ods_local_" + kind + "_constraint_" + uniqueOutputLabel +
333 Twine(index))
334 .str();
335}
336
337void StaticVerifierFunctionEmitter::collectConstraint(ConstraintMap &map,
338 StringRef kind,
339 Constraint constraint) {
340 auto [it, inserted] = map.try_emplace(constraint);
341 if (inserted)
342 it->second = getUniqueName(kind, map.size());
343}
344
347 const auto collectTypeConstraints = [&](Operator::const_value_range values) {
348 for (const NamedTypeConstraint &value : values)
349 if (value.hasPredicate())
350 collectConstraint(typeConstraints, "type", value.constraint);
351 };
352
353 for (const Record *def : opDefs) {
354 Operator op(*def);
355 /// Collect type constraints.
356 collectTypeConstraints(op.getOperands());
357 collectTypeConstraints(op.getResults());
358 /// Collect attribute constraints.
359 for (const NamedAttribute &namedAttr : op.getAttributes()) {
360 if (!namedAttr.attr.getPredicate().isNull() &&
361 !namedAttr.attr.isDerivedAttr() &&
362 canUniqueAttrConstraint(namedAttr.attr))
363 collectConstraint(attrConstraints, "attr", namedAttr.attr);
364 }
365 /// Collect non-trivial property constraints.
366 for (const NamedProperty &namedProp : op.getProperties()) {
367 if (!namedProp.prop.getPredicate().isNull() &&
368 canUniquePropConstraint(namedProp.prop)) {
369 collectConstraint(propConstraints, "prop", namedProp.prop);
370 }
371 }
372 /// Collect successor constraints.
373 for (const NamedSuccessor &successor : op.getSuccessors()) {
374 if (!successor.constraint.getPredicate().isNull()) {
375 collectConstraint(successorConstraints, "successor",
376 successor.constraint);
377 }
378 }
379 /// Collect region constraints.
380 for (const NamedRegion &region : op.getRegions())
381 if (!region.constraint.getPredicate().isNull())
382 collectConstraint(regionConstraints, "region", region.constraint);
383 }
384}
385
386void StaticVerifierFunctionEmitter::collectPatternConstraints(
387 const ArrayRef<DagLeaf> constraints) {
388 for (auto &leaf : constraints) {
389 assert(leaf.isOperandMatcher() || leaf.isAttrMatcher() ||
390 leaf.isPropMatcher());
391 Constraint constraint = leaf.getAsConstraint();
392 if (leaf.isOperandMatcher())
393 collectConstraint(typeConstraints, "type", constraint);
394 else if (leaf.isAttrMatcher())
395 collectConstraint(attrConstraints, "attr", constraint);
396 else if (leaf.isPropMatcher())
397 collectConstraint(propConstraints, "prop", constraint);
398 }
399}
400
401//===----------------------------------------------------------------------===//
402// Public Utility Functions
403//===----------------------------------------------------------------------===//
404
405std::string mlir::tblgen::escapeString(StringRef value) {
406 std::string ret;
407 raw_string_ostream os(ret);
408 os.write_escaped(value);
409 return ret;
410}
static const char *const successorConstraintCode
Code for a successor constraint.
static const char *const patternConstraintCode
Code for a pattern type or attribute constraint.
static const char *const regionConstraintCode
Code for a region constraint.
static const char *const typeConstraintCode
Code templates for emitting type, attribute, successor, and region constraints.
static std::string getUniqueOutputLabel(const RecordKeeper &records, StringRef tag)
Generate a unique label based on the current file name to prevent name collisions if multiple generat...
static const char *const propConstraintCode
Code for a property constraint.
static bool canUniqueAttrConstraint(Attribute attr)
An attribute constraint that references anything other than itself and the current op cannot be gener...
static bool canUniquePropConstraint(Property prop)
A property constraint that references anything other than itself and the current op cannot be generic...
static const char *const attrConstraintCode
Code for an attribute constraint.
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
Attributes are known-constant values of operations.
Definition Attributes.h:25
StringRef getSummary() const
std::string getConditionTemplate() const
Format context containing substitutions for special placeholders.
Definition Format.h:40
FmtContext & withBuilder(Twine subst)
Definition Format.cpp:36
FmtContext & withSelf(Twine subst)
Definition Format.cpp:41
FmtContext & addSubst(StringRef placeholder, const Twine &subst)
Definition Format.cpp:31
Wrapper class that contains a MLIR op's information (e.g., operands, attributes) defined in TableGen ...
Definition Operator.h:77
llvm::iterator_range< const_region_iterator > getRegions() const
Definition Operator.cpp:279
const_value_range getResults() const
Definition Operator.cpp:197
const_value_range getOperands() const
Definition Operator.cpp:353
llvm::iterator_range< const_property_iterator > getProperties() const
Definition Operator.h:200
llvm::iterator_range< const_attribute_iterator > getAttributes() const
Definition Operator.cpp:333
llvm::iterator_range< const_value_iterator > const_value_range
Definition Operator.h:138
llvm::iterator_range< const_successor_iterator > getSuccessors() const
Definition Operator.cpp:301
StringRef getInterfaceType() const
Definition Property.cpp:35
StringRef getInterfaceType() const
Definition Property.h:70
StringRef getRegionConstraintFn(const Constraint &constraint) const
Get the name of the static function used for the given region constraint.
void emitPatternConstraints(const ArrayRef< DagLeaf > constraints)
Unique all compatible type and attribute constraints from a pattern file and emit them at the top of ...
std::optional< StringRef > getAttrConstraintFn(const Constraint &constraint) const
Get the name of the static function used for the given attribute constraint.
std::optional< StringRef > getPropConstraintFn(const Constraint &constraint) const
Get the name of the static function used for the given property constraint.
StaticVerifierFunctionEmitter(raw_ostream &os, const llvm::RecordKeeper &records, StringRef tag="")
Create a constraint uniquer with a unique prefix derived from the record keeper with an optional tag.
void collectOpConstraints(ArrayRef< const llvm::Record * > opDefs)
Collect and unique all the constraints used by operations.
StringRef getTypeConstraintFn(const Constraint &constraint) const
Get the name of the static function used for the given type constraint.
void emitOpConstraints()
Collect and unique all compatible type, attribute, successor, and region constraints from the operati...
StringRef getSuccessorConstraintFn(const Constraint &constraint) const
Get the name of the static function used for the given successor constraint.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
auto tgfmt(StringRef fmt, const FmtContext *ctx, Ts &&...vals) -> FmtObject< decltype(std::make_tuple(llvm::support::detail::build_format_adapter(std::forward< Ts >(vals))...))>
Formats text by substituting placeholders in format string with replacement parameters.
Definition Format.h:262
std::string escapeString(StringRef value)
Escape a string using C++ encoding. E.g. foo"bar -> foo\x22bar.
Include the generated interface declarations.