MLIR 22.0.0git
InliningUtils.h
Go to the documentation of this file.
1//===- InliningUtils.h - Inliner utilities ----------------------*- C++ -*-===//
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// This header file defines interfaces for various inlining utility methods.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_TRANSFORMS_INLININGUTILS_H
14#define MLIR_TRANSFORMS_INLININGUTILS_H
15
18#include "mlir/IR/Location.h"
19#include "mlir/IR/Region.h"
20#include "mlir/IR/ValueRange.h"
21#include <optional>
22
23namespace mlir {
24
25class Block;
26class IRMapping;
27class CallableOpInterface;
28class CallOpInterface;
29class OpBuilder;
30class Operation;
31class Region;
32class TypeRange;
33class Value;
34class ValueRange;
35
36//===----------------------------------------------------------------------===//
37// InlinerInterface
38//===----------------------------------------------------------------------===//
39
40/// This is the interface that must be implemented by the dialects of operations
41/// to be inlined. This interface should only handle the operations of the
42/// given dialect.
44 : public DialectInterface::Base<DialectInlinerInterface> {
45public:
46 DialectInlinerInterface(Dialect *dialect) : Base(dialect) {}
47
48 //===--------------------------------------------------------------------===//
49 // Analysis Hooks
50 //===--------------------------------------------------------------------===//
51
52 /// Returns true if the given operation 'callable', that implements the
53 /// 'CallableOpInterface', can be inlined into the position given call
54 /// operation 'call', that is registered to the current dialect and implements
55 /// the `CallOpInterface`. 'wouldBeCloned' is set to true if the region of the
56 /// given 'callable' is set to be cloned during the inlining process, or false
57 /// if the region is set to be moved in-place(i.e. no duplicates would be
58 /// created).
59 virtual bool isLegalToInline(Operation *call, Operation *callable,
60 bool wouldBeCloned) const {
61 return false;
62 }
63
64 /// Returns true if the given region 'src' can be inlined into the region
65 /// 'dest' that is attached to an operation registered to the current dialect.
66 /// 'wouldBeCloned' is set to true if the given 'src' region is set to be
67 /// cloned during the inlining process, or false if the region is set to be
68 /// moved in-place(i.e. no duplicates would be created). 'valueMapping'
69 /// contains any remapped values from within the 'src' region. This can be
70 /// used to examine what values will replace entry arguments into the 'src'
71 /// region for example.
72 virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
73 IRMapping &valueMapping) const {
74 return false;
75 }
76
77 /// Returns true if the given operation 'op', that is registered to this
78 /// dialect, can be inlined into the given region, false otherwise.
79 /// 'wouldBeCloned' is set to true if the given 'op' is set to be cloned
80 /// during the inlining process, or false if the operation is set to be moved
81 /// in-place(i.e. no duplicates would be created). 'valueMapping' contains any
82 /// remapped values from within the 'src' region. This can be used to examine
83 /// what values may potentially replace the operands to 'op'.
84 virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
85 IRMapping &valueMapping) const {
86 return false;
87 }
88
89 /// This hook is invoked on an operation that contains regions. It should
90 /// return true if the analyzer should recurse within the regions of this
91 /// operation when computing legality and cost, false otherwise. The default
92 /// implementation returns true.
93 virtual bool shouldAnalyzeRecursively(Operation *op) const { return true; }
94
95 //===--------------------------------------------------------------------===//
96 // Transformation Hooks
97 //===--------------------------------------------------------------------===//
98
99 /// Handle the given inlined terminator by replacing it with a new operation
100 /// as necessary. This overload is called when the inlined region has more
101 /// than one block. The 'newDest' block represents the new final branching
102 /// destination of blocks within this region, i.e. operations that release
103 /// control to the parent operation will likely now branch to this block.
104 /// Its block arguments correspond to any values that need to be replaced by
105 /// terminators within the inlined region.
106 virtual void handleTerminator(Operation *op, Block *newDest) const {
107 llvm_unreachable("must implement handleTerminator in the case of multiple "
108 "inlined blocks");
109 }
110
111 /// Handle the given inlined terminator by replacing it with a new operation
112 /// as necessary. This overload is called when the inlined region only
113 /// contains one block. 'valuesToReplace' contains the previously returned
114 /// values of the call site before inlining. These values must be replaced by
115 /// this callback if they had any users (for example for traditional function
116 /// calls, these are directly replaced with the operands of the `return`
117 /// operation). The given 'op' will be removed by the caller, after this
118 /// function has been called.
119 virtual void handleTerminator(Operation *op,
120 ValueRange valuesToReplace) const {
121 llvm_unreachable(
122 "must implement handleTerminator in the case of one inlined block");
123 }
124
125 /// Attempt to materialize a conversion for a type mismatch between a call
126 /// from this dialect, and a callable region. This method should generate an
127 /// operation that takes 'input' as the only operand, and produces a single
128 /// result of 'resultType'. If a conversion can not be generated, nullptr
129 /// should be returned. For example, this hook may be invoked in the following
130 /// scenarios:
131 /// func @foo(i32) -> i32 { ... }
132 ///
133 /// // Mismatched input operand
134 /// ... = foo.call @foo(%input : i16) -> i32
135 ///
136 /// // Mismatched result type.
137 /// ... = foo.call @foo(%input : i32) -> i16
138 ///
139 /// NOTE: This hook may be invoked before the 'isLegal' checks above.
141 Type resultType,
142 Location conversionLoc) const {
143 return nullptr;
144 }
145
146 /// Hook to transform the call arguments before using them to replace the
147 /// callee arguments. Returns a value of the same type or the `argument`
148 /// itself if nothing changed. The `argumentAttrs` dictionary is non-null even
149 /// if no attribute is present. The hook is called after converting the
150 /// callsite argument types using the materializeCallConversion callback, and
151 /// right before inlining the callee region. Any operations created using the
152 /// provided `builder` are inserted right before the inlined callee region. An
153 /// example use case is the insertion of copies for by value arguments.
154 virtual Value handleArgument(OpBuilder &builder, Operation *call,
155 Operation *callable, Value argument,
156 DictionaryAttr argumentAttrs) const {
157 return argument;
158 }
159
160 /// Hook to transform the callee results before using them to replace the call
161 /// results. Returns a value of the same type or the `result` itself if
162 /// nothing changed. The `resultAttrs` dictionary is non-null even if no
163 /// attribute is present. The hook is called right before handling
164 /// terminators, and obtains the callee result before converting its type
165 /// using the `materializeCallConversion` callback. Any operations created
166 /// using the provided `builder` are inserted right after the inlined callee
167 /// region. An example use case is the insertion of copies for by value
168 /// results. NOTE: This hook is invoked after inlining the `callable` region.
169 virtual Value handleResult(OpBuilder &builder, Operation *call,
170 Operation *callable, Value result,
171 DictionaryAttr resultAttrs) const {
172 return result;
173 }
174
175 /// Process a set of blocks that have been inlined for a call. This callback
176 /// is invoked before inlined terminator operations have been processed.
178 Operation *call, iterator_range<Region::iterator> inlinedBlocks) const {}
179
180 /// Returns true if the inliner can assume a fast path of not creating a new
181 /// block, if there is only one block.
183 iterator_range<Region::iterator> inlinedBlocks) const {
184 return true;
185 }
186};
187
188/// This interface provides the hooks into the inlining interface.
189/// Note: this class automatically collects 'DialectInlinerInterface' objects
190/// registered to each dialect within the given context.
192 : public DialectInterfaceCollection<DialectInlinerInterface> {
193public:
194 using CloneCallbackSigTy = void(OpBuilder &builder, Region *src,
195 Block *inlineBlock, Block *postInsertBlock,
196 IRMapping &mapper,
197 bool shouldCloneInlinedRegion);
198 using CloneCallbackTy = std::function<CloneCallbackSigTy>;
199
200 using Base::Base;
201
202 /// Process a set of blocks that have been inlined. This callback is invoked
203 /// *before* inlined terminator operations have been processed.
204 virtual void
206
207 /// These hooks mirror the hooks for the DialectInlinerInterface, with default
208 /// implementations that call the hook on the handler for the dialect 'op' is
209 /// registered to.
210
211 //===--------------------------------------------------------------------===//
212 // Analysis Hooks
213 //===--------------------------------------------------------------------===//
214
215 virtual bool isLegalToInline(Operation *call, Operation *callable,
216 bool wouldBeCloned) const;
217 virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
218 IRMapping &valueMapping) const;
219 virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
220 IRMapping &valueMapping) const;
221 virtual bool shouldAnalyzeRecursively(Operation *op) const;
222
223 //===--------------------------------------------------------------------===//
224 // Transformation Hooks
225 //===--------------------------------------------------------------------===//
226
227 virtual void handleTerminator(Operation *op, Block *newDest) const;
228 virtual void handleTerminator(Operation *op, ValueRange valuesToRepl) const;
229
230 virtual Value handleArgument(OpBuilder &builder, Operation *call,
231 Operation *callable, Value argument,
232 DictionaryAttr argumentAttrs) const;
233 virtual Value handleResult(OpBuilder &builder, Operation *call,
234 Operation *callable, Value result,
235 DictionaryAttr resultAttrs) const;
236
237 virtual void processInlinedCallBlocks(
238 Operation *call, iterator_range<Region::iterator> inlinedBlocks) const;
239
240 virtual bool allowSingleBlockOptimization(
241 iterator_range<Region::iterator> inlinedBlocks) const;
242};
243
244//===----------------------------------------------------------------------===//
245// Inline Methods.
246//===----------------------------------------------------------------------===//
247
248/// This function inlines a region, 'src', into another. This function returns
249/// failure if it is not possible to inline this function. If the function
250/// returned failure, then no changes to the module have been made.
251///
252/// The provided 'inlinePoint' must be within a region, and corresponds to the
253/// location where the 'src' region should be inlined. 'mapping' contains any
254/// remapped operands that are used within the region, and *must* include
255/// remappings for the entry arguments to the region. 'resultsToReplace'
256/// corresponds to any results that should be replaced by terminators within the
257/// inlined region. 'regionResultTypes' specifies the expected return types of
258/// the terminators in the region. 'inlineLoc' is an optional Location that, if
259/// provided, will be used to update the inlined operations' location
260/// information. 'shouldCloneInlinedRegion' corresponds to whether the source
261/// region should be cloned into the 'inlinePoint' or spliced directly.
262LogicalResult
263inlineRegion(InlinerInterface &interface,
265 Region *src, Operation *inlinePoint, IRMapping &mapper,
266 ValueRange resultsToReplace, TypeRange regionResultTypes,
267 std::optional<Location> inlineLoc = std::nullopt,
268 bool shouldCloneInlinedRegion = true);
269LogicalResult
270inlineRegion(InlinerInterface &interface,
272 Region *src, Block *inlineBlock, Block::iterator inlinePoint,
273 IRMapping &mapper, ValueRange resultsToReplace,
274 TypeRange regionResultTypes,
275 std::optional<Location> inlineLoc = std::nullopt,
276 bool shouldCloneInlinedRegion = true);
277
278/// This function is an overload of the above 'inlineRegion' that allows for
279/// providing the set of operands ('inlinedOperands') that should be used
280/// in-favor of the region arguments when inlining.
281LogicalResult
282inlineRegion(InlinerInterface &interface,
284 Region *src, Operation *inlinePoint, ValueRange inlinedOperands,
285 ValueRange resultsToReplace,
286 std::optional<Location> inlineLoc = std::nullopt,
287 bool shouldCloneInlinedRegion = true);
288LogicalResult
289inlineRegion(InlinerInterface &interface,
291 Region *src, Block *inlineBlock, Block::iterator inlinePoint,
292 ValueRange inlinedOperands, ValueRange resultsToReplace,
293 std::optional<Location> inlineLoc = std::nullopt,
294 bool shouldCloneInlinedRegion = true);
295
296/// This function inlines a given region, 'src', of a callable operation,
297/// 'callable', into the location defined by the given call operation. This
298/// function returns failure if inlining is not possible, success otherwise. On
299/// failure, no changes are made to the module. 'shouldCloneInlinedRegion'
300/// corresponds to whether the source region should be cloned into the 'call' or
301/// spliced directly.
302LogicalResult
303inlineCall(InlinerInterface &interface,
305 CallOpInterface call, CallableOpInterface callable, Region *src,
306 bool shouldCloneInlinedRegion = true);
307
308} // namespace mlir
309
310#endif // MLIR_TRANSFORMS_INLININGUTILS_H
Block represents an ordered list of Operations.
Definition Block.h:33
OpListType::iterator iterator
Definition Block.h:140
virtual Value handleResult(OpBuilder &builder, Operation *call, Operation *callable, Value result, DictionaryAttr resultAttrs) const
Hook to transform the callee results before using them to replace the call results.
virtual bool isLegalToInline(Operation *call, Operation *callable, bool wouldBeCloned) const
Returns true if the given operation 'callable', that implements the 'CallableOpInterface',...
virtual Operation * materializeCallConversion(OpBuilder &builder, Value input, Type resultType, Location conversionLoc) const
Attempt to materialize a conversion for a type mismatch between a call from this dialect,...
virtual bool shouldAnalyzeRecursively(Operation *op) const
This hook is invoked on an operation that contains regions.
virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned, IRMapping &valueMapping) const
Returns true if the given region 'src' can be inlined into the region 'dest' that is attached to an o...
virtual Value handleArgument(OpBuilder &builder, Operation *call, Operation *callable, Value argument, DictionaryAttr argumentAttrs) const
Hook to transform the call arguments before using them to replace the callee arguments.
DialectInlinerInterface(Dialect *dialect)
virtual void processInlinedCallBlocks(Operation *call, iterator_range< Region::iterator > inlinedBlocks) const
Process a set of blocks that have been inlined for a call.
virtual bool allowSingleBlockOptimization(iterator_range< Region::iterator > inlinedBlocks) const
Returns true if the inliner can assume a fast path of not creating a new block, if there is only one ...
virtual void handleTerminator(Operation *op, ValueRange valuesToReplace) const
Handle the given inlined terminator by replacing it with a new operation as necessary.
virtual void handleTerminator(Operation *op, Block *newDest) const
Handle the given inlined terminator by replacing it with a new operation as necessary.
virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned, IRMapping &valueMapping) const
Returns true if the given operation 'op', that is registered to this dialect, can be inlined into the...
DialectInterfaceCollection< DialectInlinerInterface > Base
detail::DialectInterfaceBase< ConcreteType, DialectInterface > Base
The base class used for all derived interface types.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
This interface provides the hooks into the inlining interface.
virtual Value handleResult(OpBuilder &builder, Operation *call, Operation *callable, Value result, DictionaryAttr resultAttrs) const
virtual Value handleArgument(OpBuilder &builder, Operation *call, Operation *callable, Value argument, DictionaryAttr argumentAttrs) const
virtual bool shouldAnalyzeRecursively(Operation *op) const
std::function< CloneCallbackSigTy > CloneCallbackTy
void(OpBuilder &builder, Region *src, Block *inlineBlock, Block *postInsertBlock, IRMapping &mapper, bool shouldCloneInlinedRegion) CloneCallbackSigTy
virtual bool allowSingleBlockOptimization(iterator_range< Region::iterator > inlinedBlocks) const
Returns true if the inliner can assume a fast path of not creating a new block, if there is only one ...
virtual void handleTerminator(Operation *op, Block *newDest) const
Handle the given inlined terminator by replacing it with a new operation as necessary.
virtual void processInlinedCallBlocks(Operation *call, iterator_range< Region::iterator > inlinedBlocks) const
virtual void processInlinedBlocks(iterator_range< Region::iterator > inlinedBlocks)
Process a set of blocks that have been inlined.
virtual bool isLegalToInline(Operation *call, Operation *callable, bool wouldBeCloned) const
These hooks mirror the hooks for the DialectInlinerInterface, with default implementations that call ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:207
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
DialectInterfaceBase< ConcreteType, DialectInterface > Base
Include the generated interface declarations.
LogicalResult inlineCall(InlinerInterface &interface, function_ref< InlinerInterface::CloneCallbackSigTy > cloneCallback, CallOpInterface call, CallableOpInterface callable, Region *src, bool shouldCloneInlinedRegion=true)
This function inlines a given region, 'src', of a callable operation, 'callable', into the location d...
LogicalResult inlineRegion(InlinerInterface &interface, function_ref< InlinerInterface::CloneCallbackSigTy > cloneCallback, Region *src, Operation *inlinePoint, IRMapping &mapper, ValueRange resultsToReplace, TypeRange regionResultTypes, std::optional< Location > inlineLoc=std::nullopt, bool shouldCloneInlinedRegion=true)
This function inlines a region, 'src', into another.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152