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