30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/SmallVectorExtras.h"
32#include "llvm/Support/FormatVariadic.h"
39#define DEBUG_TYPE "vector-to-vector"
49 return builder.
create(state);
81struct MultiReduceToContract
83 MultiReduceToContract(MLIRContext *context,
bool allowFastMathFlagLoss,
84 PatternBenefit benefit = 1)
85 : OpRewritePattern(context, benefit),
86 allowFastMathFlagLoss(allowFastMathFlagLoss) {}
88 LogicalResult matchAndRewrite(vector::MultiDimReductionOp reduceOp,
89 PatternRewriter &rewriter)
const override {
91 if (reduceOp.getKind() != vector::CombiningKind::ADD)
93 Operation *mulOp = reduceOp.getSource().getDefiningOp();
94 if (!mulOp || !isa<arith::MulIOp, arith::MulFOp>(mulOp))
102 arith::FastMathFlags mulFlags = arith::FastMathFlags::none;
103 if (
auto mulFOp = dyn_cast<arith::MulFOp>(mulOp))
104 mulFlags = mulFOp.getFastmath();
105 arith::FastMathFlags reduceFlags = reduceOp.getFastmath();
106 if (!allowFastMathFlagLoss && mulFlags != reduceFlags)
108 reduceOp,
"converting would drop fast-math flags");
109 arith::FastMathFlags fastMathFlags = mulFlags & reduceFlags;
110 SmallVector<bool> reductionMask = reduceOp.getReductionMask();
112 SmallVector<AffineExpr> exprs;
113 SmallVector<vector::IteratorType> iteratorTypes;
114 for (
const auto &isReduceDim : llvm::enumerate(reductionMask)) {
115 if (!isReduceDim.value()) {
116 iteratorTypes.push_back(vector::IteratorType::parallel);
119 iteratorTypes.push_back(vector::IteratorType::reduction);
124 0, exprs, reduceOp.getContext());
130 [&](IteratorType t) -> mlir::Attribute {
131 return IteratorTypeAttr::get(rewriter.getContext(), t);
133 CombiningKind::ADD, fastMathFlags);
138 bool allowFastMathFlagLoss;
164struct CombineContractABTranspose final
168 LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
169 PatternRewriter &rewriter)
const override {
170 SmallVector<AffineMap> maps =
171 llvm::to_vector<4>(contractOp.getIndexingMapsArray());
172 Value
lhs = contractOp.getLhs();
173 Value
rhs = contractOp.getRhs();
175 bool changed =
false;
176 for (Value *operand : {&
lhs, &
rhs}) {
177 AffineMap &map = maps[index++];
178 auto transposeOp = operand->getDefiningOp<vector::TransposeOp>();
182 transposeOp.getPermutation(), contractOp.getContext());
184 *operand = transposeOp.getVector();
190 contractOp,
lhs,
rhs, contractOp.getAcc(),
192 contractOp.getKind(), contractOp.getFastmath());
229struct CombineContractResultTranspose final
233 LogicalResult matchAndRewrite(vector::TransposeOp resTOp,
234 PatternRewriter &rewriter)
const override {
235 auto contractOp = resTOp.getVector().getDefiningOp<vector::ContractionOp>();
236 if (!contractOp || !contractOp->hasOneUse())
239 auto accTOp = contractOp.getAcc().getDefiningOp<vector::TransposeOp>();
243 MLIRContext *context = contractOp.getContext();
244 auto maps = llvm::to_vector<3>(contractOp.getIndexingMapsArray());
245 AffineMap contractMap = maps.back();
256 auto combinedResMap = resTMap.compose(contractMap);
263 maps.back() = combinedResMap;
266 resTOp, contractOp.getLhs(), contractOp.getRhs(), accTOp.getVector(),
268 contractOp.getKind(), contractOp.getFastmath());
300FailureOr<Value> combineContractAndBroadcast(vector::ContractionOp contractOp,
301 MaskingOpInterface maskingOp,
304 llvm::to_vector<4>(contractOp.getIndexingMapsArray());
305 Value lhs = contractOp.getLhs();
306 Value rhs = contractOp.getRhs();
308 bool changed =
false;
309 for (
Value *operand : {&lhs, &rhs}) {
314 auto sc = operand->getDefiningOp<vector::ShapeCastOp>();
315 auto broadcast = operand->getDefiningOp<vector::BroadcastOp>();
319 if (sc && !sc.isBroadcastLike())
321 contractOp,
"Operand defined via vector.shape_cast that has "
322 "non-broadcast semantics");
325 VectorType srcType = sc ? sc.getSourceVectorType()
326 : dyn_cast<VectorType>(
broadcast.getSourceType());
328 sc ? sc.getResultVectorType() :
broadcast.getResultVectorType();
332 if (!srcType || srcType.getRank() >= resType.getRank())
334 int64_t rankDiff = resType.getRank() - srcType.getRank();
335 bool innerDimBroadcast =
false;
337 for (
const auto &dim : llvm::enumerate(srcType.getShape())) {
338 if (dim.value() != resType.getDimSize(rankDiff + dim.index())) {
339 innerDimBroadcast =
true;
346 if (innerDimBroadcast)
351 bool nonUnitDimReductionBroadcast =
false;
352 for (
int64_t i = 0; i < rankDiff; ++i) {
353 if (resType.getDimSize(i) != 1 &&
356 nonUnitDimReductionBroadcast =
true;
360 if (nonUnitDimReductionBroadcast)
364 contractOp.getContext());
365 map = broadcastMap.
compose(map);
381 for (
unsigned i = 0, e = unusedDimsBitVector.size(); i < e; ++i) {
382 if (!unusedDimsBitVector.test(i))
383 iterators.push_back(contractOp.getIteratorTypes().getValue()[i]);
389 VectorType oldMaskType;
390 bool isAnyUnusedDimNonUnit =
false;
392 oldMaskType = cast<VectorType>(maskingOp.getMask().getType());
393 for (
unsigned i = 0, e = unusedDimsBitVector.size(); i < e; ++i) {
394 if (unusedDimsBitVector.test(i) && oldMaskType.getShape()[i] != 1) {
395 isAnyUnusedDimNonUnit =
true;
404 bool hasReductionIteratorApplyingOnBothSides =
false;
405 for (
unsigned i = 0; i < iterators.size(); ++i) {
410 hasReductionIteratorApplyingOnBothSides =
true;
412 if (!hasReductionIteratorApplyingOnBothSides)
420 Operation *newOp = vector::ContractionOp::create(
421 rewriter, contractOp.getLoc(), lhs, rhs, contractOp.getAcc(),
423 contractOp.getKind(), contractOp.getFastmath());
427 if (isAnyUnusedDimNonUnit)
429 "Cannont drop non-unit mask dim.");
430 assert(unusedDimsBitVector.size() ==
431 static_cast<size_t>(oldMaskType.getRank()) &&
432 "The mask rank is incorrect!");
436 Value mask = maskingOp.getMask();
437 if (unusedDimsBitVector.count() != 0) {
445 oldMaskType.getShape().drop_front(unusedDimsBitVector.count());
446 auto newShapeScalableDims =
447 oldMaskType.getScalableDims().drop_front(unusedDimsBitVector.count());
448 VectorType maskOpType =
449 VectorType::get(newShape, rewriter.
getI1Type(), newShapeScalableDims);
450 mask = vector::ShapeCastOp::create(rewriter, contractOp.getLoc(),
451 maskOpType, maskingOp.getMask())
460struct CombineContractBroadcastMask
462 using MaskableOpRewritePattern::MaskableOpRewritePattern;
465 matchAndRewriteMaskableOp(vector::ContractionOp contractOp,
466 MaskingOpInterface maskingOp,
467 PatternRewriter &rewriter)
const override {
468 return combineContractAndBroadcast(contractOp, maskingOp, rewriter);
485struct ReorderCastOpsOnBroadcast
487 using OpInterfaceRewritePattern<CastOpInterface>::OpInterfaceRewritePattern;
489 LogicalResult matchAndRewrite(CastOpInterface op,
490 PatternRewriter &rewriter)
const override {
491 if (op->getNumOperands() != 1)
493 if (!isa<VectorType>(op->getResult(0).getType()))
495 auto bcastOp = op->getOperand(0).getDefiningOp<vector::BroadcastOp>();
500 if (
auto vecTy = dyn_cast<VectorType>(bcastOp.getSourceType()))
501 castResTy = vecTy.clone(castResTy);
505 op, op->getResult(0).
getType(), castOp->getResult(0));
524struct ReorderElementwiseOpsOnTranspose final
527 LogicalResult matchAndRewrite(Operation *op,
528 PatternRewriter &rewriter)
const override {
534 SmallVector<ArrayRef<int64_t>> transposeMaps;
540 auto transposeOp = operand.getDefiningOp<vector::TransposeOp>();
542 transposeMaps.push_back(transposeOp.getPermutation());
543 srcType = transposeOp.getSourceVectorType();
548 if (transposeMaps.empty())
553 if (!llvm::all_equal(transposeMaps))
556 SmallVector<Value> srcValues;
561 auto order = transposeMaps.front();
562 SmallVector<int64_t> invOrder(order.size());
563 for (
int i = 0, e = order.size(); i < e; ++i)
564 invOrder[order[i]] = i;
567 auto transposeOp = operand.getDefiningOp<vector::TransposeOp>();
569 srcValues.push_back(transposeOp.getVector());
573 srcType.clone(cast<VectorType>(operand.getType()).getElementType());
574 srcValues.push_back(vector::TransposeOp::create(
575 rewriter, operand.getLoc(), vectorType, operand, invOrder));
579 auto vectorType = srcType.clone(
581 Operation *elementwiseOp =
585 transposeMaps.front());
592 return llvm::map_to_vector<4>(arrayAttr.getAsRange<IntegerAttr>(),
593 [](IntegerAttr attr) { return attr.getInt(); });
605struct BubbleDownVectorBitCastForExtract
609 LogicalResult matchAndRewrite(vector::ExtractOp extractOp,
610 PatternRewriter &rewriter)
const override {
612 if (extractOp.getSourceVectorType().getRank() != 1)
615 auto castOp = extractOp.getSource().getDefiningOp<vector::BitCastOp>();
619 VectorType castSrcType = castOp.getSourceVectorType();
620 VectorType castDstType = castOp.getResultVectorType();
621 assert(castSrcType.getRank() == castDstType.getRank());
626 if (castSrcType.getNumElements() == 1)
631 if (castSrcType.getNumElements() > castDstType.getNumElements())
634 unsigned expandRatio =
635 castDstType.getNumElements() / castSrcType.getNumElements();
638 auto mixedPos = extractOp.getMixedPosition();
639 if (!mixedPos.empty() && !isa<Attribute>(mixedPos[0]))
641 uint64_t index = cast<IntegerAttr>(cast<Attribute>(mixedPos[0])).getInt();
645 Location loc = extractOp.getLoc();
646 Value packedValue = vector::ExtractOp::create(
647 rewriter, loc, castOp.getSource(), index / expandRatio);
648 Type packedVecType = VectorType::get({1}, packedValue.
getType());
649 Value zero = arith::ConstantOp::create(rewriter, loc, packedVecType,
651 packedValue = vector::InsertOp::create(rewriter, loc, packedValue, zero,
656 VectorType packedType =
657 VectorType::get({expandRatio}, castDstType.getElementType());
659 vector::BitCastOp::create(rewriter, loc, packedType, packedValue);
663 index % expandRatio);
680struct BubbleDownBitCastForStridedSliceExtract
684 LogicalResult matchAndRewrite(vector::ExtractStridedSliceOp extractOp,
685 PatternRewriter &rewriter)
const override {
686 auto castOp = extractOp.getSource().getDefiningOp<vector::BitCastOp>();
690 VectorType castSrcType = castOp.getSourceVectorType();
691 VectorType castDstType = castOp.getResultVectorType();
692 assert(castSrcType.getRank() == castDstType.getRank());
694 int64_t castSrcLastDim = castSrcType.getShape().back();
695 int64_t castDstLastDim = castDstType.getShape().back();
697 if (castSrcLastDim > castDstLastDim)
701 if (llvm::any_of(extractOp.getStrides().getAsValueRange<IntegerAttr>(),
702 [](
const APInt &val) { return !val.isOne(); }))
705 unsigned rank = extractOp.getSourceVectorType().getRank();
706 assert(castDstLastDim % castSrcLastDim == 0);
707 int64_t expandRatio = castDstLastDim / castSrcLastDim;
713 ArrayAttr newOffsets = extractOp.getOffsets();
714 if (newOffsets.size() == rank) {
715 SmallVector<int64_t> offsets = getIntValueVector(newOffsets);
716 if (offsets.back() % expandRatio != 0)
718 offsets.back() = offsets.back() / expandRatio;
723 ArrayAttr newSizes = extractOp.getSizes();
724 if (newSizes.size() == rank) {
725 SmallVector<int64_t> sizes = getIntValueVector(newSizes);
726 if (sizes.back() % expandRatio != 0)
728 sizes.back() = sizes.back() / expandRatio;
732 SmallVector<int64_t> dims =
733 llvm::to_vector<4>(cast<VectorType>(extractOp.getType()).getShape());
734 dims.back() = dims.back() / expandRatio;
735 VectorType newExtractType =
736 VectorType::get(dims, castSrcType.getElementType());
738 auto newExtractOp = vector::ExtractStridedSliceOp::create(
739 rewriter, extractOp.getLoc(), newExtractType, castOp.getSource(),
740 newOffsets, newSizes, extractOp.getStrides());
743 extractOp, extractOp.getType(), newExtractOp);
759struct BubbleUpBitCastForInsert :
public OpRewritePattern<vector::BitCastOp> {
762 LogicalResult matchAndRewrite(vector::BitCastOp bitcastOp,
763 PatternRewriter &rewriter)
const override {
764 VectorType castSrcType = bitcastOp.getSourceVectorType();
765 VectorType castDstType = bitcastOp.getResultVectorType();
768 if (castSrcType.getRank() == 0 || castSrcType.isScalable() ||
769 castDstType.isScalable())
772 int64_t castSrcLastDim = castSrcType.getShape().back();
773 int64_t castDstLastDim = castDstType.getShape().back();
774 bool isNumElemsShrink = castSrcLastDim >= castDstLastDim;
776 if (isNumElemsShrink) {
777 assert(castSrcLastDim % castDstLastDim == 0);
778 ratio = castSrcLastDim / castDstLastDim;
780 assert(castDstLastDim % castSrcLastDim == 0);
781 ratio = castDstLastDim / castSrcLastDim;
784 auto insertOp = bitcastOp.getSource().getDefiningOp<vector::InsertOp>();
789 auto insertSrcType = dyn_cast<VectorType>(insertOp.getValueToStoreType());
794 SmallVector<int64_t> srcDims(insertSrcType.getShape());
796 isNumElemsShrink ? srcDims.back() / ratio : srcDims.back() * ratio;
797 VectorType newCastSrcType =
798 VectorType::get(srcDims, castDstType.getElementType());
800 vector::BitCastOp::create(rewriter, bitcastOp.getLoc(), newCastSrcType,
801 insertOp.getValueToStore());
803 SmallVector<int64_t> dstDims(insertOp.getDestVectorType().getShape());
805 isNumElemsShrink ? dstDims.back() / ratio : dstDims.back() * ratio;
806 VectorType newCastDstType =
807 VectorType::get(dstDims, castDstType.getElementType());
810 auto newCastDstOp = vector::BitCastOp::create(
811 rewriter, bitcastOp.getLoc(), newCastDstType, insertOp.getDest());
815 bitcastOp, newCastSrcOp, newCastDstOp, insertOp.getMixedPosition());
831struct BubbleUpBitCastForStridedSliceInsert
835 LogicalResult matchAndRewrite(vector::BitCastOp bitcastOp,
836 PatternRewriter &rewriter)
const override {
837 VectorType castSrcType = bitcastOp.getSourceVectorType();
838 VectorType castDstType = bitcastOp.getResultVectorType();
839 assert(castSrcType.getRank() == castDstType.getRank());
841 if (castSrcType.getRank() == 0)
844 int64_t castSrcLastDim = castSrcType.getShape().back();
845 int64_t castDstLastDim = castDstType.getShape().back();
847 if (castSrcLastDim < castDstLastDim)
850 assert(castSrcLastDim % castDstLastDim == 0);
851 int64_t shrinkRatio = castSrcLastDim / castDstLastDim;
854 bitcastOp.getSource().getDefiningOp<vector::InsertStridedSliceOp>();
859 if (llvm::any_of(insertOp.getStrides().getAsValueRange<IntegerAttr>(),
860 [](
const APInt &val) { return !val.isOne(); }))
863 unsigned rank = insertOp.getSourceVectorType().getRank();
866 if (rank != insertOp.getDestVectorType().getRank())
870 unsigned sourceWidth = castSrcType.getElementType().getIntOrFloatBitWidth();
871 unsigned destinationWidth =
872 castDstType.getElementType().getIntOrFloatBitWidth();
873 unsigned numElements = destinationWidth / sourceWidth;
874 if (insertOp.getSourceVectorType().getNumElements() % numElements != 0)
877 ArrayAttr newOffsets = insertOp.getOffsets();
878 assert(newOffsets.size() == rank);
879 SmallVector<int64_t> offsets = getIntValueVector(newOffsets);
880 if (offsets.back() % shrinkRatio != 0)
882 offsets.back() = offsets.back() / shrinkRatio;
885 SmallVector<int64_t> srcDims =
886 llvm::to_vector<4>(insertOp.getSourceVectorType().getShape());
887 srcDims.back() = srcDims.back() / shrinkRatio;
888 VectorType newCastSrcType =
889 VectorType::get(srcDims, castDstType.getElementType());
892 vector::BitCastOp::create(rewriter, bitcastOp.getLoc(), newCastSrcType,
893 insertOp.getValueToStore());
895 SmallVector<int64_t> dstDims =
896 llvm::to_vector<4>(insertOp.getDestVectorType().getShape());
897 dstDims.back() = dstDims.back() / shrinkRatio;
898 VectorType newCastDstType =
899 VectorType::get(dstDims, castDstType.getElementType());
901 auto newCastDstOp = vector::BitCastOp::create(
902 rewriter, bitcastOp.getLoc(), newCastDstType, insertOp.getDest());
905 bitcastOp, bitcastOp.getType(), newCastSrcOp, newCastDstOp, newOffsets,
906 insertOp.getStrides());
934 BreakDownVectorBitCast(MLIRContext *context,
935 std::function<
bool(vector::BitCastOp)> controlFn,
936 PatternBenefit benefit)
937 : OpRewritePattern(context, benefit), controlFn(std::move(controlFn)) {}
939 LogicalResult matchAndRewrite(vector::BitCastOp bitcastOp,
940 PatternRewriter &rewriter)
const override {
942 if (controlFn && !controlFn(bitcastOp))
945 VectorType castSrcType = bitcastOp.getSourceVectorType();
946 VectorType castDstType = bitcastOp.getResultVectorType();
947 assert(castSrcType.getRank() == castDstType.getRank());
952 if (castSrcType.isScalable())
954 "Scalable vectors are not supported");
957 if (castSrcType.getRank() != 1)
960 int64_t castSrcLastDim = castSrcType.getShape().back();
961 int64_t castDstLastDim = castDstType.getShape().back();
963 if (castSrcLastDim < castDstLastDim)
966 assert(castSrcLastDim % castDstLastDim == 0);
967 int64_t shrinkRatio = castSrcLastDim / castDstLastDim;
969 if (castSrcLastDim == shrinkRatio)
972 Location loc = bitcastOp.getLoc();
973 Type elemType = castDstType.getElementType();
976 Value zero = arith::ConstantOp::create(rewriter, loc, elemType,
978 Value res = BroadcastOp::create(rewriter, loc, castDstType, zero);
980 SmallVector<int64_t> sliceShape = {castDstLastDim};
981 SmallVector<int64_t> strides = {1};
982 VectorType newCastDstType =
983 VectorType::get(SmallVector<int64_t>{castDstLastDim / shrinkRatio},
984 castDstType.getElementType());
986 for (
int i = 0, e = shrinkRatio; i < e; ++i) {
987 Value extracted = ExtractStridedSliceOp::create(
988 rewriter, loc, bitcastOp.getSource(),
989 ArrayRef<int64_t>{i * castDstLastDim}, sliceShape, strides);
991 BitCastOp::create(rewriter, loc, newCastDstType, extracted);
992 res = InsertStridedSliceOp::create(
993 rewriter, loc, bitcast, res,
994 ArrayRef<int64_t>{i * castDstLastDim / shrinkRatio}, strides);
1001 std::function<bool(BitCastOp)> controlFn;
1004static bool haveSameShapeAndScaling(
Type t,
Type u) {
1005 auto tVec = dyn_cast<VectorType>(t);
1006 auto uVec = dyn_cast<VectorType>(u);
1013 return tVec.getShape() == uVec.getShape() &&
1014 tVec.getScalableDims() == uVec.getScalableDims();
1019static Type cloneOrReplace(
Type type,
Type newElementType) {
1020 if (
auto shapedType = dyn_cast<ShapedType>(type)) {
1021 return shapedType.clone(newElementType);
1023 return newElementType;
1028static Value getBroadcastLikeSource(
Value value) {
1034 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op))
1053struct ReorderElementwiseOpsOnBroadcast final
1056 LogicalResult matchAndRewrite(Operation *op,
1057 PatternRewriter &rewriter)
const override {
1065 op,
"Op doesn't have ElementwiseMappableTraits");
1069 Type resultElemType = resultType.getElementType();
1075 Value broadcastSource;
1076 Value firstBroadcastSource;
1078 Operation *definingOp = operand.getDefiningOp();
1081 if (definingOp->
hasTrait<OpTrait::ConstantLike>())
1083 Value source = getBroadcastLikeSource(operand);
1086 if (!firstBroadcastSource)
1087 firstBroadcastSource = source;
1088 if (isa<VectorType>(source.
getType())) {
1089 broadcastSource = source;
1094 if (!broadcastSource)
1095 broadcastSource = firstBroadcastSource;
1096 if (!broadcastSource)
1098 Type unbroadcastResultType =
1099 cloneOrReplace(broadcastSource.
getType(), resultElemType);
1106 if (isa<vector::FMAOp>(op) && !isa<VectorType>(unbroadcastResultType)) {
1108 op,
"Op only accepts vector types, but the broadcast source is a "
1115 if (!llvm::all_of(op->
getOperands(), [broadcastSource](Value val) {
1116 if (auto source = getBroadcastLikeSource(val))
1117 return haveSameShapeAndScaling(source.getType(),
1118 broadcastSource.getType()) ||
1119 (isa<VectorType>(broadcastSource.getType()) &&
1120 !isa<VectorType>(source.getType()));
1121 SplatElementsAttr splatConst;
1122 return matchPattern(val, m_Constant(&splatConst));
1126 "not all operands are constants or broadcasts from the same type");
1130 SmallVector<Value> srcValues;
1133 SplatElementsAttr splatConst;
1137 Type newType = cloneOrReplace(unbroadcastResultType, elementType);
1138 if (
auto newTypeShaped = dyn_cast<ShapedType>(newType)) {
1143 Operation *newConstOp =
1144 operand.getDefiningOp()->getDialect()->materializeConstant(
1145 rewriter, newConst, newType, operand.getLoc());
1146 srcValues.push_back(newConstOp->
getResult(0));
1149 if (isa<VectorType>(broadcastSource.
getType()) &&
1150 !isa<VectorType>(source.
getType()))
1151 source = vector::BroadcastOp::create(
1152 rewriter, operand.getLoc(),
1155 srcValues.push_back(source);
1160 Operation *elementwiseOp =
1165 op, resultType, elementwiseOp->
getResults());
1187class ExtractOpFromElementwise final
1192 LogicalResult matchAndRewrite(vector::ExtractOp op,
1193 PatternRewriter &rewriter)
const override {
1194 Operation *eltwise = op.getSource().getDefiningOp();
1199 isa<vector::FMAOp>(eltwise))
1213 if (!op.getDynamicPosition().empty())
1215 op,
"dynamic position not yet implemented");
1217 Type dstType = op.getType();
1219 OpBuilder::InsertionGuard g(rewriter);
1223 Location loc = eltwise->
getLoc();
1224 SmallVector<OpFoldResult> pos = op.getMixedPosition();
1226 Value newArg = vector::ExtractOp::create(rewriter, loc, arg, pos);
1227 mapping.
map(arg, newArg);
1230 Operation *newEltwise = rewriter.
clone(*eltwise, mapping);
1241static bool isSupportedMemSinkElementType(
Type type) {
1242 if (isa<IndexType>(type))
1263class ExtractOpFromLoad final :
public OpRewritePattern<vector::ExtractOp> {
1268 PatternRewriter &rewriter)
const override {
1269 auto loadOp = op.getSource().getDefiningOp<vector::LoadOp>();
1274 if (!loadOp->hasOneUse())
1277 VectorType loadVecType = loadOp.getVectorType();
1278 if (loadVecType.isScalable())
1280 "scalable vectors are not supported");
1282 MemRefType memType = loadOp.getMemRefType();
1286 if (!isSupportedMemSinkElementType(memType.getElementType()))
1289 int64_t rankOffset = memType.getRank() - loadVecType.getRank();
1293 auto extractVecType = dyn_cast<VectorType>(op.getResult().getType());
1294 int64_t finalRank = 0;
1296 finalRank = extractVecType.getRank();
1298 SmallVector<Value>
indices = loadOp.getIndices();
1299 SmallVector<OpFoldResult> extractPos = op.getMixedPosition();
1304 OpBuilder::InsertionGuard g(rewriter);
1306 Location loc = loadOp.getLoc();
1307 ArithIndexingBuilder idxBuilderf(rewriter, loc);
1308 for (
auto i : llvm::seq<int64_t>(rankOffset,
indices.size() - finalRank)) {
1309 OpFoldResult pos = extractPos[i - rankOffset];
1317 Value base = loadOp.getBase();
1318 if (extractVecType) {
1341class StoreOpFromBroadcast final :
public OpRewritePattern<vector::StoreOp> {
1346 PatternRewriter &rewriter)
const override {
1347 VectorType vecType = op.getVectorType();
1348 if (vecType.isScalable())
1350 "scalable vectors are not supported");
1352 if (isa<VectorType>(op.getMemRefType().getElementType()))
1354 op,
"memrefs of vectors are not supported");
1356 if (vecType.getNumElements() != 1)
1358 op,
"only 1-element vectors are supported");
1360 Value toStore = op.getValueToStore();
1361 Value source = getBroadcastLikeSource(toStore);
1364 op,
"value to store is not from a broadcast");
1371 Value base = op.getBase();
1374 if (isa<VectorType>(source.
getType())) {
1394 bool force32BitVectorIndices,
int64_t dim,
1403 if (dim == 0 && force32BitVectorIndices) {
1406 }
else if (dim == 0) {
1409 }
else if (force32BitVectorIndices) {
1411 llvm::to_vector<4>(llvm::seq<int32_t>(0, dim)));
1414 llvm::to_vector<4>(llvm::seq<int64_t>(0, dim)));
1416 Value indices = arith::ConstantOp::create(rewriter, loc, indicesAttr);
1420 Value ov = vector::BroadcastOp::create(rewriter, loc,
indices.getType(), o);
1429 if (force32BitVectorIndices) {
1432 b = arith::MinSIOp::create(rewriter, loc,
b, maxBound);
1436 vector::BroadcastOp::create(rewriter, loc,
indices.getType(), bound);
1437 return arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::slt,
1441template <
typename ConcreteOp>
1444 explicit MaterializeTransferMask(MLIRContext *context,
bool enableIndexOpt,
1445 PatternBenefit benefit = 1)
1446 : mlir::OpRewritePattern<ConcreteOp>(context, benefit),
1447 force32BitVectorIndices(enableIndexOpt) {}
1450 PatternRewriter &rewriter)
const override {
1451 if (!xferOp.hasOutOfBoundsDim())
1454 if (xferOp.getVectorType().getRank() > 1 || xferOp.getIndices().empty())
1457 Location loc = xferOp->getLoc();
1458 VectorType vtp = xferOp.getVectorType();
1465 unsigned lastIndex = llvm::size(xferOp.getIndices()) - 1;
1466 Value off = xferOp.getIndices()[lastIndex];
1469 Value
b = arith::SubIOp::create(rewriter, loc, dim.
getType(), dim, off);
1470 Value mask = vector::CreateMaskOp::create(
1472 VectorType::get(vtp.getShape(), rewriter.
getI1Type(),
1473 vtp.getScalableDims()),
1475 if (xferOp.getMask()) {
1477 mask = arith::AndIOp::create(rewriter, loc, mask, xferOp.getMask());
1481 xferOp.getMaskMutable().assign(mask);
1489 const bool force32BitVectorIndices;
1493class VectorCreateMaskOpConversion
1496 explicit VectorCreateMaskOpConversion(MLIRContext *context,
1497 bool enableIndexOpt,
1498 PatternBenefit benefit = 1)
1499 : mlir::OpRewritePattern<vector::CreateMaskOp>(context, benefit),
1500 force32BitVectorIndices(enableIndexOpt) {}
1502 LogicalResult matchAndRewrite(vector::CreateMaskOp op,
1503 PatternRewriter &rewriter)
const override {
1504 auto dstType = op.getType();
1505 if (cast<VectorType>(dstType).isScalable())
1507 int64_t rank = dstType.getRank();
1511 op, buildVectorComparison(rewriter, op, force32BitVectorIndices,
1512 rank == 0 ? 0 : dstType.getDimSize(0),
1518 const bool force32BitVectorIndices;
1522static bool allI1ConstantValuesSetTo(arith::ConstantOp constantOp,
bool value) {
1523 auto denseAttr = dyn_cast<DenseIntElementsAttr>(constantOp.getValue());
1528 assert(denseAttr.getElementType().isInteger(1) &&
"Unexpected type");
1529 return denseAttr.isSplat() && denseAttr.getSplatValue<
bool>() == value;
1547 PatternRewriter &rewriter)
const override {
1548 auto vecType = dyn_cast<VectorType>(selectOp.getType());
1549 if (!vecType || !vecType.getElementType().isInteger(1))
1553 Value cond = selectOp.getCondition();
1554 if (isa<VectorType>(cond.
getType()))
1558 if (vecType.getRank() != 1 || vecType.isScalable())
1562 if (vecType.getShape()[0] != 1)
1565 auto trueConst = selectOp.getTrueValue().getDefiningOp<arith::ConstantOp>();
1566 if (!trueConst || !allI1ConstantValuesSetTo(trueConst,
true))
1570 selectOp.getFalseValue().getDefiningOp<arith::ConstantOp>();
1571 if (!falseConst || !allI1ConstantValuesSetTo(falseConst,
false))
1575 auto elemType = rewriter.
getIntegerType(vecType.getNumElements());
1576 auto bcastType = VectorType::get({1}, elemType);
1597static FailureOr<size_t>
1601 if (failed(srcType.getStridesAndOffset(srcStrides, srcOffset)))
1604 auto isUnitDim = [](VectorType type,
int dim) {
1605 return type.getDimSize(dim) == 1 && !type.getScalableDims()[dim];
1612 int rankDiff = srcType.getRank() - vectorType.getRank();
1613 for (
int64_t i = 0, e = vectorType.getRank(); i < e; ++i) {
1616 int dim = vectorType.getRank() - i - 1;
1617 if (srcStrides[dim + rankDiff] != 1 ||
1618 srcType.getDimSize(dim + rankDiff) != 1 || !isUnitDim(vectorType, dim))
1630 LogicalResult matchAndRewrite(vector::TransferReadOp readOp,
1633 if (readOp.getTransferRank() == 0)
1636 auto srcType = dyn_cast<MemRefType>(readOp.getBase().getType());
1640 if (!readOp.getPermutationMap().isMinorIdentity())
1643 auto targetType = readOp.getVectorType();
1644 if (targetType.getRank() <= 1)
1647 FailureOr<size_t> maybeDimsToDrop =
1649 if (failed(maybeDimsToDrop))
1652 size_t dimsToDrop = maybeDimsToDrop.value();
1653 if (dimsToDrop == 0)
1656 auto inBounds = readOp.getInBoundsValues();
1657 auto droppedInBounds =
ArrayRef<bool>(inBounds).take_back(dimsToDrop);
1658 if (llvm::is_contained(droppedInBounds,
false))
1661 auto resultTargetVecType =
1662 VectorType::get(targetType.getShape().drop_back(dimsToDrop),
1663 targetType.getElementType(),
1664 targetType.getScalableDims().drop_back(dimsToDrop));
1666 auto loc = readOp.getLoc();
1673 MemRefType resultMemrefType = memref::SubViewOp::inferRankReducedResultType(
1674 srcType.getShape().drop_back(dimsToDrop), srcType, offsets, sizes,
1677 readOp.getInBoundsAttr().getValue().drop_back(dimsToDrop));
1678 Value rankedReducedView =
1679 memref::SubViewOp::create(rewriter, loc, resultMemrefType,
1680 readOp.getBase(), offsets, sizes, strides);
1682 cast<ShapedType>(rankedReducedView.
getType()), resultTargetVecType);
1685 Value mask = readOp.getMask();
1687 auto maskType = cast<VectorType>(mask.getType());
1688 auto reducedMaskType = VectorType::get(
1689 maskType.getShape().drop_back(dimsToDrop), maskType.getElementType(),
1690 maskType.getScalableDims().drop_back(dimsToDrop));
1691 mask = rewriter.
createOrFold<vector::ShapeCastOp>(loc, reducedMaskType,
1696 rewriter, loc, resultTargetVecType, rankedReducedView,
1697 readOp.getIndices().drop_back(dimsToDrop), AffineMapAttr::get(permMap),
1698 readOp.getPadding(), mask, inBoundsAttr);
1727 LogicalResult matchAndRewrite(vector::TransferWriteOp writeOp,
1730 if (writeOp.getTransferRank() == 0)
1733 auto srcType = dyn_cast<MemRefType>(writeOp.getBase().getType());
1737 if (!writeOp.getPermutationMap().isMinorIdentity())
1740 auto targetType = writeOp.getVectorType();
1741 if (targetType.getRank() <= 1)
1744 FailureOr<size_t> maybeDimsToDrop =
1746 if (failed(maybeDimsToDrop))
1749 size_t dimsToDrop = maybeDimsToDrop.value();
1750 if (dimsToDrop == 0)
1753 auto inBounds = writeOp.getInBoundsValues();
1754 auto droppedInBounds =
ArrayRef<bool>(inBounds).take_back(dimsToDrop);
1755 if (llvm::is_contained(droppedInBounds,
false))
1758 auto resultTargetVecType =
1759 VectorType::get(targetType.getShape().drop_back(dimsToDrop),
1760 targetType.getElementType(),
1761 targetType.getScalableDims().drop_back(dimsToDrop));
1770 MemRefType resultMemrefType = memref::SubViewOp::inferRankReducedResultType(
1771 srcType.getShape().drop_back(dimsToDrop), srcType, offsets, sizes,
1774 writeOp.getInBoundsAttr().getValue().drop_back(dimsToDrop));
1776 Value rankedReducedView =
1777 memref::SubViewOp::create(rewriter, loc, resultMemrefType,
1778 writeOp.getBase(), offsets, sizes, strides);
1780 cast<ShapedType>(rankedReducedView.
getType()), resultTargetVecType);
1782 auto shapeCast = rewriter.
createOrFold<vector::ShapeCastOp>(
1783 loc, resultTargetVecType, writeOp.getVector());
1786 Value mask = writeOp.getMask();
1788 auto maskType = cast<VectorType>(mask.getType());
1789 auto reducedMaskType = VectorType::get(
1790 maskType.getShape().drop_back(dimsToDrop), maskType.getElementType(),
1791 maskType.getScalableDims().drop_back(dimsToDrop));
1792 mask = rewriter.
createOrFold<vector::ShapeCastOp>(loc, reducedMaskType,
1797 writeOp, shapeCast, rankedReducedView,
1798 writeOp.getIndices().drop_back(dimsToDrop), AffineMapAttr::get(permMap),
1799 mask, inBoundsAttr);
1812 std::function<LogicalResult(vector::ContractionOp op)>;
1817 filter(std::move(constraint)) {}
1821 if (failed(filter(op)))
1829 Value lhs = op.getLhs();
1831 Value res = op.getAcc();
1835 auto infer = [&](MapList m) {
1842 static constexpr std::array<int64_t, 2> perm = {1, 0};
1843 auto iteratorTypes = op.getIteratorTypes().getValue();
1845 if (iteratorTypes.size() != 3 ||
1852 const auto canonicalForm = infer({{m, k}, {n, k}, {m, n}});
1853 if (maps == canonicalForm)
1858 auto createTranspose = [&rewriter, loc](
Value mat) ->
Value {
1859 if (
auto sext = mat.getDefiningOp<arith::ExtSIOp>()) {
1861 vector::TransposeOp::create(rewriter, loc, sext.getIn(), perm);
1862 VectorType newType =
1863 cast<VectorType>(trans.
getType())
1864 .clone(cast<VectorType>(mat.getType()).getElementType());
1865 return arith::ExtSIOp::create(rewriter, loc, newType, trans);
1867 if (
auto zext = mat.getDefiningOp<arith::ExtUIOp>()) {
1869 vector::TransposeOp::create(rewriter, loc,
zext.getIn(), perm);
1870 VectorType newType =
1871 VectorType::get(cast<VectorType>(trans.
getType()).getShape(),
1872 cast<VectorType>(mat.getType()).getElementType());
1873 return arith::ExtUIOp::create(rewriter, loc, newType, trans);
1875 return vector::TransposeOp::create(rewriter, loc, mat, perm);
1878 if (maps == infer({{m, k}, {k, n}, {m, n}})) {
1879 rhs = createTranspose(
rhs);
1880 }
else if (maps == infer({{k, m}, {n, k}, {m, n}})) {
1881 lhs = createTranspose(lhs);
1882 }
else if (maps == infer({{k, m}, {k, n}, {m, n}})) {
1883 rhs = createTranspose(
rhs);
1884 lhs = createTranspose(lhs);
1885 }
else if (maps == infer({{k, m}, {k, n}, {n, m}})) {
1886 std::swap(
rhs, lhs);
1887 rhs = createTranspose(
rhs);
1888 lhs = createTranspose(lhs);
1889 }
else if (maps == infer({{k, m}, {n, k}, {n, m}})) {
1890 std::swap(
rhs, lhs);
1891 rhs = createTranspose(
rhs);
1892 }
else if (maps == infer({{m, k}, {k, n}, {n, m}})) {
1893 std::swap(lhs,
rhs);
1894 lhs = createTranspose(lhs);
1895 }
else if (maps == infer({{m, k}, {n, k}, {n, m}})) {
1896 std::swap(lhs,
rhs);
1902 op.getIteratorTypes(), op.getKind(), op.getFastmath());
1927template <
typename ExtOp>
1935 auto lhsDefOp = contractOp.getLhs().getDefiningOp<ExtOp>();
1936 auto rhsDefOp = contractOp.getRhs().getDefiningOp<ExtOp>();
1938 if (!lhsDefOp || !rhsDefOp) {
1940 "no defining op on contract operands");
1944 contractOp, lhsDefOp->getOperand(0), rhsDefOp->getOperand(0),
1945 contractOp.getAcc(), contractOp.getIndexingMapsAttr(),
1946 contractOp.getIteratorTypesAttr(), contractOp.getKind(),
1947 contractOp.getFastmath());
1969 if (op.getKind() != vector::CombiningKind::ADD)
1977 if (!
acc.getType().isIntOrFloat())
1980 auto parentReduction =
acc.getDefiningOp<vector::ReductionOp>();
1981 if (!parentReduction)
1986 if (isa<IntegerType>(
acc.getType())) {
1988 loc, parentReduction.getVector(), op.getVector());
1990 vAdd = arith::AddFOp::create(rewriter, loc, parentReduction.getVector(),
1994 parentReduction.getAcc());
2005 auto inVecShape = inVecTy.getShape();
2008 for (
auto [dim, isScalable] :
2009 llvm::zip_equal(inVecShape, inVecTy.getScalableDims())) {
2010 if (dim == 1 && !isScalable)
2013 newShape.push_back(dim);
2014 newScalableDims.push_back(isScalable);
2017 if (newShape.empty()) {
2018 newShape.push_back(1);
2019 newScalableDims.push_back(
false);
2022 return VectorType::get(newShape, inVecTy.getElementType(), newScalableDims);
2059 if (!resultVectorType)
2066 if (!sourceVectorType)
2068 if (sourceVectorType.getRank() < 2)
2074 auto opVectorType = cast<VectorType>(operand.getType());
2076 if (newVType == opVectorType)
2079 auto opSC = vector::ShapeCastOp::create(rewriter, loc, newVType, operand);
2080 newOperands.push_back(opSC);
2083 VectorType newResultVectorType =
2122 VectorType sourceType = op.getSourceVectorType();
2123 VectorType sourceTypeWithoutUnitDims =
2126 if (sourceType == sourceTypeWithoutUnitDims)
2133 for (
auto [i, dim] : llvm::enumerate(sourceDims)) {
2134 droppedDimsBefore[i] = droppedDims;
2135 if (dim == std::make_tuple(1,
false))
2143 if (sourceDims[idx] == std::make_tuple(1,
false))
2145 newPerm.push_back(idx - droppedDimsBefore[idx]);
2151 if (newPerm.empty()) {
2152 newPerm.push_back(0);
2157 auto dropDimsShapeCast = vector::ShapeCastOp::create(
2158 rewriter, loc, sourceTypeWithoutUnitDims, op.getVector());
2160 auto transposeWithoutUnitDims =
2161 vector::TransposeOp::create(rewriter, loc, dropDimsShapeCast, newPerm);
2164 op, op.getResultVectorType(), transposeWithoutUnitDims);
2201 for (
OpOperand &operand : forOp.getInitArgsMutable()) {
2202 auto vectorType = dyn_cast<VectorType>(operand.get().getType());
2207 if (vectorType == newVectorType)
2212 return vector::ShapeCastOp::create(
b, loc, type, source);
2216 castFn(rewriter, forOp.getLoc(), newVectorType, operand.get());
2218 replaceAndCastForOpIterArg(rewriter, forOp, operand,
2245 if (op.getKind() != vector::CombiningKind::ADD)
2248 Type elemType = op.getSourceVectorType().getElementType();
2251 if (!isa<FloatType>(elemType))
2254 auto vAdd = op.getVector().getDefiningOp<arith::AddFOp>();
2257 auto addLhs = vAdd.getLhs().getDefiningOp<arith::AddFOp>();
2264 auto newAdd = arith::AddFOp::create(rewriter, vAdd.getLoc(),
2265 addLhs.getLhs(), vAdd.getRhs());
2284 unsigned maxNumElementsToExtract,
2287 maxNumElementsToExtract(maxNumElementsToExtract) {}
2291 VectorType type = op.getSourceVectorType();
2292 if (type.isScalable() || op.isMasked())
2294 assert(type.getRank() == 1 &&
"Expected a 1-d vector");
2296 int64_t numElems = type.getNumElements();
2297 if (numElems > maxNumElementsToExtract) {
2299 op, llvm::formatv(
"has too many vector elements ({0}) to break down "
2300 "(max allowed: {1})",
2301 numElems, maxNumElementsToExtract));
2306 for (
auto [idx, extractedElem] : llvm::enumerate(extracted))
2307 extractedElem = vector::ExtractOp::create(rewriter, loc, op.getVector(),
2310 Value res = extracted.front();
2311 for (
auto extractedElem : llvm::drop_begin(extracted))
2313 extractedElem, op.getFastmathAttr());
2316 op.getFastmathAttr());
2323 unsigned maxNumElementsToExtract = 0;
2342template <
typename MulOpType>
2347 bool isValidBroadcastSource(vector::BroadcastOp broadcastOp)
const {
2350 if (!broadcastOp.computeBroadcastedUnitDims().empty())
2353 auto srcType = dyn_cast<VectorType>(broadcastOp.getSourceType());
2354 return srcType && srcType.getRank() != 2;
2359 auto resType = llvm::dyn_cast<VectorType>(mulOp.getResult().getType());
2362 if (resType.getRank() != 2)
2367 auto matchOuterProduct =
2369 Value operandB) -> FailureOr<vector::OuterProductOp> {
2370 auto transposedLhs = operandA.
getDefiningOp<vector::TransposeOp>();
2375 if (permutation.size() != 2 || permutation[0] != 1 || permutation[1] != 0)
2378 auto broadcastedLhs =
2379 transposedLhs.getVector().getDefiningOp<vector::BroadcastOp>();
2380 if (!broadcastedLhs || !isValidBroadcastSource(broadcastedLhs))
2383 auto broadcastedRhs = operandB.getDefiningOp<vector::BroadcastOp>();
2384 if (!broadcastedRhs || !isValidBroadcastSource(broadcastedRhs))
2387 return vector::OuterProductOp::create(
2388 rewriter, mulOp->getLoc(), resType, broadcastedLhs.getSource(),
2389 broadcastedRhs.getSource(),
Value(), vector::CombiningKind::ADD);
2392 Value lhs = mulOp->getOperand(0), rhs = mulOp->getOperand(1);
2393 auto maybeOuterP = matchOuterProduct(lhs, rhs);
2395 if (failed(maybeOuterP))
2396 maybeOuterP = matchOuterProduct(rhs, lhs);
2397 if (failed(maybeOuterP))
2399 rewriter.
replaceOp(mulOp, maybeOuterP->getResult());
2413void mlir::vector::populateVectorMaskMaterializationPatterns(
2416 patterns.
add<VectorCreateMaskOpConversion,
2417 MaterializeTransferMask<vector::TransferReadOp>,
2418 MaterializeTransferMask<vector::TransferWriteOp>>(
2419 patterns.
getContext(), force32BitVectorIndices, benefit);
2423void mlir::vector::populateDropUnitDimWithShapeCastPatterns(
2429void mlir::vector::populateBubbleVectorBitCastOpPatterns(
2431 patterns.
add<BubbleDownVectorBitCastForExtract,
2432 BubbleDownBitCastForStridedSliceExtract,
2433 BubbleUpBitCastForInsert, BubbleUpBitCastForStridedSliceInsert>(
2437void mlir::vector::populateBreakDownVectorBitCastOpPatterns(
2439 std::function<
bool(vector::BitCastOp)> controlFn,
PatternBenefit benefit) {
2441 std::move(controlFn), benefit);
2446 std::function<LogicalResult(vector::ContractionOp)> constraint,
2449 std::move(constraint));
2454 bool allowFastMathFlagLoss) {
2456 allowFastMathFlagLoss, benefit);
2457 patterns.
add<CombineContractBroadcastMask, CombineContractABTranspose,
2458 CombineContractResultTranspose>(patterns.
getContext(), benefit);
2470 patterns.
add<ReorderElementwiseOpsOnTranspose, ReorderCastOpsOnBroadcast,
2471 ReorderElementwiseOpsOnBroadcast, ExtractOpFromElementwise>(
2478 patterns.
add<ExtractOpFromLoad, StoreOpFromBroadcast>(patterns.
getContext(),
2482void mlir::vector::populateChainedVectorReductionFoldingPatterns(
2489void mlir::vector::populateBreakDownVectorReductionPatterns(
2493 maxNumElementsToExtract, benefit);
2498 patterns.
add<FoldArithToVectorOuterProduct<arith::MulFOp>,
2499 FoldArithToVectorOuterProduct<arith::MulIOp>>(
2507#include "mlir/Dialect/Vector/Transforms/VectorTransformsEnums.cpp.inc"
static uint64_t zext(uint32_t arg)
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
Drop inner most contiguous unit dimensions from transfer_read operand.
Drop inner most contiguous unit dimensions from transfer_write operand. E.g., vector....
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumResults() const
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr > > exprsList, MLIRContext *context)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
IntegerAttr getIndexAttr(int64_t value)
AffineMap getMultiDimIdentityMap(unsigned rank)
IntegerType getIntegerType(unsigned width)
TypedAttr getZeroAttr(Type type)
AffineExpr getAffineDimExpr(unsigned position)
DenseIntElementsAttr getI32VectorAttr(ArrayRef< int32_t > values)
DenseIntElementsAttr getI64VectorAttr(ArrayRef< int64_t > values)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
MLIRContext * getContext() const
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > values)
ArrayAttr getBoolArrayAttr(ArrayRef< bool > values)
ArrayAttr getAffineMapArrayAttr(ArrayRef< AffineMap > values)
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
std::enable_if_t<!std::is_base_of< Attribute, T >::value||std::is_same< Attribute, T >::value, T > getSplatValue() const
Return the splat value for this attribute.
An attribute that represents a reference to a dense integer vector or tensor object.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
This class represents an operand of an operation.
OpTraitRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting again...
OpTraitRewritePattern(MLIRContext *context, PatternBenefit benefit=1)
OpTraitRewritePattern Base
Type alias to allow derived classes to inherit constructors with using Base::Base;.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
bool hasOneUse()
Returns true if this operation has exactly one use.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Attribute getPropertiesAsAttribute()
Return the properties converted to an attribute.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
unsigned short getBenefit() const
If the corresponding pattern can match, return its benefit. If the.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
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,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
bool isSignlessIntOrIndexOrFloat() const
Return true if this is a signless integer, index, or float type.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void setType(Type newType)
Mutate the type of this Value to be of the specified type.
Type getType() const
Return the type of this value.
bool hasOneUse() const
Returns true if this value has exactly one use.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given memref value.
Value makeArithReduction(OpBuilder &b, Location loc, CombiningKind kind, Value v1, Value acc, arith::FastMathFlagsAttr fastmath=nullptr, Value mask=nullptr)
Returns the result value of reducing two scalar/vector values with the corresponding arith operation.
Operation * maskOperation(OpBuilder &builder, Operation *maskableOp, Value mask, Value passthru=Value())
Creates a vector.mask operation around a maskable operation.
bool isReductionIterator(Attribute attr)
Returns true if attr has "reduction" iterator type semantics.
auto getDims(VectorType vType)
Returns a range over the dims (size and scalability) of a VectorType.
void populateElementwiseToVectorOpsPatterns(RewritePatternSet &patterns)
Collect a set of patterns that fold elementwise op on vectors to the vector dialect.
AffineMap getTransferMinorIdentityMap(ShapedType shapedType, VectorType vectorType)
Build the default minor identity map suitable for a vector transfer.
void populateVectorReductionToContractPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1, bool allowFastMathFlagLoss=true)
Collect patterns to convert reduction op to vector.contract and fold transpose/broadcast ops into the...
void populateDropInnerMostUnitDimsXferOpPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Collect a set of patterns to collapse the most inner unit dims in xfer Ops.
bool isParallelIterator(Attribute attr)
Returns true if attr has "parallel" iterator type semantics.
void populateFoldArithExtensionPatterns(RewritePatternSet &patterns)
Collect a set of patterns that fold arithmetic extension on floating point into vector contract for t...
void populateVectorContractCanonicalizeMatmulToMMT(RewritePatternSet &patterns, std::function< LogicalResult(vector::ContractionOp)> constraint=[](vector::ContractionOp) { return success();}, PatternBenefit=1)
Canonicalization of a vector.contract a, b, c with row-major matmul semantics to a contraction with M...
void populateSinkVectorOpsPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Patterns that remove redundant Vector Ops by re-ordering them with e.g.
Value createOrFoldDimOp(OpBuilder &b, Location loc, Value source, int64_t dim)
Helper function that creates a memref::DimOp or tensor::DimOp depending on the type of source.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
Value getValueOrCreateCastToIndexLike(OpBuilder &b, Location loc, Type targetType, Value value)
Create a cast from an index-like value (index or integer) to another index-like value.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
detail::constant_float_predicate_matcher m_AnyZeroFloat()
Matches a constant scalar / vector splat / tensor splat float (both positive and negative) zero.
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims)
Drop the dims that are listed in unusedDims.
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
LogicalResult matchAndRewrite(vector::ReductionOp op, PatternRewriter &rewriter) const override
BreakDownVectorReduction(MLIRContext *context, unsigned maxNumElementsToExtract, PatternBenefit benefit)
Canonicalization of a vector.contract a, b, c with row-major matmul semantics to a contraction suitab...
LogicalResult matchAndRewrite(vector::ContractionOp op, PatternRewriter &rewriter) const override
std::function< LogicalResult(vector::ContractionOp op)> FilterConstraintType
CanonicalizeContractMatmulToMMT(MLIRContext *context, PatternBenefit benefit, FilterConstraintType constraint)
Pattern to fold chained reduction to a series of vector additions and a final reduction....
LogicalResult matchAndRewrite(vector::ReductionOp op, PatternRewriter &rewriter) const override
For vectors with at least one unit dim, replaces: elementwise(a, b) with: sc_a = shape_cast(a) sc_b =...
LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const override
Attempt to match against code rooted at the specified operation, which is the same operation code as ...
A pattern to drop unit dims from the iter_args of an scf.for.
LogicalResult matchAndRewrite(scf::ForOp forOp, PatternRewriter &rewriter) const override
A pattern to drop unit dims from vector.transpose.
LogicalResult matchAndRewrite(vector::TransposeOp op, PatternRewriter &rewriter) const override
Pattern to fold arithmetic extensions on floating point data types into vector contraction operations...
LogicalResult matchAndRewrite(vector::ContractionOp contractOp, PatternRewriter &rewriter) const override
Pattern to eliminate redundant zero-constants added to reduction operands. It's enough for there to b...
LogicalResult matchAndRewrite(vector::ReductionOp op, PatternRewriter &rewriter) const override
OpInterfaceRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting a...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern Base
Type alias to allow derived classes to inherit constructors with using Base::Base;.
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const final
Wrapper around the RewritePattern method that passes the derived op type.
A pattern for ops that implement MaskableOpInterface and that might be masked (i.e.