12f16bf7aSAlex Zinenko //===- FunctionImplementation.cpp - Utilities for function-like ops -------===//
22f16bf7aSAlex Zinenko //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62f16bf7aSAlex Zinenko //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
82f16bf7aSAlex Zinenko 
92f16bf7aSAlex Zinenko #include "mlir/IR/FunctionImplementation.h"
102f16bf7aSAlex Zinenko #include "mlir/IR/Builders.h"
117ceffae1SRiver Riddle #include "mlir/IR/FunctionInterfaces.h"
122f16bf7aSAlex Zinenko #include "mlir/IR/SymbolTable.h"
132f16bf7aSAlex Zinenko 
142f16bf7aSAlex Zinenko using namespace mlir;
152f16bf7aSAlex Zinenko 
16d85eb4e2SChris Lattner static ParseResult
parseFunctionArgumentList(OpAsmParser & parser,bool allowVariadic,SmallVectorImpl<OpAsmParser::Argument> & arguments,bool & isVariadic)17d85eb4e2SChris Lattner parseFunctionArgumentList(OpAsmParser &parser, bool allowVariadic,
18d85eb4e2SChris Lattner                           SmallVectorImpl<OpAsmParser::Argument> &arguments,
1931c8abc3SChris Lattner                           bool &isVariadic) {
202f16bf7aSAlex Zinenko 
21d85eb4e2SChris Lattner   // Parse the function arguments.  The argument list either has to consistently
22d85eb4e2SChris Lattner   // have ssa-id's followed by types, or just be a type list.  It isn't ok to
23d85eb4e2SChris Lattner   // sometimes have SSA ID's and sometimes not.
24d85eb4e2SChris Lattner   isVariadic = false;
252f16bf7aSAlex Zinenko 
26d85eb4e2SChris Lattner   return parser.parseCommaSeparatedList(
27d85eb4e2SChris Lattner       OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
28d85eb4e2SChris Lattner         // Ellipsis must be at end of the list.
29d85eb4e2SChris Lattner         if (isVariadic)
30d85eb4e2SChris Lattner           return parser.emitError(
31d85eb4e2SChris Lattner               parser.getCurrentLocation(),
32d85eb4e2SChris Lattner               "variadic arguments must be in the end of the argument list");
33d85eb4e2SChris Lattner 
34d85eb4e2SChris Lattner         // Handle ellipsis as a special case.
35d85eb4e2SChris Lattner         if (allowVariadic && succeeded(parser.parseOptionalEllipsis())) {
36d85eb4e2SChris Lattner           // This is a variadic designator.
37d85eb4e2SChris Lattner           isVariadic = true;
38d85eb4e2SChris Lattner           return success(); // Stop parsing arguments.
39d85eb4e2SChris Lattner         }
402f16bf7aSAlex Zinenko         // Parse argument name if present.
41d85eb4e2SChris Lattner         OpAsmParser::Argument argument;
42d85eb4e2SChris Lattner         auto argPresent = parser.parseOptionalArgument(
43d85eb4e2SChris Lattner             argument, /*allowType=*/true, /*allowAttrs=*/true);
44*3b7c3a65SKazu Hirata         if (argPresent.hasValue()) {
45*3b7c3a65SKazu Hirata           if (failed(argPresent.getValue()))
46d85eb4e2SChris Lattner             return failure(); // Present but malformed.
475dedf911SChris Lattner 
482f16bf7aSAlex Zinenko           // Reject this if the preceding argument was missing a name.
49d85eb4e2SChris Lattner           if (!arguments.empty() && arguments.back().ssaName.name.empty())
50d85eb4e2SChris Lattner             return parser.emitError(argument.ssaName.location,
51d85eb4e2SChris Lattner                                     "expected type instead of SSA identifier");
522f16bf7aSAlex Zinenko 
53d85eb4e2SChris Lattner         } else {
54d85eb4e2SChris Lattner           argument.ssaName.location = parser.getCurrentLocation();
55d85eb4e2SChris Lattner           // Otherwise we just have a type list without SSA names.  Reject
56d85eb4e2SChris Lattner           // this if the preceding argument had a name.
57d85eb4e2SChris Lattner           if (!arguments.empty() && !arguments.back().ssaName.name.empty())
58d85eb4e2SChris Lattner             return parser.emitError(argument.ssaName.location,
59d85eb4e2SChris Lattner                                     "expected SSA identifier");
602f16bf7aSAlex Zinenko 
615eae715aSJacques Pienaar           NamedAttrList attrs;
62d85eb4e2SChris Lattner           if (parser.parseType(argument.type) ||
63d85eb4e2SChris Lattner               parser.parseOptionalAttrDict(attrs) ||
6431c8abc3SChris Lattner               parser.parseOptionalLocationSpecifier(argument.sourceLoc))
652f16bf7aSAlex Zinenko             return failure();
66d85eb4e2SChris Lattner           argument.attrs = attrs.getDictionary(parser.getContext());
672f16bf7aSAlex Zinenko         }
68d85eb4e2SChris Lattner         arguments.push_back(argument);
692f16bf7aSAlex Zinenko         return success();
70d85eb4e2SChris Lattner       });
712f16bf7aSAlex Zinenko }
722f16bf7aSAlex Zinenko 
732f16bf7aSAlex Zinenko /// Parse a function result list.
742f16bf7aSAlex Zinenko ///
752f16bf7aSAlex Zinenko ///   function-result-list ::= function-result-list-parens
762f16bf7aSAlex Zinenko ///                          | non-function-type
772f16bf7aSAlex Zinenko ///   function-result-list-parens ::= `(` `)`
782f16bf7aSAlex Zinenko ///                                 | `(` function-result-list-no-parens `)`
792f16bf7aSAlex Zinenko ///   function-result-list-no-parens ::= function-result (`,` function-result)*
802f16bf7aSAlex Zinenko ///   function-result ::= type attribute-dict?
812f16bf7aSAlex Zinenko ///
825eae715aSJacques Pienaar static ParseResult
parseFunctionResultList(OpAsmParser & parser,SmallVectorImpl<Type> & resultTypes,SmallVectorImpl<DictionaryAttr> & resultAttrs)835eae715aSJacques Pienaar parseFunctionResultList(OpAsmParser &parser, SmallVectorImpl<Type> &resultTypes,
84d85eb4e2SChris Lattner                         SmallVectorImpl<DictionaryAttr> &resultAttrs) {
852f16bf7aSAlex Zinenko   if (failed(parser.parseOptionalLParen())) {
862f16bf7aSAlex Zinenko     // We already know that there is no `(`, so parse a type.
872f16bf7aSAlex Zinenko     // Because there is no `(`, it cannot be a function type.
882f16bf7aSAlex Zinenko     Type ty;
892f16bf7aSAlex Zinenko     if (parser.parseType(ty))
902f16bf7aSAlex Zinenko       return failure();
912f16bf7aSAlex Zinenko     resultTypes.push_back(ty);
922f16bf7aSAlex Zinenko     resultAttrs.emplace_back();
932f16bf7aSAlex Zinenko     return success();
942f16bf7aSAlex Zinenko   }
952f16bf7aSAlex Zinenko 
962f16bf7aSAlex Zinenko   // Special case for an empty set of parens.
972f16bf7aSAlex Zinenko   if (succeeded(parser.parseOptionalRParen()))
982f16bf7aSAlex Zinenko     return success();
992f16bf7aSAlex Zinenko 
1002f16bf7aSAlex Zinenko   // Parse individual function results.
101d85eb4e2SChris Lattner   if (parser.parseCommaSeparatedList([&]() -> ParseResult {
1022f16bf7aSAlex Zinenko         resultTypes.emplace_back();
1032f16bf7aSAlex Zinenko         resultAttrs.emplace_back();
104d85eb4e2SChris Lattner         NamedAttrList attrs;
1052f16bf7aSAlex Zinenko         if (parser.parseType(resultTypes.back()) ||
106d85eb4e2SChris Lattner             parser.parseOptionalAttrDict(attrs))
1072f16bf7aSAlex Zinenko           return failure();
108d85eb4e2SChris Lattner         resultAttrs.back() = attrs.getDictionary(parser.getContext());
109d85eb4e2SChris Lattner         return success();
110d85eb4e2SChris Lattner       }))
111d85eb4e2SChris Lattner     return failure();
112d85eb4e2SChris Lattner 
1132f16bf7aSAlex Zinenko   return parser.parseRParen();
1142f16bf7aSAlex Zinenko }
1152f16bf7aSAlex Zinenko 
parseFunctionSignature(OpAsmParser & parser,bool allowVariadic,SmallVectorImpl<OpAsmParser::Argument> & arguments,bool & isVariadic,SmallVectorImpl<Type> & resultTypes,SmallVectorImpl<DictionaryAttr> & resultAttrs)1167ceffae1SRiver Riddle ParseResult mlir::function_interface_impl::parseFunctionSignature(
1172f16bf7aSAlex Zinenko     OpAsmParser &parser, bool allowVariadic,
118d85eb4e2SChris Lattner     SmallVectorImpl<OpAsmParser::Argument> &arguments, bool &isVariadic,
119d85eb4e2SChris Lattner     SmallVectorImpl<Type> &resultTypes,
120d85eb4e2SChris Lattner     SmallVectorImpl<DictionaryAttr> &resultAttrs) {
121d85eb4e2SChris Lattner   if (parseFunctionArgumentList(parser, allowVariadic, arguments, isVariadic))
1222f16bf7aSAlex Zinenko     return failure();
1232f16bf7aSAlex Zinenko   if (succeeded(parser.parseOptionalArrow()))
1242f16bf7aSAlex Zinenko     return parseFunctionResultList(parser, resultTypes, resultAttrs);
1252f16bf7aSAlex Zinenko   return success();
1262f16bf7aSAlex Zinenko }
1272f16bf7aSAlex Zinenko 
addArgAndResultAttrs(Builder & builder,OperationState & result,ArrayRef<DictionaryAttr> argAttrs,ArrayRef<DictionaryAttr> resultAttrs)1287ceffae1SRiver Riddle void mlir::function_interface_impl::addArgAndResultAttrs(
12953b946aaSRiver Riddle     Builder &builder, OperationState &result, ArrayRef<DictionaryAttr> argAttrs,
13053b946aaSRiver Riddle     ArrayRef<DictionaryAttr> resultAttrs) {
131d85eb4e2SChris Lattner   auto nonEmptyAttrsFn = [](DictionaryAttr attrs) {
132d85eb4e2SChris Lattner     return attrs && !attrs.empty();
13353b946aaSRiver Riddle   };
134d85eb4e2SChris Lattner   // Convert the specified array of dictionary attrs (which may have null
135d85eb4e2SChris Lattner   // entries) to an ArrayAttr of dictionaries.
136d85eb4e2SChris Lattner   auto getArrayAttr = [&](ArrayRef<DictionaryAttr> dictAttrs) {
137d85eb4e2SChris Lattner     SmallVector<Attribute> attrs;
138d85eb4e2SChris Lattner     for (auto &dict : dictAttrs)
139d85eb4e2SChris Lattner       attrs.push_back(dict ? dict : builder.getDictionaryAttr({}));
140d85eb4e2SChris Lattner     return builder.getArrayAttr(attrs);
141d85eb4e2SChris Lattner   };
142d85eb4e2SChris Lattner 
143d85eb4e2SChris Lattner   // Add the attributes to the function arguments.
144d85eb4e2SChris Lattner   if (llvm::any_of(argAttrs, nonEmptyAttrsFn))
145d85eb4e2SChris Lattner     result.addAttribute(function_interface_impl::getArgDictAttrName(),
146d85eb4e2SChris Lattner                         getArrayAttr(argAttrs));
147d85eb4e2SChris Lattner 
148d85eb4e2SChris Lattner   // Add the attributes to the function results.
149d85eb4e2SChris Lattner   if (llvm::any_of(resultAttrs, nonEmptyAttrsFn))
150d85eb4e2SChris Lattner     result.addAttribute(function_interface_impl::getResultDictAttrName(),
151d85eb4e2SChris Lattner                         getArrayAttr(resultAttrs));
15253b946aaSRiver Riddle }
153d85eb4e2SChris Lattner 
addArgAndResultAttrs(Builder & builder,OperationState & result,ArrayRef<OpAsmParser::Argument> args,ArrayRef<DictionaryAttr> resultAttrs)1547ceffae1SRiver Riddle void mlir::function_interface_impl::addArgAndResultAttrs(
155d85eb4e2SChris Lattner     Builder &builder, OperationState &result,
156d85eb4e2SChris Lattner     ArrayRef<OpAsmParser::Argument> args,
157d85eb4e2SChris Lattner     ArrayRef<DictionaryAttr> resultAttrs) {
158d85eb4e2SChris Lattner   SmallVector<DictionaryAttr> argAttrs;
159d85eb4e2SChris Lattner   for (const auto &arg : args)
160d85eb4e2SChris Lattner     argAttrs.push_back(arg.attrs);
161d85eb4e2SChris Lattner   addArgAndResultAttrs(builder, result, argAttrs, resultAttrs);
1622f16bf7aSAlex Zinenko }
1632f16bf7aSAlex Zinenko 
parseFunctionOp(OpAsmParser & parser,OperationState & result,bool allowVariadic,FuncTypeBuilder funcTypeBuilder)1647ceffae1SRiver Riddle ParseResult mlir::function_interface_impl::parseFunctionOp(
16553b946aaSRiver Riddle     OpAsmParser &parser, OperationState &result, bool allowVariadic,
16653b946aaSRiver Riddle     FuncTypeBuilder funcTypeBuilder) {
167d85eb4e2SChris Lattner   SmallVector<OpAsmParser::Argument> entryArgs;
168d85eb4e2SChris Lattner   SmallVector<DictionaryAttr> resultAttrs;
1691e09f0a9SDominik Grewe   SmallVector<Type> resultTypes;
1702f16bf7aSAlex Zinenko   auto &builder = parser.getBuilder();
1712f16bf7aSAlex Zinenko 
172dea24b42SRahul Joshi   // Parse visibility.
1731d7b5cd5SChris Lattner   (void)impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1748b5a3e46SRahul Joshi 
1752f16bf7aSAlex Zinenko   // Parse the name as a symbol.
1762f16bf7aSAlex Zinenko   StringAttr nameAttr;
1778b5a3e46SRahul Joshi   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1782f16bf7aSAlex Zinenko                              result.attributes))
1792f16bf7aSAlex Zinenko     return failure();
1802f16bf7aSAlex Zinenko 
1812f16bf7aSAlex Zinenko   // Parse the function signature.
1826842ec42SRiver Riddle   SMLoc signatureLocation = parser.getCurrentLocation();
1832f16bf7aSAlex Zinenko   bool isVariadic = false;
184d85eb4e2SChris Lattner   if (parseFunctionSignature(parser, allowVariadic, entryArgs, isVariadic,
185d85eb4e2SChris Lattner                              resultTypes, resultAttrs))
1862f16bf7aSAlex Zinenko     return failure();
1872f16bf7aSAlex Zinenko 
1882f16bf7aSAlex Zinenko   std::string errorMessage;
189d85eb4e2SChris Lattner   SmallVector<Type> argTypes;
190d85eb4e2SChris Lattner   argTypes.reserve(entryArgs.size());
191d85eb4e2SChris Lattner   for (auto &arg : entryArgs)
192d85eb4e2SChris Lattner     argTypes.push_back(arg.type);
19353b946aaSRiver Riddle   Type type = funcTypeBuilder(builder, argTypes, resultTypes,
19453b946aaSRiver Riddle                               VariadicFlag(isVariadic), errorMessage);
19553b946aaSRiver Riddle   if (!type) {
1962f16bf7aSAlex Zinenko     return parser.emitError(signatureLocation)
1972f16bf7aSAlex Zinenko            << "failed to construct function type"
1982f16bf7aSAlex Zinenko            << (errorMessage.empty() ? "" : ": ") << errorMessage;
19953b946aaSRiver Riddle   }
20053b946aaSRiver Riddle   result.addAttribute(getTypeAttrName(), TypeAttr::get(type));
2012f16bf7aSAlex Zinenko 
2022f16bf7aSAlex Zinenko   // If function attributes are present, parse them.
20367a339e9SRahul Joshi   NamedAttrList parsedAttributes;
2046842ec42SRiver Riddle   SMLoc attributeDictLocation = parser.getCurrentLocation();
20567a339e9SRahul Joshi   if (parser.parseOptionalAttrDictWithKeyword(parsedAttributes))
2062f16bf7aSAlex Zinenko     return failure();
2072f16bf7aSAlex Zinenko 
20867a339e9SRahul Joshi   // Disallow attributes that are inferred from elsewhere in the attribute
20967a339e9SRahul Joshi   // dictionary.
21067a339e9SRahul Joshi   for (StringRef disallowed :
21167a339e9SRahul Joshi        {SymbolTable::getVisibilityAttrName(), SymbolTable::getSymbolAttrName(),
21267a339e9SRahul Joshi         getTypeAttrName()}) {
21367a339e9SRahul Joshi     if (parsedAttributes.get(disallowed))
21467a339e9SRahul Joshi       return parser.emitError(attributeDictLocation, "'")
21567a339e9SRahul Joshi              << disallowed
21667a339e9SRahul Joshi              << "' is an inferred attribute and should not be specified in the "
21767a339e9SRahul Joshi                 "explicit attribute dictionary";
21867a339e9SRahul Joshi   }
21967a339e9SRahul Joshi   result.attributes.append(parsedAttributes);
22067a339e9SRahul Joshi 
2212f16bf7aSAlex Zinenko   // Add the attributes to the function arguments.
2222f16bf7aSAlex Zinenko   assert(resultAttrs.size() == resultTypes.size());
223d85eb4e2SChris Lattner   addArgAndResultAttrs(builder, result, entryArgs, resultAttrs);
2242f16bf7aSAlex Zinenko 
225fe7fdcacSRahul Joshi   // Parse the optional function body. The printer will not print the body if
226fe7fdcacSRahul Joshi   // its empty, so disallow parsing of empty body in the parser.
2272f16bf7aSAlex Zinenko   auto *body = result.addRegion();
2286842ec42SRiver Riddle   SMLoc loc = parser.getCurrentLocation();
229d85eb4e2SChris Lattner   OptionalParseResult parseResult =
230d85eb4e2SChris Lattner       parser.parseOptionalRegion(*body, entryArgs,
231fe7fdcacSRahul Joshi                                  /*enableNameShadowing=*/false);
232*3b7c3a65SKazu Hirata   if (parseResult.hasValue()) {
233fe7fdcacSRahul Joshi     if (failed(*parseResult))
234fe7fdcacSRahul Joshi       return failure();
235fe7fdcacSRahul Joshi     // Function body was parsed, make sure its not empty.
236fe7fdcacSRahul Joshi     if (body->empty())
237fe7fdcacSRahul Joshi       return parser.emitError(loc, "expected non-empty function body");
238fe7fdcacSRahul Joshi   }
239fe7fdcacSRahul Joshi   return success();
2402f16bf7aSAlex Zinenko }
2412f16bf7aSAlex Zinenko 
24253b946aaSRiver Riddle /// Print a function result list. The provided `attrs` must either be null, or
24353b946aaSRiver Riddle /// contain a set of DictionaryAttrs of the same arity as `types`.
printFunctionResultList(OpAsmPrinter & p,ArrayRef<Type> types,ArrayAttr attrs)2442f16bf7aSAlex Zinenko static void printFunctionResultList(OpAsmPrinter &p, ArrayRef<Type> types,
24553b946aaSRiver Riddle                                     ArrayAttr attrs) {
2462f16bf7aSAlex Zinenko   assert(!types.empty() && "Should not be called for empty result list.");
24753b946aaSRiver Riddle   assert((!attrs || attrs.size() == types.size()) &&
24853b946aaSRiver Riddle          "Invalid number of attributes.");
24953b946aaSRiver Riddle 
2502f16bf7aSAlex Zinenko   auto &os = p.getStream();
25153b946aaSRiver Riddle   bool needsParens = types.size() > 1 || types[0].isa<FunctionType>() ||
25253b946aaSRiver Riddle                      (attrs && !attrs[0].cast<DictionaryAttr>().empty());
2532f16bf7aSAlex Zinenko   if (needsParens)
2542f16bf7aSAlex Zinenko     os << '(';
25553b946aaSRiver Riddle   llvm::interleaveComma(llvm::seq<size_t>(0, types.size()), os, [&](size_t i) {
25653b946aaSRiver Riddle     p.printType(types[i]);
25753b946aaSRiver Riddle     if (attrs)
25853b946aaSRiver Riddle       p.printOptionalAttrDict(attrs[i].cast<DictionaryAttr>().getValue());
2592f16bf7aSAlex Zinenko   });
2602f16bf7aSAlex Zinenko   if (needsParens)
2612f16bf7aSAlex Zinenko     os << ')';
2622f16bf7aSAlex Zinenko }
2632f16bf7aSAlex Zinenko 
printFunctionSignature(OpAsmPrinter & p,Operation * op,ArrayRef<Type> argTypes,bool isVariadic,ArrayRef<Type> resultTypes)2647ceffae1SRiver Riddle void mlir::function_interface_impl::printFunctionSignature(
26553b946aaSRiver Riddle     OpAsmPrinter &p, Operation *op, ArrayRef<Type> argTypes, bool isVariadic,
2662f16bf7aSAlex Zinenko     ArrayRef<Type> resultTypes) {
2672f16bf7aSAlex Zinenko   Region &body = op->getRegion(0);
2682f16bf7aSAlex Zinenko   bool isExternal = body.empty();
2692f16bf7aSAlex Zinenko 
2702f16bf7aSAlex Zinenko   p << '(';
27153b946aaSRiver Riddle   ArrayAttr argAttrs = op->getAttrOfType<ArrayAttr>(getArgDictAttrName());
2722f16bf7aSAlex Zinenko   for (unsigned i = 0, e = argTypes.size(); i < e; ++i) {
2732f16bf7aSAlex Zinenko     if (i > 0)
2742f16bf7aSAlex Zinenko       p << ", ";
2752f16bf7aSAlex Zinenko 
2762f16bf7aSAlex Zinenko     if (!isExternal) {
27781467f50SChris Lattner       ArrayRef<NamedAttribute> attrs;
27881467f50SChris Lattner       if (argAttrs)
27981467f50SChris Lattner         attrs = argAttrs[i].cast<DictionaryAttr>().getValue();
28081467f50SChris Lattner       p.printRegionArgument(body.getArgument(i), attrs);
28181467f50SChris Lattner     } else {
2822f16bf7aSAlex Zinenko       p.printType(argTypes[i]);
28353b946aaSRiver Riddle       if (argAttrs)
28453b946aaSRiver Riddle         p.printOptionalAttrDict(argAttrs[i].cast<DictionaryAttr>().getValue());
2852f16bf7aSAlex Zinenko     }
28681467f50SChris Lattner   }
2872f16bf7aSAlex Zinenko 
2882f16bf7aSAlex Zinenko   if (isVariadic) {
2892f16bf7aSAlex Zinenko     if (!argTypes.empty())
2902f16bf7aSAlex Zinenko       p << ", ";
2912f16bf7aSAlex Zinenko     p << "...";
2922f16bf7aSAlex Zinenko   }
2932f16bf7aSAlex Zinenko 
2942f16bf7aSAlex Zinenko   p << ')';
2952f16bf7aSAlex Zinenko 
2962f16bf7aSAlex Zinenko   if (!resultTypes.empty()) {
2972f16bf7aSAlex Zinenko     p.getStream() << " -> ";
29853b946aaSRiver Riddle     auto resultAttrs = op->getAttrOfType<ArrayAttr>(getResultDictAttrName());
2992f16bf7aSAlex Zinenko     printFunctionResultList(p, resultTypes, resultAttrs);
3002f16bf7aSAlex Zinenko   }
3012f16bf7aSAlex Zinenko }
3022f16bf7aSAlex Zinenko 
printFunctionAttributes(OpAsmPrinter & p,Operation * op,unsigned numInputs,unsigned numResults,ArrayRef<StringRef> elided)3037ceffae1SRiver Riddle void mlir::function_interface_impl::printFunctionAttributes(
30453b946aaSRiver Riddle     OpAsmPrinter &p, Operation *op, unsigned numInputs, unsigned numResults,
3052f16bf7aSAlex Zinenko     ArrayRef<StringRef> elided) {
3062f16bf7aSAlex Zinenko   // Print out function attributes, if present.
3072f16bf7aSAlex Zinenko   SmallVector<StringRef, 2> ignoredAttrs = {
30853b946aaSRiver Riddle       ::mlir::SymbolTable::getSymbolAttrName(), getTypeAttrName(),
30953b946aaSRiver Riddle       getArgDictAttrName(), getResultDictAttrName()};
3102f16bf7aSAlex Zinenko   ignoredAttrs.append(elided.begin(), elided.end());
3112f16bf7aSAlex Zinenko 
3122f16bf7aSAlex Zinenko   p.printOptionalAttrDictWithKeyword(op->getAttrs(), ignoredAttrs);
3132f16bf7aSAlex Zinenko }
3142f16bf7aSAlex Zinenko 
printFunctionOp(OpAsmPrinter & p,FunctionOpInterface op,bool isVariadic)315f96a8675SRiver Riddle void mlir::function_interface_impl::printFunctionOp(OpAsmPrinter &p,
316f96a8675SRiver Riddle                                                     FunctionOpInterface op,
317f96a8675SRiver Riddle                                                     bool isVariadic) {
3182f16bf7aSAlex Zinenko   // Print the operation and the function name.
3192f16bf7aSAlex Zinenko   auto funcName =
3208b5a3e46SRahul Joshi       op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
3212f16bf7aSAlex Zinenko           .getValue();
322c41b16c2SMehdi Amini   p << ' ';
323dea24b42SRahul Joshi 
324dea24b42SRahul Joshi   StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
325dea24b42SRahul Joshi   if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
3268b5a3e46SRahul Joshi     p << visibility.getValue() << ' ';
3272f16bf7aSAlex Zinenko   p.printSymbolName(funcName);
3282f16bf7aSAlex Zinenko 
329f96a8675SRiver Riddle   ArrayRef<Type> argTypes = op.getArgumentTypes();
330f96a8675SRiver Riddle   ArrayRef<Type> resultTypes = op.getResultTypes();
3312f16bf7aSAlex Zinenko   printFunctionSignature(p, op, argTypes, isVariadic, resultTypes);
3328b5a3e46SRahul Joshi   printFunctionAttributes(p, op, argTypes.size(), resultTypes.size(),
333dea24b42SRahul Joshi                           {visibilityAttrName});
3342f16bf7aSAlex Zinenko   // Print the body if this is not an external function.
3352f16bf7aSAlex Zinenko   Region &body = op->getRegion(0);
3365c36ee8dSMogball   if (!body.empty()) {
3375c36ee8dSMogball     p << ' ';
3382f16bf7aSAlex Zinenko     p.printRegion(body, /*printEntryBlockArgs=*/false,
3392f16bf7aSAlex Zinenko                   /*printBlockTerminators=*/true);
3402f16bf7aSAlex Zinenko   }
3415c36ee8dSMogball }
342