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 
16*d85eb4e2SChris Lattner static ParseResult
17*d85eb4e2SChris Lattner parseFunctionArgumentList(OpAsmParser &parser, bool allowVariadic,
18*d85eb4e2SChris Lattner                           SmallVectorImpl<OpAsmParser::Argument> &arguments,
1931c8abc3SChris Lattner                           bool &isVariadic) {
202f16bf7aSAlex Zinenko 
21*d85eb4e2SChris Lattner   // Parse the function arguments.  The argument list either has to consistently
22*d85eb4e2SChris Lattner   // have ssa-id's followed by types, or just be a type list.  It isn't ok to
23*d85eb4e2SChris Lattner   // sometimes have SSA ID's and sometimes not.
24*d85eb4e2SChris Lattner   isVariadic = false;
252f16bf7aSAlex Zinenko 
26*d85eb4e2SChris Lattner   return parser.parseCommaSeparatedList(
27*d85eb4e2SChris Lattner       OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
28*d85eb4e2SChris Lattner         // Ellipsis must be at end of the list.
29*d85eb4e2SChris Lattner         if (isVariadic)
30*d85eb4e2SChris Lattner           return parser.emitError(
31*d85eb4e2SChris Lattner               parser.getCurrentLocation(),
32*d85eb4e2SChris Lattner               "variadic arguments must be in the end of the argument list");
33*d85eb4e2SChris Lattner 
34*d85eb4e2SChris Lattner         // Handle ellipsis as a special case.
35*d85eb4e2SChris Lattner         if (allowVariadic && succeeded(parser.parseOptionalEllipsis())) {
36*d85eb4e2SChris Lattner           // This is a variadic designator.
37*d85eb4e2SChris Lattner           isVariadic = true;
38*d85eb4e2SChris Lattner           return success(); // Stop parsing arguments.
39*d85eb4e2SChris Lattner         }
402f16bf7aSAlex Zinenko         // Parse argument name if present.
41*d85eb4e2SChris Lattner         OpAsmParser::Argument argument;
42*d85eb4e2SChris Lattner         auto argPresent = parser.parseOptionalArgument(
43*d85eb4e2SChris Lattner             argument, /*allowType=*/true, /*allowAttrs=*/true);
44*d85eb4e2SChris Lattner         if (argPresent.hasValue()) {
45*d85eb4e2SChris Lattner           if (failed(argPresent.getValue()))
46*d85eb4e2SChris Lattner             return failure(); // Present but malformed.
475dedf911SChris Lattner 
482f16bf7aSAlex Zinenko           // Reject this if the preceding argument was missing a name.
49*d85eb4e2SChris Lattner           if (!arguments.empty() && arguments.back().ssaName.name.empty())
50*d85eb4e2SChris Lattner             return parser.emitError(argument.ssaName.location,
51*d85eb4e2SChris Lattner                                     "expected type instead of SSA identifier");
522f16bf7aSAlex Zinenko 
53*d85eb4e2SChris Lattner         } else {
54*d85eb4e2SChris Lattner           argument.ssaName.location = parser.getCurrentLocation();
55*d85eb4e2SChris Lattner           // Otherwise we just have a type list without SSA names.  Reject
56*d85eb4e2SChris Lattner           // this if the preceding argument had a name.
57*d85eb4e2SChris Lattner           if (!arguments.empty() && !arguments.back().ssaName.name.empty())
58*d85eb4e2SChris Lattner             return parser.emitError(argument.ssaName.location,
59*d85eb4e2SChris Lattner                                     "expected SSA identifier");
602f16bf7aSAlex Zinenko 
615eae715aSJacques Pienaar           NamedAttrList attrs;
62*d85eb4e2SChris Lattner           if (parser.parseType(argument.type) ||
63*d85eb4e2SChris Lattner               parser.parseOptionalAttrDict(attrs) ||
6431c8abc3SChris Lattner               parser.parseOptionalLocationSpecifier(argument.sourceLoc))
652f16bf7aSAlex Zinenko             return failure();
66*d85eb4e2SChris Lattner           argument.attrs = attrs.getDictionary(parser.getContext());
672f16bf7aSAlex Zinenko         }
68*d85eb4e2SChris Lattner         arguments.push_back(argument);
692f16bf7aSAlex Zinenko         return success();
70*d85eb4e2SChris 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
835eae715aSJacques Pienaar parseFunctionResultList(OpAsmParser &parser, SmallVectorImpl<Type> &resultTypes,
84*d85eb4e2SChris 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.
101*d85eb4e2SChris Lattner   if (parser.parseCommaSeparatedList([&]() -> ParseResult {
1022f16bf7aSAlex Zinenko         resultTypes.emplace_back();
1032f16bf7aSAlex Zinenko         resultAttrs.emplace_back();
104*d85eb4e2SChris Lattner         NamedAttrList attrs;
1052f16bf7aSAlex Zinenko         if (parser.parseType(resultTypes.back()) ||
106*d85eb4e2SChris Lattner             parser.parseOptionalAttrDict(attrs))
1072f16bf7aSAlex Zinenko           return failure();
108*d85eb4e2SChris Lattner         resultAttrs.back() = attrs.getDictionary(parser.getContext());
109*d85eb4e2SChris Lattner         return success();
110*d85eb4e2SChris Lattner       }))
111*d85eb4e2SChris Lattner     return failure();
112*d85eb4e2SChris Lattner 
1132f16bf7aSAlex Zinenko   return parser.parseRParen();
1142f16bf7aSAlex Zinenko }
1152f16bf7aSAlex Zinenko 
1167ceffae1SRiver Riddle ParseResult mlir::function_interface_impl::parseFunctionSignature(
1172f16bf7aSAlex Zinenko     OpAsmParser &parser, bool allowVariadic,
118*d85eb4e2SChris Lattner     SmallVectorImpl<OpAsmParser::Argument> &arguments, bool &isVariadic,
119*d85eb4e2SChris Lattner     SmallVectorImpl<Type> &resultTypes,
120*d85eb4e2SChris Lattner     SmallVectorImpl<DictionaryAttr> &resultAttrs) {
121*d85eb4e2SChris 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 
1287ceffae1SRiver Riddle void mlir::function_interface_impl::addArgAndResultAttrs(
12953b946aaSRiver Riddle     Builder &builder, OperationState &result, ArrayRef<DictionaryAttr> argAttrs,
13053b946aaSRiver Riddle     ArrayRef<DictionaryAttr> resultAttrs) {
131*d85eb4e2SChris Lattner   auto nonEmptyAttrsFn = [](DictionaryAttr attrs) {
132*d85eb4e2SChris Lattner     return attrs && !attrs.empty();
13353b946aaSRiver Riddle   };
134*d85eb4e2SChris Lattner   // Convert the specified array of dictionary attrs (which may have null
135*d85eb4e2SChris Lattner   // entries) to an ArrayAttr of dictionaries.
136*d85eb4e2SChris Lattner   auto getArrayAttr = [&](ArrayRef<DictionaryAttr> dictAttrs) {
137*d85eb4e2SChris Lattner     SmallVector<Attribute> attrs;
138*d85eb4e2SChris Lattner     for (auto &dict : dictAttrs)
139*d85eb4e2SChris Lattner       attrs.push_back(dict ? dict : builder.getDictionaryAttr({}));
140*d85eb4e2SChris Lattner     return builder.getArrayAttr(attrs);
141*d85eb4e2SChris Lattner   };
142*d85eb4e2SChris Lattner 
143*d85eb4e2SChris Lattner   // Add the attributes to the function arguments.
144*d85eb4e2SChris Lattner   if (llvm::any_of(argAttrs, nonEmptyAttrsFn))
145*d85eb4e2SChris Lattner     result.addAttribute(function_interface_impl::getArgDictAttrName(),
146*d85eb4e2SChris Lattner                         getArrayAttr(argAttrs));
147*d85eb4e2SChris Lattner 
148*d85eb4e2SChris Lattner   // Add the attributes to the function results.
149*d85eb4e2SChris Lattner   if (llvm::any_of(resultAttrs, nonEmptyAttrsFn))
150*d85eb4e2SChris Lattner     result.addAttribute(function_interface_impl::getResultDictAttrName(),
151*d85eb4e2SChris Lattner                         getArrayAttr(resultAttrs));
15253b946aaSRiver Riddle }
153*d85eb4e2SChris Lattner 
1547ceffae1SRiver Riddle void mlir::function_interface_impl::addArgAndResultAttrs(
155*d85eb4e2SChris Lattner     Builder &builder, OperationState &result,
156*d85eb4e2SChris Lattner     ArrayRef<OpAsmParser::Argument> args,
157*d85eb4e2SChris Lattner     ArrayRef<DictionaryAttr> resultAttrs) {
158*d85eb4e2SChris Lattner   SmallVector<DictionaryAttr> argAttrs;
159*d85eb4e2SChris Lattner   for (const auto &arg : args)
160*d85eb4e2SChris Lattner     argAttrs.push_back(arg.attrs);
161*d85eb4e2SChris Lattner   addArgAndResultAttrs(builder, result, argAttrs, resultAttrs);
1622f16bf7aSAlex Zinenko }
1632f16bf7aSAlex Zinenko 
1647ceffae1SRiver Riddle ParseResult mlir::function_interface_impl::parseFunctionOp(
16553b946aaSRiver Riddle     OpAsmParser &parser, OperationState &result, bool allowVariadic,
16653b946aaSRiver Riddle     FuncTypeBuilder funcTypeBuilder) {
167*d85eb4e2SChris Lattner   SmallVector<OpAsmParser::Argument> entryArgs;
168*d85eb4e2SChris Lattner   SmallVector<DictionaryAttr> resultAttrs;
1691e09f0a9SDominik Grewe   SmallVector<Type> resultTypes;
1702f16bf7aSAlex Zinenko   auto &builder = parser.getBuilder();
1712f16bf7aSAlex Zinenko 
172dea24b42SRahul Joshi   // Parse visibility.
1738b5a3e46SRahul Joshi   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;
184*d85eb4e2SChris Lattner   if (parseFunctionSignature(parser, allowVariadic, entryArgs, isVariadic,
185*d85eb4e2SChris Lattner                              resultTypes, resultAttrs))
1862f16bf7aSAlex Zinenko     return failure();
1872f16bf7aSAlex Zinenko 
1882f16bf7aSAlex Zinenko   std::string errorMessage;
189*d85eb4e2SChris Lattner   SmallVector<Type> argTypes;
190*d85eb4e2SChris Lattner   argTypes.reserve(entryArgs.size());
191*d85eb4e2SChris Lattner   for (auto &arg : entryArgs)
192*d85eb4e2SChris 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());
223*d85eb4e2SChris 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();
229*d85eb4e2SChris Lattner   OptionalParseResult parseResult =
230*d85eb4e2SChris Lattner       parser.parseOptionalRegion(*body, entryArgs,
231fe7fdcacSRahul Joshi                                  /*enableNameShadowing=*/false);
232fe7fdcacSRahul Joshi   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`.
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 
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 
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 
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