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
16#include "mlir/IR/IRMapping.h"
17#include "mlir/IR/Matchers.h"
21#include "mlir/IR/Value.h"
24#include "llvm/ADT/APFloat.h"
25#include "llvm/ADT/MapVector.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/SmallVectorExtras.h"
28
29#include "mlir/Dialect/Func/IR/FuncOpsDialect.cpp.inc"
30
31using namespace mlir;
32using namespace mlir::func;
33
34namespace {
35struct FuncDialectBytecodeInterface : BytecodeDialectInterface {
36 using BytecodeDialectInterface::BytecodeDialectInterface;
37
38 void writeVersion(DialectBytecodeWriter &writer) const override {
39 writer.writeVarInt(1);
40 }
41
42 std::unique_ptr<DialectVersion>
43 readVersion(DialectBytecodeReader &reader) const override {
44 uint64_t version;
45 if (failed(reader.readVarInt(version)))
46 return nullptr;
47 if (version != 1) {
48 reader.emitError("unsupported func dialect bytecode version");
49 return nullptr;
50 }
51 return std::make_unique<DialectVersion>();
52 }
53};
54} // namespace
55
56//===----------------------------------------------------------------------===//
57// FuncDialect
58//===----------------------------------------------------------------------===//
59
60void FuncDialect::initialize() {
61 addInterfaces<FuncDialectBytecodeInterface>();
62 addOperations<
63#define GET_OP_LIST
64#include "mlir/Dialect/Func/IR/FuncOps.cpp.inc"
65 >();
66 declarePromisedInterface<ConvertToEmitCPatternInterface, FuncDialect>();
67 declarePromisedInterface<DialectInlinerInterface, FuncDialect>();
68 declarePromisedInterface<ConvertToLLVMPatternInterface, FuncDialect>();
69 declarePromisedInterfaces<bufferization::BufferizableOpInterface, CallOp,
70 FuncOp, ReturnOp>();
71}
72
73/// Materialize a single constant operation from a given attribute value with
74/// the desired resultant type.
75Operation *FuncDialect::materializeConstant(OpBuilder &builder, Attribute value,
76 Type type, Location loc) {
77 if (ConstantOp::isBuildableWith(value, type))
78 return ConstantOp::create(builder, loc, type,
79 llvm::cast<FlatSymbolRefAttr>(value));
80 return nullptr;
81}
82
83//===----------------------------------------------------------------------===//
84// CallOp
85//===----------------------------------------------------------------------===//
86
87LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
88 // Check that the callee attribute was specified.
89 auto fnAttr = getCalleeAttr();
90 if (!fnAttr)
91 return emitOpError("requires a 'callee' symbol reference attribute");
92 FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);
93 if (!fn)
94 return emitOpError() << "'" << fnAttr.getValue()
95 << "' does not reference a valid function";
96
97 // Verify that the operand and result types match the callee.
99}
100
101FunctionType CallOp::getCalleeType() {
102 return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());
103}
104
105//===----------------------------------------------------------------------===//
106// CallIndirectOp
107//===----------------------------------------------------------------------===//
108
109/// Fold indirect calls that have a constant function as the callee operand.
110LogicalResult CallIndirectOp::canonicalize(CallIndirectOp indirectCall,
111 PatternRewriter &rewriter) {
112 // Check that the callee is a constant callee.
113 FlatSymbolRefAttr calledFn;
114 if (!matchPattern(indirectCall.getCallee(), m_Constant(&calledFn)))
115 return failure();
116
117 // Replace with a direct call, preserving the call-site attributes.
118 auto directCall = CallOp::create(
119 rewriter, indirectCall.getLoc(), indirectCall.getResultTypes(), calledFn,
120 indirectCall.getArgOperands(), indirectCall.getArgAttrsAttr(),
121 indirectCall.getResAttrsAttr());
122 directCall->setDiscardableAttrs(indirectCall->getDiscardableAttrDictionary());
123 rewriter.replaceOp(indirectCall, directCall.getResults());
124 return success();
125}
126
127//===----------------------------------------------------------------------===//
128// ConstantOp
129//===----------------------------------------------------------------------===//
130
131LogicalResult ConstantOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
132 StringRef fnName = getValue();
133 Type type = getType();
134
135 // Try to find the referenced function.
136 auto fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(
137 this->getOperation(), StringAttr::get(getContext(), fnName));
138 if (!fn)
139 return emitOpError() << "reference to undefined function '" << fnName
140 << "'";
141
142 // Check that the referenced function has the correct type.
143 if (fn.getFunctionType() != type)
144 return emitOpError("reference to function with mismatched type");
145
146 return success();
147}
148
149OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
150 return getValueAttr();
151}
152
153void ConstantOp::getAsmResultNames(
154 function_ref<void(Value, StringRef)> setNameFn) {
155 setNameFn(getResult(), "f");
156}
157
158bool ConstantOp::isBuildableWith(Attribute value, Type type) {
159 return llvm::isa<FlatSymbolRefAttr>(value) && llvm::isa<FunctionType>(type);
160}
161
162//===----------------------------------------------------------------------===//
163// FuncOp
164//===----------------------------------------------------------------------===//
165
166LogicalResult FuncOp::readProperties(DialectBytecodeReader &reader,
167 OperationState &state) {
168 auto &properties = state.getOrAddProperties<Properties>();
169 // Preserve the pre-DLTI field order for unversioned bytecode.
170 if (failed(reader.readOptionalAttribute(properties.arg_attrs)) ||
171 failed(reader.readAttribute(properties.function_type)) ||
172 failed(reader.readOptionalAttribute(properties.no_inline)) ||
173 failed(reader.readOptionalAttribute(properties.res_attrs)) ||
174 failed(reader.readAttribute(properties.sym_name)) ||
175 failed(reader.readOptionalAttribute(properties.sym_visibility)))
176 return failure();
177
178 if (failed(reader.getDialectVersion<FuncDialect>()))
179 return success();
180 return reader.readOptionalAttribute(properties.dlti);
181}
182
183void FuncOp::writeProperties(DialectBytecodeWriter &writer) {
184 Properties &properties = getProperties();
185 writer.writeOptionalAttribute(properties.arg_attrs);
186 writer.writeAttribute(properties.function_type);
187 writer.writeOptionalAttribute(properties.no_inline);
188 writer.writeOptionalAttribute(properties.res_attrs);
189 writer.writeAttribute(properties.sym_name);
190 writer.writeOptionalAttribute(properties.sym_visibility);
192 writer.writeOptionalAttribute(properties.dlti);
193}
194
195FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
197 OpBuilder builder(location->getContext());
198 OperationState state(location, getOperationName());
199 FuncOp::build(builder, state, name, type, attrs);
200 return cast<FuncOp>(Operation::create(state));
201}
202FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
204 SmallVector<NamedAttribute, 8> attrRef(attrs);
205 return create(location, name, type, llvm::ArrayRef(attrRef));
206}
207FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
209 ArrayRef<DictionaryAttr> argAttrs) {
210 FuncOp func = create(location, name, type, attrs);
211 func.setAllArgAttrs(argAttrs);
212 return func;
213}
214
215void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
216 FunctionType type, ArrayRef<NamedAttribute> attrs,
217 ArrayRef<DictionaryAttr> argAttrs) {
218 state.getOrAddProperties<Properties>().sym_name = builder.getStringAttr(name);
219 state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));
220 state.attributes.append(attrs.begin(), attrs.end());
221 state.addRegion();
222
223 if (argAttrs.empty())
224 return;
225 assert(type.getNumInputs() == argAttrs.size());
227 builder, state, argAttrs, /*resultAttrs=*/{},
228 getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));
229}
230
231ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
232 auto buildFuncType =
233 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
235 std::string &) { return builder.getFunctionType(argTypes, results); };
236
238 parser, result, /*allowVariadic=*/false,
239 getFunctionTypeAttrName(result.name), buildFuncType,
240 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
241}
242
243void FuncOp::print(OpAsmPrinter &p) {
245 p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
246 getArgAttrsAttrName(), getResAttrsAttrName());
247}
248
249/// Clone the internal blocks from this function into dest and all attributes
250/// from this function to dest.
251void FuncOp::cloneInto(FuncOp dest, IRMapping &mapper) {
252 // Add the attributes of this function to dest.
254 for (const auto &attr : dest->getDiscardableAttrDictionary().getValue())
255 newAttrMap.insert({attr.getName(), attr.getValue()});
256 for (const auto &attr : (*this)->getDiscardableAttrDictionary().getValue())
257 newAttrMap.insert({attr.getName(), attr.getValue()});
258
259 auto newAttrs = llvm::map_to_vector(
260 newAttrMap, [](std::pair<StringAttr, Attribute> attrPair) {
261 return NamedAttribute(attrPair.first, attrPair.second);
262 });
263 dest->setDiscardableAttrs(DictionaryAttr::get(getContext(), newAttrs));
264
265 // Clone the body.
266 getBody().cloneInto(&dest.getBody(), mapper);
267}
268
269/// Create a deep copy of this function and all of its blocks, remapping
270/// any operands that use values outside of the function using the map that is
271/// provided (leaving them alone if no entry is present). Replaces references
272/// to cloned sub-values with the corresponding value that is copied, and adds
273/// those mappings to the mapper.
274FuncOp FuncOp::clone(IRMapping &mapper) {
275 // Create the new function.
276 FuncOp newFunc = cast<FuncOp>(getOperation()->cloneWithoutRegions());
277
278 // If the function has a body, then the user might be deleting arguments to
279 // the function by specifying them in the mapper. If so, we don't add the
280 // argument to the input type vector.
281 if (!isExternal()) {
282 FunctionType oldType = getFunctionType();
283
284 unsigned oldNumArgs = oldType.getNumInputs();
285 SmallVector<Type, 4> newInputs;
286 newInputs.reserve(oldNumArgs);
287 for (unsigned i = 0; i != oldNumArgs; ++i)
288 if (!mapper.contains(getArgument(i)))
289 newInputs.push_back(oldType.getInput(i));
290
291 /// If any of the arguments were dropped, update the type and drop any
292 /// necessary argument attributes.
293 if (newInputs.size() != oldNumArgs) {
294 newFunc.setType(FunctionType::get(oldType.getContext(), newInputs,
295 oldType.getResults()));
296
297 if (ArrayAttr argAttrs = getAllArgAttrs()) {
298 SmallVector<Attribute> newArgAttrs;
299 newArgAttrs.reserve(newInputs.size());
300 for (unsigned i = 0; i != oldNumArgs; ++i)
301 if (!mapper.contains(getArgument(i)))
302 newArgAttrs.push_back(argAttrs[i]);
303 newFunc.setAllArgAttrs(newArgAttrs);
304 }
305 }
306 }
307
308 /// Clone the current function into the new one and return it.
309 cloneInto(newFunc, mapper);
310 return newFunc;
311}
312FuncOp FuncOp::clone() {
313 IRMapping mapper;
314 return clone(mapper);
315}
316
317//===----------------------------------------------------------------------===//
318// ReturnOp
319//===----------------------------------------------------------------------===//
320
321LogicalResult FuncOp::verifyRegions() {
322 // External declarations have no body to check.
323 if (isDeclaration())
324 return success();
325 // Hoist the result types once; they are the same for every return site.
326 auto resultTypes = getFunctionType().getResults();
327 for (Block &block : getBody()) {
328 if (block.empty())
329 continue;
330 // Check func.return or other return-like terminators ops (e.g.
331 // llvm.return, test.return).
332 auto returnOp = dyn_cast<RegionBranchTerminatorOpInterface>(&block.back());
333 if (!returnOp)
334 continue;
335 auto operands =
336 returnOp.getMutableSuccessorOperands(RegionSuccessor(getOperation()));
337 if (operands.size() != resultTypes.size())
338 return returnOp->emitOpError("has ")
339 << operands.size() << " operands, but enclosing function (@"
340 << getName() << ") returns " << resultTypes.size();
341
342 for (auto [i, opType] : llvm::enumerate(llvm::zip(operands, resultTypes))) {
343 auto [operand, resTy] = opType;
344 if (operand.get().getType() != resTy)
345 return returnOp->emitError() << "type of return operand " << i << " ("
346 << operand.get().getType()
347 << ") doesn't match function result type ("
348 << resTy << ") in function @" << getName();
349 }
350 }
351
352 return success();
353}
354
355//===----------------------------------------------------------------------===//
356// TableGen'd op method definitions
357//===----------------------------------------------------------------------===//
358
359#define GET_OP_CLASSES
360#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
This class defines a virtual interface for reading a bytecode stream, providing hooks into the byteco...
virtual LogicalResult readVarInt(uint64_t &result)=0
Read a variable width integer.
virtual FailureOr< const DialectVersion * > getDialectVersion(StringRef dialectName) const =0
Retrieve the dialect version by name if available.
virtual LogicalResult readOptionalAttribute(Attribute &attr)=0
Read an optional reference to the given attribute.
virtual InFlightDiagnostic emitError(const Twine &msg={}) const =0
Emit an error to the reader.
virtual LogicalResult readAttribute(Attribute &result)=0
Read a reference to the given attribute.
This class defines a virtual interface for writing to a bytecode stream, providing hooks into the byt...
virtual void writeOptionalAttribute(Attribute attr)=0
virtual void writeVarInt(uint64_t value)=0
Write a variable width integer to the output stream.
virtual void writeAttribute(Attribute attr)=0
Write a reference to the given attribute.
virtual int64_t getBytecodeVersion() const =0
Return the bytecode version being emitted for.
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.
@ kDialectVersioning
Dialects versioning was added in version 1.
Definition Encoding.h:32
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.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:734
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:311
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:155
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.