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 
22 using namespace mlir;
23 using namespace mlir::irdl;
24 
26  ArrayRef<std::unique_ptr<Constraint>> constraints)
27  : constraints(constraints), assigned() {
28  assigned.resize(this->constraints.size());
29 }
30 
31 LogicalResult
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 
68 LogicalResult
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 
81 LogicalResult
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 
180 LogicalResult
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 
196 LogicalResult
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 
208 LogicalResult
210  Attribute attr,
211  ConstraintVerifier &context) const {
212  return success();
213 }
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 }
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.
Definition: TypeSupport.h:110
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
StringRef getNamespace() const
Definition: Dialect.h:54
ExtensibleDialect * getDialect() const
Return the dialect defining the attribute.
StringRef getName() const
Return the name of the attribute, in the format 'attrname' and not 'dialectname.attrname'.
StringRef getName() const
Return the name of the type, in the format 'typename' and not 'dialectname.typename'.
ExtensibleDialect * getDialect() const
Return the dialect defining the type.
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
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
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
BlockListType & getBlocks()
Definition: Region.h:45
Location getLoc()
Return a location for this region.
Definition: Region.cpp:31
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.
Definition: IRDLVerifiers.h:40
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.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(mlir::Region &region, ConstraintVerifier &constraintContext)
Check that the region satisfies the constraint.