Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/mlir/lib/IR/Function.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Function.cpp - MLIR Function Classes -------------------------------===//
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "mlir/IR/Function.h"
10
#include "mlir/IR/BlockAndValueMapping.h"
11
#include "mlir/IR/Builders.h"
12
#include "mlir/IR/FunctionImplementation.h"
13
#include "llvm/ADT/BitVector.h"
14
#include "llvm/ADT/MapVector.h"
15
#include "llvm/ADT/SmallString.h"
16
#include "llvm/ADT/Twine.h"
17
18
using namespace mlir;
19
20
//===----------------------------------------------------------------------===//
21
// Function Operation.
22
//===----------------------------------------------------------------------===//
23
24
FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
25
0
                      ArrayRef<NamedAttribute> attrs) {
26
0
  OperationState state(location, "func");
27
0
  OpBuilder builder(location->getContext());
28
0
  FuncOp::build(builder, state, name, type, attrs);
29
0
  return cast<FuncOp>(Operation::create(state));
30
0
}
31
FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
32
0
                      iterator_range<dialect_attr_iterator> attrs) {
33
0
  SmallVector<NamedAttribute, 8> attrRef(attrs);
34
0
  return create(location, name, type, llvm::makeArrayRef(attrRef));
35
0
}
36
FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
37
                      ArrayRef<NamedAttribute> attrs,
38
0
                      ArrayRef<MutableDictionaryAttr> argAttrs) {
39
0
  FuncOp func = create(location, name, type, attrs);
40
0
  func.setAllArgAttrs(argAttrs);
41
0
  return func;
42
0
}
43
44
void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
45
0
                   FunctionType type, ArrayRef<NamedAttribute> attrs) {
46
0
  result.addAttribute(SymbolTable::getSymbolAttrName(),
47
0
                      builder.getStringAttr(name));
48
0
  result.addAttribute(getTypeAttrName(), TypeAttr::get(type));
49
0
  result.attributes.append(attrs.begin(), attrs.end());
50
0
  result.addRegion();
51
0
}
52
53
void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
54
                   FunctionType type, ArrayRef<NamedAttribute> attrs,
