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 ®ion, 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