xref: /llvm-project/mlir/include/mlir/Dialect/IRDL/IRDLVerifiers.h (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1 //===- IRDLVerifiers.h - 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 
13 #ifndef MLIR_DIALECT_IRDL_IRDLVERIFIERS_H
14 #define MLIR_DIALECT_IRDL_IRDLVERIFIERS_H
15 
16 #include "mlir/IR/Attributes.h"
17 #include "mlir/IR/Region.h"
18 #include "mlir/Support/LLVM.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include <optional>
22 
23 namespace mlir {
24 class InFlightDiagnostic;
25 class DynamicAttrDefinition;
26 class DynamicTypeDefinition;
27 } // namespace mlir
28 
29 namespace mlir {
30 namespace irdl {
31 
32 class AttributeOp;
33 class Constraint;
34 class OperationOp;
35 class TypeOp;
36 
37 /// Provides context to the verification of constraints.
38 /// It contains the assignment of variables to attributes, and the assignment
39 /// of variables to constraints.
40 class ConstraintVerifier {
41 public:
42   ConstraintVerifier(ArrayRef<std::unique_ptr<Constraint>> constraints);
43 
44   /// Check that a constraint is satisfied by an attribute.
45   ///
46   /// Constraints may call other constraint verifiers. If that is the case,
47   /// the constraint verifier will check if the variable is already assigned,
48   /// and if so, check that the attribute is the same as the one assigned.
49   /// If the variable is not assigned, the constraint verifier will
50   /// assign the attribute to the variable, and check that the constraint
51   /// is satisfied.
52   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
53                        Attribute attr, unsigned variable);
54 
55 private:
56   /// The constraints that can be used for verification.
57   ArrayRef<std::unique_ptr<Constraint>> constraints;
58 
59   /// The assignment of variables to attributes. Variables that are not assigned
60   /// are represented by nullopt. Null attributes needs to be supported here as
61   /// some attributes or types might use the null attribute to represent
62   /// optional parameters.
63   SmallVector<std::optional<Attribute>> assigned;
64 };
65 
66 /// Once turned into IRDL verifiers, all constraints are
67 /// attribute constraints. Type constraints are represented
68 /// as `TypeAttr` attribute constraints to simplify verification.
69 /// Verification that a type constraint must yield a
70 /// `TypeAttr` attribute happens before conversion, at the MLIR level.
71 class Constraint {
72 public:
73   virtual ~Constraint() = default;
74 
75   /// Check that an attribute is satisfying the constraint.
76   ///
77   /// Constraints may call other constraint verifiers. If that is the case,
78   /// the constraint verifier will check if the variable is already assigned,
79   /// and if so, check that the attribute is the same as the one assigned.
80   /// If the variable is not assigned, the constraint verifier will
81   /// assign the attribute to the variable, and check that the constraint
82   /// is satisfied.
83   virtual LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
84                                Attribute attr,
85                                ConstraintVerifier &context) const = 0;
86 };
87 
88 /// A constraint that checks that an attribute is equal to a given attribute.
89 class IsConstraint : public Constraint {
90 public:
IsConstraint(Attribute expectedAttribute)91   IsConstraint(Attribute expectedAttribute)
92       : expectedAttribute(expectedAttribute) {}
93 
94   virtual ~IsConstraint() = default;
95 
96   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
97                        Attribute attr,
98                        ConstraintVerifier &context) const override;
99 
100 private:
101   Attribute expectedAttribute;
102 };
103 
104 /// A constraint that checks that an attribute is of a given attribute base
105 /// (e.g. IntegerAttr).
106 class BaseAttrConstraint : public Constraint {
107 public:
BaseAttrConstraint(TypeID baseTypeID,StringRef baseName)108   BaseAttrConstraint(TypeID baseTypeID, StringRef baseName)
109       : baseTypeID(baseTypeID), baseName(baseName) {}
110 
111   virtual ~BaseAttrConstraint() = default;
112 
113   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
114                        Attribute attr,
115                        ConstraintVerifier &context) const override;
116 
117 private:
118   /// The expected base attribute typeID.
119   TypeID baseTypeID;
120 
121   /// The base attribute name, only used for error reporting.
122   StringRef baseName;
123 };
124 
125 /// A constraint that checks that a type is of a given type base (e.g.
126 /// IntegerType).
127 class BaseTypeConstraint : public Constraint {
128 public:
BaseTypeConstraint(TypeID baseTypeID,StringRef baseName)129   BaseTypeConstraint(TypeID baseTypeID, StringRef baseName)
130       : baseTypeID(baseTypeID), baseName(baseName) {}
131 
132   virtual ~BaseTypeConstraint() = default;
133 
134   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
135                        Attribute attr,
136                        ConstraintVerifier &context) const override;
137 
138 private:
139   /// The expected base type typeID.
140   TypeID baseTypeID;
141 
142   /// The base type name, only used for error reporting.
143   StringRef baseName;
144 };
145 
146 /// A constraint that checks that an attribute is of a
147 /// specific dynamic attribute definition, and that all of its parameters
148 /// satisfy the given constraints.
149 class DynParametricAttrConstraint : public Constraint {
150 public:
DynParametricAttrConstraint(DynamicAttrDefinition * attrDef,SmallVector<unsigned> constraints)151   DynParametricAttrConstraint(DynamicAttrDefinition *attrDef,
152                               SmallVector<unsigned> constraints)
153       : attrDef(attrDef), constraints(std::move(constraints)) {}
154 
155   virtual ~DynParametricAttrConstraint() = default;
156 
157   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
158                        Attribute attr,
159                        ConstraintVerifier &context) const override;
160 
161 private:
162   DynamicAttrDefinition *attrDef;
163   SmallVector<unsigned> constraints;
164 };
165 
166 /// A constraint that checks that a type is of a specific dynamic type
167 /// definition, and that all of its parameters satisfy the given constraints.
168 class DynParametricTypeConstraint : public Constraint {
169 public:
DynParametricTypeConstraint(DynamicTypeDefinition * typeDef,SmallVector<unsigned> constraints)170   DynParametricTypeConstraint(DynamicTypeDefinition *typeDef,
171                               SmallVector<unsigned> constraints)
172       : typeDef(typeDef), constraints(std::move(constraints)) {}
173 
174   virtual ~DynParametricTypeConstraint() = default;
175 
176   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
177                        Attribute attr,
178                        ConstraintVerifier &context) const override;
179 
180 private:
181   DynamicTypeDefinition *typeDef;
182   SmallVector<unsigned> constraints;
183 };
184 
185 /// A constraint checking that one of the given constraints is satisfied.
186 class AnyOfConstraint : public Constraint {
187 public:
AnyOfConstraint(SmallVector<unsigned> constraints)188   AnyOfConstraint(SmallVector<unsigned> constraints)
189       : constraints(std::move(constraints)) {}
190 
191   virtual ~AnyOfConstraint() = default;
192 
193   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
194                        Attribute attr,
195                        ConstraintVerifier &context) const override;
196 
197 private:
198   SmallVector<unsigned> constraints;
199 };
200 
201 /// A constraint checking that all of the given constraints are satisfied.
202 class AllOfConstraint : public Constraint {
203 public:
AllOfConstraint(SmallVector<unsigned> constraints)204   AllOfConstraint(SmallVector<unsigned> constraints)
205       : constraints(std::move(constraints)) {}
206 
207   virtual ~AllOfConstraint() = default;
208 
209   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
210                        Attribute attr,
211                        ConstraintVerifier &context) const override;
212 
213 private:
214   SmallVector<unsigned> constraints;
215 };
216 
217 /// A constraint that is always satisfied.
218 class AnyAttributeConstraint : public Constraint {
219 public:
220   virtual ~AnyAttributeConstraint() = default;
221 
222   LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
223                        Attribute attr,
224                        ConstraintVerifier &context) const override;
225 };
226 
227 /// A constraint checking that a region satisfies `irdl.region` requirements
228 struct RegionConstraint {
229   /// The constructor accepts constrained entities from the `irdl.region`
230   /// operation, such as slots of constraints for the region's arguments and the
231   /// block count.
232 
233   // Both entities are optional, which means if an entity is not present, then
234   // it is not constrained.
RegionConstraintRegionConstraint235   RegionConstraint(std::optional<SmallVector<unsigned>> argumentConstraints,
236                    std::optional<size_t> blockCount)
237       : argumentConstraints(std::move(argumentConstraints)),
238         blockCount(blockCount) {}
239 
240   /// Check that the `region` satisfies the constraint.
241   ///
242   /// `constraintContext` is needed to verify the region's arguments
243   /// constraints.
244   LogicalResult verify(mlir::Region &region,
245                        ConstraintVerifier &constraintContext);
246 
247 private:
248   std::optional<SmallVector<unsigned>> argumentConstraints;
249   std::optional<size_t> blockCount;
250 };
251 
252 /// Generate an op verifier function from the given IRDL operation definition.
253 llvm::unique_function<LogicalResult(Operation *) const> createVerifier(
254     OperationOp operation,
255     const DenseMap<irdl::TypeOp, std::unique_ptr<DynamicTypeDefinition>>
256         &typeDefs,
257     const DenseMap<irdl::AttributeOp, std::unique_ptr<DynamicAttrDefinition>>
258         &attrDefs);
259 } // namespace irdl
260 } // namespace mlir
261 
262 #endif // MLIR_DIALECT_IRDL_IRDLVERIFIERS_H
263