55
0
                   ArrayRef<MutableDictionaryAttr> argAttrs) {
56
0
  build(builder, result, name, type, attrs);
57
0
  assert(type.getNumInputs() == argAttrs.size());
58
0
  SmallString<8> argAttrName;
59
0
  for (unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
60
0
    if (auto argDict = argAttrs[i].getDictionary(builder.getContext()))
61
0
      result.addAttribute(getArgAttrName(i, argAttrName), argDict);
62
0
}
63
64
/// Parsing/Printing methods.
65
66
0
ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
67
0
  auto buildFuncType = [](Builder &builder, ArrayRef<Type> argTypes,
68
0
                          ArrayRef<Type> results, impl::VariadicFlag,
69
0
                          std::string &) {
70
0
    return builder.getFunctionType(argTypes, results);
71
0
  };
72
0
73
0
  return impl::parseFunctionLikeOp(parser, result, /*allowVariadic=*/false,
74
0
                                   buildFuncType);
75
0
}
76
77
0
void FuncOp::print(OpAsmPrinter &p) {
78
0
  FunctionType fnType = getType();
79
0
  impl::printFunctionLikeOp(p, *this, fnType.getInputs(), /*isVariadic=*/false,
80
0
                            fnType.getResults());
81
0
}
82
83
0
LogicalResult FuncOp::verify() {
84
0
  // If this function is external there is nothing to do.
85
0
  if (isExternal())
86
0
    return success();
87
0
88
0
  // Verify that the argument list of the function and the arg list of the entry
89
0
  // block line up.  The trait already verified that the number of arguments is
90
0
  // the same between the signature and the block.
91
0
  auto fnInputTypes = getType().getInputs();
92
0
  Block &entryBlock = front();
93
0
  for (unsigned i = 0, e = entryBlock.getNumArguments(); i != e; ++i)
94
0
    if (fnInputTypes[i] != entryBlock.getArgument(i).getType())
95
0
      return emitOpError("type of entry block argument #")
96
0
             << i << '(' << entryBlock.getArgument(i).getType()
97
0
             << ") must match the type of the corresponding argument in "
98
0
             << "function signature(" << fnInputTypes[i] << ')';
99
0
100
0
  return success();
101
0
}
102
103
0
void FuncOp::eraseArguments(ArrayRef<unsigned> argIndices) {
104
0
  auto oldType = getType();
105
0
  int originalNumArgs = oldType.getNumInputs();
106
0
  llvm::BitVector eraseIndices(originalNumArgs);
107
0
  for (auto index : argIndices)
108
0
    eraseIndices.set(index);
109
0
  auto shouldEraseArg = [&](int i) { return eraseIndices.test(i); };
110
0
111
0
  // There are 3 things that need to be updated:
112
0
  // - Function type.
113
0
  // - Arg attrs.
114
0
  // - Block arguments of entry block.
115
0
116
0
  // Update the function type and arg attrs.
117
0
  SmallVector<Type, 4> newInputTypes;
118
0
  SmallVector<MutableDictionaryAttr, 4> newArgAttrs;
119
0
  for (int i = 0; i < originalNumArgs; i++) {
120
0
    if (shouldEraseArg(i))
121
0
      continue;
122
0
    newInputTypes.emplace_back(oldType.getInput(i));
123
0
    newArgAttrs.emplace_back(getArgAttrDict(i));
124
0
  }
125
0
  setType(FunctionType::get(newInputTypes, oldType.getResults(), getContext()));
126
0
  setAllArgAttrs(newArgAttrs);
127
0
128
0
  // Update the entry block's arguments.
129
0
  // We do this in reverse so that we erase later indices before earlier
130
0
  // indices, to avoid shifting the later indices.
131
0
  Block &entry = front();
132
0
  for (int i = 0; i < originalNumArgs; i++)
133
0
    if (shouldEraseArg(originalNumArgs - i - 1))
134
0
      entry.eraseArgument(originalNumArgs - i - 1);
135
0
}
136
137
/// Clone the internal blocks from this function into dest and all attributes
138
/// from this function to dest.
139
0
void FuncOp::cloneInto(FuncOp dest, BlockAndValueMapping &mapper) {
140
0
  // Add the attributes of this function to dest.
141
0
  llvm::MapVector<Identifier, Attribute> newAttrs;
142
0
  for (auto &attr : dest.getAttrs())
143
0
    newAttrs.insert(attr);
144
0
  for (auto &attr : getAttrs())
145
0
    newAttrs.insert(attr);
146
0
  dest.getOperation()->setAttrs(
147
0
      DictionaryAttr::get(newAttrs.takeVector(), getContext()));
148
0
149
0
  // Clone the body.
150
0
  getBody().cloneInto(&dest.getBody(), mapper);
151
0
}
152
153
/// Create a deep copy of this function and all of its blocks, remapping
154
/// any operands that use values outside of the function using the map that is
155
/// provided (leaving them alone if no entry is present). Replaces references
156
/// to cloned sub-values with the corresponding value that is copied, and adds
157
/// those mappings to the mapper.
158
0
FuncOp FuncOp::clone(BlockAndValueMapping &mapper) {
159
0
  FunctionType newType = getType();
160
0
161
0
  // If the function has a body, then the user might be deleting arguments to
162
0
  // the function by specifying them in the mapper. If so, we don't add the
163
0
  // argument to the input type vector.
164
0
  bool isExternalFn = isExternal();
165
0
  if (!isExternalFn) {
166
0
    SmallVector<Type, 4> inputTypes;
167
0
    inputTypes.reserve(newType.getNumInputs());
168
0
    for (unsigned i = 0, e = getNumArguments(); i != e; ++i)
169
0
      if (!mapper.contains(getArgument(i)))
170
0
        inputTypes.push_back(newType.getInput(i));
171
0
    newType = FunctionType::get(inputTypes, newType.getResults(), getContext());
172
0
  }
173
0
174
0
  // Create the new function.
175
0
  FuncOp newFunc = cast<FuncOp>(getOperation()->cloneWithoutRegions());
176
0
  newFunc.setType(newType);
177
0
178
0
  /// Set the argument attributes for arguments that aren't being replaced.
179
0
  for (unsigned i = 0, e = getNumArguments(), destI = 0; i != e; ++i)
180
0
    if (isExternalFn || !mapper.contains(getArgument(i)))
181
0
      newFunc.setArgAttrs(destI++, getArgAttrs(i));
182
0
183
0
  /// Clone the current function into the new one and return it.
184
0
  cloneInto(newFunc, mapper);
185
0
  return newFunc;
186
0
}
187
0
FuncOp FuncOp::clone() {
188
0
  BlockAndValueMapping mapper;
189
0
  return clone(mapper);
190
0
}