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