MLIR  20.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 
23 namespace mlir {
24 
25 class Block;
26 class IRMapping;
27 class CallableOpInterface;
28 class CallOpInterface;
29 class OpBuilder;
30 class Operation;
31 class Region;
32 class TypeRange;
33 class Value;
34 class 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> {
45 public:
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 
181 /// This interface provides the hooks into the inlining interface.
182 /// Note: this class automatically collects 'DialectInlinerInterface' objects
183 /// registered to each dialect within the given context.
185  : public DialectInterfaceCollection<DialectInlinerInterface> {
186 public:
187  using Base::Base;
188 
189  /// Process a set of blocks that have been inlined. This callback is invoked
190  /// *before* inlined terminator operations have been processed.
191  virtual void
193 
194  /// These hooks mirror the hooks for the DialectInlinerInterface, with default
195  /// implementations that call the hook on the handler for the dialect 'op' is
196  /// registered to.
197 
198  //===--------------------------------------------------------------------===//
199  // Analysis Hooks
200  //===--------------------------------------------------------------------===//
201 
202  virtual bool isLegalToInline(Operation *call, Operation *callable,
203  bool wouldBeCloned) const;
204  virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
205  IRMapping &valueMapping) const;
206  virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
207  IRMapping &valueMapping) const;
208  virtual bool shouldAnalyzeRecursively(Operation *op) const;
209 
210  //===--------------------------------------------------------------------===//
211  // Transformation Hooks
212  //===--------------------------------------------------------------------===//
213 
214  virtual void handleTerminator(Operation *op, Block *newDest) const;
215  virtual void handleTerminator(Operation *op, ValueRange valuesToRepl) const;
216 
217  virtual Value handleArgument(OpBuilder &builder, Operation *call,
218  Operation *callable, Value argument,
219  DictionaryAttr argumentAttrs) const;
220  virtual Value handleResult(OpBuilder &builder, Operation *call,
221  Operation *callable, Value result,
222  DictionaryAttr resultAttrs) const;
223 
224  virtual void processInlinedCallBlocks(
225  Operation *call, iterator_range<Region::iterator> inlinedBlocks) const;
226 };
227 
228 //===----------------------------------------------------------------------===//
229 // Inline Methods.
230 //===----------------------------------------------------------------------===//
231 
232 /// This function inlines a region, 'src', into another. This function returns
233 /// failure if it is not possible to inline this function. If the function
234 /// returned failure, then no changes to the module have been made.
235 ///
236 /// The provided 'inlinePoint' must be within a region, and corresponds to the
237 /// location where the 'src' region should be inlined. 'mapping' contains any
238 /// remapped operands that are used within the region, and *must* include
239 /// remappings for the entry arguments to the region. 'resultsToReplace'
240 /// corresponds to any results that should be replaced by terminators within the
241 /// inlined region. 'regionResultTypes' specifies the expected return types of
242 /// the terminators in the region. 'inlineLoc' is an optional Location that, if
243 /// provided, will be used to update the inlined operations' location
244 /// information. 'shouldCloneInlinedRegion' corresponds to whether the source
245 /// region should be cloned into the 'inlinePoint' or spliced directly.
246 LogicalResult inlineRegion(InlinerInterface &interface, Region *src,
247  Operation *inlinePoint, IRMapping &mapper,
248  ValueRange resultsToReplace,
249  TypeRange regionResultTypes,
250  std::optional<Location> inlineLoc = std::nullopt,
251  bool shouldCloneInlinedRegion = true);
252 LogicalResult inlineRegion(InlinerInterface &interface, Region *src,
253  Block *inlineBlock, Block::iterator inlinePoint,
254  IRMapping &mapper, ValueRange resultsToReplace,
255  TypeRange regionResultTypes,
256  std::optional<Location> inlineLoc = std::nullopt,
257  bool shouldCloneInlinedRegion = true);
258 
259 /// This function is an overload of the above 'inlineRegion' that allows for
260 /// providing the set of operands ('inlinedOperands') that should be used
261 /// in-favor of the region arguments when inlining.
262 LogicalResult inlineRegion(InlinerInterface &interface, Region *src,
263  Operation *inlinePoint, ValueRange inlinedOperands,
264  ValueRange resultsToReplace,
265  std::optional<Location> inlineLoc = std::nullopt,
266  bool shouldCloneInlinedRegion = true);
267 LogicalResult inlineRegion(InlinerInterface &interface, Region *src,
268  Block *inlineBlock, Block::iterator inlinePoint,
269  ValueRange inlinedOperands,
270  ValueRange resultsToReplace,
271  std::optional<Location> inlineLoc = std::nullopt,
272  bool shouldCloneInlinedRegion = true);
273 
274 /// This function inlines a given region, 'src', of a callable operation,
275 /// 'callable', into the location defined by the given call operation. This
276 /// function returns failure if inlining is not possible, success otherwise. On
277 /// failure, no changes are made to the module. 'shouldCloneInlinedRegion'
278 /// corresponds to whether the source region should be cloned into the 'call' or
279 /// spliced directly.
280 LogicalResult inlineCall(InlinerInterface &interface, CallOpInterface call,
281  CallableOpInterface callable, Region *src,
282  bool shouldCloneInlinedRegion = true);
283 
284 } // namespace mlir
285 
286 #endif // MLIR_TRANSFORMS_INLININGUTILS_H
Block represents an ordered list of Operations.
Definition: Block.h:33
OpListType::iterator iterator
Definition: Block.h:140
This is the interface that must be implemented by the dialects of operations to be inlined.
Definition: InliningUtils.h:44
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',...
Definition: InliningUtils.h:59
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.
Definition: InliningUtils.h:93
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...
Definition: InliningUtils.h:72
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)
Definition: InliningUtils.h:46
virtual void processInlinedCallBlocks(Operation *call, iterator_range< Region::iterator > inlinedBlocks) const
Process a set of blocks that have been inlined for a call.
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...
Definition: InliningUtils.h:84
A collection of dialect interfaces within a context, for a given concrete interface type.
DialectInterfaceCollection< DialectInlinerInterface > Base
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
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:66
This class helps build Operations.
Definition: Builders.h:216
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
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:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
The base class used for all derived interface types.
Include the generated interface declarations.
LogicalResult inlineRegion(InlinerInterface &interface, 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.
LogicalResult inlineCall(InlinerInterface &interface, 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...