MLIR 22.0.0git
IRDLVerifiers.cpp
Go to the documentation of this file.
1//===- IRDLVerifiers.cpp - IRDL verifiers ------------------------- C++ -*-===//
2//
3// This file is licensed 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// Verifiers for objects declared by IRDL.
10//
11//===----------------------------------------------------------------------===//
12
14#include "mlir/IR/Attributes.h"
16#include "mlir/IR/Diagnostics.h"
18#include "mlir/IR/Location.h"
19#include "mlir/IR/Region.h"
20#include "mlir/IR/Value.h"
21
22using namespace mlir;
23using namespace mlir::irdl;
24
26 ArrayRef<std::unique_ptr<Constraint>> constraints)
27 : constraints(constraints), assigned() {
28 assigned.resize(this->constraints.size());
29}
30
31LogicalResult
33 Attribute attr, unsigned variable) {
34
35 assert(variable < constraints.size() && "invalid constraint variable");
36
37 // If the variable is already assigned, check that the attribute is the same.
38 if (assigned[variable].has_value()) {
39 if (attr == assigned[variable].value()) {
40 return success();
41 }
42 if (emitError)
43 return emitError() << "expected '" << assigned[variable].value()
44 << "' but got '" << attr << "'";
45 return failure();
46 }
47
48 // Otherwise, check the constraint and assign the attribute to the variable.
49 LogicalResult result = constraints[variable]->verify(emitError, attr, *this);
50 if (succeeded(result))
51 assigned[variable] = attr;
52
53 return result;
54}
55
57 Attribute attr,
58 ConstraintVerifier &context) const {
59 if (attr == expectedAttribute)
60 return success();
61
62 if (emitError)
63 return emitError() << "expected '" << expectedAttribute << "' but got '"
64 << attr << "'";
65 return failure();
66}
67
68LogicalResult
70 Attribute attr, ConstraintVerifier &context) const {
71 if (attr.getTypeID() == baseTypeID)
72 return success();
73
74 if (emitError)
75 return emitError() << "expected base attribute '" << baseName
76 << "' but got '" << attr.getAbstractAttribute().getName()
77 << "'";
78 return failure();
79}
80
81LogicalResult
83 Attribute attr, ConstraintVerifier &context) const {
84 auto typeAttr = dyn_cast<TypeAttr>(attr);
85 if (!typeAttr) {
86 if (emitError)
87 return emitError() << "expected type, got attribute '" << attr;
88 return failure();
89 }
90
91 Type type = typeAttr.getValue();
92 if (type.getTypeID() == baseTypeID)
93 return success();
94
95 if (emitError)
96 return emitError() << "expected base type '" << baseName << "' but got '"
97 << type.getAbstractType().getName() << "'";
98 return failure();
99}
100
103 ConstraintVerifier &context) const {
104
105 // Check that the base is the expected one.
106 auto dynAttr = dyn_cast<DynamicAttr>(attr);
107 if (!dynAttr || dynAttr.getAttrDef() != attrDef) {
108 if (emitError) {
109 StringRef dialectName = attrDef->getDialect()->getNamespace();
110 StringRef attrName = attrDef->getName();
111 return emitError() << "expected base attribute '" << attrName << '.'
112 << dialectName << "' but got '" << attr << "'";
113 }
114 return failure();
115 }
116
117 // Check that the parameters satisfy the constraints.
118 ArrayRef<Attribute> params = dynAttr.getParams();
119 if (params.size() != constraints.size()) {
120 if (emitError) {
121 StringRef dialectName = attrDef->getDialect()->getNamespace();
122 StringRef attrName = attrDef->getName();
123 emitError() << "attribute '" << dialectName << "." << attrName
124 << "' expects " << params.size() << " parameters but got "
125 << constraints.size();
126 }
127 return failure();
128 }
129
130 for (size_t i = 0, s = params.size(); i < s; i++)
131 if (failed(context.verify(emitError, params[i], constraints[i])))
132 return failure();
133
134 return success();
135}
136
139 ConstraintVerifier &context) const {
140 // Check that the base is a TypeAttr.
141 auto typeAttr = dyn_cast<TypeAttr>(attr);
142 if (!typeAttr) {
143 if (emitError)
144 return emitError() << "expected type, got attribute '" << attr;
145 return failure();
146 }
147
148 // Check that the type base is the expected one.
149 auto dynType = dyn_cast<DynamicType>(typeAttr.getValue());
150 if (!dynType || dynType.getTypeDef() != typeDef) {
151 if (emitError) {
152 StringRef dialectName = typeDef->getDialect()->getNamespace();
153 StringRef attrName = typeDef->getName();
154 return emitError() << "expected base type '" << dialectName << '.'
155 << attrName << "' but got '" << attr << "'";
156 }
157 return failure();
158 }
159
160 // Check that the parameters satisfy the constraints.
161 ArrayRef<Attribute> params = dynType.getParams();
162 if (params.size() != constraints.size()) {
163 if (emitError) {
164 StringRef dialectName = typeDef->getDialect()->getNamespace();
165 StringRef attrName = typeDef->getName();
166 emitError() << "attribute '" << dialectName << "." << attrName
167 << "' expects " << params.size() << " parameters but got "
168 << constraints.size();
169 }
170 return failure();
171 }
172
173 for (size_t i = 0, s = params.size(); i < s; i++)
174 if (failed(context.verify(emitError, params[i], constraints[i])))
175 return failure();
176
177 return success();
178}
179
180LogicalResult
182 Attribute attr, ConstraintVerifier &context) const {
183 for (unsigned constr : constraints) {
184 // We do not pass the `emitError` here, since we want to emit an error
185 // only if none of the constraints are satisfied.
186 if (succeeded(context.verify({}, attr, constr))) {
187 return success();
188 }
189 }
190
191 if (emitError)
192 return emitError() << "'" << attr << "' does not satisfy the constraint";
193 return failure();
194}
195
196LogicalResult
198 Attribute attr, ConstraintVerifier &context) const {
199 for (unsigned constr : constraints) {
200 if (failed(context.verify(emitError, attr, constr))) {
201 return failure();
202 }
203 }
204
205 return success();
206}
207
208LogicalResult
214
216 ConstraintVerifier &constraintContext) {
217 const auto emitError = [parentOp = region.getParentOp()](mlir::Location loc) {
218 return [loc, parentOp] {
220 // If we already have been given location of the parent operation, which
221 // might happen when the region location is passed, we do not want to
222 // produce the note on the same location
223 if (loc != parentOp->getLoc())
224 diag.attachNote(parentOp->getLoc()).append("see the operation");
225 return diag;
226 };
227 };
228
229 if (blockCount.has_value() && *blockCount != region.getBlocks().size()) {
230 return emitError(region.getLoc())()
231 << "expected region " << region.getRegionNumber() << " to have "
232 << *blockCount << " block(s) but got " << region.getBlocks().size();
233 }
234
235 if (argumentConstraints.has_value()) {
236 auto actualArgs = region.getArguments();
237 if (actualArgs.size() != argumentConstraints->size()) {
238 const mlir::Location firstArgLoc =
239 actualArgs.empty() ? region.getLoc() : actualArgs.front().getLoc();
240 return emitError(firstArgLoc)()
241 << "expected region " << region.getRegionNumber() << " to have "
242 << argumentConstraints->size() << " arguments but got "
243 << actualArgs.size();
244 }
245
246 for (auto [arg, constraint] : llvm::zip(actualArgs, *argumentConstraints)) {
247 mlir::Attribute type = TypeAttr::get(arg.getType());
248 if (failed(constraintContext.verify(emitError(arg.getLoc()), type,
249 constraint))) {
250 return failure();
251 }
252 }
253 }
254 return success();
255}
return success()
static std::string diag(const llvm::Value &value)
StringRef getName() const
Return the unique name representing the type.
StringRef getName() const
Return the unique name representing the type.
Attributes are known-constant values of operations.
Definition Attributes.h:25
const AbstractTy & getAbstractAttribute() const
Return the abstract descriptor for this attribute.
Definition Attributes.h:97
TypeID getTypeID()
Return a unique identifier for the concrete attribute type.
Definition Attributes.h:52
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
BlockArgListType getArguments()
Definition Region.h:81
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Definition Region.cpp:62
Location getLoc()
Return a location for this region.
Definition Region.cpp:31
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:200
BlockListType & getBlocks()
Definition Region.h:45
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
const AbstractTy & getAbstractType() const
Return the abstract type descriptor for this type.
Definition Types.h:187
TypeID getTypeID()
Return a unique identifier for the concrete type.
Definition Types.h:101
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
Provides context to the verification of constraints.
ConstraintVerifier(ArrayRef< std::unique_ptr< Constraint > > constraints)
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, unsigned variable)
Check that a constraint is satisfied by an attribute.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
LogicalResult verify(function_ref< InFlightDiagnostic()> emitError, Attribute attr, ConstraintVerifier &context) const override
Check that an attribute is satisfying the constraint.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152
LogicalResult verify(mlir::Region &region, ConstraintVerifier &constraintContext)
Check that the region satisfies the constraint.