MLIR 24.0.0git
FusePadOpWithLinalgProducer.cpp
Go to the documentation of this file.
1//===- FusePadOpWithLinalgProducer.cpp ---- Fuse pad with linalg producer -===//
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 file implements patterns that fuses a linalg.generic -> tensor.pad op
10// chain into a tensor.extract_slice -> linalg.generic -> tensor.insert_slice
11// op chain.
12//
13//===----------------------------------------------------------------------===//
14
16
18
19using namespace mlir;
20
21namespace {
22/// A sequence of operations
23///
24/// ```mlir
25/// %0 = linalg. ...
26/// %1 = tensor.pad %0 ...
27/// ```
28///
29/// can be replaced with
30///
31/// ```mlir
32/// %0 = linalg.fill
33/// %1 = tensor.extract_slice %0 ...
34/// %2 = linalg. .... outs(..., %1, ....) ....
35/// %3 = tensor.insert_slice %2 into %1 ...
36/// ```
37///
38/// if the `linalg.generic` has all parallel iterator types.
39struct FusePadOp : OpRewritePattern<tensor::PadOp> {
40 using OpRewritePattern<tensor::PadOp>::OpRewritePattern;
41
42 LogicalResult matchAndRewrite(tensor::PadOp padOp,
43 PatternRewriter &rewriter) const override {
44 // Only works on padding op that sets the padded value to a constant.
45 Value padValue = padOp.getConstantPaddingValue();
46 if (!padValue)
47 return rewriter.notifyMatchFailure(padOp, "non constant padding");
48
49 // This pattern could work for any Linalg op. For now restrict it to generic
50 // ops.
51 Value source = padOp.getSource();
52 auto linalgOp = source.getDefiningOp<linalg::GenericOp>();
53 if (!linalgOp) {
54 return rewriter.notifyMatchFailure(
55 padOp, "expected source to be linalg.generic op");
56 }
57 // All iterator types need to be parallel.
58 if (linalgOp.getNumLoops() != linalgOp.getNumParallelLoops()) {
59 return rewriter.notifyMatchFailure(
60 padOp, "only supported for ops with all parallel iterator types");
61 }
63 if (failed(reifyResultShapes(rewriter, padOp, resultShape)) ||
64 resultShape.size() != 1) {
65 return rewriter.notifyMatchFailure(
66 padOp, "failed to get shape of pad op result");
67 }
68
69 Location loc = padOp.getLoc();
70
71 // Create the tensor of same size as output of the pad op.
72 RankedTensorType padResultType = padOp.getResultType();
73 auto resultSizes = resultShape[0];
74 auto emptyTensor = tensor::EmptyOp::create(rewriter, loc, resultSizes,
75 padResultType.getElementType());
76
77 // Fill the tensor with the pad value.
78 // TODO: There is an option to fill only the boundaries. For now just
79 // filling the whole tensor.
80 // Move the padding value defined inside the PadOp block to outside.
81 if (padValue.getParentBlock() == &padOp.getRegion().front())
82 rewriter.moveOpBefore(padValue.getDefiningOp(), padOp);
83 auto fillTensor = linalg::FillOp::create(rewriter, loc, padValue,
84 emptyTensor.getResult());
85
86 // Construct a slice of the fill result that is to be replaced with the
87 // result of the generic op. The low pad values are the offsets, the size of
88 // the source is the size of the slice.
89 // TODO: This insert/extract could be potentially made a utility method.
90 unsigned resultNumber = cast<OpResult>(source).getResultNumber();
91 SmallVector<OpFoldResult> offsets = padOp.getMixedLowPad();
92 SmallVector<OpFoldResult> sizes;
93 sizes.reserve(offsets.size());
94 for (const auto &shape :
95 llvm::enumerate(cast<RankedTensorType>(source.getType()).getShape())) {
96 if (ShapedType::isDynamic(shape.value())) {
97 sizes.push_back(
98 tensor::DimOp::create(rewriter, loc, source, shape.index())
99 .getResult());
100 } else {
101 sizes.push_back(rewriter.getIndexAttr(shape.value()));
102 }
103 }
104 SmallVector<OpFoldResult> strides(offsets.size(), rewriter.getIndexAttr(1));
105 auto slice = tensor::ExtractSliceOp::create(
106 rewriter, loc, fillTensor.getResult(0), offsets, sizes, strides);
107
108 // Clone the generic op.
109 auto clonedOp =
110 cast<linalg::GenericOp>(rewriter.clone(*linalgOp.getOperation()));
111 clonedOp.setDpsInitOperand(resultNumber, slice.getResult());
112
113 // Insert it back into the result of the fill.
114 rewriter.replaceOpWithNewOp<tensor::InsertSliceOp>(
115 padOp, clonedOp.getResult(resultNumber), fillTensor.getResult(0),
116 offsets, sizes, strides);
117 return success();
118 }
119};
120} // namespace
121
123 RewritePatternSet &patterns) {
124 patterns.add<FusePadOp>(patterns.getContext());
125}
return success()
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
Operation & front()
Definition Block.h:178
IntegerAttr getIndexAttr(int64_t value)
Definition Builders.cpp:116
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Definition Builders.cpp:581
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
void moveOpBefore(Operation *op, Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Type getType() const
Return the type of this value.
Definition Value.h:105
Block * getParentBlock()
Return the Block in which this Value is defined.
Definition Value.cpp:46
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
void populateFuseTensorPadWithProducerLinalgOpPatterns(RewritePatternSet &patterns)
Pattern to fuse a tensor.pad operation with the producer of its source, if the producer is a linalg o...
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:744
Include the generated interface declarations.
LogicalResult reifyResultShapes(OpBuilder &b, Operation *op, ReifiedRankedShapedTypeDims &reifiedReturnShapes)
Reify the shape of the result of an operation (typically in terms of the shape of its operands).
SmallVector< SmallVector< OpFoldResult > > ReifiedRankedShapedTypeDims
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...