diff options
| author | Matthias Springer <springerm@google.com> | 2022-01-31 19:10:51 +0900 |
|---|---|---|
| committer | Matthias Springer <springerm@google.com> | 2022-01-31 19:17:09 +0900 |
| commit | 99ef9eebad51fbb5f73ffe747a529ea189f336b7 (patch) | |
| tree | 3ddabecd9ff5da3f86b3f50cb17f5a1e755237d1 /mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp | |
| parent | b8290ffa9fd935b8a0e99634fccfae9ed87ad9b5 (diff) | |
[mlir][vector][NFC] Split into IR, Transforms and Utils
This reduces the dependencies of the MLIRVector target and makes the dialect consistent with other dialects.
Differential Revision: https://reviews.llvm.org/D118533
Diffstat (limited to 'mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp')
| -rw-r--r-- | mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp b/mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp new file mode 100644 index 000000000000..469ee756cc5e --- /dev/null +++ b/mlir/lib/Dialect/Vector/Transforms/VectorInsertExtractStridedSliceRewritePatterns.cpp @@ -0,0 +1,266 @@ +//===- VectorInsertExtractStridedSliceRewritePatterns.cpp - Rewrites ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/StandardOps/IR/Ops.h" +#include "mlir/Dialect/Utils/IndexingUtils.h" +#include "mlir/Dialect/Vector/IR/VectorOps.h" +#include "mlir/Dialect/Vector/Transforms/VectorRewritePatterns.h" +#include "mlir/Dialect/Vector/Utils/VectorUtils.h" +#include "mlir/IR/BuiltinTypes.h" + +using namespace mlir; +using namespace mlir::vector; + +// Helper that picks the proper sequence for inserting. +static Value insertOne(PatternRewriter &rewriter, Location loc, Value from, + Value into, int64_t offset) { + auto vectorType = into.getType().cast<VectorType>(); + if (vectorType.getRank() > 1) + return rewriter.create<InsertOp>(loc, from, into, offset); + return rewriter.create<vector::InsertElementOp>( + loc, vectorType, from, into, + rewriter.create<arith::ConstantIndexOp>(loc, offset)); +} + +// Helper that picks the proper sequence for extracting. +static Value extractOne(PatternRewriter &rewriter, Location loc, Value vector, + int64_t offset) { + auto vectorType = vector.getType().cast<VectorType>(); + if (vectorType.getRank() > 1) + return rewriter.create<ExtractOp>(loc, vector, offset); + return rewriter.create<vector::ExtractElementOp>( + loc, vectorType.getElementType(), vector, + rewriter.create<arith::ConstantIndexOp>(loc, offset)); +} + +/// RewritePattern for InsertStridedSliceOp where source and destination vectors +/// have different ranks. +/// +/// When ranks are different, InsertStridedSlice needs to extract a properly +/// ranked vector from the destination vector into which to insert. This pattern +/// only takes care of this extraction part and forwards the rest to +/// [VectorInsertStridedSliceOpSameRankRewritePattern]. +/// +/// For a k-D source and n-D destination vector (k < n), we emit: +/// 1. ExtractOp to extract the (unique) (n-1)-D subvector into which to +/// insert the k-D source. +/// 2. k-D -> (n-1)-D InsertStridedSlice op +/// 3. InsertOp that is the reverse of 1. +class VectorInsertStridedSliceOpDifferentRankRewritePattern + : public OpRewritePattern<InsertStridedSliceOp> { +public: + using OpRewritePattern<InsertStridedSliceOp>::OpRewritePattern; + + LogicalResult matchAndRewrite(InsertStridedSliceOp op, + PatternRewriter &rewriter) const override { + auto srcType = op.getSourceVectorType(); + auto dstType = op.getDestVectorType(); + + if (op.offsets().getValue().empty()) + return failure(); + + auto loc = op.getLoc(); + int64_t rankDiff = dstType.getRank() - srcType.getRank(); + assert(rankDiff >= 0); + if (rankDiff == 0) + return failure(); + + int64_t rankRest = dstType.getRank() - rankDiff; + // Extract / insert the subvector of matching rank and InsertStridedSlice + // on it. + Value extracted = + rewriter.create<ExtractOp>(loc, op.dest(), + getI64SubArray(op.offsets(), /*dropFront=*/0, + /*dropBack=*/rankRest)); + + // A different pattern will kick in for InsertStridedSlice with matching + // ranks. + auto stridedSliceInnerOp = rewriter.create<InsertStridedSliceOp>( + loc, op.source(), extracted, + getI64SubArray(op.offsets(), /*dropFront=*/rankDiff), + getI64SubArray(op.strides(), /*dropFront=*/0)); + + rewriter.replaceOpWithNewOp<InsertOp>( + op, stridedSliceInnerOp.getResult(), op.dest(), + getI64SubArray(op.offsets(), /*dropFront=*/0, + /*dropBack=*/rankRest)); + return success(); + } +}; + +/// RewritePattern for InsertStridedSliceOp where source and destination vectors +/// have the same rank. For each outermost index in the slice: +/// begin end stride +/// [offset : offset+size*stride : stride] +/// 1. ExtractOp one (k-1)-D source subvector and one (n-1)-D dest subvector. +/// 2. InsertStridedSlice (k-1)-D into (n-1)-D +/// 3. the destination subvector is inserted back in the proper place +/// 3. InsertOp that is the reverse of 1. +class VectorInsertStridedSliceOpSameRankRewritePattern + : public OpRewritePattern<InsertStridedSliceOp> { +public: + using OpRewritePattern<InsertStridedSliceOp>::OpRewritePattern; + + void initialize() { + // This pattern creates recursive InsertStridedSliceOp, but the recursion is + // bounded as the rank is strictly decreasing. + setHasBoundedRewriteRecursion(); + } + + LogicalResult matchAndRewrite(InsertStridedSliceOp op, + PatternRewriter &rewriter) const override { + auto srcType = op.getSourceVectorType(); + auto dstType = op.getDestVectorType(); + + if (op.offsets().getValue().empty()) + return failure(); + + int64_t srcRank = srcType.getRank(); + int64_t dstRank = dstType.getRank(); + assert(dstRank >= srcRank); + if (dstRank != srcRank) + return failure(); + + if (srcType == dstType) { + rewriter.replaceOp(op, op.source()); + return success(); + } + + int64_t offset = + op.offsets().getValue().front().cast<IntegerAttr>().getInt(); + int64_t size = srcType.getShape().front(); + int64_t stride = + op.strides().getValue().front().cast<IntegerAttr>().getInt(); + + auto loc = op.getLoc(); + Value res = op.dest(); + + if (srcRank == 1) { + int nSrc = srcType.getShape().front(); + int nDest = dstType.getShape().front(); + // 1. Scale source to destType so we can shufflevector them together. + SmallVector<int64_t> offsets(nDest, 0); + for (int64_t i = 0; i < nSrc; ++i) + offsets[i] = i; + Value scaledSource = + rewriter.create<ShuffleOp>(loc, op.source(), op.source(), offsets); + + // 2. Create a mask where we take the value from scaledSource of dest + // depending on the offset. + offsets.clear(); + for (int64_t i = 0, e = offset + size * stride; i < nDest; ++i) { + if (i < offset || i >= e || (i - offset) % stride != 0) + offsets.push_back(nDest + i); + else + offsets.push_back((i - offset) / stride); + } + + // 3. Replace with a ShuffleOp. + rewriter.replaceOpWithNewOp<ShuffleOp>(op, scaledSource, op.dest(), + offsets); + + return success(); + } + + // For each slice of the source vector along the most major dimension. + for (int64_t off = offset, e = offset + size * stride, idx = 0; off < e; + off += stride, ++idx) { + // 1. extract the proper subvector (or element) from source + Value extractedSource = extractOne(rewriter, loc, op.source(), idx); + if (extractedSource.getType().isa<VectorType>()) { + // 2. If we have a vector, extract the proper subvector from destination + // Otherwise we are at the element level and no need to recurse. + Value extractedDest = extractOne(rewriter, loc, op.dest(), off); + // 3. Reduce the problem to lowering a new InsertStridedSlice op with + // smaller rank. + extractedSource = rewriter.create<InsertStridedSliceOp>( + loc, extractedSource, extractedDest, + getI64SubArray(op.offsets(), /* dropFront=*/1), + getI64SubArray(op.strides(), /* dropFront=*/1)); + } + // 4. Insert the extractedSource into the res vector. + res = insertOne(rewriter, loc, extractedSource, res, off); + } + + rewriter.replaceOp(op, res); + return success(); + } +}; + +/// Progressive lowering of ExtractStridedSliceOp to either: +/// 1. single offset extract as a direct vector::ShuffleOp. +/// 2. ExtractOp/ExtractElementOp + lower rank ExtractStridedSliceOp + +/// InsertOp/InsertElementOp for the n-D case. +class VectorExtractStridedSliceOpRewritePattern + : public OpRewritePattern<ExtractStridedSliceOp> { +public: + using OpRewritePattern<ExtractStridedSliceOp>::OpRewritePattern; + + void initialize() { + // This pattern creates recursive ExtractStridedSliceOp, but the recursion + // is bounded as the rank is strictly decreasing. + setHasBoundedRewriteRecursion(); + } + + LogicalResult matchAndRewrite(ExtractStridedSliceOp op, + PatternRewriter &rewriter) const override { + auto dstType = op.getType(); + + assert(!op.offsets().getValue().empty() && "Unexpected empty offsets"); + + int64_t offset = + op.offsets().getValue().front().cast<IntegerAttr>().getInt(); + int64_t size = op.sizes().getValue().front().cast<IntegerAttr>().getInt(); + int64_t stride = + op.strides().getValue().front().cast<IntegerAttr>().getInt(); + + auto loc = op.getLoc(); + auto elemType = dstType.getElementType(); + assert(elemType.isSignlessIntOrIndexOrFloat()); + + // Single offset can be more efficiently shuffled. + if (op.offsets().getValue().size() == 1) { + SmallVector<int64_t, 4> offsets; + offsets.reserve(size); + for (int64_t off = offset, e = offset + size * stride; off < e; + off += stride) + offsets.push_back(off); + rewriter.replaceOpWithNewOp<ShuffleOp>(op, dstType, op.vector(), + op.vector(), + rewriter.getI64ArrayAttr(offsets)); + return success(); + } + + // Extract/insert on a lower ranked extract strided slice op. + Value zero = rewriter.create<arith::ConstantOp>( + loc, elemType, rewriter.getZeroAttr(elemType)); + Value res = rewriter.create<SplatOp>(loc, dstType, zero); + for (int64_t off = offset, e = offset + size * stride, idx = 0; off < e; + off += stride, ++idx) { + Value one = extractOne(rewriter, loc, op.vector(), off); + Value extracted = rewriter.create<ExtractStridedSliceOp>( + loc, one, getI64SubArray(op.offsets(), /* dropFront=*/1), + getI64SubArray(op.sizes(), /* dropFront=*/1), + getI64SubArray(op.strides(), /* dropFront=*/1)); + res = insertOne(rewriter, loc, extracted, res, idx); + } + rewriter.replaceOp(op, res); + return success(); + } +}; + +/// Populate the given list with patterns that convert from Vector to LLVM. +void mlir::vector::populateVectorInsertExtractStridedSliceTransforms( + RewritePatternSet &patterns) { + patterns.add<VectorInsertStridedSliceOpDifferentRankRewritePattern, + VectorInsertStridedSliceOpSameRankRewritePattern, + VectorExtractStridedSliceOpRewritePattern>( + patterns.getContext()); +} |
