//===- VectorTransferPermutationMapRewritePatterns.cpp - Xfer map rewrite -===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements rewrite patterns for the permutation_map attribute of // vector.transfer operations. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/Dialect/Tensor/IR/Tensor.h" #include "mlir/Dialect/Vector/Transforms/LoweringPatterns.h" #include "mlir/Interfaces/VectorInterfaces.h" usingnamespacemlir; usingnamespacemlir::vector; /// Transpose a vector transfer op's `in_bounds` attribute by applying reverse /// permutation based on the given indices. static ArrayAttr inverseTransposeInBoundsAttr(OpBuilder &builder, ArrayAttr attr, const SmallVector<unsigned> &permutation) { … } /// Extend the rank of a vector Value by `addedRanks` by adding outer unit /// dimensions. static Value extendVectorRank(OpBuilder &builder, Location loc, Value vec, int64_t addedRank) { … } /// Extend the rank of a vector Value by `addedRanks` by adding inner unit /// dimensions. static Value extendMaskRank(OpBuilder &builder, Location loc, Value vec, int64_t addedRank) { … } //===----------------------------------------------------------------------===// // populateVectorTransferPermutationMapLoweringPatterns //===----------------------------------------------------------------------===// namespace { /// Lower transfer_read op with permutation into a transfer_read with a /// permutation map composed of leading zeros followed by a minor identiy + /// vector.transpose op. /// Ex: /// vector.transfer_read ... /// permutation_map: (d0, d1, d2) -> (0, d1) /// into: /// %v = vector.transfer_read ... /// permutation_map: (d0, d1, d2) -> (d1, 0) /// vector.transpose %v, [1, 0] /// /// vector.transfer_read ... /// permutation_map: (d0, d1, d2, d3) -> (0, 0, 0, d1, d3) /// into: /// %v = vector.transfer_read ... /// permutation_map: (d0, d1, d2, d3) -> (0, 0, d1, 0, d3) /// vector.transpose %v, [0, 1, 3, 2, 4] /// Note that an alternative is to transform it to linalg.transpose + /// vector.transfer_read to do the transpose in memory instead. struct TransferReadPermutationLowering : public MaskableOpRewritePattern<vector::TransferReadOp> { … }; /// Lower transfer_write op with permutation into a transfer_write with a /// minor identity permutation map. (transfer_write ops cannot have broadcasts.) /// Ex: /// vector.transfer_write %v ... /// permutation_map: (d0, d1, d2) -> (d2, d0, d1) /// into: /// %tmp = vector.transpose %v, [2, 0, 1] /// vector.transfer_write %tmp ... /// permutation_map: (d0, d1, d2) -> (d0, d1, d2) /// /// vector.transfer_write %v ... /// permutation_map: (d0, d1, d2, d3) -> (d3, d2) /// into: /// %tmp = vector.transpose %v, [1, 0] /// %v = vector.transfer_write %tmp ... /// permutation_map: (d0, d1, d2, d3) -> (d2, d3) struct TransferWritePermutationLowering : public MaskableOpRewritePattern<vector::TransferWriteOp> { … }; /// Convert a transfer.write op with a map which isn't the permutation of a /// minor identity into a vector.broadcast + transfer_write with permutation of /// minor identity map by adding unit dim on inner dimension. Ex: /// ``` /// vector.transfer_write %v /// {permutation_map = affine_map<(d0, d1, d2, d3) -> (d1, d2)>} : /// vector<8x16xf32> /// ``` /// into: /// ``` /// %v1 = vector.broadcast %v : vector<8x16xf32> to vector<1x8x16xf32> /// vector.transfer_write %v1 /// {permutation_map = affine_map<(d0, d1, d2, d3) -> (d3, d1, d2)>} : /// vector<1x8x16xf32> /// ``` struct TransferWriteNonPermutationLowering : public MaskableOpRewritePattern<vector::TransferWriteOp> { … }; /// Lower transfer_read op with broadcast in the leading dimensions into /// transfer_read of lower rank + vector.broadcast. /// Ex: vector.transfer_read ... /// permutation_map: (d0, d1, d2, d3) -> (0, d1, 0, d3) /// into: /// %v = vector.transfer_read ... /// permutation_map: (d0, d1, d2, d3) -> (d1, 0, d3) /// vector.broadcast %v struct TransferOpReduceRank : public MaskableOpRewritePattern<vector::TransferReadOp> { … }; } // namespace void mlir::vector::populateVectorTransferPermutationMapLoweringPatterns( RewritePatternSet &patterns, PatternBenefit benefit) { … } //===----------------------------------------------------------------------===// // populateVectorTransferLoweringPatterns //===----------------------------------------------------------------------===// namespace { /// Progressive lowering of transfer_read. This pattern supports lowering of /// `vector.transfer_read` to a combination of `vector.load` and /// `vector.broadcast` if all of the following hold: /// - Stride of most minor memref dimension must be 1. /// - Out-of-bounds masking is not required. /// - If the memref's element type is a vector type then it coincides with the /// result type. /// - The permutation map doesn't perform permutation (broadcasting is allowed). struct TransferReadToVectorLoadLowering : public MaskableOpRewritePattern<vector::TransferReadOp> { … }; /// Replace a 0-d vector.load with a memref.load + vector.broadcast. // TODO: we shouldn't cross the vector/scalar domains just for this // but atm we lack the infra to avoid it. Possible solutions include: // - go directly to LLVM + bitcast // - introduce a bitcast op and likely a new pointer dialect // - let memref.load/store additionally support the 0-d vector case // There are still deeper data layout issues lingering even in this // trivial case (for architectures for which this matters). struct VectorLoadToMemrefLoadLowering : public OpRewritePattern<vector::LoadOp> { … }; /// Replace a 0-d vector.store with a vector.extractelement + memref.store. struct VectorStoreToMemrefStoreLowering : public OpRewritePattern<vector::StoreOp> { … }; /// Progressive lowering of transfer_write. This pattern supports lowering of /// `vector.transfer_write` to `vector.store` if all of the following hold: /// - Stride of most minor memref dimension must be 1. /// - Out-of-bounds masking is not required. /// - If the memref's element type is a vector type then it coincides with the /// type of the written value. /// - The permutation map is the minor identity map (neither permutation nor /// broadcasting is allowed). struct TransferWriteToVectorStoreLowering : public MaskableOpRewritePattern<vector::TransferWriteOp> { … }; } // namespace void mlir::vector::populateVectorTransferLoweringPatterns( RewritePatternSet &patterns, std::optional<unsigned> maxTransferRank, PatternBenefit benefit) { … }