|
| 1 | +//===- InlinerInterface.h - Inliner interface -------------------*- 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_INTERFACES_INLINERINTERFACE_H |
| 14 | +#define MLIR_INTERFACES_INLINERINTERFACE_H |
| 15 | + |
| 16 | +#include "mlir/IR/BuiltinAttributes.h" |
| 17 | +#include "mlir/IR/DialectInterface.h" |
| 18 | +#include "mlir/IR/Location.h" |
| 19 | +#include "mlir/IR/Region.h" |
| 20 | +#include "mlir/IR/ValueRange.h" |
| 21 | + |
| 22 | +namespace mlir { |
| 23 | + |
| 24 | +class IRMapping; |
| 25 | +class OpBuilder; |
| 26 | + |
| 27 | +//===----------------------------------------------------------------------===// |
| 28 | +// InlinerInterface |
| 29 | +//===----------------------------------------------------------------------===// |
| 30 | + |
| 31 | +/// This is the interface that must be implemented by the dialects of operations |
| 32 | +/// to be inlined. This interface should only handle the operations of the |
| 33 | +/// given dialect. |
| 34 | +class DialectInlinerInterface |
| 35 | + : public DialectInterface::Base<DialectInlinerInterface> { |
| 36 | +public: |
| 37 | + DialectInlinerInterface(Dialect *dialect) : Base(dialect) {} |
| 38 | + |
| 39 | + //===--------------------------------------------------------------------===// |
| 40 | + // Analysis Hooks |
| 41 | + //===--------------------------------------------------------------------===// |
| 42 | + |
| 43 | + /// Returns true if the given operation 'callable', that implements the |
| 44 | + /// 'CallableOpInterface', can be inlined into the position given call |
| 45 | + /// operation 'call', that is registered to the current dialect and implements |
| 46 | + /// the `CallOpInterface`. 'wouldBeCloned' is set to true if the region of the |
| 47 | + /// given 'callable' is set to be cloned during the inlining process, or false |
| 48 | + /// if the region is set to be moved in-place(i.e. no duplicates would be |
| 49 | + /// created). |
| 50 | + virtual bool isLegalToInline(Operation *call, Operation *callable, |
| 51 | + bool wouldBeCloned) const { |
| 52 | + return false; |
| 53 | + } |
| 54 | + |
| 55 | + /// Returns true if the given region 'src' can be inlined into the region |
| 56 | + /// 'dest' that is attached to an operation registered to the current dialect. |
| 57 | + /// 'wouldBeCloned' is set to true if the given 'src' region is set to be |
| 58 | + /// cloned during the inlining process, or false if the region is set to be |
| 59 | + /// moved in-place(i.e. no duplicates would be created). 'valueMapping' |
| 60 | + /// contains any remapped values from within the 'src' region. This can be |
| 61 | + /// used to examine what values will replace entry arguments into the 'src' |
| 62 | + /// region for example. |
| 63 | + virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned, |
| 64 | + IRMapping &valueMapping) const { |
| 65 | + return false; |
| 66 | + } |
| 67 | + |
| 68 | + /// Returns true if the given operation 'op', that is registered to this |
| 69 | + /// dialect, can be inlined into the given region, false otherwise. |
| 70 | + /// 'wouldBeCloned' is set to true if the given 'op' is set to be cloned |
| 71 | + /// during the inlining process, or false if the operation is set to be moved |
| 72 | + /// in-place(i.e. no duplicates would be created). 'valueMapping' contains any |
| 73 | + /// remapped values from within the 'src' region. This can be used to examine |
| 74 | + /// what values may potentially replace the operands to 'op'. |
| 75 | + virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned, |
| 76 | + IRMapping &valueMapping) const { |
| 77 | + return false; |
| 78 | + } |
| 79 | + |
| 80 | + /// This hook is invoked on an operation that contains regions. It should |
| 81 | + /// return true if the analyzer should recurse within the regions of this |
| 82 | + /// operation when computing legality and cost, false otherwise. The default |
| 83 | + /// implementation returns true. |
| 84 | + virtual bool shouldAnalyzeRecursively(Operation *op) const { return true; } |
| 85 | + |
| 86 | + //===--------------------------------------------------------------------===// |
| 87 | + // Transformation Hooks |
| 88 | + //===--------------------------------------------------------------------===// |
| 89 | + |
| 90 | + /// Handle the given inlined terminator by replacing it with a new operation |
| 91 | + /// as necessary. This overload is called when the inlined region has more |
| 92 | + /// than one block. The 'newDest' block represents the new final branching |
| 93 | + /// destination of blocks within this region, i.e. operations that release |
| 94 | + /// control to the parent operation will likely now branch to this block. |
| 95 | + /// Its block arguments correspond to any values that need to be replaced by |
| 96 | + /// terminators within the inlined region. |
| 97 | + virtual void handleTerminator(Operation *op, Block *newDest) const { |
| 98 | + llvm_unreachable("must implement handleTerminator in the case of multiple " |
| 99 | + "inlined blocks"); |
| 100 | + } |
| 101 | + |
| 102 | + /// Handle the given inlined terminator by replacing it with a new operation |
| 103 | + /// as necessary. This overload is called when the inlined region only |
| 104 | + /// contains one block. 'valuesToReplace' contains the previously returned |
| 105 | + /// values of the call site before inlining. These values must be replaced by |
| 106 | + /// this callback if they had any users (for example for traditional function |
| 107 | + /// calls, these are directly replaced with the operands of the `return` |
| 108 | + /// operation). The given 'op' will be removed by the caller, after this |
| 109 | + /// function has been called. |
| 110 | + virtual void handleTerminator(Operation *op, |
| 111 | + ValueRange valuesToReplace) const { |
| 112 | + llvm_unreachable( |
| 113 | + "must implement handleTerminator in the case of one inlined block"); |
| 114 | + } |
| 115 | + |
| 116 | + /// Attempt to materialize a conversion for a type mismatch between a call |
| 117 | + /// from this dialect, and a callable region. This method should generate an |
| 118 | + /// operation that takes 'input' as the only operand, and produces a single |
| 119 | + /// result of 'resultType'. If a conversion can not be generated, nullptr |
| 120 | + /// should be returned. For example, this hook may be invoked in the following |
| 121 | + /// scenarios: |
| 122 | + /// func @foo(i32) -> i32 { ... } |
| 123 | + /// |
| 124 | + /// // Mismatched input operand |
| 125 | + /// ... = foo.call @foo(%input : i16) -> i32 |
| 126 | + /// |
| 127 | + /// // Mismatched result type. |
| 128 | + /// ... = foo.call @foo(%input : i32) -> i16 |
| 129 | + /// |
| 130 | + /// NOTE: This hook may be invoked before the 'isLegal' checks above. |
| 131 | + virtual Operation *materializeCallConversion(OpBuilder &builder, Value input, |
| 132 | + Type resultType, |
| 133 | + Location conversionLoc) const { |
| 134 | + return nullptr; |
| 135 | + } |
| 136 | + |
| 137 | + /// Hook to transform the call arguments before using them to replace the |
| 138 | + /// callee arguments. Returns a value of the same type or the `argument` |
| 139 | + /// itself if nothing changed. The `argumentAttrs` dictionary is non-null even |
| 140 | + /// if no attribute is present. The hook is called after converting the |
| 141 | + /// callsite argument types using the materializeCallConversion callback, and |
| 142 | + /// right before inlining the callee region. Any operations created using the |
| 143 | + /// provided `builder` are inserted right before the inlined callee region. An |
| 144 | + /// example use case is the insertion of copies for by value arguments. |
| 145 | + virtual Value handleArgument(OpBuilder &builder, Operation *call, |
| 146 | + Operation *callable, Value argument, |
| 147 | + DictionaryAttr argumentAttrs) const { |
| 148 | + return argument; |
| 149 | + } |
| 150 | + |
| 151 | + /// Hook to transform the callee results before using them to replace the call |
| 152 | + /// results. Returns a value of the same type or the `result` itself if |
| 153 | + /// nothing changed. The `resultAttrs` dictionary is non-null even if no |
| 154 | + /// attribute is present. The hook is called right before handling |
| 155 | + /// terminators, and obtains the callee result before converting its type |
| 156 | + /// using the `materializeCallConversion` callback. Any operations created |
| 157 | + /// using the provided `builder` are inserted right after the inlined callee |
| 158 | + /// region. An example use case is the insertion of copies for by value |
| 159 | + /// results. NOTE: This hook is invoked after inlining the `callable` region. |
| 160 | + virtual Value handleResult(OpBuilder &builder, Operation *call, |
| 161 | + Operation *callable, Value result, |
| 162 | + DictionaryAttr resultAttrs) const { |
| 163 | + return result; |
| 164 | + } |
| 165 | + |
| 166 | + /// Process a set of blocks that have been inlined for a call. This callback |
| 167 | + /// is invoked before inlined terminator operations have been processed. |
| 168 | + virtual void processInlinedCallBlocks( |
| 169 | + Operation *call, iterator_range<Region::iterator> inlinedBlocks) const {} |
| 170 | +}; |
| 171 | + |
| 172 | +/// This interface provides the hooks into the inlining interface. |
| 173 | +/// Note: this class automatically collects 'DialectInlinerInterface' objects |
| 174 | +/// registered to each dialect within the given context. |
| 175 | +class InlinerInterface |
| 176 | + : public DialectInterfaceCollection<DialectInlinerInterface> { |
| 177 | +public: |
| 178 | + using Base::Base; |
| 179 | + |
| 180 | + /// Process a set of blocks that have been inlined. This callback is invoked |
| 181 | + /// *before* inlined terminator operations have been processed. |
| 182 | + virtual void |
| 183 | + processInlinedBlocks(iterator_range<Region::iterator> inlinedBlocks) {} |
| 184 | + |
| 185 | + /// These hooks mirror the hooks for the DialectInlinerInterface, with default |
| 186 | + /// implementations that call the hook on the handler for the dialect 'op' is |
| 187 | + /// registered to. |
| 188 | + |
| 189 | + //===--------------------------------------------------------------------===// |
| 190 | + // Analysis Hooks |
| 191 | + //===--------------------------------------------------------------------===// |
| 192 | + |
| 193 | + virtual bool isLegalToInline(Operation *call, Operation *callable, |
| 194 | + bool wouldBeCloned) const; |
| 195 | + virtual bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned, |
| 196 | + IRMapping &valueMapping) const; |
| 197 | + virtual bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned, |
| 198 | + IRMapping &valueMapping) const; |
| 199 | + virtual bool shouldAnalyzeRecursively(Operation *op) const; |
| 200 | + |
| 201 | + //===--------------------------------------------------------------------===// |
| 202 | + // Transformation Hooks |
| 203 | + //===--------------------------------------------------------------------===// |
| 204 | + |
| 205 | + virtual void handleTerminator(Operation *op, Block *newDest) const; |
| 206 | + virtual void handleTerminator(Operation *op, ValueRange valuesToRepl) const; |
| 207 | + |
| 208 | + virtual Value handleArgument(OpBuilder &builder, Operation *call, |
| 209 | + Operation *callable, Value argument, |
| 210 | + DictionaryAttr argumentAttrs) const; |
| 211 | + virtual Value handleResult(OpBuilder &builder, Operation *call, |
| 212 | + Operation *callable, Value result, |
| 213 | + DictionaryAttr resultAttrs) const; |
| 214 | + |
| 215 | + virtual void processInlinedCallBlocks( |
| 216 | + Operation *call, iterator_range<Region::iterator> inlinedBlocks) const; |
| 217 | +}; |
| 218 | + |
| 219 | +} // namespace mlir |
| 220 | + |
| 221 | +#endif // MLIR_INTERFACES_INLINERINTERFACE_H |
0 commit comments