MLIR 24.0.0git
FuncOps.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
10
15#include "mlir/IR/IRMapping.h"
16#include "mlir/IR/Matchers.h"
20#include "mlir/IR/Value.h"
23#include "llvm/ADT/APFloat.h"
24#include "llvm/ADT/MapVector.h"
25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/SmallVectorExtras.h"
27
28#include "mlir/Dialect/Func/IR/FuncOpsDialect.cpp.inc"
29
30using namespace mlir;
31using namespace mlir::func;
32
33//===----------------------------------------------------------------------===//
34// FuncDialect
35//===----------------------------------------------------------------------===//
36
37void FuncDialect::initialize() {
38 addOperations<
39#define GET_OP_LIST
40#include "mlir/Dialect/Func/IR/FuncOps.cpp.inc"
41 >();
42 declarePromisedInterface<ConvertToEmitCPatternInterface, FuncDialect>();
43 declarePromisedInterface<DialectInlinerInterface, FuncDialect>();
44 declarePromisedInterface<ConvertToLLVMPatternInterface, FuncDialect>();
45 declarePromisedInterfaces<bufferization::BufferizableOpInterface, CallOp,
46 FuncOp, ReturnOp>();
47}
48
49/// Materialize a single constant operation from a given attribute value with
50/// the desired resultant type.
51Operation *FuncDialect::materializeConstant(OpBuilder &builder, Attribute value,
52 Type type, Location loc) {
53 if (ConstantOp::isBuildableWith(value, type))
54 return ConstantOp::create(builder, loc, type,
55 llvm::cast<FlatSymbolRefAttr>(value));
56 return nullptr;
57}
58
59//===----------------------------------------------------------------------===//
60// CallOp
61//===----------------------------------------------------------------------===//
62
63LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
64 // Check that the callee attribute was specified.
65 auto fnAttr = getCalleeAttr();
66 if (!fnAttr)
67 return emitOpError("requires a 'callee' symbol reference attribute");
68 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
69 if (!fn)
70 return emitOpError() << "'" << fnAttr.getValue()
71 << "' does not reference a valid function";
72
73 // Verify that the operand and result types match the callee.
75}
76
77FunctionType CallOp::getCalleeType() {
78 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
79}
80
81//===----------------------------------------------------------------------===//
82// CallIndirectOp
83//===----------------------------------------------------------------------===//
84
85/// Fold indirect calls that have a constant function as the callee operand.
86LogicalResult CallIndirectOp::canonicalize(CallIndirectOp indirectCall,
87 PatternRewriter &rewriter) {
88 // Check that the callee is a constant callee.
89 FlatSymbolRefAttr calledFn;
90 if (!matchPattern(indirectCall.getCallee(), m_Constant(&calledFn)))
91 return failure();
92
93 // Replace with a direct call, preserving the call-site attributes.
94 auto directCall = CallOp::create(
95 rewriter, indirectCall.getLoc(), indirectCall.getResultTypes(), calledFn,
96 indirectCall.getArgOperands(), indirectCall.getArgAttrsAttr(),
97 indirectCall.getResAttrsAttr());
98 directCall->setDiscardableAttrs(indirectCall->getDiscardableAttrDictionary());
99 rewriter.replaceOp(indirectCall, directCall.getResults());
100 return success();
101}
102
103//===----------------------------------------------------------------------===//
104// ConstantOp
105//===----------------------------------------------------------------------===//
106
107LogicalResult ConstantOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
108 StringRef fnName = getValue();
109 Type type = getType();
110
111 // Try to find the referenced function.
112 auto fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(
113 this->getOperation(), StringAttr::get(getContext(), fnName));
114 if (!fn)
115 return emitOpError() << "reference to undefined function '" << fnName
116 << "'";
117
118 // Check that the referenced function has the correct type.
119 if (fn.getFunctionType() != type)
120 return emitOpError("reference to function with mismatched type");
121
122 return success();
123}
124
125OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
126 return getValueAttr();
127}
128
129void ConstantOp::getAsmResultNames(
130 function_ref<void(Value, StringRef)> setNameFn) {
131 setNameFn(getResult(), "f");
132}
133
134bool ConstantOp::isBuildableWith(Attribute value, Type type) {
135 return llvm::isa<FlatSymbolRefAttr>(value) && llvm::isa<FunctionType>(type);
136}
137
138//===----------------------------------------------------------------------===//
139// FuncOp
140//===----------------------------------------------------------------------===//
141
142FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
144 OpBuilder builder(location->getContext());
145 OperationState state(location, getOperationName());
146 FuncOp::build(builder, state, name, type, attrs);
147 return cast<FuncOp>(Operation::create(state));
148}
149FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
151 SmallVector<NamedAttribute, 8> attrRef(attrs);
152 return create(location, name, type, llvm::ArrayRef(attrRef));
153}
154FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
156 ArrayRef<DictionaryAttr> argAttrs) {
157 FuncOp func = create(location, name, type, attrs);
158 func.setAllArgAttrs(argAttrs);
159 return func;
160}
161
162void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
163 FunctionType type, ArrayRef<NamedAttribute> attrs,
164 ArrayRef<DictionaryAttr> argAttrs) {
165 state.getOrAddProperties<Properties>().sym_name = builder.getStringAttr(name);
166 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
167 state.attributes.append(attrs.begin(), attrs.end());
168 state.addRegion();
169
170 if (argAttrs.empty())
171 return;
172 assert(type.getNumInputs() == argAttrs.size());
174 builder, state, argAttrs, /*resultAttrs=*/{},
175 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
176}
177
178ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
179 auto buildFuncType =
180 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
182 std::string &) { return builder.getFunctionType(argTypes, results); };
183
185 parser, result, /*allowVariadic=*/false,
186 getFunctionTypeAttrName(result.name), buildFuncType,
187 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
188}
189
190void FuncOp::print(OpAsmPrinter &p) {
192 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
193 getArgAttrsAttrName(), getResAttrsAttrName());
194}
195
196/// Clone the internal blocks from this function into dest and all attributes
197/// from this function to dest.
198void FuncOp::cloneInto(FuncOp dest, IRMapping &mapper) {
199 // Add the attributes of this function to dest.
200 llvm::MapVector<StringAttr, Attribute> newAttrMap;
201 for (const auto &attr : dest->getDiscardableAttrDictionary().getValue())
202 newAttrMap.insert({attr.getName(), attr.getValue()});
203 for (const auto &attr : (*this)->getDiscardableAttrDictionary().getValue())
204 newAttrMap.insert({attr.getName(), attr.getValue()});
205
206 auto newAttrs = llvm::map_to_vector(
207 newAttrMap, [](std::pair<StringAttr, Attribute> attrPair) {
208 return NamedAttribute(attrPair.first, attrPair.second);
209 });
210 dest->setDiscardableAttrs(DictionaryAttr::get(getContext(), newAttrs));
211
212 // Clone the body.
213 getBody().cloneInto(&dest.getBody(), mapper);
214}
215
216/// Create a deep copy of this function and all of its blocks, remapping
217/// any operands that use values outside of the function using the map that is
218/// provided (leaving them alone if no entry is present). Replaces references
219/// to cloned sub-values with the corresponding value that is copied, and adds
220/// those mappings to the mapper.
221FuncOp FuncOp::clone(IRMapping &mapper) {
222 // Create the new function.
223 FuncOp newFunc = cast<FuncOp>(getOperation()->cloneWithoutRegions());
224
225 // If the function has a body, then the user might be deleting arguments to
226 // the function by specifying them in the mapper. If so, we don't add the
227 // argument to the input type vector.
228 if (!isExternal()) {
229 FunctionType oldType = getFunctionType();
230
231 unsigned oldNumArgs = oldType.getNumInputs();
232 SmallVector<Type, 4> newInputs;
233 newInputs.reserve(oldNumArgs);
234 for (unsigned i = 0; i != oldNumArgs; ++i)
235 if (!mapper.contains(getArgument(i)))
236 newInputs.push_back(oldType.getInput(i));
237
238 /// If any of the arguments were dropped, update the type and drop any
239 /// necessary argument attributes.
240 if (newInputs.size() != oldNumArgs) {
241 newFunc.setType(FunctionType::get(oldType.getContext(), newInputs,
242 oldType.getResults()));
243
244 if (ArrayAttr argAttrs = getAllArgAttrs()) {
245 SmallVector<Attribute> newArgAttrs;
246 newArgAttrs.reserve(newInputs.size());
247 for (unsigned i = 0; i != oldNumArgs; ++i)
248 if (!mapper.contains(getArgument(i)))
249 newArgAttrs.push_back(argAttrs[i]);
250 newFunc.setAllArgAttrs(newArgAttrs);
251 }
252 }
253 }
254
255 /// Clone the current function into the new one and return it.
256 cloneInto(newFunc, mapper);
257 return newFunc;
258}
259FuncOp FuncOp::clone() {
260 IRMapping mapper;
261 return clone(mapper);
262}
263
264//===----------------------------------------------------------------------===//
265// ReturnOp
266//===----------------------------------------------------------------------===//
267
268LogicalResult FuncOp::verifyRegions() {
269 // External declarations have no body to check.
270 if (isDeclaration())
271 return success();
272 // Hoist the result types once; they are the same for every return site.
273 auto resultTypes = getFunctionType().getResults();
274 for (Block &block : getBody()) {
275 if (block.empty())
276 continue;
277 // Check func.return or other return-like terminators ops (e.g.
278 // llvm.return, test.return).
279 auto returnOp = dyn_cast<RegionBranchTerminatorOpInterface>(&block.back());
280 if (!returnOp)
281 continue;
282 auto operands =
283 returnOp.getMutableSuccessorOperands(RegionSuccessor(getOperation()));
284 if (operands.size() != resultTypes.size())
285 return returnOp->emitOpError("has ")
286 << operands.size() << " operands, but enclosing function (@"
287 << getName() << ") returns " << resultTypes.size();
288
289 for (auto [i, opType] : llvm::enumerate(llvm::zip(operands, resultTypes))) {
290 auto [operand, resTy] = opType;
291 if (operand.get().getType() != resTy)
292 return returnOp->emitError() << "type of return operand " << i << " ("
293 << operand.get().getType()
294 << ") doesn't match function result type ("
295 << resTy << ") in function @" << getName();
296 }
297 }
298
299 return success();
300}
301
302//===----------------------------------------------------------------------===//
303// TableGen'd op method definitions
304//===----------------------------------------------------------------------===//
305
306#define GET_OP_CLASSES
307#include "mlir/Dialect/Func/IR/FuncOps.cpp.inc"
return success()
ArrayAttr()
b getContext())
Attributes are known-constant values of operations.
Definition Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Block represents an ordered list of Operations.
Definition Block.h:34
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
Definition Builders.cpp:84
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:271
A symbol reference with a reference path containing a single element.
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
bool contains(T from) const
Checks to see if a mapping for 'from' exists.
Definition IRMapping.h:51
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttribute represents a combination of a name and an Attribute value.
Definition Attributes.h:164
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This class helps build Operations.
Definition Builders.h:210
This class represents a single result from folding an operation.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
iterator_range< dialect_attr_iterator > dialect_attr_range
Definition Operation.h:686
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition Operation.cpp:65
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class represents a successor of a region.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
This class represents a collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
A named class for passing around the variadic flag.
LogicalResult verifyCallOpInterface(CallOpInterface call, TypeRange argumentTypes, TypeRange resultTypes)
Verify that the forwarded operands and results of call are in a 1:1 relationship with the given argum...
void addArgAndResultAttrs(Builder &builder, OperationState &result, ArrayRef< DictionaryAttr > argAttrs, ArrayRef< DictionaryAttr > resultAttrs, StringAttr argAttrsName, StringAttr resAttrsName)
Adds argument and result attributes, provided as argAttrs and resultAttrs arguments,...
void printFunctionOp(OpAsmPrinter &p, FunctionOpInterface op, bool isVariadic, StringRef typeAttrName, StringAttr argAttrsName, StringAttr resAttrsName)
Printer implementation for function-like operations.
ParseResult parseFunctionOp(OpAsmParser &parser, OperationState &result, bool allowVariadic, StringAttr typeAttrName, FuncTypeBuilder funcTypeBuilder, StringAttr argAttrsName, StringAttr resAttrsName)
Parser implementation for function-like operations.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition Matchers.h:490
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:310
Operation * cloneWithoutRegions(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Definition Matchers.h:369
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
This represents an operation in an abstracted form, suitable for use with the builder APIs.
T & getOrAddProperties()
Get (or create) the properties of the provided type to be set on the operation on creation.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
Region * addRegion()
Create a region that should be attached to the operation.