#pragma once #include "mlir/Dialect/Tensor/IR/Tensor.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Value.h" #include "mlir/Transforms/DialectConversion.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include #include #include #include namespace onnx_mlir { template inline auto getImageWidth(const ShapedType& shapedType) { return shapedType.getDimSize(2); } template inline auto getImageHeight(const ShapedType& shapedType) { return shapedType.getDimSize(3); } template inline auto getImageChannel(const ShapedType& shapedType) { return shapedType.getDimSize(1); } template inline auto getImageN(const ShapedType& shapedType) { return shapedType.getDimSize(0); } template inline auto getKernelWidth(const ShapedType& shapedType) { return shapedType.getDimSize(2); } template inline auto getKernelHeight(const ShapedType& shapedType) { return shapedType.getDimSize(3); } template inline auto getFilterCount(const ShapedType& shapedType) { return shapedType.getDimSize(0); } using HSliceId = size_t; using CoreId = size_t; template > constexpr C ceilIntegerDivide(A a, B b) { static_assert(std::is_integral_v, "A must be an integer type"); static_assert(std::is_integral_v, "B must be an integer type"); C ac = static_cast(a); C bc = static_cast(b); return 1 + (ac - 1) / bc; } template > constexpr std::pair ceilIntegerDivideWithRemainder(A a, B b) { static_assert(std::is_integral_v, "A must be an integer type"); static_assert(std::is_integral_v, "B must be an integer type"); C ac = static_cast(a); C bc = static_cast(b); return {ceilIntegerDivide(ac, bc), ac % bc}; } template bool isVectorShape(mlir::ArrayRef shape) { return shape.size() == 2 && (shape[0] == 1 || shape[1] == 1); } template bool isMatrixShape(mlir::ArrayRef shape) { return shape.size() == 2; } template bool isHVectorShape(mlir::ArrayRef shape) { return shape.size() == 2 && shape[0] == 1; } template bool isVVectorShape(mlir::ArrayRef shape) { return shape.size() == 2 && shape[1] == 1; } template T getVectorLength(mlir::ArrayRef shape) { assert(isVectorShape(shape)); return shape[0] != 1 ? shape[0] : shape[1]; } inline auto getTensorShape(mlir::Value tensor) { return mlir::cast(tensor.getType()).getShape(); } inline bool haveSameStaticShape(mlir::Value lhs, mlir::Value rhs) { auto lhsType = mlir::dyn_cast(lhs.getType()); auto rhsType = mlir::dyn_cast(rhs.getType()); return lhsType && rhsType && lhsType.hasStaticShape() && rhsType.hasStaticShape() && lhsType.getShape() == rhsType.getShape(); } /// Slices a statically shaped tensor along one axis into contiguous pieces of /// at most `sliceSize` elements. llvm::SmallVector sliceTensor(const mlir::Value& tensorToSlice, size_t axis, int64_t sliceSize, mlir::ConversionPatternRewriter& rewriter, mlir::Location loc); llvm::SmallVector sliceVector(const mlir::Value& vectorToSlice, int64_t sliceSize, mlir::ConversionPatternRewriter& rewriter, mlir::Location loc); /// Partitions one logical vector into per-core crossbar-sized slices using the /// current PIM target geometry. llvm::DenseMap> sliceVectorPerCrossbarPerCore( const mlir::Value& vectorToSlice, mlir::ConversionPatternRewriter& rewriter, mlir::Location loc); /// Tiles a matrix first across output columns and then across input rows so it /// can be assigned to crossbars grouped by core. llvm::DenseMap>> tileMatrix(mlir::Value& matrixToTile, int64_t hSliceSize, int64_t vSliceSize, mlir::ConversionPatternRewriter& rewriter, mlir::Location& loc); mlir::tensor::SplatOp broadcastToVector(mlir::Value scalarToBroadcast, int64_t length, mlir::ConversionPatternRewriter& rewriter, mlir::Location loc); } // namespace onnx_mlir