1//===- IRDLOps.cpp - IRDL dialect -------------------------------*- 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#include "mlir/Dialect/IRDL/IR/IRDL.h"
10#include "mlir/IR/ValueRange.h"
11#include <optional>
12
13using namespace mlir;
14using namespace mlir::irdl;
15
16/// Maps given `args` to the index in the `valueToConstr`
17static SmallVector<unsigned>
18getConstraintIndicesForArgs(mlir::OperandRange args,
19 ArrayRef<Value> valueToConstr) {
20 SmallVector<unsigned> constraints;
21 for (Value arg : args) {
22 for (auto [i, value] : enumerate(First&: valueToConstr)) {
23 if (value == arg) {
24 constraints.push_back(Elt: i);
25 break;
26 }
27 }
28 }
29 return constraints;
30}
31
32std::unique_ptr<Constraint> IsOp::getVerifier(
33 ArrayRef<Value> valueToConstr,
34 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
35 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
36 &attrs) {
37 return std::make_unique<IsConstraint>(getExpectedAttr());
38}
39
40std::unique_ptr<Constraint> BaseOp::getVerifier(
41 ArrayRef<Value> valueToConstr,
42 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
43 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
44 &attrs) {
45 MLIRContext *ctx = getContext();
46
47 // Case where the input is a symbol reference.
48 // This corresponds to the case where the base is an IRDL type or attribute.
49 if (auto baseRef = getBaseRef()) {
50 Operation *defOp =
51 SymbolTable::lookupNearestSymbolFrom(getOperation(), baseRef.value());
52
53 // Type case.
54 if (auto typeOp = dyn_cast<TypeOp>(defOp)) {
55 DynamicTypeDefinition *typeDef = types.at(typeOp).get();
56 auto name = StringAttr::get(ctx, typeDef->getDialect()->getNamespace() +
57 "." + typeDef->getName().str());
58 return std::make_unique<BaseTypeConstraint>(typeDef->getTypeID(), name);
59 }
60
61 // Attribute case.
62 auto attrOp = cast<AttributeOp>(defOp);
63 DynamicAttrDefinition *attrDef = attrs.at(attrOp).get();
64 auto name = StringAttr::get(ctx, attrDef->getDialect()->getNamespace() +
65 "." + attrDef->getName().str());
66 return std::make_unique<BaseAttrConstraint>(attrDef->getTypeID(), name);
67 }
68
69 // Case where the input is string literal.
70 // This corresponds to the case where the base is a registered type or
71 // attribute.
72 StringRef baseName = getBaseName().value();
73
74 // Type case.
75 if (baseName[0] == '!') {
76 auto abstractType = AbstractType::lookup(baseName.drop_front(1), ctx);
77 if (!abstractType) {
78 emitError() << "no registered type with name " << baseName;
79 return nullptr;
80 }
81 return std::make_unique<BaseTypeConstraint>(abstractType->get().getTypeID(),
82 abstractType->get().getName());
83 }
84
85 auto abstractAttr = AbstractAttribute::lookup(baseName.drop_front(1), ctx);
86 if (!abstractAttr) {
87 emitError() << "no registered attribute with name " << baseName;
88 return nullptr;
89 }
90 return std::make_unique<BaseAttrConstraint>(abstractAttr->get().getTypeID(),
91 abstractAttr->get().getName());
92}
93
94std::unique_ptr<Constraint> ParametricOp::getVerifier(
95 ArrayRef<Value> valueToConstr,
96 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
97 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
98 &attrs) {
99 SmallVector<unsigned> constraints =
100 getConstraintIndicesForArgs(getArgs(), valueToConstr);
101
102 // Symbol reference case for the base
103 SymbolRefAttr symRef = getBaseType();
104 Operation *defOp =
105 SymbolTable::lookupNearestSymbolFrom(getOperation(), symRef);
106 if (!defOp) {
107 emitError() << symRef << " does not refer to any existing symbol";
108 return nullptr;
109 }
110
111 if (auto typeOp = dyn_cast<TypeOp>(defOp))
112 return std::make_unique<DynParametricTypeConstraint>(types.at(typeOp).get(),
113 constraints);
114
115 if (auto attrOp = dyn_cast<AttributeOp>(defOp))
116 return std::make_unique<DynParametricAttrConstraint>(attrs.at(attrOp).get(),
117 constraints);
118
119 llvm_unreachable("verifier should ensure that the referenced operation is "
120 "either a type or an attribute definition");
121}
122
123std::unique_ptr<Constraint> AnyOfOp::getVerifier(
124 ArrayRef<Value> valueToConstr,
125 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
126 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
127 &attrs) {
128 return std::make_unique<AnyOfConstraint>(
129 getConstraintIndicesForArgs(getArgs(), valueToConstr));
130}
131
132std::unique_ptr<Constraint> AllOfOp::getVerifier(
133 ArrayRef<Value> valueToConstr,
134 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
135 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
136 &attrs) {
137 return std::make_unique<AllOfConstraint>(
138 getConstraintIndicesForArgs(getArgs(), valueToConstr));
139}
140
141std::unique_ptr<Constraint> AnyOp::getVerifier(
142 ArrayRef<Value> valueToConstr,
143 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
144 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
145 &attrs) {
146 return std::make_unique<AnyAttributeConstraint>();
147}
148
149std::unique_ptr<RegionConstraint> RegionOp::getVerifier(
150 ArrayRef<Value> valueToConstr,
151 DenseMap<TypeOp, std::unique_ptr<DynamicTypeDefinition>> const &types,
152 DenseMap<AttributeOp, std::unique_ptr<DynamicAttrDefinition>> const
153 &attrs) {
154 return std::make_unique<RegionConstraint>(
155 getConstrainedArguments() ? std::optional{getConstraintIndicesForArgs(
156 getEntryBlockArgs(), valueToConstr)}
157 : std::nullopt,
158 getNumberOfBlocks());
159}
160

source code of mlir/lib/Dialect/IRDL/IR/IRDLOps.cpp