MLIR  15.0.0git
FunctionImplementation.cpp
Go to the documentation of this file.
1 //===- FunctionImplementation.cpp - Utilities for function-like ops -------===//
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 
10 #include "mlir/IR/Builders.h"
12 #include "mlir/IR/SymbolTable.h"
13 
14 using namespace mlir;
15 
16 static ParseResult
19  bool &isVariadic) {
20 
21  // Parse the function arguments. The argument list either has to consistently
22  // have ssa-id's followed by types, or just be a type list. It isn't ok to
23  // sometimes have SSA ID's and sometimes not.
24  isVariadic = false;
25 
26  return parser.parseCommaSeparatedList(
28  // Ellipsis must be at end of the list.
29  if (isVariadic)
30  return parser.emitError(
31  parser.getCurrentLocation(),
32  "variadic arguments must be in the end of the argument list");
33 
34  // Handle ellipsis as a special case.
35  if (allowVariadic && succeeded(parser.parseOptionalEllipsis())) {
36  // This is a variadic designator.
37  isVariadic = true;
38  return success(); // Stop parsing arguments.
39  }
40  // Parse argument name if present.
41  OpAsmParser::Argument argument;
42  auto argPresent = parser.parseOptionalArgument(
43  argument, /*allowType=*/true, /*allowAttrs=*/true);
44  if (argPresent.hasValue()) {
45  if (failed(argPresent.getValue()))
46  return failure(); // Present but malformed.
47 
48  // Reject this if the preceding argument was missing a name.
49  if (!arguments.empty() && arguments.back().ssaName.name.empty())
50  return parser.emitError(argument.ssaName.location,
51  "expected type instead of SSA identifier");
52 
53  } else {
54  argument.ssaName.location = parser.getCurrentLocation();
55  // Otherwise we just have a type list without SSA names. Reject
56  // this if the preceding argument had a name.
57  if (!arguments.empty() && !arguments.back().ssaName.name.empty())
58  return parser.emitError(argument.ssaName.location,
59  "expected SSA identifier");
60 
61  NamedAttrList attrs;
62  if (parser.parseType(argument.type) ||
63  parser.parseOptionalAttrDict(attrs) ||
65  return failure();
66  argument.attrs = attrs.getDictionary(parser.getContext());
67  }
68  arguments.push_back(argument);
69  return success();
70  });
71 }
72 
73 /// Parse a function result list.
74 ///
75 /// function-result-list ::= function-result-list-parens
76 /// | non-function-type
77 /// function-result-list-parens ::= `(` `)`
78 /// | `(` function-result-list-no-parens `)`
79 /// function-result-list-no-parens ::= function-result (`,` function-result)*
80 /// function-result ::= type attribute-dict?
81 ///
82 static ParseResult
84  SmallVectorImpl<DictionaryAttr> &resultAttrs) {
85  if (failed(parser.parseOptionalLParen())) {
86  // We already know that there is no `(`, so parse a type.
87  // Because there is no `(`, it cannot be a function type.
88  Type ty;
89  if (parser.parseType(ty))
90  return failure();
91  resultTypes.push_back(ty);
92  resultAttrs.emplace_back();
93  return success();
94  }
95 
96  // Special case for an empty set of parens.
97  if (succeeded(parser.parseOptionalRParen()))
98  return success();
99 
100  // Parse individual function results.
101  if (parser.parseCommaSeparatedList([&]() -> ParseResult {
102  resultTypes.emplace_back();
103  resultAttrs.emplace_back();
104  NamedAttrList attrs;
105  if (parser.parseType(resultTypes.back()) ||
106  parser.parseOptionalAttrDict(attrs))
107  return failure();
108  resultAttrs.back() = attrs.getDictionary(parser.getContext());
109  return success();
110  }))
111  return failure();
112 
113  return parser.parseRParen();
114 }
115 
117  OpAsmParser &parser, bool allowVariadic,
118  SmallVectorImpl<OpAsmParser::Argument> &arguments, bool &isVariadic,
119  SmallVectorImpl<Type> &resultTypes,
120  SmallVectorImpl<DictionaryAttr> &resultAttrs) {
121  if (parseFunctionArgumentList(parser, allowVariadic, arguments, isVariadic))
122  return failure();
123  if (succeeded(parser.parseOptionalArrow()))
124  return parseFunctionResultList(parser, resultTypes, resultAttrs);
125  return success();
126 }
127 
129  Builder &builder, OperationState &result, ArrayRef<DictionaryAttr> argAttrs,
130  ArrayRef<DictionaryAttr> resultAttrs) {
131  auto nonEmptyAttrsFn = [](DictionaryAttr attrs) {
132  return attrs && !attrs.empty();
133  };
134  // Convert the specified array of dictionary attrs (which may have null
135  // entries) to an ArrayAttr of dictionaries.
136  auto getArrayAttr = [&](ArrayRef<DictionaryAttr> dictAttrs) {
138  for (auto &dict : dictAttrs)
139  attrs.push_back(dict ? dict : builder.getDictionaryAttr({}));
140  return builder.getArrayAttr(attrs);
141  };
142 
143  // Add the attributes to the function arguments.
144  if (llvm::any_of(argAttrs, nonEmptyAttrsFn))
146  getArrayAttr(argAttrs));
147 
148  // Add the attributes to the function results.
149  if (llvm::any_of(resultAttrs, nonEmptyAttrsFn))
151  getArrayAttr(resultAttrs));
152 }
153 
155  Builder &builder, OperationState &result,
157  ArrayRef<DictionaryAttr> resultAttrs) {
159  for (const auto &arg : args)
160  argAttrs.push_back(arg.attrs);
161  addArgAndResultAttrs(builder, result, argAttrs, resultAttrs);
162 }
163 
165  OpAsmParser &parser, OperationState &result, bool allowVariadic,
166  FuncTypeBuilder funcTypeBuilder) {
168  SmallVector<DictionaryAttr> resultAttrs;
169  SmallVector<Type> resultTypes;
170  auto &builder = parser.getBuilder();
171 
172  // Parse visibility.
174 
175  // Parse the name as a symbol.
176  StringAttr nameAttr;
177  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
178  result.attributes))
179  return failure();
180 
181  // Parse the function signature.
182  SMLoc signatureLocation = parser.getCurrentLocation();
183  bool isVariadic = false;
184  if (parseFunctionSignature(parser, allowVariadic, entryArgs, isVariadic,
185  resultTypes, resultAttrs))
186  return failure();
187 
188  std::string errorMessage;
189  SmallVector<Type> argTypes;
190  argTypes.reserve(entryArgs.size());
191  for (auto &arg : entryArgs)
192  argTypes.push_back(arg.type);
193  Type type = funcTypeBuilder(builder, argTypes, resultTypes,
194  VariadicFlag(isVariadic), errorMessage);
195  if (!type) {
196  return parser.emitError(signatureLocation)
197  << "failed to construct function type"
198  << (errorMessage.empty() ? "" : ": ") << errorMessage;
199  }
200  result.addAttribute(getTypeAttrName(), TypeAttr::get(type));
201 
202  // If function attributes are present, parse them.
203  NamedAttrList parsedAttributes;
204  SMLoc attributeDictLocation = parser.getCurrentLocation();
205  if (parser.parseOptionalAttrDictWithKeyword(parsedAttributes))
206  return failure();
207 
208  // Disallow attributes that are inferred from elsewhere in the attribute
209  // dictionary.
210  for (StringRef disallowed :
212  getTypeAttrName()}) {
213  if (parsedAttributes.get(disallowed))
214  return parser.emitError(attributeDictLocation, "'")
215  << disallowed
216  << "' is an inferred attribute and should not be specified in the "
217  "explicit attribute dictionary";
218  }
219  result.attributes.append(parsedAttributes);
220 
221  // Add the attributes to the function arguments.
222  assert(resultAttrs.size() == resultTypes.size());
223  addArgAndResultAttrs(builder, result, entryArgs, resultAttrs);
224 
225  // Parse the optional function body. The printer will not print the body if
226  // its empty, so disallow parsing of empty body in the parser.
227  auto *body = result.addRegion();
228  SMLoc loc = parser.getCurrentLocation();
229  OptionalParseResult parseResult =
230  parser.parseOptionalRegion(*body, entryArgs,
231  /*enableNameShadowing=*/false);
232  if (parseResult.hasValue()) {
233  if (failed(*parseResult))
234  return failure();
235  // Function body was parsed, make sure its not empty.
236  if (body->empty())
237  return parser.emitError(loc, "expected non-empty function body");
238  }
239  return success();
240 }
241 
242 /// Print a function result list. The provided `attrs` must either be null, or
243 /// contain a set of DictionaryAttrs of the same arity as `types`.
245  ArrayAttr attrs) {
246  assert(!types.empty() && "Should not be called for empty result list.");
247  assert((!attrs || attrs.size() == types.size()) &&
248  "Invalid number of attributes.");
249 
250  auto &os = p.getStream();
251  bool needsParens = types.size() > 1 || types[0].isa<FunctionType>() ||
252  (attrs && !attrs[0].cast<DictionaryAttr>().empty());
253  if (needsParens)
254  os << '(';
255  llvm::interleaveComma(llvm::seq<size_t>(0, types.size()), os, [&](size_t i) {
256  p.printType(types[i]);
257  if (attrs)
258  p.printOptionalAttrDict(attrs[i].cast<DictionaryAttr>().getValue());
259  });
260  if (needsParens)
261  os << ')';
262 }
263 
265  OpAsmPrinter &p, Operation *op, ArrayRef<Type> argTypes, bool isVariadic,
266  ArrayRef<Type> resultTypes) {
267  Region &body = op->getRegion(0);
268  bool isExternal = body.empty();
269 
270  p << '(';
271  ArrayAttr argAttrs = op->getAttrOfType<ArrayAttr>(getArgDictAttrName());
272  for (unsigned i = 0, e = argTypes.size(); i < e; ++i) {
273  if (i > 0)
274  p << ", ";
275 
276  if (!isExternal) {
278  if (argAttrs)
279  attrs = argAttrs[i].cast<DictionaryAttr>().getValue();
280  p.printRegionArgument(body.getArgument(i), attrs);
281  } else {
282  p.printType(argTypes[i]);
283  if (argAttrs)
284  p.printOptionalAttrDict(argAttrs[i].cast<DictionaryAttr>().getValue());
285  }
286  }
287 
288  if (isVariadic) {
289  if (!argTypes.empty())
290  p << ", ";
291  p << "...";
292  }
293 
294  p << ')';
295 
296  if (!resultTypes.empty()) {
297  p.getStream() << " -> ";
298  auto resultAttrs = op->getAttrOfType<ArrayAttr>(getResultDictAttrName());
299  printFunctionResultList(p, resultTypes, resultAttrs);
300  }
301 }
302 
304  OpAsmPrinter &p, Operation *op, unsigned numInputs, unsigned numResults,
305  ArrayRef<StringRef> elided) {
306  // Print out function attributes, if present.
307  SmallVector<StringRef, 2> ignoredAttrs = {
310  ignoredAttrs.append(elided.begin(), elided.end());
311 
312  p.printOptionalAttrDictWithKeyword(op->getAttrs(), ignoredAttrs);
313 }
314 
316  FunctionOpInterface op,
317  bool isVariadic) {
318  // Print the operation and the function name.
319  auto funcName =
320  op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
321  .getValue();
322  p << ' ';
323 
324  StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
325  if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
326  p << visibility.getValue() << ' ';
327  p.printSymbolName(funcName);
328 
329  ArrayRef<Type> argTypes = op.getArgumentTypes();
330  ArrayRef<Type> resultTypes = op.getResultTypes();
331  printFunctionSignature(p, op, argTypes, isVariadic, resultTypes);
332  printFunctionAttributes(p, op, argTypes.size(), resultTypes.size(),
333  {visibilityAttrName});
334  // Print the body if this is not an external function.
335  Region &body = op->getRegion(0);
336  if (!body.empty()) {
337  p << ' ';
338  p.printRegion(body, /*printEntryBlockArgs=*/false,
339  /*printBlockTerminators=*/true);
340  }
341 }
virtual void printSymbolName(StringRef symbolRef)
Print the given string as a symbol reference, i.e.
void printFunctionSignature(OpAsmPrinter &p, Operation *op, ArrayRef< Type > argTypes, bool isVariadic, ArrayRef< Type > resultTypes)
Prints the signature of the function-like operation op.
TODO: Remove this file when SCCP and integer range analysis have been ported to the new framework...
StringRef getResultDictAttrName()
Return the name of the attribute used for function argument attributes.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
Definition: Region.h:26
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:55
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
StringRef getArgDictAttrName()
Return the name of the attribute used for function argument attributes.
virtual void printType(Type type)
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Definition: Operation.h:363
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:382
void addArgAndResultAttrs(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs)
Adds argument and result attributes, provided as argAttrs and resultAttrs arguments, to the list of operation attributes in result.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
static StringRef getVisibilityAttrName()
Return the name of the attribute used for symbol visibility.
Definition: SymbolTable.h:61
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
StringRef getTypeAttrName()
Return the name of the attribute used for function types.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it...
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
A named class for passing around the variadic flag.
static void printFunctionResultList(OpAsmPrinter &p, ArrayRef< Type > types, ArrayAttr attrs)
Print a function result list.
ParseResult parseSymbolName(StringAttr &result, StringRef attrName, NamedAttrList &attrs)
Parse an -identifier and store it (without the &#39;@&#39; symbol) in a string attribute named &#39;attrName&#39;...
void printFunctionAttributes(OpAsmPrinter &p, Operation *op, unsigned numInputs, unsigned numResults, ArrayRef< StringRef > elided={})
Prints the list of function prefixed with the "attributes" keyword.
BlockArgument getArgument(unsigned i)
Definition: Region.h:124
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
Attribute get(StringAttr name) const
Return the specified attribute if present, null otherwise.
bool empty()
Definition: Region.h:60
virtual OptionalParseResult parseOptionalRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region if present.
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
Definition: Builders.cpp:91
virtual ParseResult parseRParen()=0
Parse a ) token.
void printFunctionOp(OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic)
Printer implementation for function-like operations.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This represents an operation in an abstracted form, suitable for use with the builder APIs...
Parens surrounding zero or more operands.
static ParseResult parseFunctionResultList(OpAsmParser &parser, SmallVectorImpl< Type > &resultTypes, SmallVectorImpl< DictionaryAttr > &resultAttrs)
Parse a function result list.
Optional< Location > sourceLoc
ParseResult parseOptionalVisibilityKeyword(OpAsmParser &parser, NamedAttrList &attrs)
Parse an optional visibility attribute keyword (i.e., public, private, or nested) without quotes in a...
virtual ParseResult parseOptionalLocationSpecifier(Optional< Location > &result)=0
Parse a loc(...) specifier if present, filling in result if so.
virtual ParseResult parseOptionalAttrDictWithKeyword(NamedAttrList &result)=0
Parse a named dictionary into &#39;result&#39; if the attributes keyword is present.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:37
static ParseResult parseFunctionArgumentList(OpAsmParser &parser, bool allowVariadic, SmallVectorImpl< OpAsmParser::Argument > &arguments, bool &isVariadic)
virtual ParseResult parseOptionalArrow()=0
Parse a &#39;->&#39; token if present.
virtual void printRegionArgument(BlockArgument arg, ArrayRef< NamedAttribute > argAttrs={}, bool omitType=false)=0
Print a block argument in the usual format of: ssaName : type {attr1=42} loc("here") where location p...
NamedAttrList attributes
ParseResult parseFunctionSignature(OpAsmParser &parser, bool allowVariadic, SmallVectorImpl< OpAsmParser::Argument > &arguments, bool &isVariadic, SmallVectorImpl< Type > &resultTypes, SmallVectorImpl< DictionaryAttr > &resultAttrs)
Parses a function signature using parser.
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values...
Region * addRegion()
Create a region that should be attached to the operation.
virtual OptionalParseResult parseOptionalArgument(Argument &result, bool allowType=false, bool allowAttrs=false)=0
Parse a single argument if present.
This class is a general helper class for creating context-global objects like types, attributes, and affine expressions.
Definition: Builders.h:49
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual void printOptionalAttrDictWithKeyword(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary prefixed with &#39;attribute...
ParseResult parseFunctionOp(OpAsmParser &parser, OperationState &result, bool allowVariadic, FuncTypeBuilder funcTypeBuilder)
Parser implementation for function-like operations.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into &#39;result&#39; if it is present.
bool hasValue() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:47
virtual ParseResult parseOptionalEllipsis()=0
Parse a ... token if present;.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:66
This class represents success/failure for parsing-like operations that find it important to chain tog...
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:205
Region & getRegion(unsigned index)
Returns the region held by this operation at position &#39;index&#39;.
Definition: Operation.h:484
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.