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