| //===- FunctionImplementation.cpp - Utilities for function-like ops -------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "mlir/Interfaces/FunctionImplementation.h" | |
| #include "mlir/IR/Builders.h" | |
| #include "mlir/IR/SymbolTable.h" | |
| #include "mlir/Interfaces/FunctionInterfaces.h" | |
| using namespace mlir; | |
| static ParseResult | |
| parseFunctionArgumentList(OpAsmParser &parser, bool allowVariadic, | |
| SmallVectorImpl<OpAsmParser::Argument> &arguments, | |
| bool &isVariadic) { | |
| // Parse the function arguments. The argument list either has to consistently | |
| // have ssa-id's followed by types, or just be a type list. It isn't ok to | |
| // sometimes have SSA ID's and sometimes not. | |
| isVariadic = false; | |
| return parser.parseCommaSeparatedList( | |
| OpAsmParser::Delimiter::Paren, [&]() -> ParseResult { | |
| // Ellipsis must be at end of the list. | |
| if (isVariadic) | |
| return parser.emitError( | |
| parser.getCurrentLocation(), | |
| "variadic arguments must be in the end of the argument list"); | |
| // Handle ellipsis as a special case. | |
| if (allowVariadic && succeeded(parser.parseOptionalEllipsis())) { | |
| // This is a variadic designator. | |
| isVariadic = true; | |
| return success(); // Stop parsing arguments. | |
| } | |
| // Parse argument name if present. | |
| OpAsmParser::Argument argument; | |
| auto argPresent = parser.parseOptionalArgument( | |
| argument, /*allowType=*/true, /*allowAttrs=*/true); | |
| if (argPresent.has_value()) { | |
| if (failed(argPresent.value())) | |
| return failure(); // Present but malformed. | |
| // Reject this if the preceding argument was missing a name. | |
| if (!arguments.empty() && arguments.back().ssaName.name.empty()) | |
| return parser.emitError(argument.ssaName.location, | |
| "expected type instead of SSA identifier"); | |
| } else { | |
| argument.ssaName.location = parser.getCurrentLocation(); | |
| // Otherwise we just have a type list without SSA names. Reject | |
| // this if the preceding argument had a name. | |
| if (!arguments.empty() && !arguments.back().ssaName.name.empty()) | |
| return parser.emitError(argument.ssaName.location, | |
| "expected SSA identifier"); | |
| NamedAttrList attrs; | |
| if (parser.parseType(argument.type) || | |
| parser.parseOptionalAttrDict(attrs) || | |
| parser.parseOptionalLocationSpecifier(argument.sourceLoc)) | |
| return failure(); | |
| argument.attrs = attrs.getDictionary(parser.getContext()); | |
| } | |
| arguments.push_back(argument); | |
| return success(); | |
| }); | |
| } | |
| ParseResult function_interface_impl::parseFunctionSignatureWithArguments( | |
| OpAsmParser &parser, bool allowVariadic, | |
| SmallVectorImpl<OpAsmParser::Argument> &arguments, bool &isVariadic, | |
| SmallVectorImpl<Type> &resultTypes, | |
| SmallVectorImpl<DictionaryAttr> &resultAttrs) { | |
| if (parseFunctionArgumentList(parser, allowVariadic, arguments, isVariadic)) | |
| return failure(); | |
| if (succeeded(parser.parseOptionalArrow())) | |
| return call_interface_impl::parseFunctionResultList(parser, resultTypes, | |
| resultAttrs); | |
| return success(); | |
| } | |
| ParseResult function_interface_impl::parseFunctionOp( | |
| OpAsmParser &parser, OperationState &result, bool allowVariadic, | |
| StringAttr typeAttrName, FuncTypeBuilder funcTypeBuilder, | |
| StringAttr argAttrsName, StringAttr resAttrsName) { | |
| SmallVector<OpAsmParser::Argument> entryArgs; | |
| SmallVector<DictionaryAttr> resultAttrs; | |
| SmallVector<Type> resultTypes; | |
| auto &builder = parser.getBuilder(); | |
| // Parse visibility. | |
| (void)impl::parseOptionalVisibilityKeyword(parser, result.attributes); | |
| // Parse the name as a symbol. | |
| StringAttr nameAttr; | |
| if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), | |
| result.attributes)) | |
| return failure(); | |
| // Parse the function signature. | |
| SMLoc signatureLocation = parser.getCurrentLocation(); | |
| bool isVariadic = false; | |
| if (parseFunctionSignatureWithArguments(parser, allowVariadic, entryArgs, | |
| isVariadic, resultTypes, resultAttrs)) | |
| return failure(); | |
| std::string errorMessage; | |
| SmallVector<Type> argTypes; | |
| argTypes.reserve(entryArgs.size()); | |
| for (auto &arg : entryArgs) | |
| argTypes.push_back(arg.type); | |
| Type type = funcTypeBuilder(builder, argTypes, resultTypes, | |
| VariadicFlag(isVariadic), errorMessage); | |
| if (!type) { | |
| return parser.emitError(signatureLocation) | |
| << "failed to construct function type" | |
| << (errorMessage.empty() ? "" : ": ") << errorMessage; | |
| } | |
| result.addAttribute(typeAttrName, TypeAttr::get(type)); | |
| // If function attributes are present, parse them. | |
| NamedAttrList parsedAttributes; | |
| SMLoc attributeDictLocation = parser.getCurrentLocation(); | |
| if (parser.parseOptionalAttrDictWithKeyword(parsedAttributes)) | |
| return failure(); | |
| // Disallow attributes that are inferred from elsewhere in the attribute | |
| // dictionary. | |
| for (StringRef disallowed : | |
| {SymbolTable::getVisibilityAttrName(), SymbolTable::getSymbolAttrName(), | |
| typeAttrName.getValue()}) { | |
| if (parsedAttributes.get(disallowed)) | |
| return parser.emitError(attributeDictLocation, "'") | |
| << disallowed | |
| << "' is an inferred attribute and should not be specified in the " | |
| "explicit attribute dictionary"; | |
| } | |
| result.attributes.append(parsedAttributes); | |
| // Add the attributes to the function arguments. | |
| assert(resultAttrs.size() == resultTypes.size()); | |
| call_interface_impl::addArgAndResultAttrs( | |
| builder, result, entryArgs, resultAttrs, argAttrsName, resAttrsName); | |
| // Parse the optional function body. The printer will not print the body if | |
| // its empty, so disallow parsing of empty body in the parser. | |
| auto *body = result.addRegion(); | |
| SMLoc loc = parser.getCurrentLocation(); | |
| OptionalParseResult parseResult = | |
| parser.parseOptionalRegion(*body, entryArgs, | |
| /*enableNameShadowing=*/false); | |
| if (parseResult.has_value()) { | |
| if (failed(*parseResult)) | |
| return failure(); | |
| // Function body was parsed, make sure its not empty. | |
| if (body->empty()) | |
| return parser.emitError(loc, "expected non-empty function body"); | |
| } | |
| return success(); | |
| } | |
| void function_interface_impl::printFunctionAttributes( | |
| OpAsmPrinter &p, Operation *op, ArrayRef<StringRef> elided) { | |
| // Print out function attributes, if present. | |
| SmallVector<StringRef, 8> ignoredAttrs = {SymbolTable::getSymbolAttrName()}; | |
| ignoredAttrs.append(elided.begin(), elided.end()); | |
| p.printOptionalAttrDictWithKeyword(op->getAttrs(), ignoredAttrs); | |
| } | |
| void function_interface_impl::printFunctionOp( | |
| OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic, | |
| StringRef typeAttrName, StringAttr argAttrsName, StringAttr resAttrsName) { | |
| // Print the operation and the function name. | |
| auto funcName = | |
| op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()) | |
| .getValue(); | |
| p << ' '; | |
| StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName(); | |
| if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName)) | |
| p << visibility.getValue() << ' '; | |
| p.printSymbolName(funcName); | |
| ArrayRef<Type> argTypes = op.getArgumentTypes(); | |
| ArrayRef<Type> resultTypes = op.getResultTypes(); | |
| printFunctionSignature(p, op, argTypes, isVariadic, resultTypes); | |
| printFunctionAttributes( | |
| p, op, {visibilityAttrName, typeAttrName, argAttrsName, resAttrsName}); | |
| // Print the body if this is not an external function. | |
| Region &body = op->getRegion(0); | |
| if (!body.empty()) { | |
| p << ' '; | |
| p.printRegion(body, /*printEntryBlockArgs=*/false, | |
| /*printBlockTerminators=*/true); | |
| } | |
| } |