MLIR 24.0.0git
ArmGraphOps.cpp
Go to the documentation of this file.
1//===- ArmGraphOps.cpp - MLIR SPIR-V SPV_ARM_graph operations -------------===//
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// This file defines the SPV_ARM_graph operations in the SPIR-V dialect.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "SPIRVParsingUtils.h"
16
20#include "mlir/IR/Builders.h"
22#include "mlir/IR/Operation.h"
24#include "llvm/Support/InterleavedRange.h"
25
26using namespace mlir;
27using namespace mlir::spirv::AttrNames;
28
29//===----------------------------------------------------------------------===//
30// spirv.GraphARM
31//===----------------------------------------------------------------------===//
32
33ParseResult spirv::GraphARMOp::parse(OpAsmParser &parser,
35 Builder &builder = parser.getBuilder();
36
38
39 // Parse the name as a symbol.
40 StringAttr nameAttr;
41 if (parser.parseSymbolName(nameAttr, getSymNameAttrName(result.name),
42 result.attributes))
43 return failure();
44
45 // Parse the function signature.
46 bool isVariadic = false;
48 SmallVector<Type> resultTypes;
51 parser, /*allowVariadic=*/false, entryArgs, isVariadic, resultTypes,
52 resultAttrs))
53 return failure();
54
55 SmallVector<Type> argTypes = llvm::map_to_vector(
56 entryArgs, [](const OpAsmParser::Argument &arg) { return arg.type; });
57 GraphType grType = builder.getGraphType(argTypes, resultTypes);
58 result.addAttribute(getFunctionTypeAttrName(result.name),
59 TypeAttr::get(grType));
60
61 // If additional attributes are present, parse them.
62 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
63 return failure();
64
65 // Add the attributes to the function arguments.
66 assert(resultAttrs.size() == resultTypes.size());
68 builder, result, entryArgs, resultAttrs, getArgAttrsAttrName(result.name),
69 getResAttrsAttrName(result.name));
70
71 // Parse the optional function body.
72 Region *body = result.addRegion();
73 OptionalParseResult parseResult =
74 parser.parseOptionalRegion(*body, entryArgs);
75 return failure(parseResult.has_value() && failed(*parseResult));
76}
77
78void spirv::GraphARMOp::print(OpAsmPrinter &printer) {
79 // Print graph name, signature, and control.
80 printer << ' ';
81 if (StringAttr visibility = getSymVisibilityAttr())
82 printer << visibility.getValue() << ' ';
83 printer.printSymbolName(getSymName());
84 GraphType grType = getFunctionType();
86 printer, *this, grType.getInputs(),
87 /*isVariadic=*/false, grType.getResults());
89 printer, *this,
90 {getFunctionTypeAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(),
91 getSymVisibilityAttrName()});
92
93 // Print the body.
94 Region &body = this->getBody();
95 if (!body.empty()) {
96 printer << ' ';
97 printer.printRegion(body, /*printEntryBlockArgs=*/false,
98 /*printBlockTerminators=*/true);
99 }
100}
101
102LogicalResult spirv::GraphARMOp::verifyType() {
103 if (getFunctionType().getNumResults() < 1)
104 return emitOpError("there should be at least one result");
105 return success();
106}
107
108LogicalResult spirv::GraphARMOp::verifyBody() {
109 for (auto [index, graphArgType] : llvm::enumerate(getArgumentTypes())) {
110 if (!isa<spirv::TensorArmType>(graphArgType)) {
111 return emitOpError("type of argument #")
112 << index << " must be a TensorArmType, but got " << graphArgType;
113 }
114 }
115 for (auto [index, graphResType] : llvm::enumerate(getResultTypes())) {
116 if (!isa<spirv::TensorArmType>(graphResType)) {
117 return emitOpError("type of result #")
118 << index << " must be a TensorArmType, but got " << graphResType;
119 }
120 }
121
122 if (!isExternal()) {
123 Block &entryBlock = front();
124
125 unsigned numArguments = this->getNumArguments();
126 if (entryBlock.getNumArguments() != numArguments)
127 return emitOpError("entry block must have ")
128 << numArguments << " arguments to match graph signature";
129
130 for (auto [index, grArgType, blockArgType] :
131 llvm::enumerate(getArgumentTypes(), entryBlock.getArgumentTypes())) {
132 if (blockArgType != grArgType) {
133 return emitOpError("type of entry block argument #")
134 << index << '(' << blockArgType
135 << ") must match the type of the corresponding argument in "
136 << "graph signature(" << grArgType << ')';
137 }
138 }
139 }
140
141 GraphType grType = getFunctionType();
142 auto walkResult = walk([grType](spirv::GraphOutputsARMOp op) -> WalkResult {
143 if (grType.getNumResults() != op.getNumOperands())
144 return op.emitOpError("is returning ")
145 << op.getNumOperands()
146 << " value(s) but enclosing spirv.ARM.Graph requires "
147 << grType.getNumResults() << " result(s)";
148
149 ValueTypeRange<OperandRange> graphOutputOperandTypes =
150 op.getValue().getType();
151 for (auto [index, type] : llvm::enumerate(graphOutputOperandTypes)) {
152 if (type != grType.getResult(index))
153 return op.emitError("type of return operand ")
154 << index << " (" << type << ") doesn't match graph result type ("
155 << grType.getResult(index) << ")";
156 }
157 return WalkResult::advance();
158 });
159
160 return failure(walkResult.wasInterrupted());
161}
162
163void spirv::GraphARMOp::build(OpBuilder &builder, OperationState &state,
164 StringRef name, GraphType type,
165 ArrayRef<NamedAttribute> attrs, bool entryPoint) {
166 state.addAttribute(getSymNameAttrName(state.name),
167 builder.getStringAttr(name));
168 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
169 state.attributes.append(attrs);
170 state.addAttribute(getEntryPointAttrName(state.name),
171 builder.getBoolAttr(entryPoint));
172 state.addRegion();
173}
174
175ArrayRef<Type> spirv::GraphARMOp::getArgumentTypes() {
176 return getFunctionType().getInputs();
177}
178
179ArrayRef<Type> spirv::GraphARMOp::getResultTypes() {
180 return getFunctionType().getResults();
181}
182
183Region *spirv::GraphARMOp::getCallableRegion() {
184 return isExternal() ? nullptr : &getBody();
185}
186
187//===----------------------------------------------------------------------===//
188// spirv.GraphOutputsARM
189//===----------------------------------------------------------------------===//
190
191LogicalResult spirv::GraphOutputsARMOp::verify() {
192 auto graph = cast<GraphARMOp>((*this)->getParentOp());
193
194 // The operand number and types must match the graph signature.
195 const ArrayRef<Type> &results = graph.getFunctionType().getResults();
196 if (getNumOperands() != results.size())
197 return emitOpError("has ")
198 << getNumOperands() << " operands, but enclosing spirv.ARM.Graph (@"
199 << graph.getName() << ") returns " << results.size();
200
201 for (auto [index, result] : llvm::enumerate(results))
202 if (getOperand(index).getType() != result)
203 return emitError() << "type of return operand " << index << " ("
204 << getOperand(index).getType()
205 << ") doesn't match spirv.ARM.Graph result type ("
206 << result << ")"
207 << " in graph @" << graph.getName();
208 return success();
209}
210
211//===----------------------------------------------------------------------===//
212// spirv.GraphEntryPointARM
213//===----------------------------------------------------------------------===//
214
215void spirv::GraphEntryPointARMOp::build(OpBuilder &builder,
216 OperationState &state,
217 spirv::GraphARMOp graph,
218 ArrayRef<Attribute> interfaceVars) {
219 build(builder, state, SymbolRefAttr::get(graph),
220 builder.getArrayAttr(interfaceVars));
221}
222
223ParseResult spirv::GraphEntryPointARMOp::parse(OpAsmParser &parser,
226 if (parser.parseAttribute(fn, Type(), kFnNameAttrName, result.attributes))
227 return failure();
228
229 SmallVector<Attribute, 4> interfaceVars;
230 if (!parser.parseOptionalComma()) {
231 // Parse the interface variables.
232 if (parser.parseCommaSeparatedList([&]() -> ParseResult {
233 // The name of the interface variable attribute is not important.
234 FlatSymbolRefAttr var;
235 NamedAttrList attrs;
236 if (parser.parseAttribute(var, Type(), "var_symbol", attrs))
237 return failure();
238 interfaceVars.push_back(var);
239 return success();
240 }))
241 return failure();
242 }
243 result.addAttribute("interface",
244 parser.getBuilder().getArrayAttr(interfaceVars));
245 return success();
246}
247
248void spirv::GraphEntryPointARMOp::print(OpAsmPrinter &printer) {
249 printer << " ";
250 printer.printSymbolName(getFn());
251 ArrayRef<Attribute> interfaceVars = getInterface().getValue();
252 if (!interfaceVars.empty()) {
253 printer << ", " << llvm::interleaved(interfaceVars);
254 }
255}
return success()
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
ParseResult parseSymbolName(StringAttr &result)
Parse an -identifier and store it (without the '@' symbol) in a string attribute.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
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 ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into 'result' if the attributes keyword is present.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
Block represents an ordered list of Operations.
Definition Block.h:33
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
Definition Block.cpp:154
unsigned getNumArguments()
Definition Block.h:152
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
BoolAttr getBoolAttr(bool value)
Definition Builders.cpp:108
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:271
GraphType getGraphType(TypeRange inputs, TypeRange results)
Definition Builders.cpp:88
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition Builders.cpp:275
A symbol reference with a reference path containing a single element.
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
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.
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 helps build Operations.
Definition Builders.h:210
This class implements Optional functionality for ParseResult.
bool has_value() const
Returns true if we contain a valid ParseResult value.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class implements iteration on the types of a given range of values.
Definition TypeRange.h:147
A utility result that is used to signal how to proceed with an ongoing walk:
Definition WalkResult.h:29
static WalkResult advance()
Definition WalkResult.h:47
void addArgAndResultAttrs(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs, StringAttr argAttrsName, StringAttr resAttrsName)
Adds argument and result attributes, provided as argAttrs and resultAttrs arguments,...
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation.
Definition Visitors.h:102
ParseResult parseFunctionSignatureWithArguments(OpAsmParser &parser, bool allowVariadic, SmallVectorImpl< OpAsmParser::Argument > &arguments, bool &isVariadic, SmallVectorImpl< Type > &resultTypes, SmallVectorImpl< DictionaryAttr > &resultAttrs)
Parses a function signature using parser.
void printFunctionAttributes(OpAsmPrinter &p, Operation *op, ArrayRef< StringRef > elided={})
Prints the list of function prefixed with the "attributes" keyword.
void printFunctionSignature(OpAsmPrinter &p, FunctionOpInterface op, ArrayRef< Type > argTypes, bool isVariadic, ArrayRef< Type > resultTypes)
Prints the signature of the function-like operation op.
ParseResult parseOptionalVisibilityKeyword(OpAsmParser &parser, NamedAttrList &attrs)
Parse an optional visibility attribute keyword (i.e., public, private, or nested) without quotes in a...
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
constexpr char kFnNameAttrName[]
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:310
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
Region * addRegion()
Create a region that should be attached to the operation.