MLIR  20.0.0git
FuncConversions.cpp
Go to the documentation of this file.
1 //===- FuncConversions.cpp - Function conversions -------------------------===//
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 
12 
13 using namespace mlir;
14 using namespace mlir::func;
15 
16 namespace {
17 /// Converts the operand and result types of the CallOp, used together with the
18 /// FuncOpSignatureConversion.
19 struct CallOpSignatureConversion : public OpConversionPattern<CallOp> {
21 
22  /// Hook for derived classes to implement combined matching and rewriting.
23  LogicalResult
24  matchAndRewrite(CallOp callOp, OpAdaptor adaptor,
25  ConversionPatternRewriter &rewriter) const override {
26  // Convert the original function results.
27  SmallVector<Type, 1> convertedResults;
28  if (failed(typeConverter->convertTypes(callOp.getResultTypes(),
29  convertedResults)))
30  return failure();
31 
32  // If this isn't a one-to-one type mapping, we don't know how to aggregate
33  // the results.
34  if (callOp->getNumResults() != convertedResults.size())
35  return failure();
36 
37  // Substitute with the new result types from the corresponding FuncType
38  // conversion.
39  rewriter.replaceOpWithNewOp<CallOp>(
40  callOp, callOp.getCallee(), convertedResults, adaptor.getOperands());
41  return success();
42  }
43 };
44 } // namespace
45 
47  const TypeConverter &converter) {
48  patterns.add<CallOpSignatureConversion>(converter, patterns.getContext());
49 }
50 
51 namespace {
52 /// Only needed to support partial conversion of functions where this pattern
53 /// ensures that the branch operation arguments matches up with the succesor
54 /// block arguments.
55 class BranchOpInterfaceTypeConversion
56  : public OpInterfaceConversionPattern<BranchOpInterface> {
57 public:
59  BranchOpInterface>::OpInterfaceConversionPattern;
60 
61  BranchOpInterfaceTypeConversion(
62  const TypeConverter &typeConverter, MLIRContext *ctx,
63  function_ref<bool(BranchOpInterface, int)> shouldConvertBranchOperand)
64  : OpInterfaceConversionPattern(typeConverter, ctx, /*benefit=*/1),
65  shouldConvertBranchOperand(shouldConvertBranchOperand) {}
66 
67  LogicalResult
68  matchAndRewrite(BranchOpInterface op, ArrayRef<Value> operands,
69  ConversionPatternRewriter &rewriter) const final {
70  // For a branch operation, only some operands go to the target blocks, so
71  // only rewrite those.
72  SmallVector<Value, 4> newOperands(op->operand_begin(), op->operand_end());
73  for (int succIdx = 0, succEnd = op->getBlock()->getNumSuccessors();
74  succIdx < succEnd; ++succIdx) {
75  OperandRange forwardedOperands =
76  op.getSuccessorOperands(succIdx).getForwardedOperands();
77  if (forwardedOperands.empty())
78  continue;
79 
80  for (int idx = forwardedOperands.getBeginOperandIndex(),
81  eidx = idx + forwardedOperands.size();
82  idx < eidx; ++idx) {
83  if (!shouldConvertBranchOperand || shouldConvertBranchOperand(op, idx))
84  newOperands[idx] = operands[idx];
85  }
86  }
87  rewriter.modifyOpInPlace(
88  op, [newOperands, op]() { op->setOperands(newOperands); });
89  return success();
90  }
91 
92 private:
93  function_ref<bool(BranchOpInterface, int)> shouldConvertBranchOperand;
94 };
95 } // namespace
96 
97 namespace {
98 /// Only needed to support partial conversion of functions where this pattern
99 /// ensures that the branch operation arguments matches up with the succesor
100 /// block arguments.
101 class ReturnOpTypeConversion : public OpConversionPattern<ReturnOp> {
102 public:
104 
105  LogicalResult
106  matchAndRewrite(ReturnOp op, OpAdaptor adaptor,
107  ConversionPatternRewriter &rewriter) const final {
108  // For a return, all operands go to the results of the parent, so
109  // rewrite them all.
110  rewriter.modifyOpInPlace(op,
111  [&] { op->setOperands(adaptor.getOperands()); });
112  return success();
113  }
114 };
115 } // namespace
116 
118  RewritePatternSet &patterns, const TypeConverter &typeConverter,
119  function_ref<bool(BranchOpInterface, int)> shouldConvertBranchOperand) {
120  patterns.add<BranchOpInterfaceTypeConversion>(
121  typeConverter, patterns.getContext(), shouldConvertBranchOperand);
122 }
123 
125  Operation *op, const TypeConverter &converter) {
126  // All successor operands of branch like operations must be rewritten.
127  if (auto branchOp = dyn_cast<BranchOpInterface>(op)) {
128  for (int p = 0, e = op->getBlock()->getNumSuccessors(); p < e; ++p) {
129  auto successorOperands = branchOp.getSuccessorOperands(p);
130  if (!converter.isLegal(
131  successorOperands.getForwardedOperands().getTypes()))
132  return false;
133  }
134  return true;
135  }
136 
137  return false;
138 }
139 
141  RewritePatternSet &patterns, const TypeConverter &typeConverter) {
142  patterns.add<ReturnOpTypeConversion>(typeConverter, patterns.getContext());
143 }
144 
146  Operation *op, const TypeConverter &converter, bool returnOpAlwaysLegal) {
147  // If this is a `return` and the user pass wants to convert/transform across
148  // function boundaries, then `converter` is invoked to check whether the
149  // `return` op is legal.
150  if (isa<ReturnOp>(op) && !returnOpAlwaysLegal)
151  return converter.isLegal(op);
152 
153  // ReturnLike operations have to be legalized with their parent. For
154  // return this is handled, for other ops they remain as is.
155  return op->hasTrait<OpTrait::ReturnLike>();
156 }
157 
159  // If it is not a terminator, ignore it.
161  return true;
162 
163  // If it is not the last operation in the block, also ignore it. We do
164  // this to handle unknown operations, as well.
165  Block *block = op->getBlock();
166  if (!block || &block->back() != op)
167  return true;
168 
169  // We don't want to handle terminators in nested regions, assume they are
170  // always legal.
171  if (!isa_and_nonnull<FuncOp>(op->getParentOp()))
172  return true;
173 
174  return false;
175 }
Block represents an ordered list of Operations.
Definition: Block.h:31
unsigned getNumSuccessors()
Definition: Block.cpp:254
Operation & back()
Definition: Block.h:150
This class implements a pattern rewriter for use with ConversionPatterns.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
OpInterfaceConversionPattern is a wrapper around ConversionPattern that allows for matching and rewri...
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:764
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:42
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:745
operand_iterator operand_begin()
Definition: Operation.h:369
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
Definition: Operation.h:753
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:213
operand_iterator operand_end()
Definition: Operation.h:370
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
Definition: Operation.cpp:237
MLIRContext * getContext() const
Definition: PatternMatch.h:823
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Definition: PatternMatch.h:847
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
Definition: PatternMatch.h:630
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Definition: PatternMatch.h:536
Type conversion class.
bool isLegal(Type type) const
Return true if the given type is legal for this type converter, i.e.
Include the generated interface declarations.
bool isLegalForReturnOpTypeConversionPattern(Operation *op, const TypeConverter &converter, bool returnOpAlwaysLegal=false)
For ReturnLike ops (except return), return True.
bool isNotBranchOpInterfaceOrReturnLikeOp(Operation *op)
Return true if op is neither BranchOpInterface nor ReturnLike.
void populateBranchOpInterfaceTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter, function_ref< bool(BranchOpInterface branchOp, int idx)> shouldConvertBranchOperand=nullptr)
Add a pattern to the given pattern list to rewrite branch operations to use operands that have been l...
void populateCallOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to convert the operand and result types of a CallOp with the ...
void populateReturnOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to rewrite return ops to use operands that have been legalize...
bool isLegalForBranchOpInterfaceTypeConversionPattern(Operation *op, const TypeConverter &converter)
Return true if op is a BranchOpInterface op whose operands are all legal according to converter.
This trait indicates that a terminator operation is "return-like".