202 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Interfaces/FunctionImplementation.h"10#include "mlir/IR/Builders.h"11#include "mlir/IR/SymbolTable.h"12#include "mlir/Interfaces/FunctionInterfaces.h"13 14using namespace mlir;15 16static ParseResult17parseFunctionArgumentList(OpAsmParser &parser, bool allowVariadic,18 SmallVectorImpl<OpAsmParser::Argument> &arguments,19 bool &isVariadic) {20 21 // Parse the function arguments. The argument list either has to consistently22 // have ssa-id's followed by types, or just be a type list. It isn't ok to23 // sometimes have SSA ID's and sometimes not.24 isVariadic = false;25 26 return parser.parseCommaSeparatedList(27 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {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.has_value()) {45 if (failed(argPresent.value()))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. Reject56 // 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) ||64 parser.parseOptionalLocationSpecifier(argument.sourceLoc))65 return failure();66 argument.attrs = attrs.getDictionary(parser.getContext());67 }68 arguments.push_back(argument);69 return success();70 });71}72 73ParseResult function_interface_impl::parseFunctionSignatureWithArguments(74 OpAsmParser &parser, bool allowVariadic,75 SmallVectorImpl<OpAsmParser::Argument> &arguments, bool &isVariadic,76 SmallVectorImpl<Type> &resultTypes,77 SmallVectorImpl<DictionaryAttr> &resultAttrs) {78 if (parseFunctionArgumentList(parser, allowVariadic, arguments, isVariadic))79 return failure();80 if (succeeded(parser.parseOptionalArrow()))81 return call_interface_impl::parseFunctionResultList(parser, resultTypes,82 resultAttrs);83 return success();84}85 86ParseResult function_interface_impl::parseFunctionOp(87 OpAsmParser &parser, OperationState &result, bool allowVariadic,88 StringAttr typeAttrName, FuncTypeBuilder funcTypeBuilder,89 StringAttr argAttrsName, StringAttr resAttrsName) {90 SmallVector<OpAsmParser::Argument> entryArgs;91 SmallVector<DictionaryAttr> resultAttrs;92 SmallVector<Type> resultTypes;93 auto &builder = parser.getBuilder();94 95 // Parse visibility.96 (void)impl::parseOptionalVisibilityKeyword(parser, result.attributes);97 98 // Parse the name as a symbol.99 StringAttr nameAttr;100 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),101 result.attributes))102 return failure();103 104 // Parse the function signature.105 SMLoc signatureLocation = parser.getCurrentLocation();106 bool isVariadic = false;107 if (parseFunctionSignatureWithArguments(parser, allowVariadic, entryArgs,108 isVariadic, resultTypes, resultAttrs))109 return failure();110 111 std::string errorMessage;112 SmallVector<Type> argTypes;113 argTypes.reserve(entryArgs.size());114 for (auto &arg : entryArgs)115 argTypes.push_back(arg.type);116 Type type = funcTypeBuilder(builder, argTypes, resultTypes,117 VariadicFlag(isVariadic), errorMessage);118 if (!type) {119 return parser.emitError(signatureLocation)120 << "failed to construct function type"121 << (errorMessage.empty() ? "" : ": ") << errorMessage;122 }123 result.addAttribute(typeAttrName, TypeAttr::get(type));124 125 // If function attributes are present, parse them.126 NamedAttrList parsedAttributes;127 SMLoc attributeDictLocation = parser.getCurrentLocation();128 if (parser.parseOptionalAttrDictWithKeyword(parsedAttributes))129 return failure();130 131 // Disallow attributes that are inferred from elsewhere in the attribute132 // dictionary.133 for (StringRef disallowed :134 {SymbolTable::getVisibilityAttrName(), SymbolTable::getSymbolAttrName(),135 typeAttrName.getValue()}) {136 if (parsedAttributes.get(disallowed))137 return parser.emitError(attributeDictLocation, "'")138 << disallowed139 << "' is an inferred attribute and should not be specified in the "140 "explicit attribute dictionary";141 }142 result.attributes.append(parsedAttributes);143 144 // Add the attributes to the function arguments.145 assert(resultAttrs.size() == resultTypes.size());146 call_interface_impl::addArgAndResultAttrs(147 builder, result, entryArgs, resultAttrs, argAttrsName, resAttrsName);148 149 // Parse the optional function body. The printer will not print the body if150 // its empty, so disallow parsing of empty body in the parser.151 auto *body = result.addRegion();152 SMLoc loc = parser.getCurrentLocation();153 OptionalParseResult parseResult =154 parser.parseOptionalRegion(*body, entryArgs,155 /*enableNameShadowing=*/false);156 if (parseResult.has_value()) {157 if (failed(*parseResult))158 return failure();159 // Function body was parsed, make sure its not empty.160 if (body->empty())161 return parser.emitError(loc, "expected non-empty function body");162 }163 return success();164}165 166void function_interface_impl::printFunctionAttributes(167 OpAsmPrinter &p, Operation *op, ArrayRef<StringRef> elided) {168 // Print out function attributes, if present.169 SmallVector<StringRef, 8> ignoredAttrs = {SymbolTable::getSymbolAttrName()};170 ignoredAttrs.append(elided.begin(), elided.end());171 172 p.printOptionalAttrDictWithKeyword(op->getAttrs(), ignoredAttrs);173}174 175void function_interface_impl::printFunctionOp(176 OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic,177 StringRef typeAttrName, StringAttr argAttrsName, StringAttr resAttrsName) {178 // Print the operation and the function name.179 auto funcName =180 op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())181 .getValue();182 p << ' ';183 184 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();185 if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))186 p << visibility.getValue() << ' ';187 p.printSymbolName(funcName);188 189 ArrayRef<Type> argTypes = op.getArgumentTypes();190 ArrayRef<Type> resultTypes = op.getResultTypes();191 printFunctionSignature(p, op, argTypes, isVariadic, resultTypes);192 printFunctionAttributes(193 p, op, {visibilityAttrName, typeAttrName, argAttrsName, resAttrsName});194 // Print the body if this is not an external function.195 Region &body = op->getRegion(0);196 if (!body.empty()) {197 p << ' ';198 p.printRegion(body, /*printEntryBlockArgs=*/false,199 /*printBlockTerminators=*/true);200 }201}202