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