/home/arjun/llvm-project/mlir/include/mlir/Transforms/InliningUtils.h
Line | Count | Source (jump to first uncovered line) |
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_INLINING_UTILS_H |
14 | | #define MLIR_TRANSFORMS_INLINING_UTILS_H |
15 | | |
16 | | #include "mlir/IR/DialectInterface.h" |
17 | | #include "mlir/IR/Location.h" |
18 | | #include "mlir/IR/Region.h" |
19 | | |
20 | | namespace mlir { |
21 | | |
22 | | class Block; |
23 | | class BlockAndValueMapping; |
24 | | class CallableOpInterface; |
25 | | class CallOpInterface; |
26 | | class FuncOp; |
27 | | class OpBuilder; |
28 | | class Operation; |
29 | | class Region; |
30 | | class TypeRange; |
31 | | class Value; |
32 | | class ValueRange; |
33 | | |
34 | | //===----------------------------------------------------------------------===// |
35 | | // InlinerInterface |
36 | | //===----------------------------------------------------------------------===// |
37 | | |
38 | | /// This is the interface that must be implemented by the dialects of operations |
39 | | /// to be inlined. This interface should only handle the operations of the |
40 | | /// given dialect. |
41 | | class DialectInlinerInterface |
42 | | : public DialectInterface::Base<DialectInlinerInterface> { |
43 | | public: |
44 | 0 | DialectInlinerInterface(Dialect *dialect) : Base(dialect) {} |
45 | | |
46 | | //===--------------------------------------------------------------------===// |
47 | | // Analysis Hooks |
48 | | //===--------------------------------------------------------------------===// |
49 | | |
50 | | /// Returns true if the given region 'src' can be inlined into the region |
51 | | /// 'dest' that is attached to an operation registered to the current dialect. |
52 | | /// 'valueMapping' contains any remapped values from within the 'src' region. |
53 | | /// This can be used to examine what values will replace entry arguments into |
54 | | /// the 'src' region for example. |
55 | | virtual bool isLegalToInline(Region *dest, Region *src, |
56 | 0 | BlockAndValueMapping &valueMapping) const { |
57 | 0 | return false; |
58 | 0 | } |
59 | | |
60 | | /// Returns true if the given operation 'op', that is registered to this |
61 | | /// dialect, can be inlined into the given region, false otherwise. |
62 | | /// 'valueMapping' contains any remapped values from within the 'src' region. |
63 | | /// This can be used to examine what values may potentially replace the |
64 | | /// operands to 'op'. |
65 | | virtual bool isLegalToInline(Operation *op, Region *dest, |
66 | 0 | BlockAndValueMapping &valueMapping) const { |
67 | 0 | return false; |
68 | 0 | } |
69 | | |
70 | | /// This hook is invoked on an operation that contains regions. It should |
71 | | /// return true if the analyzer should recurse within the regions of this |
72 | | /// operation when computing legality and cost, false otherwise. The default |
73 | | /// implementation returns true. |
74 | 0 | virtual bool shouldAnalyzeRecursively(Operation *op) const { return true; } |
75 | | |
76 | | //===--------------------------------------------------------------------===// |
77 | | // Transformation Hooks |
78 | | //===--------------------------------------------------------------------===// |
79 | | |
80 | | /// Handle the given inlined terminator by replacing it with a new operation |
81 | | /// as necessary. This overload is called when the inlined region has more |
82 | | /// than one block. The 'newDest' block represents the new final branching |
83 | | /// destination of blocks within this region, i.e. operations that release |
84 | | /// control to the parent operation will likely now branch to this block. |
85 | | /// Its block arguments correspond to any values that need to be replaced by |
86 | | /// terminators within the inlined region. |
87 | 0 | virtual void handleTerminator(Operation *op, Block *newDest) const { |
88 | 0 | llvm_unreachable("must implement handleTerminator in the case of multiple " |
89 | 0 | "inlined blocks"); |
90 | 0 | } |
91 | | |
92 | | /// Handle the given inlined terminator by replacing it with a new operation |
93 | | /// as necessary. This overload is called when the inlined region only |
94 | | /// contains one block. 'valuesToReplace' contains the previously returned |
95 | | /// values of the call site before inlining. These values must be replaced by |
96 | | /// this callback if they had any users (for example for traditional function |
97 | | /// calls, these are directly replaced with the operands of the `return` |
98 | | /// operation). The given 'op' will be removed by the caller, after this |
99 | | /// function has been called. |
100 | | virtual void handleTerminator(Operation *op, |
101 | 0 | ArrayRef<Value> valuesToReplace) const { |
102 | 0 | llvm_unreachable( |
103 | 0 | "must implement handleTerminator in the case of one inlined block"); |
104 | 0 | } |
105 | | |
106 | | /// Attempt to materialize a conversion for a type mismatch between a call |
107 | | /// from this dialect, and a callable region. This method should generate an |
108 | | /// operation that takes 'input' as the only operand, and produces a single |
109 | | /// result of 'resultType'. If a conversion can not be generated, nullptr |
110 | | /// should be returned. For example, this hook may be invoked in the following |
111 | | /// scenarios: |
112 | | /// func @foo(i32) -> i32 { ... } |
113 | | /// |
114 | | /// // Mismatched input operand |
115 | | /// ... = foo.call @foo(%input : i16) -> i32 |
116 | | /// |
117 | | /// // Mismatched result type. |
118 | | /// ... = foo.call @foo(%input : i32) -> i16 |
119 | | /// |
120 | | /// NOTE: This hook may be invoked before the 'isLegal' checks above. |
121 | | virtual Operation *materializeCallConversion(OpBuilder &builder, Value input, |
122 | | Type resultType, |
123 | 0 | Location conversionLoc) const { |
124 | 0 | return nullptr; |
125 | 0 | } |
126 | | }; |
127 | | |
128 | | /// This interface provides the hooks into the inlining interface. |
129 | | /// Note: this class automatically collects 'DialectInlinerInterface' objects |
130 | | /// registered to each dialect within the given context. |
131 | | class InlinerInterface |
132 | | : public DialectInterfaceCollection<DialectInlinerInterface> { |
133 | | public: |
134 | | using Base::Base; |
135 | | |
136 | | /// Process a set of blocks that have been inlined. This callback is invoked |
137 | | /// *before* inlined terminator operations have been processed. |
138 | | virtual void |
139 | 0 | processInlinedBlocks(iterator_range<Region::iterator> inlinedBlocks) {} |
140 | | |
141 | | /// These hooks mirror the hooks for the DialectInlinerInterface, with default |
142 | | /// implementations that call the hook on the handler for the dialect 'op' is |
143 | | /// registered to. |
144 | | |
145 | | //===--------------------------------------------------------------------===// |
146 | | // Analysis Hooks |
147 | | //===--------------------------------------------------------------------===// |
148 | | |
149 | | virtual bool isLegalToInline(Region *dest, Region *src, |
150 | | BlockAndValueMapping &valueMapping) const; |
151 | | virtual bool isLegalToInline(Operation *op, Region *dest, |
152 | | BlockAndValueMapping &valueMapping) const; |
153 | | virtual bool shouldAnalyzeRecursively(Operation *op) const; |
154 | | |
155 | | //===--------------------------------------------------------------------===// |
156 | | // Transformation Hooks |
157 | | //===--------------------------------------------------------------------===// |
158 | | |
159 | | virtual void handleTerminator(Operation *op, Block *newDest) const; |
160 | | virtual void handleTerminator(Operation *op, |
161 | | ArrayRef<Value> valuesToRepl) const; |
162 | | }; |
163 | | |
164 | | //===----------------------------------------------------------------------===// |
165 | | // Inline Methods. |
166 | | //===----------------------------------------------------------------------===// |
167 | | |
168 | | /// This function inlines a region, 'src', into another. This function returns |
169 | | /// failure if it is not possible to inline this function. If the function |
170 | | /// returned failure, then no changes to the module have been made. |
171 | | /// |
172 | | /// The provided 'inlinePoint' must be within a region, and corresponds to the |
173 | | /// location where the 'src' region should be inlined. 'mapping' contains any |
174 | | /// remapped operands that are used within the region, and *must* include |
175 | | /// remappings for the entry arguments to the region. 'resultsToReplace' |
176 | | /// corresponds to any results that should be replaced by terminators within the |
177 | | /// inlined region. 'regionResultTypes' specifies the expected return types of |
178 | | /// the terminators in the region. 'inlineLoc' is an optional Location that, if |
179 | | /// provided, will be used to update the inlined operations' location |
180 | | /// information. 'shouldCloneInlinedRegion' corresponds to whether the source |
181 | | /// region should be cloned into the 'inlinePoint' or spliced directly. |
182 | | LogicalResult inlineRegion(InlinerInterface &interface, Region *src, |
183 | | Operation *inlinePoint, BlockAndValueMapping &mapper, |
184 | | ValueRange resultsToReplace, |
185 | | TypeRange regionResultTypes, |
186 | | Optional<Location> inlineLoc = llvm::None, |
187 | | bool shouldCloneInlinedRegion = true); |
188 | | |
189 | | /// This function is an overload of the above 'inlineRegion' that allows for |
190 | | /// providing the set of operands ('inlinedOperands') that should be used |
191 | | /// in-favor of the region arguments when inlining. |
192 | | LogicalResult inlineRegion(InlinerInterface &interface, Region *src, |
193 | | Operation *inlinePoint, |
194 | | ValueRange inlinedOperands, |
195 | | ValueRange resultsToReplace, |
196 | | Optional<Location> inlineLoc = llvm::None, |
197 | | bool shouldCloneInlinedRegion = true); |
198 | | |
199 | | /// This function inlines a given region, 'src', of a callable operation, |
200 | | /// 'callable', into the location defined by the given call operation. This |
201 | | /// function returns failure if inlining is not possible, success otherwise. On |
202 | | /// failure, no changes are made to the module. 'shouldCloneInlinedRegion' |
203 | | /// corresponds to whether the source region should be cloned into the 'call' or |
204 | | /// spliced directly. |
205 | | LogicalResult inlineCall(InlinerInterface &interface, CallOpInterface call, |
206 | | CallableOpInterface callable, Region *src, |
207 | | bool shouldCloneInlinedRegion = true); |
208 | | |
209 | | } // end namespace mlir |
210 | | |
211 | | #endif // MLIR_TRANSFORMS_INLINING_UTILS_H |