1 //===- PDLInterp.cpp - PDL Interpreter Dialect ------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, 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/PDLInterp/IR/PDLInterp.h"
10 #include "mlir/Dialect/PDL/IR/PDLTypes.h"
11 #include "mlir/IR/BuiltinTypes.h"
12 #include "mlir/IR/DialectImplementation.h"
13 
14 using namespace mlir;
15 using namespace mlir::pdl_interp;
16 
17 #include "mlir/Dialect/PDLInterp/IR/PDLInterpOpsDialect.cpp.inc"
18 
19 //===----------------------------------------------------------------------===//
20 // PDLInterp Dialect
21 //===----------------------------------------------------------------------===//
22 
23 void PDLInterpDialect::initialize() {
24   addOperations<
25 #define GET_OP_LIST
26 #include "mlir/Dialect/PDLInterp/IR/PDLInterpOps.cpp.inc"
27       >();
28 }
29 
30 template <typename OpT>
31 static LogicalResult verifySwitchOp(OpT op) {
32   // Verify that the number of case destinations matches the number of case
33   // values.
34   size_t numDests = op.cases().size();
35   size_t numValues = op.caseValues().size();
36   if (numDests != numValues) {
37     return op.emitOpError(
38                "expected number of cases to match the number of case "
39                "values, got ")
40            << numDests << " but expected " << numValues;
41   }
42   return success();
43 }
44 
45 //===----------------------------------------------------------------------===//
46 // pdl_interp::CreateOperationOp
47 //===----------------------------------------------------------------------===//
48 
49 static ParseResult parseCreateOperationOpAttributes(
50     OpAsmParser &p, SmallVectorImpl<OpAsmParser::OperandType> &attrOperands,
51     ArrayAttr &attrNamesAttr) {
52   Builder &builder = p.getBuilder();
53   SmallVector<Attribute, 4> attrNames;
54   if (succeeded(p.parseOptionalLBrace())) {
55     do {
56       StringAttr nameAttr;
57       OpAsmParser::OperandType operand;
58       if (p.parseAttribute(nameAttr) || p.parseEqual() ||
59           p.parseOperand(operand))
60         return failure();
61       attrNames.push_back(nameAttr);
62       attrOperands.push_back(operand);
63     } while (succeeded(p.parseOptionalComma()));
64     if (p.parseRBrace())
65       return failure();
66   }
67   attrNamesAttr = builder.getArrayAttr(attrNames);
68   return success();
69 }
70 
71 static void printCreateOperationOpAttributes(OpAsmPrinter &p,
72                                              CreateOperationOp op,
73                                              OperandRange attrArgs,
74                                              ArrayAttr attrNames) {
75   if (attrNames.empty())
76     return;
77   p << " {";
78   interleaveComma(llvm::seq<int>(0, attrNames.size()), p,
79                   [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });
80   p << '}';
81 }
82 
83 //===----------------------------------------------------------------------===//
84 // pdl_interp::ForEachOp
85 //===----------------------------------------------------------------------===//
86 
87 void ForEachOp::build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
88                       Value range, Block *successor, bool initLoop) {
89   build(builder, state, range, successor);
90   if (initLoop) {
91     // Create the block and the loop variable.
92     // FIXME: Allow passing in a proper location for the loop variable.
93     auto rangeType = range.getType().cast<pdl::RangeType>();
94     state.regions.front()->emplaceBlock();
95     state.regions.front()->addArgument(rangeType.getElementType(),
96                                        state.location);
97   }
98 }
99 
100 ParseResult ForEachOp::parse(OpAsmParser &parser, OperationState &result) {
101   // Parse the loop variable followed by type.
102   OpAsmParser::OperandType loopVariable;
103   Type loopVariableType;
104   if (parser.parseRegionArgument(loopVariable) ||
105       parser.parseColonType(loopVariableType))
106     return failure();
107 
108   // Parse the "in" keyword.
109   if (parser.parseKeyword("in", " after loop variable"))
110     return failure();
111 
112   // Parse the operand (value range).
113   OpAsmParser::OperandType operandInfo;
114   if (parser.parseOperand(operandInfo))
115     return failure();
116 
117   // Resolve the operand.
118   Type rangeType = pdl::RangeType::get(loopVariableType);
119   if (parser.resolveOperand(operandInfo, rangeType, result.operands))
120     return failure();
121 
122   // Parse the body region.
123   Region *body = result.addRegion();
124   if (parser.parseRegion(*body, {loopVariable}, {loopVariableType}))
125     return failure();
126 
127   // Parse the attribute dictionary.
128   if (parser.parseOptionalAttrDict(result.attributes))
129     return failure();
130 
131   // Parse the successor.
132   Block *successor;
133   if (parser.parseArrow() || parser.parseSuccessor(successor))
134     return failure();
135   result.addSuccessors(successor);
136 
137   return success();
138 }
139 
140 void ForEachOp::print(OpAsmPrinter &p) {
141   BlockArgument arg = getLoopVariable();
142   p << ' ' << arg << " : " << arg.getType() << " in " << values() << ' ';
143   p.printRegion(region(), /*printEntryBlockArgs=*/false);
144   p.printOptionalAttrDict((*this)->getAttrs());
145   p << " -> ";
146   p.printSuccessor(successor());
147 }
148 
149 LogicalResult ForEachOp::verify() {
150   // Verify that the operation has exactly one argument.
151   if (region().getNumArguments() != 1)
152     return emitOpError("requires exactly one argument");
153 
154   // Verify that the loop variable and the operand (value range)
155   // have compatible types.
156   BlockArgument arg = getLoopVariable();
157   Type rangeType = pdl::RangeType::get(arg.getType());
158   if (rangeType != values().getType())
159     return emitOpError("operand must be a range of loop variable type");
160 
161   return success();
162 }
163 
164 //===----------------------------------------------------------------------===//
165 // pdl_interp::GetValueTypeOp
166 //===----------------------------------------------------------------------===//
167 
168 /// Given the result type of a `GetValueTypeOp`, return the expected input type.
169 static Type getGetValueTypeOpValueType(Type type) {
170   Type valueTy = pdl::ValueType::get(type.getContext());
171   return type.isa<pdl::RangeType>() ? pdl::RangeType::get(valueTy) : valueTy;
172 }
173 
174 //===----------------------------------------------------------------------===//
175 // pdl_interp::SwitchAttributeOp
176 //===----------------------------------------------------------------------===//
177 
178 LogicalResult SwitchAttributeOp::verify() { return verifySwitchOp(*this); }
179 
180 //===----------------------------------------------------------------------===//
181 // pdl_interp::SwitchOperandCountOp
182 //===----------------------------------------------------------------------===//
183 
184 LogicalResult SwitchOperandCountOp::verify() { return verifySwitchOp(*this); }
185 
186 //===----------------------------------------------------------------------===//
187 // pdl_interp::SwitchOperationNameOp
188 //===----------------------------------------------------------------------===//
189 
190 LogicalResult SwitchOperationNameOp::verify() { return verifySwitchOp(*this); }
191 
192 //===----------------------------------------------------------------------===//
193 // pdl_interp::SwitchResultCountOp
194 //===----------------------------------------------------------------------===//
195 
196 LogicalResult SwitchResultCountOp::verify() { return verifySwitchOp(*this); }
197 
198 //===----------------------------------------------------------------------===//
199 // pdl_interp::SwitchTypeOp
200 //===----------------------------------------------------------------------===//
201 
202 LogicalResult SwitchTypeOp::verify() { return verifySwitchOp(*this); }
203 
204 //===----------------------------------------------------------------------===//
205 // pdl_interp::SwitchTypesOp
206 //===----------------------------------------------------------------------===//
207 
208 LogicalResult SwitchTypesOp::verify() { return verifySwitchOp(*this); }
209 
210 //===----------------------------------------------------------------------===//
211 // TableGen Auto-Generated Op and Interface Definitions
212 //===----------------------------------------------------------------------===//
213 
214 #define GET_OP_CLASSES
215 #include "mlir/Dialect/PDLInterp/IR/PDLInterpOps.cpp.inc"
216