MLIR  20.0.0git
IRDL.cpp
Go to the documentation of this file.
1 //===- IRDL.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 
11 #include "mlir/IR/Builders.h"
13 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/OpDefinition.h"
18 #include "mlir/IR/Operation.h"
19 #include "mlir/Support/LLVM.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/TypeSwitch.h"
22 #include "llvm/IR/Metadata.h"
23 #include "llvm/Support/Casting.h"
24 
25 using namespace mlir;
26 using namespace mlir::irdl;
27 
28 //===----------------------------------------------------------------------===//
29 // IRDL dialect.
30 //===----------------------------------------------------------------------===//
31 
32 #include "mlir/Dialect/IRDL/IR/IRDL.cpp.inc"
33 
34 #include "mlir/Dialect/IRDL/IR/IRDLDialect.cpp.inc"
35 
36 void IRDLDialect::initialize() {
37  addOperations<
38 #define GET_OP_LIST
39 #include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"
40  >();
41  addTypes<
42 #define GET_TYPEDEF_LIST
43 #include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
44  >();
45  addAttributes<
46 #define GET_ATTRDEF_LIST
47 #include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
48  >();
49 }
50 
51 //===----------------------------------------------------------------------===//
52 // Parsing/Printing
53 //===----------------------------------------------------------------------===//
54 
55 /// Parse a region, and add a single block if the region is empty.
56 /// If no region is parsed, create a new region with a single empty block.
57 static ParseResult parseSingleBlockRegion(OpAsmParser &p, Region &region) {
58  auto regionParseRes = p.parseOptionalRegion(region);
59  if (regionParseRes.has_value() && failed(regionParseRes.value()))
60  return failure();
61 
62  // If the region is empty, add a single empty block.
63  if (region.empty())
64  region.push_back(new Block());
65 
66  return success();
67 }
68 
70  Region &region) {
71  if (!region.getBlocks().front().empty())
72  p.printRegion(region);
73 }
74 
75 LogicalResult DialectOp::verify() {
76  if (!Dialect::isValidNamespace(getName()))
77  return emitOpError("invalid dialect name");
78  return success();
79 }
80 
81 LogicalResult OperandsOp::verify() {
82  size_t numVariadicities = getVariadicity().size();
83  size_t numOperands = getNumOperands();
84 
85  if (numOperands != numVariadicities)
86  return emitOpError()
87  << "the number of operands and their variadicities must be "
88  "the same, but got "
89  << numOperands << " and " << numVariadicities << " respectively";
90 
91  return success();
92 }
93 
94 LogicalResult ResultsOp::verify() {
95  size_t numVariadicities = getVariadicity().size();
96  size_t numOperands = this->getNumOperands();
97 
98  if (numOperands != numVariadicities)
99  return emitOpError()
100  << "the number of operands and their variadicities must be "
101  "the same, but got "
102  << numOperands << " and " << numVariadicities << " respectively";
103 
104  return success();
105 }
106 
107 LogicalResult AttributesOp::verify() {
108  size_t namesSize = getAttributeValueNames().size();
109  size_t valuesSize = getAttributeValues().size();
110 
111  if (namesSize != valuesSize)
112  return emitOpError()
113  << "the number of attribute names and their constraints must be "
114  "the same but got "
115  << namesSize << " and " << valuesSize << " respectively";
116 
117  return success();
118 }
119 
120 LogicalResult BaseOp::verify() {
121  std::optional<StringRef> baseName = getBaseName();
122  std::optional<SymbolRefAttr> baseRef = getBaseRef();
123  if (baseName.has_value() == baseRef.has_value())
124  return emitOpError() << "the base type or attribute should be specified by "
125  "either a name or a reference";
126 
127  if (baseName &&
128  (baseName->empty() || ((*baseName)[0] != '!' && (*baseName)[0] != '#')))
129  return emitOpError() << "the base type or attribute name should start with "
130  "'!' or '#'";
131 
132  return success();
133 }
134 
135 /// Finds whether the provided symbol is an IRDL type or attribute definition.
136 /// The source operation must be within a DialectOp.
137 static LogicalResult
139  Operation *source, SymbolRefAttr symbol) {
140  Operation *targetOp =
141  irdl::lookupSymbolNearDialect(symbolTable, source, symbol);
142 
143  if (!targetOp)
144  return source->emitOpError() << "symbol '" << symbol << "' not found";
145 
146  if (!isa<TypeOp, AttributeOp>(targetOp))
147  return source->emitOpError() << "symbol '" << symbol
148  << "' does not refer to a type or attribute "
149  "definition (refers to '"
150  << targetOp->getName() << "')";
151 
152  return success();
153 }
154 
155 LogicalResult BaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
156  std::optional<SymbolRefAttr> baseRef = getBaseRef();
157  if (!baseRef)
158  return success();
159 
160  return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);
161 }
162 
163 LogicalResult
164 ParametricOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
165  std::optional<SymbolRefAttr> baseRef = getBaseType();
166  if (!baseRef)
167  return success();
168 
169  return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);
170 }
171 
172 /// Parse a value with its variadicity first. By default, the variadicity is
173 /// single.
174 ///
175 /// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
176 static ParseResult
179  VariadicityAttr &variadicityAttr) {
180  MLIRContext *ctx = p.getBuilder().getContext();
181 
182  // Parse the variadicity, if present
183  if (p.parseOptionalKeyword("single").succeeded()) {
184  variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
185  } else if (p.parseOptionalKeyword("optional").succeeded()) {
186  variadicityAttr = VariadicityAttr::get(ctx, Variadicity::optional);
187  } else if (p.parseOptionalKeyword("variadic").succeeded()) {
188  variadicityAttr = VariadicityAttr::get(ctx, Variadicity::variadic);
189  } else {
190  variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
191  }
192 
193  // Parse the value
194  if (p.parseOperand(operand))
195  return failure();
196  return success();
197 }
198 
199 /// Parse a list of values with their variadicities first. By default, the
200 /// variadicity is single.
201 ///
202 /// values-with-variadicity ::=
203 /// `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
204 /// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
205 static ParseResult parseValuesWithVariadicity(
207  VariadicityArrayAttr &variadicityAttr) {
208  Builder &builder = p.getBuilder();
209  MLIRContext *ctx = builder.getContext();
210  SmallVector<VariadicityAttr> variadicities;
211 
212  // Parse a single value with its variadicity
213  auto parseOne = [&] {
215  VariadicityAttr variadicity;
216  if (parseValueWithVariadicity(p, operand, variadicity))
217  return failure();
218  operands.push_back(operand);
219  variadicities.push_back(variadicity);
220  return success();
221  };
222 
224  return failure();
225  variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);
226  return success();
227 }
228 
229 /// Print a list of values with their variadicities first. By default, the
230 /// variadicity is single.
231 ///
232 /// values-with-variadicity ::=
233 /// `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
234 /// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
236  OperandRange operands,
237  VariadicityArrayAttr variadicityAttr) {
238  p << "(";
239  interleaveComma(llvm::seq<int>(0, operands.size()), p, [&](int i) {
240  Variadicity variadicity = variadicityAttr[i].getValue();
241  if (variadicity != Variadicity::single) {
242  p << stringifyVariadicity(variadicity) << " ";
243  }
244  p << operands[i];
245  });
246  p << ")";
247 }
248 
249 static ParseResult
252  ArrayAttr &attrNamesAttr) {
253  Builder &builder = p.getBuilder();
254  SmallVector<Attribute> attrNames;
255  if (succeeded(p.parseOptionalLBrace())) {
256  auto parseOperands = [&]() {
257  if (p.parseAttribute(attrNames.emplace_back()) || p.parseEqual() ||
258  p.parseOperand(attrOperands.emplace_back()))
259  return failure();
260  return success();
261  };
262  if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())
263  return failure();
264  }
265  attrNamesAttr = builder.getArrayAttr(attrNames);
266  return success();
267 }
268 
269 static void printAttributesOp(OpAsmPrinter &p, AttributesOp op,
270  OperandRange attrArgs, ArrayAttr attrNames) {
271  if (attrNames.empty())
272  return;
273  p << "{";
274  interleaveComma(llvm::seq<int>(0, attrNames.size()), p,
275  [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });
276  p << '}';
277 }
278 
279 LogicalResult RegionOp::verify() {
280  if (IntegerAttr numberOfBlocks = getNumberOfBlocksAttr())
281  if (int64_t number = numberOfBlocks.getInt(); number <= 0) {
282  return emitOpError("the number of blocks is expected to be >= 1 but got ")
283  << number;
284  }
285  return success();
286 }
287 
288 #include "mlir/Dialect/IRDL/IR/IRDLInterfaces.cpp.inc"
289 
290 #define GET_TYPEDEF_CLASSES
291 #include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
292 
293 #include "mlir/Dialect/IRDL/IR/IRDLEnums.cpp.inc"
294 
295 #define GET_ATTRDEF_CLASSES
296 #include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
297 
298 #define GET_OP_CLASSES
299 #include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"
static ParseResult parseValueWithVariadicity(OpAsmParser &p, OpAsmParser::UnresolvedOperand &operand, VariadicityAttr &variadicityAttr)
Parse a value with its variadicity first.
Definition: IRDL.cpp:177
static void printAttributesOp(OpAsmPrinter &p, AttributesOp op, OperandRange attrArgs, ArrayAttr attrNames)
Definition: IRDL.cpp:269
static LogicalResult checkSymbolIsTypeOrAttribute(SymbolTableCollection &symbolTable, Operation *source, SymbolRefAttr symbol)
Finds whether the provided symbol is an IRDL type or attribute definition.
Definition: IRDL.cpp:138
static ParseResult parseValuesWithVariadicity(OpAsmParser &p, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, VariadicityArrayAttr &variadicityAttr)
Parse a list of values with their variadicities first.
Definition: IRDL.cpp:205
static ParseResult parseSingleBlockRegion(OpAsmParser &p, Region &region)
Parse a region, and add a single block if the region is empty.
Definition: IRDL.cpp:57
static ParseResult parseAttributesOp(OpAsmParser &p, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &attrOperands, ArrayAttr &attrNamesAttr)
Definition: IRDL.cpp:250
static void printSingleBlockRegion(OpAsmPrinter &p, Operation *op, Region &region)
Definition: IRDL.cpp:69
static void printValuesWithVariadicity(OpAsmPrinter &p, Operation *op, OperandRange operands, VariadicityArrayAttr variadicityAttr)
Print a list of values with their variadicities first.
Definition: IRDL.cpp:235
@ Paren
Parens surrounding zero or more operands.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual ParseResult parseRBrace()=0
Parse a } token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual ParseResult parseOptionalLBrace()=0
Parse a { token if present.
Block represents an ordered list of Operations.
Definition: Block.h:31
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
MLIRContext * getContext() const
Definition: Builders.h:55
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:277
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
Definition: Dialect.cpp:92
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual OptionalParseResult parseOptionalRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region if present.
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:42
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:671
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
void push_back(Block *block)
Definition: Region.h:61
bool empty()
Definition: Region.h:60
BlockListType & getBlocks()
Definition: Region.h:45
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
Operation * lookupSymbolNearDialect(SymbolTableCollection &symbolTable, Operation *source, SymbolRefAttr symbol)
Looks up a symbol from the symbol table containing the source operation's dialect definition operatio...
Definition: IRDLSymbols.cpp:28
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:421
This is the representation of an operand reference.