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