brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.2 KiB · 3c09a21 Raw
313 lines · cpp
1//===- FuncOps.cpp - Func Dialect Operations ------------------------------===//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/Dialect/Func/IR/FuncOps.h"10 11#include "mlir/Conversion/ConvertToEmitC/ToEmitCInterface.h"12#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"13#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"14#include "mlir/IR/BuiltinTypes.h"15#include "mlir/IR/IRMapping.h"16#include "mlir/IR/Matchers.h"17#include "mlir/IR/OpImplementation.h"18#include "mlir/IR/PatternMatch.h"19#include "mlir/IR/TypeUtilities.h"20#include "mlir/IR/Value.h"21#include "mlir/Interfaces/FunctionImplementation.h"22#include "mlir/Transforms/InliningUtils.h"23#include "llvm/ADT/APFloat.h"24#include "llvm/ADT/MapVector.h"25#include "llvm/ADT/STLExtras.h"26 27#include "mlir/Dialect/Func/IR/FuncOpsDialect.cpp.inc"28 29using namespace mlir;30using namespace mlir::func;31 32//===----------------------------------------------------------------------===//33// FuncDialect34//===----------------------------------------------------------------------===//35 36void FuncDialect::initialize() {37  addOperations<38#define GET_OP_LIST39#include "mlir/Dialect/Func/IR/FuncOps.cpp.inc"40      >();41  declarePromisedInterface<ConvertToEmitCPatternInterface, FuncDialect>();42  declarePromisedInterface<DialectInlinerInterface, FuncDialect>();43  declarePromisedInterface<ConvertToLLVMPatternInterface, FuncDialect>();44  declarePromisedInterfaces<bufferization::BufferizableOpInterface, CallOp,45                            FuncOp, ReturnOp>();46}47 48/// Materialize a single constant operation from a given attribute value with49/// the desired resultant type.50Operation *FuncDialect::materializeConstant(OpBuilder &builder, Attribute value,51                                            Type type, Location loc) {52  if (ConstantOp::isBuildableWith(value, type))53    return ConstantOp::create(builder, loc, type,54                              llvm::cast<FlatSymbolRefAttr>(value));55  return nullptr;56}57 58//===----------------------------------------------------------------------===//59// CallOp60//===----------------------------------------------------------------------===//61 62LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {63  // Check that the callee attribute was specified.64  auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");65  if (!fnAttr)66    return emitOpError("requires a 'callee' symbol reference attribute");67  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);68  if (!fn)69    return emitOpError() << "'" << fnAttr.getValue()70                         << "' does not reference a valid function";71 72  // Verify that the operand and result types match the callee.73  auto fnType = fn.getFunctionType();74  if (fnType.getNumInputs() != getNumOperands())75    return emitOpError("incorrect number of operands for callee");76 77  for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)78    if (getOperand(i).getType() != fnType.getInput(i))79      return emitOpError("operand type mismatch: expected operand type ")80             << fnType.getInput(i) << ", but provided "81             << getOperand(i).getType() << " for operand number " << i;82 83  if (fnType.getNumResults() != getNumResults())84    return emitOpError("incorrect number of results for callee");85 86  for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)87    if (getResult(i).getType() != fnType.getResult(i)) {88      auto diag = emitOpError("result type mismatch at index ") << i;89      diag.attachNote() << "      op result types: " << getResultTypes();90      diag.attachNote() << "function result types: " << fnType.getResults();91      return diag;92    }93 94  return success();95}96 97FunctionType CallOp::getCalleeType() {98  return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());99}100 101//===----------------------------------------------------------------------===//102// CallIndirectOp103//===----------------------------------------------------------------------===//104 105/// Fold indirect calls that have a constant function as the callee operand.106LogicalResult CallIndirectOp::canonicalize(CallIndirectOp indirectCall,107                                           PatternRewriter &rewriter) {108  // Check that the callee is a constant callee.109  SymbolRefAttr calledFn;110  if (!matchPattern(indirectCall.getCallee(), m_Constant(&calledFn)))111    return failure();112 113  // Replace with a direct call.114  rewriter.replaceOpWithNewOp<CallOp>(indirectCall, calledFn,115                                      indirectCall.getResultTypes(),116                                      indirectCall.getArgOperands());117  return success();118}119 120//===----------------------------------------------------------------------===//121// ConstantOp122//===----------------------------------------------------------------------===//123 124LogicalResult ConstantOp::verifySymbolUses(SymbolTableCollection &symbolTable) {125  StringRef fnName = getValue();126  Type type = getType();127 128  // Try to find the referenced function.129  auto fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(130      this->getOperation(), StringAttr::get(getContext(), fnName));131  if (!fn)132    return emitOpError() << "reference to undefined function '" << fnName133                         << "'";134 135  // Check that the referenced function has the correct type.136  if (fn.getFunctionType() != type)137    return emitOpError("reference to function with mismatched type");138 139  return success();140}141 142OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {143  return getValueAttr();144}145 146void ConstantOp::getAsmResultNames(147    function_ref<void(Value, StringRef)> setNameFn) {148  setNameFn(getResult(), "f");149}150 151bool ConstantOp::isBuildableWith(Attribute value, Type type) {152  return llvm::isa<FlatSymbolRefAttr>(value) && llvm::isa<FunctionType>(type);153}154 155//===----------------------------------------------------------------------===//156// FuncOp157//===----------------------------------------------------------------------===//158 159FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,160                      ArrayRef<NamedAttribute> attrs) {161  OpBuilder builder(location->getContext());162  OperationState state(location, getOperationName());163  FuncOp::build(builder, state, name, type, attrs);164  return cast<FuncOp>(Operation::create(state));165}166FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,167                      Operation::dialect_attr_range attrs) {168  SmallVector<NamedAttribute, 8> attrRef(attrs);169  return create(location, name, type, llvm::ArrayRef(attrRef));170}171FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,172                      ArrayRef<NamedAttribute> attrs,173                      ArrayRef<DictionaryAttr> argAttrs) {174  FuncOp func = create(location, name, type, attrs);175  func.setAllArgAttrs(argAttrs);176  return func;177}178 179void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,180                   FunctionType type, ArrayRef<NamedAttribute> attrs,181                   ArrayRef<DictionaryAttr> argAttrs) {182  state.addAttribute(SymbolTable::getSymbolAttrName(),183                     builder.getStringAttr(name));184  state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));185  state.attributes.append(attrs.begin(), attrs.end());186  state.addRegion();187 188  if (argAttrs.empty())189    return;190  assert(type.getNumInputs() == argAttrs.size());191  call_interface_impl::addArgAndResultAttrs(192      builder, state, argAttrs, /*resultAttrs=*/{},193      getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));194}195 196ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {197  auto buildFuncType =198      [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,199         function_interface_impl::VariadicFlag,200         std::string &) { return builder.getFunctionType(argTypes, results); };201 202  return function_interface_impl::parseFunctionOp(203      parser, result, /*allowVariadic=*/false,204      getFunctionTypeAttrName(result.name), buildFuncType,205      getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));206}207 208void FuncOp::print(OpAsmPrinter &p) {209  function_interface_impl::printFunctionOp(210      p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),211      getArgAttrsAttrName(), getResAttrsAttrName());212}213 214/// Clone the internal blocks from this function into dest and all attributes215/// from this function to dest.216void FuncOp::cloneInto(FuncOp dest, IRMapping &mapper) {217  // Add the attributes of this function to dest.218  llvm::MapVector<StringAttr, Attribute> newAttrMap;219  for (const auto &attr : dest->getAttrs())220    newAttrMap.insert({attr.getName(), attr.getValue()});221  for (const auto &attr : (*this)->getAttrs())222    newAttrMap.insert({attr.getName(), attr.getValue()});223 224  auto newAttrs = llvm::to_vector(llvm::map_range(225      newAttrMap, [](std::pair<StringAttr, Attribute> attrPair) {226        return NamedAttribute(attrPair.first, attrPair.second);227      }));228  dest->setAttrs(DictionaryAttr::get(getContext(), newAttrs));229 230  // Clone the body.231  getBody().cloneInto(&dest.getBody(), mapper);232}233 234/// Create a deep copy of this function and all of its blocks, remapping235/// any operands that use values outside of the function using the map that is236/// provided (leaving them alone if no entry is present). Replaces references237/// to cloned sub-values with the corresponding value that is copied, and adds238/// those mappings to the mapper.239FuncOp FuncOp::clone(IRMapping &mapper) {240  // Create the new function.241  FuncOp newFunc = cast<FuncOp>(getOperation()->cloneWithoutRegions());242 243  // If the function has a body, then the user might be deleting arguments to244  // the function by specifying them in the mapper. If so, we don't add the245  // argument to the input type vector.246  if (!isExternal()) {247    FunctionType oldType = getFunctionType();248 249    unsigned oldNumArgs = oldType.getNumInputs();250    SmallVector<Type, 4> newInputs;251    newInputs.reserve(oldNumArgs);252    for (unsigned i = 0; i != oldNumArgs; ++i)253      if (!mapper.contains(getArgument(i)))254        newInputs.push_back(oldType.getInput(i));255 256    /// If any of the arguments were dropped, update the type and drop any257    /// necessary argument attributes.258    if (newInputs.size() != oldNumArgs) {259      newFunc.setType(FunctionType::get(oldType.getContext(), newInputs,260                                        oldType.getResults()));261 262      if (ArrayAttr argAttrs = getAllArgAttrs()) {263        SmallVector<Attribute> newArgAttrs;264        newArgAttrs.reserve(newInputs.size());265        for (unsigned i = 0; i != oldNumArgs; ++i)266          if (!mapper.contains(getArgument(i)))267            newArgAttrs.push_back(argAttrs[i]);268        newFunc.setAllArgAttrs(newArgAttrs);269      }270    }271  }272 273  /// Clone the current function into the new one and return it.274  cloneInto(newFunc, mapper);275  return newFunc;276}277FuncOp FuncOp::clone() {278  IRMapping mapper;279  return clone(mapper);280}281 282//===----------------------------------------------------------------------===//283// ReturnOp284//===----------------------------------------------------------------------===//285 286LogicalResult ReturnOp::verify() {287  auto function = cast<FuncOp>((*this)->getParentOp());288 289  // The operand number and types must match the function signature.290  const auto &results = function.getFunctionType().getResults();291  if (getNumOperands() != results.size())292    return emitOpError("has ")293           << getNumOperands() << " operands, but enclosing function (@"294           << function.getName() << ") returns " << results.size();295 296  for (unsigned i = 0, e = results.size(); i != e; ++i)297    if (getOperand(i).getType() != results[i])298      return emitError() << "type of return operand " << i << " ("299                         << getOperand(i).getType()300                         << ") doesn't match function result type ("301                         << results[i] << ")"302                         << " in function @" << function.getName();303 304  return success();305}306 307//===----------------------------------------------------------------------===//308// TableGen'd op method definitions309//===----------------------------------------------------------------------===//310 311#define GET_OP_CLASSES312#include "mlir/Dialect/Func/IR/FuncOps.cpp.inc"313