//===- VectorUtils.cpp - MLIR Utilities for VectorOps ------------------===// // // Part of the MLIR 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 utility methods for working with the Vector dialect. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/Vector/Utils/VectorUtils.h" #include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h" #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/Dialect/Tensor/IR/Tensor.h" #include "mlir/Dialect/Utils/IndexingUtils.h" #include "mlir/Dialect/Vector/IR/VectorOps.h" #include "mlir/IR/Builders.h" #include "mlir/IR/IntegerSet.h" #include "mlir/IR/Operation.h" #include "mlir/IR/TypeUtilities.h" #include "mlir/Support/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #define DEBUG_TYPE … #define DBGS() … #define LDBG(X) … usingnamespacemlir; /// Helper function that creates a memref::DimOp or tensor::DimOp depending on /// the type of `source`. Value mlir::vector::createOrFoldDimOp(OpBuilder &b, Location loc, Value source, int64_t dim) { … } /// Given the n-D transpose pattern 'transp', return true if 'dim0' and 'dim1' /// should be transposed with each other within the context of their 2D /// transposition slice. /// /// Example 1: dim0 = 0, dim1 = 2, transp = [2, 1, 0] /// Return true: dim0 and dim1 are transposed within the context of their 2D /// transposition slice ([1, 0]). /// /// Example 2: dim0 = 0, dim1 = 1, transp = [2, 1, 0] /// Return true: dim0 and dim1 are transposed within the context of their 2D /// transposition slice ([1, 0]). Paradoxically, note how dim1 (1) is *not* /// transposed within the full context of the transposition. /// /// Example 3: dim0 = 0, dim1 = 1, transp = [2, 0, 1] /// Return false: dim0 and dim1 are *not* transposed within the context of /// their 2D transposition slice ([0, 1]). Paradoxically, note how dim0 (0) /// and dim1 (1) are transposed within the full context of the of the /// transposition. static bool areDimsTransposedIn2DSlice(int64_t dim0, int64_t dim1, ArrayRef<int64_t> transp) { … } FailureOr<std::pair<int, int>> mlir::vector::isTranspose2DSlice(vector::TransposeOp op) { … } /// Constructs a permutation map from memref indices to vector dimension. /// /// The implementation uses the knowledge of the mapping of enclosing loop to /// vector dimension. `enclosingLoopToVectorDim` carries this information as a /// map with: /// - keys representing "vectorized enclosing loops"; /// - values representing the corresponding vector dimension. /// The algorithm traverses "vectorized enclosing loops" and extracts the /// at-most-one MemRef index that is invariant along said loop. This index is /// guaranteed to be at most one by construction: otherwise the MemRef is not /// vectorizable. /// If this invariant index is found, it is added to the permutation_map at the /// proper vector dimension. /// If no index is found to be invariant, 0 is added to the permutation_map and /// corresponds to a vector broadcast along that dimension. /// /// Returns an empty AffineMap if `enclosingLoopToVectorDim` is empty, /// signalling that no permutation map can be constructed given /// `enclosingLoopToVectorDim`. /// /// Examples can be found in the documentation of `makePermutationMap`, in the /// header file. static AffineMap makePermutationMap( ArrayRef<Value> indices, const DenseMap<Operation *, unsigned> &enclosingLoopToVectorDim) { … } /// Implementation detail that walks up the parents and records the ones with /// the specified type. /// TODO: could also be implemented as a collect parents followed by a /// filter and made available outside this file. template <typename T> static SetVector<Operation *> getParentsOfType(Block *block) { … } /// Returns the enclosing AffineForOp, from closest to farthest. static SetVector<Operation *> getEnclosingforOps(Block *block) { … } AffineMap mlir::makePermutationMap( Block *insertPoint, ArrayRef<Value> indices, const DenseMap<Operation *, unsigned> &loopToVectorDim) { … } AffineMap mlir::makePermutationMap( Operation *op, ArrayRef<Value> indices, const DenseMap<Operation *, unsigned> &loopToVectorDim) { … } bool matcher::operatesOnSuperVectorsOf(Operation &op, VectorType subVectorType) { … } bool vector::isContiguousSlice(MemRefType memrefType, VectorType vectorType) { … } std::optional<StaticTileOffsetRange> vector::createUnrollIterator(VectorType vType, int64_t targetRank) { … } SmallVector<OpFoldResult> vector::getMixedSizesXfer(bool hasTensorSemantics, Operation *xfer, RewriterBase &rewriter) { … } bool vector::isLinearizableVector(VectorType type) { … } Value vector::createReadOrMaskedRead(OpBuilder &builder, Location loc, Value source, ArrayRef<int64_t> readShape, Value padValue, bool useInBoundsInsteadOfMasking) { … } LogicalResult vector::isValidMaskedInputVector(ArrayRef<int64_t> shape, ArrayRef<int64_t> inputVectorSizes) { … }