320 lines · cpp
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-exception6//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/Interfaces/FunctionImplementation.h"13 14using namespace mlir;15using namespace mlir::pdl_interp;16 17#include "mlir/Dialect/PDLInterp/IR/PDLInterpOpsDialect.cpp.inc"18 19//===----------------------------------------------------------------------===//20// PDLInterp Dialect21//===----------------------------------------------------------------------===//22 23void PDLInterpDialect::initialize() {24 addOperations<25#define GET_OP_LIST26#include "mlir/Dialect/PDLInterp/IR/PDLInterpOps.cpp.inc"27 >();28}29 30template <typename OpT>31static LogicalResult verifySwitchOp(OpT op) {32 // Verify that the number of case destinations matches the number of case33 // values.34 size_t numDests = op.getCases().size();35 size_t numValues = op.getCaseValues().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::CreateOperationOp47//===----------------------------------------------------------------------===//48 49LogicalResult CreateOperationOp::verify() {50 if (!getInferredResultTypes())51 return success();52 if (!getInputResultTypes().empty()) {53 return emitOpError("with inferred results cannot also have "54 "explicit result types");55 }56 OperationName opName(getName(), getContext());57 if (!opName.hasInterface<InferTypeOpInterface>()) {58 return emitOpError()59 << "has inferred results, but the created operation '" << opName60 << "' does not support result type inference (or is not "61 "registered)";62 }63 return success();64}65 66static ParseResult parseCreateOperationOpAttributes(67 OpAsmParser &p,68 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &attrOperands,69 ArrayAttr &attrNamesAttr) {70 Builder &builder = p.getBuilder();71 SmallVector<Attribute, 4> attrNames;72 if (succeeded(p.parseOptionalLBrace())) {73 auto parseOperands = [&]() {74 StringAttr nameAttr;75 OpAsmParser::UnresolvedOperand operand;76 if (p.parseAttribute(nameAttr) || p.parseEqual() ||77 p.parseOperand(operand))78 return failure();79 attrNames.push_back(nameAttr);80 attrOperands.push_back(operand);81 return success();82 };83 if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())84 return failure();85 }86 attrNamesAttr = builder.getArrayAttr(attrNames);87 return success();88}89 90static void printCreateOperationOpAttributes(OpAsmPrinter &p,91 CreateOperationOp op,92 OperandRange attrArgs,93 ArrayAttr attrNames) {94 if (attrNames.empty())95 return;96 p << " {";97 interleaveComma(llvm::seq<int>(0, attrNames.size()), p,98 [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });99 p << '}';100}101 102static ParseResult parseCreateOperationOpResults(103 OpAsmParser &p,104 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &resultOperands,105 SmallVectorImpl<Type> &resultTypes, UnitAttr &inferredResultTypes) {106 if (failed(p.parseOptionalArrow()))107 return success();108 109 // Handle the case of inferred results.110 if (succeeded(p.parseOptionalLess())) {111 if (p.parseKeyword("inferred") || p.parseGreater())112 return failure();113 inferredResultTypes = p.getBuilder().getUnitAttr();114 return success();115 }116 117 // Otherwise, parse the explicit results.118 return failure(p.parseLParen() || p.parseOperandList(resultOperands) ||119 p.parseColonTypeList(resultTypes) || p.parseRParen());120}121 122static void printCreateOperationOpResults(OpAsmPrinter &p, CreateOperationOp op,123 OperandRange resultOperands,124 TypeRange resultTypes,125 UnitAttr inferredResultTypes) {126 // Handle the case of inferred results.127 if (inferredResultTypes) {128 p << " -> <inferred>";129 return;130 }131 132 // Otherwise, handle the explicit results.133 if (!resultTypes.empty())134 p << " -> (" << resultOperands << " : " << resultTypes << ")";135}136 137//===----------------------------------------------------------------------===//138// pdl_interp::ForEachOp139//===----------------------------------------------------------------------===//140 141void ForEachOp::build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,142 Value range, Block *successor, bool initLoop) {143 build(builder, state, range, successor);144 if (initLoop) {145 // Create the block and the loop variable.146 // FIXME: Allow passing in a proper location for the loop variable.147 auto rangeType = llvm::cast<pdl::RangeType>(range.getType());148 state.regions.front()->emplaceBlock();149 state.regions.front()->addArgument(rangeType.getElementType(),150 state.location);151 }152}153 154ParseResult ForEachOp::parse(OpAsmParser &parser, OperationState &result) {155 // Parse the loop variable followed by type.156 OpAsmParser::Argument loopVariable;157 OpAsmParser::UnresolvedOperand operandInfo;158 if (parser.parseArgument(loopVariable, /*allowType=*/true) ||159 parser.parseKeyword("in", " after loop variable") ||160 // Parse the operand (value range).161 parser.parseOperand(operandInfo))162 return failure();163 164 // Resolve the operand.165 Type rangeType = pdl::RangeType::get(loopVariable.type);166 if (parser.resolveOperand(operandInfo, rangeType, result.operands))167 return failure();168 169 // Parse the body region.170 Region *body = result.addRegion();171 Block *successor;172 if (parser.parseRegion(*body, loopVariable) ||173 parser.parseOptionalAttrDict(result.attributes) ||174 // Parse the successor.175 parser.parseArrow() || parser.parseSuccessor(successor))176 return failure();177 178 result.addSuccessors(successor);179 return success();180}181 182void ForEachOp::print(OpAsmPrinter &p) {183 BlockArgument arg = getLoopVariable();184 p << ' ' << arg << " : " << arg.getType() << " in " << getValues() << ' ';185 p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);186 p.printOptionalAttrDict((*this)->getAttrs());187 p << " -> ";188 p.printSuccessor(getSuccessor());189}190 191LogicalResult ForEachOp::verify() {192 // Verify that the operation has exactly one argument.193 if (getRegion().getNumArguments() != 1)194 return emitOpError("requires exactly one argument");195 196 // Verify that the loop variable and the operand (value range)197 // have compatible types.198 BlockArgument arg = getLoopVariable();199 Type rangeType = pdl::RangeType::get(arg.getType());200 if (rangeType != getValues().getType())201 return emitOpError("operand must be a range of loop variable type");202 203 return success();204}205 206//===----------------------------------------------------------------------===//207// pdl_interp::FuncOp208//===----------------------------------------------------------------------===//209 210void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,211 FunctionType type, ArrayRef<NamedAttribute> attrs) {212 buildWithEntryBlock(builder, state, name, type, attrs, type.getInputs());213}214 215ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {216 auto buildFuncType =217 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,218 function_interface_impl::VariadicFlag,219 std::string &) { return builder.getFunctionType(argTypes, results); };220 221 return function_interface_impl::parseFunctionOp(222 parser, result, /*allowVariadic=*/false,223 getFunctionTypeAttrName(result.name), buildFuncType,224 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));225}226 227void FuncOp::print(OpAsmPrinter &p) {228 function_interface_impl::printFunctionOp(229 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),230 getArgAttrsAttrName(), getResAttrsAttrName());231}232 233//===----------------------------------------------------------------------===//234// pdl_interp::GetValueTypeOp235//===----------------------------------------------------------------------===//236 237/// Given the result type of a `GetValueTypeOp`, return the expected input type.238static Type getGetValueTypeOpValueType(Type type) {239 Type valueTy = pdl::ValueType::get(type.getContext());240 return llvm::isa<pdl::RangeType>(type) ? pdl::RangeType::get(valueTy)241 : valueTy;242}243 244//===----------------------------------------------------------------------===//245// pdl::CreateRangeOp246//===----------------------------------------------------------------------===//247 248static ParseResult parseRangeType(OpAsmParser &p, TypeRange argumentTypes,249 Type &resultType) {250 // If arguments were provided, infer the result type from the argument list.251 if (!argumentTypes.empty()) {252 resultType =253 pdl::RangeType::get(pdl::getRangeElementTypeOrSelf(argumentTypes[0]));254 return success();255 }256 // Otherwise, parse the type as a trailing type.257 return p.parseColonType(resultType);258}259 260static void printRangeType(OpAsmPrinter &p, CreateRangeOp op,261 TypeRange argumentTypes, Type resultType) {262 if (argumentTypes.empty())263 p << ": " << resultType;264}265 266LogicalResult CreateRangeOp::verify() {267 Type elementType = getType().getElementType();268 for (Type operandType : getOperandTypes()) {269 Type operandElementType = pdl::getRangeElementTypeOrSelf(operandType);270 if (operandElementType != elementType) {271 return emitOpError("expected operand to have element type ")272 << elementType << ", but got " << operandElementType;273 }274 }275 return success();276}277 278//===----------------------------------------------------------------------===//279// pdl_interp::SwitchAttributeOp280//===----------------------------------------------------------------------===//281 282LogicalResult SwitchAttributeOp::verify() { return verifySwitchOp(*this); }283 284//===----------------------------------------------------------------------===//285// pdl_interp::SwitchOperandCountOp286//===----------------------------------------------------------------------===//287 288LogicalResult SwitchOperandCountOp::verify() { return verifySwitchOp(*this); }289 290//===----------------------------------------------------------------------===//291// pdl_interp::SwitchOperationNameOp292//===----------------------------------------------------------------------===//293 294LogicalResult SwitchOperationNameOp::verify() { return verifySwitchOp(*this); }295 296//===----------------------------------------------------------------------===//297// pdl_interp::SwitchResultCountOp298//===----------------------------------------------------------------------===//299 300LogicalResult SwitchResultCountOp::verify() { return verifySwitchOp(*this); }301 302//===----------------------------------------------------------------------===//303// pdl_interp::SwitchTypeOp304//===----------------------------------------------------------------------===//305 306LogicalResult SwitchTypeOp::verify() { return verifySwitchOp(*this); }307 308//===----------------------------------------------------------------------===//309// pdl_interp::SwitchTypesOp310//===----------------------------------------------------------------------===//311 312LogicalResult SwitchTypesOp::verify() { return verifySwitchOp(*this); }313 314//===----------------------------------------------------------------------===//315// TableGen Auto-Generated Op and Interface Definitions316//===----------------------------------------------------------------------===//317 318#define GET_OP_CLASSES319#include "mlir/Dialect/PDLInterp/IR/PDLInterpOps.cpp.inc"320