19#include "llvm/Support/Casting.h"
32static bool isZeroVectorConstant(
Operation *op) {
33 auto constantOp = dyn_cast_if_present<arith::ConstantOp>(op);
37 if (!isa<VectorType>(constantOp.getType()))
40 auto denseAttr = dyn_cast<DenseElementsAttr>(constantOp.getValue());
41 if (!denseAttr || !denseAttr.isSplat())
56 if (!isa<scf::YieldOp>(user))
59 auto yield = cast<scf::YieldOp>(user);
69 ShapedType inputType = cast<ShapedType>(input.
getType());
70 int64_t firstDimToCollapse = inputType.getRank() - 2;
72 if (inputType.getRank() == 1)
76 for (
int64_t i = 0; i < firstDimToCollapse; ++i)
80 for (
int64_t i = firstDimToCollapse; i < inputType.getRank(); ++i)
81 collapsedIndices.push_back(i);
83 reassociation.push_back(collapsedIndices);
84 return memref::CollapseShapeOp::create(builder, loc, input, reassociation);
88static bool isReadSrcMemref(
Value operand) {
95 .Case<TransferReadOp, LoadOp>(
96 [&](
auto readOp) { srcBuff = readOp.getOperand(0); });
98 return srcBuff && isa<MemRefType>(srcBuff.
getType());
103static bool isVnniOperandRead(
Value operand,
int64_t vnni) {
112 srcBuff = readOp.getBase();
113 vnniIndex = readOp.getIndices().back();
118 auto srcType = dyn_cast<MemRefType>(srcBuff.
getType());
119 return srcType && srcType.getRank() > 0 &&
120 srcType.getShape().back() == vnni &&
isZeroInteger(vnniIndex);
129 Value scaled = arith::MulIOp::create(rewriter, loc,
indices.back(), cVnni);
130 indices.back() = arith::AddIOp::create(rewriter, loc, scaled, inner);
135static FailureOr<std::pair<Value, SmallVector<Value>>>
145 .Case<TransferReadOp, LoadOp>([&](
auto readOp) {
147 readOp.getIndices().end());
148 srcBuff = readOp.getOperand(0);
151 if (!srcBuff || !isa<MemRefType>(srcBuff.
getType()))
155 indices.reserve(indexVals.size());
163 collapseVnniIndices(rewriter, loc,
indices,
164 cast<MemRefType>(srcBuff.
getType()).getShape().back());
168 return std::make_pair(srcBuff,
indices);
172static LogicalResult validateLoopStep(
OpBuilder &rewriter,
Value step,
179 if (cst.value() != value && cst.value() != 1)
186static LogicalResult validateContractOps(
OpBuilder &rewriter,
187 vector::ContractionOp contractOp,
188 unsigned int blockingFactor,
194 auto srcIndxLhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
195 contractOp.getLhs(),
false);
198 auto [buffLhs, indicesLhs] = *srcIndxLhs;
201 auto srcIndxRhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
202 contractOp.getRhs(),
false);
205 auto [buffRhs, indicesRhs] = *srcIndxRhs;
208 if (buffLhs != srcBuffLhs)
211 if (buffRhs != srcBuffRhs)
218 VectorType accTy = dyn_cast<VectorType>(contractOp.getAccType());
225 llvm::copy_if(accShape, std::back_inserter(nonUnitDimAcc),
226 [](
int64_t dim) {
return (dim != 16 && dim != 1); });
228 if (nonUnitDimAcc.size() != 0)
233 VectorType lhsTy = contractOp.getLhsType();
236 llvm::copy_if(lhsShape, std::back_inserter(nonUnitDimLhs),
237 [](
int64_t dim) {
return (dim != 16 && dim != 1); });
239 if (nonUnitDimLhs.size() != 1)
242 if (nonUnitDimLhs[0] != blockingFactor)
247 VectorType rhsTy = contractOp.getRhsType();
250 llvm::copy_if(rhsShape, std::back_inserter(nonUnitDimRhs),
251 [](
int64_t dim) {
return (dim != 16 && dim != 1); });
253 if (nonUnitDimRhs.size() != 1)
256 if (nonUnitDimRhs[0] != blockingFactor)
266 while (
auto arg = dyn_cast<BlockArgument>(
acc)) {
267 auto loop = dyn_cast_if_present<scf::ForOp>(arg.getOwner()->getParentOp());
268 if (!loop || !llvm::is_contained(loops, loop))
270 OpOperand *init = loop.getTiedLoopInit(arg);
280static unsigned getIndexPosition(
Value operand, scf::ForOp loop) {
281 Value iv = loop.getInductionVar();
285 .Case<TransferReadOp, LoadOp>(
286 [&](
auto readOp) { srcBuff = readOp.getOperand(0); });
292 auto offsets = subview.getOffsets();
294 for (
auto it : llvm::enumerate(offsets)) {
295 if (it.value() == iv)
305 unsigned int offset,
bool isVnni) {
307 auto srcIndx = getSrcIndxValue(rewriter, loc, operand,
false);
308 auto [srcBuff,
indices] = *srcIndx;
310 collapseVnniIndices(rewriter, loc,
indices,
311 cast<MemRefType>(srcBuff.
getType()).getShape().back());
313 amx::TileType tileType = amx::TileType::get({16, (16 * offset)}, ipType);
314 return amx::TileLoadOp::create(rewriter, loc, tileType, mat,
indices);
318 Type ipType,
unsigned int offset,
Value packedBuffer,
319 Value indxToStoreInBuffer) {
324 llvm::cast<MemRefType>(matB.
getType()).getRank(), c0);
332 rewriter, loc, c0, cBound, cStep,
ValueRange{},
335 subviewOffset[subviewOffset.size() - 2] = iv;
339 auto vectorType = VectorType::get({2, (16 * (offset / 2))}, ipType);
341 vectorType = VectorType::get((16 * offset), ipType);
343 int64_t srcRank = (dyn_cast<ShapedType>(matB.
getType())).getRank();
344 Value padding = ub::PoisonOp::create(rewriter, loc, ipType);
348 Value vec1 = vector::TransferReadOp::create(
349 rewriter, loc, vectorType, matB,
ValueRange(subviewOffset), padding,
353 vec1 = vector::ShapeCastOp::create(
354 rewriter, loc, VectorType::get((16 * offset), ipType), vec1);
358 Value incIV = arith::AddIOp::create(rewriter, loc, offsetIndx, iv);
359 subviewOffset[subviewOffset.size() - 2] = incIV;
361 Value vec2 = vector::TransferReadOp::create(
362 rewriter, loc, vectorType, matB,
ValueRange(subviewOffset), padding,
365 vec2 = vector::ShapeCastOp::create(
366 rewriter, loc, VectorType::get((16 * offset), ipType), vec2);
368 vector::ShuffleOp writeVal1;
369 vector::ShuffleOp writeVal2;
373 writeVal1 = vector::ShuffleOp::create(
374 rewriter, loc, VectorType::get({(16 * offset)}, ipType), vec1,
376 ArrayRef<int64_t>{0, 32, 1, 33, 2, 34, 3, 35, 8, 40, 9,
377 41, 10, 42, 11, 43, 16, 48, 17, 49, 18, 50,
378 19, 51, 24, 56, 25, 57, 26, 58, 27, 59});
380 writeVal2 = vector::ShuffleOp::create(
381 rewriter, loc, VectorType::get({(16 * offset)}, ipType), vec1,
383 ArrayRef<int64_t>{4, 36, 5, 37, 6, 38, 7, 39, 12, 44, 13,
384 45, 14, 46, 15, 47, 20, 52, 21, 53, 22, 54,
385 23, 55, 28, 60, 29, 61, 30, 62, 31, 63});
391 writeVal1 = vector::ShuffleOp::create(
392 rewriter, loc, VectorType::get({(16 * offset)}, ipType), vec1,
395 0, 32, 64, 96, 1, 33, 65, 97, 2, 34, 66, 98, 3,
396 35, 67, 99, 8, 40, 72, 104, 9, 41, 73, 105, 10, 42,
397 74, 106, 11, 43, 75, 107, 16, 48, 80, 112, 17, 49, 81,
398 113, 18, 50, 82, 114, 19, 51, 83, 115, 24, 56, 88, 120,
399 25, 57, 89, 121, 26, 58, 90, 122, 27, 59, 91, 123});
401 writeVal2 = vector::ShuffleOp::create(
402 rewriter, loc, VectorType::get({(16 * offset)}, ipType), vec1,
405 4, 36, 68, 100, 5, 37, 69, 101, 6, 38, 70, 102, 7, 39,
406 71, 103, 12, 44, 76, 108, 13, 45, 77, 109, 14, 46, 78, 110,
407 15, 47, 79, 111, 20, 52, 84, 116, 21, 53, 85, 117, 22, 54,
408 86, 118, 23, 55, 87, 119, 28, 60, 92, 124, 29, 61, 93, 125,
409 30, 62, 94, 126, 31, 63, 95, 127});
413 Value ivShuff1 = arith::DivUIOp::create(rewriter, loc, iv, cStep);
414 Value ivShuff2 = arith::AddIOp::create(rewriter, loc, ivShuff1, c16);
416 vector::StoreOp::create(rewriter, loc, writeVal1, packedBuffer,
417 ValueRange{indxToStoreInBuffer, ivShuff1, c0});
418 vector::StoreOp::create(rewriter, loc, writeVal2, packedBuffer,
419 ValueRange{indxToStoreInBuffer, ivShuff2, c0});
421 scf::YieldOp::create(nestedBuilder, loc);
428 unsigned int offset,
Value packedBuffer,
bool pack,
429 Value indxToStoreInBuffer,
Value indxToLoadFromMatB) {
435 for (
size_t j = 0;
j < ops.size();
j++) {
436 for (
size_t i = 0; i < ops.size(); i++) {
440 Operation *readOpRhs = ops[
j].getRhs().getDefiningOp();
441 auto itRhs = readsToTileLoads.find(readOpRhs);
442 if (itRhs != readsToTileLoads.end()) {
447 performShuffle(rewriter, loc, matB, ipType, offset, packedBuffer,
448 indxToStoreInBuffer);
452 amx::TileType::get({16, (16 * offset)}, ipType);
454 amx::TileLoadOp::create(rewriter, loc, tileType, packedBuffer,
458 amx::TileLoadOp::create(rewriter, loc, tileType, packedBuffer,
461 readsToTileLoads.try_emplace(readOpRhs, loadRow1);
462 readsToTileLoads.try_emplace(ops[i].getRhs().getDefiningOp(), loadRow2);
467 return readsToTileLoads;
475 unsigned int offset,
bool isVnni,
Value packedBuffer,
bool pack,
476 Value indxToStoreInBuffer,
Value indxToLoadFromMatB) {
491 packInputs(rewriter, loc, ops, matB, ipType, offset, packedBuffer, pack,
492 indxToStoreInBuffer, indxToLoadFromMatB);
496 for (
size_t i = 0; i < ops.size(); i++) {
498 Operation *readOpLhs = ops[i].getLhs().getDefiningOp();
499 amx::TileLoadOp tilesLhs;
500 auto itLhs = readsToTileLoads.find(readOpLhs);
501 if (itLhs != readsToTileLoads.end()) {
502 tilesLhs = itLhs->second;
504 tilesLhs = createTileLoads(rewriter, loc, ops[i].getLhs(), matA, ipType,
506 readsToTileLoads.try_emplace(readOpLhs, tilesLhs);
509 Operation *readOpRhs = ops[i].getRhs().getDefiningOp();
510 amx::TileLoadOp tilesRhs;
511 auto itRhs = readsToTileLoads.find(readOpRhs);
512 if (itRhs != readsToTileLoads.end()) {
513 tilesRhs = itRhs->second;
515 tilesRhs = createTileLoads(rewriter, loc, ops[i].getRhs(), matB, ipType,
517 readsToTileLoads.try_emplace(readOpRhs, tilesRhs);
520 auto accTileType = amx::TileType::get({16, 16}, opType);
524 dp = amx::TileMulFOp::create(rewriter, loc, accTileType, tilesLhs,
525 tilesRhs, accIterArgs[i]);
528 dp = amx::TileMulIOp::create(rewriter, loc, accTileType, tilesLhs,
529 tilesRhs, accIterArgs[i]);
531 accumulators.push_back(dp);
537 Type opType, scf::ForOp outerLoop,
542 auto zeroTileType = amx::TileType::get({16, 16}, opType);
544 for (
int i = 0; i < size; i++) {
545 auto zeroTile = amx::TileZeroOp::create(rewriter, loc, zeroTileType);
546 loopItrArgs.push_back(zeroTile);
554 bool isInnerLoopUBHasOddQuot,
555 bool isInnerLoopUBLarger,
556 bool pack,
Value blockStride) {
564 Value quotientInnerLoop =
565 arith::DivUIOp::create(rewriter, loc, ivInnerLoop, blockStride);
566 Value remInnerLoop = arith::RemUIOp::create(
567 rewriter, loc, rewriter.
getIndexType(), quotientInnerLoop, c2);
569 if (!isInnerLoopUBLarger && !pack) {
570 remInnerLoop = arith::RemUIOp::create(
571 rewriter, loc, rewriter.
getIndexType(), ivOuterLoop, c2);
574 if (isInnerLoopUBHasOddQuot) {
575 auto remOuterLoop = arith::RemUIOp::create(
576 rewriter, loc, rewriter.
getIndexType(), ivOuterLoop, c2);
577 auto remAdd = arith::AddIOp::create(rewriter, loc, rewriter.
getIndexType(),
578 remInnerLoop, remOuterLoop);
579 remInnerLoop = arith::RemUIOp::create(rewriter, loc,
589 Type ipType,
Type opType,
unsigned int blockingFactor,
bool isVnni,
591 vector::ContractionOp contractOp, scf::ForOp outerLoop,
593 Value ivOuterLoop,
Value packedBuffer,
bool pack,
595 bool isInnerLoopUBHasOddQuot) {
601 int64_t offset = 16 * blockingFactor;
603 offset = cst.value();
605 auto newLoop = scf::ForOp::create(
606 rewriter, loc, lowerBound, upperBound, step, loopItrArgs,
612 getIndexPosition(contractOp.getLhs(), outerLoop) + 1),
616 getIndexPosition(contractOp.getLhs(), innerLoop) + 1),
618 auto lhsClone = rewriterNewInnerLoop.
clone(*vectorOpLhs, mapping);
620 Value indxToStoreInBuffer = c0;
621 Value indxToLoadFromBuffer = c0;
624 if (innerLoopIndex.
value() == 0) {
627 ivOuterLoop = arith::AddIOp::create(rewriter, locNewInnerLoop,
630 if (!isInnerLoopUBLarger || isInnerLoopUBHasOddQuot) {
631 indxToStoreInBuffer = arith::RemUIOp::create(
636 Value indxToLoadFromMatB = arith::AddIOp::create(
637 rewriter, loc, indxToStoreInBuffer, c1);
638 indxToLoadFromBuffer = arith::RemUIOp::create(
639 rewriter, loc, rewriter.
getIndexType(), indxToLoadFromMatB,
645 rewriter, locNewInnerLoop, offset);
646 ivNewInnerLoop = arith::AddIOp::create(rewriter, locNewInnerLoop,
647 nLoadIndx, ivNewInnerLoop);
648 indxToStoreInBuffer = getIndxToLoadStoreFromPckBuffer(
649 rewriter, loc, ivNewInnerLoop, ivOuterLoop,
650 isInnerLoopUBHasOddQuot, isInnerLoopUBLarger, pack, step);
651 Value indxToLoadFromMatB =
652 arith::AddIOp::create(rewriter, loc, indxToStoreInBuffer, c1);
653 indxToLoadFromBuffer =
654 arith::RemUIOp::create(rewriter, loc, rewriter.
getIndexType(),
655 indxToLoadFromMatB, c2);
660 rewriter, locNewInnerLoop, offset);
661 ivNewInnerLoop = arith::AddIOp::create(rewriter, locNewInnerLoop,
662 nLoadIndx, ivNewInnerLoop);
663 Value quotient_K = arith::DivUIOp::create(
664 rewriter, loc, ivNewInnerLoop, nLoadIndx);
665 indxToStoreInBuffer = arith::RemUIOp::create(
666 rewriter, loc, rewriter.
getIndexType(), quotient_K, c2);
668 Value indxToLoadFromMatB =
669 arith::AddIOp::create(rewriter, loc, indxToStoreInBuffer, c1);
670 indxToLoadFromBuffer =
671 arith::RemUIOp::create(rewriter, loc, rewriter.
getIndexType(),
672 indxToLoadFromMatB, c2);
685 int64_t outerPos = getIndexPosition(contractOp.getRhs(), outerLoop);
688 unsigned operandIdx =
static_cast<unsigned>(outerPos + 1);
695 int64_t innerPos = getIndexPosition(contractOp.getRhs(), innerLoop);
698 unsigned operandIdx =
static_cast<unsigned>(innerPos + 1);
701 rhsMapping.
map(rhsOp->
getOperand(operandIdx), ivNewInnerLoop);
704 auto rhsClone = rewriterNewInnerLoop.
clone(*rhsOp, rhsMapping);
705 matB = rhsClone->getResult(0);
716 indxToLoadFromBuffer = c0;
722 indxToLoadFromBuffer = getIndxToLoadStoreFromPckBuffer(
723 rewriter, loc, ivNewInnerLoop, ivOuterLoop,
724 isInnerLoopUBHasOddQuot, isInnerLoopUBLarger, pack, step);
729 rewriter, locNewInnerLoop, offset);
731 Value quotient_K = arith::DivUIOp::create(
732 rewriter, loc, ivNewInnerLoop, nLoadIndx);
733 indxToLoadFromBuffer = arith::RemUIOp::create(
734 rewriter, loc, rewriter.
getIndexType(), quotient_K, c2);
740 rewriter, locNewInnerLoop, ops, lhsClone->getResult(0), matB,
741 ipType, opType, iterArgsNewInnerLoop, blockingFactor, isVnni,
742 packedBuffer, pack, indxToStoreInBuffer, indxToLoadFromBuffer);
744 scf::YieldOp::create(rewriterNewInnerLoop, locNewInnerLoop,
815struct VectorContractToAMXDotProduct
817 using OpRewritePattern<vector::ContractionOp>::OpRewritePattern;
819 LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
820 PatternRewriter &rewriter)
const override {
822 if (contractOp.getKind() != vector::CombiningKind::ADD)
824 "Expects add combining kind.");
826 unsigned int blockingFactor =
827 contractOp.getLhsType().getElementType().isBF16() ? 2 : 4;
830 contractOp.getIndexingMapsArray(), blockingFactor);
832 VectorType lhsTy = contractOp.getLhsType();
833 if (!lhsTy.getElementType().isBF16() &&
834 !lhsTy.getElementType().isSignlessInteger(8) &&
835 !lhsTy.getElementType().isF8E4M3FN() &&
836 !lhsTy.getElementType().isF8E5M2())
838 contractOp,
"Only BF16/Int8/F8 lowering is supported.");
840 if (lhsTy.getElementType() != contractOp.getRhsType().getElementType())
842 contractOp,
"Contraction should have same lhs and rhs type.");
844 VectorType accTy = dyn_cast<VectorType>(contractOp.getAccType());
848 if (((lhsTy.getElementType().isBF16() ||
849 lhsTy.getElementType().isF8E4M3FN() ||
850 lhsTy.getElementType().isF8E5M2()) &&
851 !accTy.getElementType().isF32()) ||
852 (lhsTy.getElementType().isSignlessInteger(8) &&
853 !accTy.getElementType().isSignlessInteger(32)))
855 "Only F32 for BF16 or Int32 for Int8 "
856 "accumulation type is supported.");
858 Operation *accReadOp =
861 Operation *accWrite =
869 if (!accReadOp || !resultChainEnd)
871 contractOp,
"The ACC operand of the vector.contract should be a "
872 "transfer_read or a load. And, the result should have a "
873 "single-use chain to its consumer.");
875 bool isAccZeroVectorConstant = isZeroVectorConstant(accReadOp);
882 if (lhsTy.getElementType().isSignlessInteger(8)) {
887 if (lhsTy.getElementType().isF8E4M3FN())
890 if (lhsTy.getElementType().isF8E5M2())
893 if (accReadOp->
getBlock() == contractOp->getBlock() &&
894 resultBlock != contractOp->getBlock())
896 contractOp,
"The accumulator store is in different block.");
898 if (accReadOp->
getBlock() != contractOp->getBlock() &&
899 resultBlock == contractOp->getBlock())
901 contractOp,
"The accumulator read is in different block.");
903 if (!(isReadSrcMemref(contractOp.getLhs()) &&
904 isReadSrcMemref(contractOp.getRhs())))
906 contractOp,
"The LHS or RHS src is not a MemRef type.");
908 if (isVnni && !(isVnniOperandRead(contractOp.getLhs(), blockingFactor) &&
909 isVnniOperandRead(contractOp.getRhs(), blockingFactor)))
911 contractOp,
"The LHS or RHS src does not read whole VNNI groups.");
913 unsigned int dimValue = blockingFactor;
915 dimValue = 16 * blockingFactor;
919 if (accReadOp->
getBlock() == contractOp->getBlock() &&
920 resultBlock == contractOp->getBlock()) {
922 if (!isReadSrcMemref(contractOp.getAcc()))
924 "The ACC src is not a MemRef type.");
926 bool collapse =
false;
930 LogicalResult validate = validateContractOps(
931 rewriter, contractOp, dimValue, Value(), Value(),
false);
935 contractOp,
"The contract operation doesn't satisfy the operands "
936 "dimensions. M, N, and vnni dims are 16, 16, and 2/4. "
937 "The rest dims should be 1. Op should have one user.");
939 Location loc = contractOp.getLoc();
941 auto srcIndxLhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
942 contractOp.getLhs(), collapse);
945 "Failed to get the LHS src.");
946 auto [srcBuffLhs, indicesLhs] = *srcIndxLhs;
948 auto srcIndxRhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
949 contractOp.getRhs(), collapse);
952 "Failed to get the RHS src.");
953 auto rhsSrc = *srcIndxRhs;
954 auto srcBuffRhs = rhsSrc.first;
955 auto indicesRhs = rhsSrc.second;
957 auto srcIndxAcc = getSrcIndxValue(rewriter, contractOp.getLoc(),
958 contractOp.getAcc(),
false);
961 "Failed to get the ACC src.");
962 auto [srcBuffAcc, indicesAcc] = *srcIndxAcc;
967 auto tileType = amx::TileType::get({16, (16 * blockingFactor)}, ipType);
968 auto loadLhs = amx::TileLoadOp::create(rewriter, loc, tileType,
969 srcBuffLhs, indicesLhs);
972 amx::TileLoadOp loadRhs;
975 SmallVector<OpFoldResult> indexVals;
976 llvm::TypeSwitch<Operation *>(contractOp.getRhs().getDefiningOp())
977 .Case<TransferReadOp, LoadOp>([&](
auto readOp) {
978 indexVals = SmallVector<OpFoldResult>(readOp.getIndices().begin(),
979 readOp.getIndices().end());
980 vecTy = readOp.getType();
983 SmallVector<OpFoldResult> strides(indexVals.size(), one);
986 SmallVector<int64_t> subviewShape(indexVals.size() - vecTy.getRank(),
988 llvm::append_range(subviewShape, vecTy.getShape());
989 SmallVector<OpFoldResult> sizes =
991 auto subview = memref::SubViewOp::create(rewriter, loc, srcBuffRhs,
992 indexVals, sizes, strides);
993 auto bufferType = MemRefType::get({16, (16 * blockingFactor)}, ipType);
994 auto packedBuffer = memref::AllocaOp::create(rewriter, loc, bufferType);
1000 (blockingFactor * 16));
1001 Value nextLoadIndx =
1004 rewriter, loc, 16 * (blockingFactor / 2));
1007 rewriter, loc, c0, uBound, step,
ValueRange{},
1008 [&](OpBuilder &nestedBuilder, Location loc, Value iv,
1011 arith::AddIOp::create(rewriter, loc, nextLoadIndx, iv);
1015 size_t numOffsets = indicesRhs.size();
1016 SmallVector<Value>
indices(numOffsets, c0);
1018 auto vec1 = vector::LoadOp::create(
1020 VectorType::get(16 * (blockingFactor / 2), ipType), subview,
1023 indices[numOffsets - 2] = i1_load;
1024 auto vec2 = vector::LoadOp::create(
1026 VectorType::get(16 * (blockingFactor / 2), ipType), subview,
1029 vector::ShuffleOp writeVal1;
1030 vector::ShuffleOp writeVal2;
1032 if (blockingFactor == 2) {
1034 writeVal1 = vector::ShuffleOp::create(
1035 rewriter, loc, VectorType::get({16}, ipType), vec1, vec2,
1036 ArrayRef<int64_t>{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21,
1039 writeVal2 = vector::ShuffleOp::create(
1040 rewriter, loc, VectorType::get({16}, ipType), vec1, vec2,
1041 ArrayRef<int64_t>{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13,
1042 29, 14, 30, 15, 31});
1045 if (blockingFactor == 4) {
1046 writeVal1 = vector::ShuffleOp::create(
1047 rewriter, loc, VectorType::get({32}, ipType), vec1, vec2,
1048 ArrayRef<int64_t>{0, 16, 32, 48, 1, 17, 33, 49,
1049 2, 18, 34, 50, 3, 19, 35, 51,
1050 4, 20, 36, 52, 5, 21, 37, 53,
1051 6, 22, 38, 54, 7, 23, 39, 55});
1053 writeVal2 = vector::ShuffleOp::create(
1054 rewriter, loc, VectorType::get({32}, ipType), vec1, vec2,
1055 ArrayRef<int64_t>{8, 24, 40, 56, 9, 25, 41, 57,
1056 10, 26, 42, 58, 11, 27, 43, 59,
1057 12, 28, 44, 60, 13, 29, 45, 61,
1058 14, 30, 46, 62, 15, 31, 47, 63});
1061 auto rem = arith::DivUIOp::create(
1064 vector::StoreOp::create(rewriter, loc, writeVal1, packedBuffer,
1066 vector::StoreOp::create(rewriter, loc, writeVal2, packedBuffer,
1069 scf::YieldOp::create(nestedBuilder, loc);
1071 loadRhs = amx::TileLoadOp::create(rewriter, loc, tileType, packedBuffer,
1075 loadRhs = amx::TileLoadOp::create(rewriter, loc, tileType, srcBuffRhs,
1079 auto tileTypeAcc = amx::TileType::get({16, 16}, opType);
1080 auto loadAcc = amx::TileLoadOp::create(rewriter, loc, tileTypeAcc,
1081 srcBuffAcc, indicesAcc);
1086 dp = amx::TileMulFOp::create(rewriter, loc, tileTypeAcc, loadLhs,
1090 dp = amx::TileMulIOp::create(rewriter, loc, tileTypeAcc, loadLhs,
1093 auto bufferType = MemRefType::get({16, 16}, opType);
1094 auto resultBuffer = memref::AllocaOp::create(rewriter, loc, bufferType);
1096 amx::TileStoreOp::create(rewriter, loc, resultBuffer,
ValueRange{c0, c0},
1099 auto vectorType = VectorType::get({16, 16}, opType);
1101 (dyn_cast<ShapedType>(resultBuffer.getType())).getRank();
1102 Value padding = ub::PoisonOp::create(rewriter, loc, opType);
1105 SmallVector<bool> inBounds(vectorType.getRank(),
true);
1107 Value vecRow = vector::TransferReadOp::create(
1108 rewriter, loc, vectorType, resultBuffer,
ValueRange{c0, c0}, padding,
1112 if (
auto vecType = dyn_cast<VectorType>(resultOp.getType()))
1113 vecRow = vector::ShapeCastOp::create(rewriter, loc, vecType, vecRow);
1123 SmallVector<scf::ForOp> loopLists;
1124 Operation *current = contractOp;
1134 if (!loopLists.empty())
1138 "Accumulator read and contract op not within scf.for op");
1141 loopLists.push_back(dyn_cast<scf::ForOp>(parent));
1143 if (resultBlock == parent->
getBlock()) {
1150 if (loopLists.size() > 2 || loopLists.size() == 0)
1152 contractOp,
"Rewrite is supported until reduction loop depth of 2.");
1154 if (isAccZeroVectorConstant && !accWrite)
1156 contractOp,
"The result of the contract is not written to memory.");
1158 auto srcIndxLhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
1159 contractOp.getLhs(),
false);
1162 "Failed to get the LHS src.");
1163 auto [srcBuffLhs, indicesLhs] = *srcIndxLhs;
1165 auto srcIndxRhs = getSrcIndxValue(rewriter, contractOp.getLoc(),
1166 contractOp.getRhs(),
false);
1169 "Failed to get the RHS src.");
1170 auto [srcBuffRhs, indicesRhs] = *srcIndxRhs;
1171 Operation *vectorOpLhs;
1172 llvm::TypeSwitch<Operation *>(contractOp.getLhs().getDefiningOp())
1173 .Case<TransferReadOp, LoadOp>([&](
auto readOp) {
1174 vectorOpLhs = readOp.getBase().getDefiningOp();
1177 Operation *vectorOpRhs;
1178 llvm::TypeSwitch<Operation *>(contractOp.getRhs().getDefiningOp())
1179 .Case<TransferReadOp, LoadOp>([&](
auto readOp) {
1180 vectorOpRhs = readOp.getBase().getDefiningOp();
1183 if (!vectorOpLhs || !vectorOpRhs)
1185 contractOp,
"Failed to find LHS or RHS read source operation");
1188 SmallVector<vector::ContractionOp> ops;
1192 SmallVector<std::pair<size_t, Value>> carriedAccs;
1193 for (Operation &op : loopLists[0].getBody()->getOperations()) {
1195 if (
auto contract = dyn_cast<vector::ContractionOp>(op)) {
1196 if (isVnni && !(isVnniOperandRead(
contract.getLhs(), blockingFactor) &&
1197 isVnniOperandRead(
contract.getRhs(), blockingFactor)))
1199 contractOp,
"The LHS or RHS src of an associated contract "
1200 "operation does not read whole VNNI groups.");
1202 LogicalResult validate = validateContractOps(
1203 rewriter,
contract, dimValue, srcBuffLhs, srcBuffRhs,
true);
1208 "The associated contract operations doesn't satisfy "
1209 "the re-write conditions either the dimensions are "
1210 "wrong or MemRef source are different or many users.");
1212 Operation *contractReadOp =
1215 if (isAccZeroVectorConstant != isZeroVectorConstant(contractReadOp))
1217 contractOp,
"The input acc should be a zero constant or "
1218 "transfer_read for all contracts");
1220 Value accInit = getLoopNestInit(
contract.getAcc(), loopLists);
1222 bool carried = !isa_and_present<TransferReadOp, LoadOp>(accInitOp) &&
1223 !isZeroVectorConstant(accInitOp);
1225 if (loopLists.back().getRegion().isAncestor(
1228 contractOp,
"The accumulator should enter the reduction loops "
1229 "through their init args.");
1230 carriedAccs.emplace_back(ops.size(), accInit);
1239 if (!isAccZeroVectorConstant && !carriedAccs.empty() &&
1240 carriedAccs.size() != ops.size())
1242 contractOp,
"The accumulators read from memory can't be mixed with "
1243 "carried in accumulators.");
1246 unsigned int pairCount = 0;
1247 for (
size_t j = 0; j < ops.size(); j++) {
1248 for (
size_t i = j; i < ops.size(); i++) {
1250 pairCount = pairCount + 2;
1254 if (pairCount != ops.size())
1256 contractOp,
"Coudn't find the pair vector contract ");
1259 scf::ForOp innerLoop;
1260 scf::ForOp outerLoop;
1264 if (loopLists.size() == 2) {
1265 outerLoop = loopLists[1];
1266 innerLoop = loopLists[0];
1268 LogicalResult validateOuterLoopStep =
1269 validateLoopStep(rewriter, outerLoop.getStep(), 1);
1270 if (
failed(validateOuterLoopStep))
1273 int64_t stepValue = 16;
1275 stepValue = stepValue * blockingFactor;
1276 LogicalResult validateInnerLoopStep =
1277 validateLoopStep(rewriter, innerLoop.getStep(), stepValue);
1278 if (
failed(validateInnerLoopStep))
1280 contractOp,
"Invalid loop step. The step should be 32 for BF16 and "
1283 SmallVector<Value> loopItrArgs = createTileZeros(
1284 rewriter, outerLoop.getLoc(), opType, outerLoop, ops.size());
1287 newLoop = scf::ForOp::create(
1288 rewriter, outerLoop.getLoc(), outerLoop.getLowerBound(),
1289 outerLoop.getUpperBound(), outerLoop.getStep(), loopItrArgs,
1290 [&](OpBuilder &rewriterOuterLoop, Location locOuterLoop,
1291 Value ivOuterLoop,
ValueRange iterArgsOuterLoop) {
1292 auto newInnerLoop = createLoops(
1293 rewriter, innerLoop.getLoc(), innerLoop.getLowerBound(),
1294 innerLoop.getUpperBound(), innerLoop.getStep(),
1295 iterArgsOuterLoop, ipType, opType, blockingFactor, isVnni,
1296 vectorOpLhs, vectorOpRhs, contractOp, outerLoop, innerLoop,
1297 ops, ivOuterLoop, nullptr, true, nullptr, false, false);
1299 scf::YieldOp::create(rewriterOuterLoop, locOuterLoop,
1300 newInnerLoop.getResults());
1305 bool isInnerLoopUBLarger =
false;
1306 bool isInnerLoopUBHasOddQuot =
false;
1308 int64_t ubVal = 16 * blockingFactor;
1309 Value ub = innerLoop.getUpperBound();
1311 if (
auto intAttr = dyn_cast<IntegerAttr>(constOp.getValue())) {
1312 ubVal = intAttr.getInt();
1316 isInnerLoopUBLarger = ubVal > 16 * blockingFactor;
1317 isInnerLoopUBHasOddQuot =
1318 (((ubVal / (16 * blockingFactor)) % 2) == 1) && isInnerLoopUBLarger;
1327 rewriter, outerLoop.getLoc(), 16 * blockingFactor);
1329 Value spillOuterLoop = arith::SubIOp::create(
1330 rewriter, outerLoop.getLoc(), outerLoop.getUpperBound(), c1);
1331 Value spillInnerLoop =
1332 arith::SubIOp::create(rewriter, innerLoop.getLoc(),
1333 innerLoop.getUpperBound(), spillLoopBound);
1335 MemRefType::get({2, 32, (blockingFactor * 16)}, ipType);
1337 memref::AllocaOp::create(rewriter, outerLoop.getLoc(), bufferType);
1340 IRMapping rhsMapping;
1342 vectorOpRhs->getOperand(
1343 getIndexPosition(contractOp.getRhs(), outerLoop) + 1),
1344 outerLoop.getLowerBound());
1346 vectorOpRhs->getOperand(
1347 getIndexPosition(contractOp.getRhs(), innerLoop) + 1),
1348 innerLoop.getLowerBound());
1349 auto rhsClone = rewriter.
clone(*vectorOpRhs, rhsMapping);
1351 Value quotient_batch = arith::DivUIOp::create(
1352 rewriter, outerLoop.getLoc(), outerLoop.getLowerBound(),
1353 outerLoop.getStep());
1354 Value quotient_k = arith::DivUIOp::create(rewriter, outerLoop.getLoc(),
1355 innerLoop.getLowerBound(),
1356 innerLoop.getStep());
1358 Value quotient_add = arith::AddIOp::create(rewriter, outerLoop.getLoc(),
1359 quotient_batch, quotient_k);
1362 Value
rem = arith::RemUIOp::create(rewriter, outerLoop.getLoc(),
1365 performShuffle(rewriter, outerLoop.getLoc(), rhsClone->getResult(0),
1366 ipType, blockingFactor, packedBuffer,
rem);
1369 auto newLoopNonSpill = scf::ForOp::create(
1370 rewriter, outerLoop.getLoc(), outerLoop.getLowerBound(),
1371 spillOuterLoop, outerLoop.getStep(), loopItrArgs,
1372 [&](OpBuilder &rewriterOuterLoop, Location locOuterLoop,
1373 Value ivOuterLoop,
ValueRange iterArgsOuterLoop) {
1374 auto newInnerLoop1 = createLoops(
1375 rewriter, innerLoop.getLoc(), innerLoop.getLowerBound(),
1376 spillInnerLoop, innerLoop.getStep(), iterArgsOuterLoop,
1377 ipType, opType, blockingFactor, isVnni, vectorOpLhs,
1378 vectorOpRhs, contractOp, outerLoop, innerLoop, ops,
1379 ivOuterLoop, packedBuffer, true, spillLoopBound,
1380 isInnerLoopUBLarger, isInnerLoopUBHasOddQuot);
1382 auto newInnerLoop = createLoops(
1383 rewriter, innerLoop.getLoc(), spillInnerLoop,
1384 innerLoop.getUpperBound(), innerLoop.getStep(),
1385 newInnerLoop1.getResults(), ipType, opType, blockingFactor,
1386 isVnni, vectorOpLhs, vectorOpRhs, contractOp, outerLoop,
1387 innerLoop, ops, ivOuterLoop, packedBuffer, true, c0,
1388 isInnerLoopUBLarger, isInnerLoopUBHasOddQuot);
1390 scf::YieldOp::create(rewriterOuterLoop, locOuterLoop,
1391 newInnerLoop.getResults());
1395 newLoop = scf::ForOp::create(
1396 rewriter, outerLoop.getLoc(), spillOuterLoop,
1397 outerLoop.getUpperBound(), outerLoop.getStep(),
1398 newLoopNonSpill.getResults(),
1399 [&](OpBuilder &rewriterOuterLoop, Location locOuterLoop,
1400 Value ivOuterLoop,
ValueRange iterArgsOuterLoop) {
1401 auto newInnerLoop1 = createLoops(
1402 rewriter, innerLoop.getLoc(), innerLoop.getLowerBound(),
1403 spillInnerLoop, innerLoop.getStep(), iterArgsOuterLoop,
1404 ipType, opType, blockingFactor, isVnni, vectorOpLhs,
1405 vectorOpRhs, contractOp, outerLoop, innerLoop, ops,
1406 ivOuterLoop, packedBuffer, true, spillLoopBound,
1407 isInnerLoopUBLarger, isInnerLoopUBHasOddQuot);
1409 auto newInnerLoop = createLoops(
1410 rewriter, innerLoop.getLoc(), spillInnerLoop,
1411 innerLoop.getUpperBound(), innerLoop.getStep(),
1412 newInnerLoop1.getResults(), ipType, opType, blockingFactor,
1413 isVnni, vectorOpLhs, vectorOpRhs, contractOp, outerLoop,
1414 innerLoop, ops, ivOuterLoop, packedBuffer, false, c0,
1415 isInnerLoopUBLarger, isInnerLoopUBHasOddQuot);
1417 scf::YieldOp::create(rewriterOuterLoop, locOuterLoop,
1418 newInnerLoop.getResults());
1424 if (loopLists.size() == 1) {
1426 innerLoop = loopLists[0];
1427 int64_t stepValue = 16;
1429 stepValue = stepValue * blockingFactor;
1431 LogicalResult validateInnerLoopStep =
1432 validateLoopStep(rewriter, innerLoop.getStep(), stepValue);
1433 if (
failed(validateInnerLoopStep))
1436 "Invalid loop step. The step should be 32 for BF16 and "
1437 "64 for Int8/F8 or 1 if it is rduction loop other than K.");
1439 SmallVector<Value> loopItrArgs = createTileZeros(
1440 rewriter, innerLoop.getLoc(), opType, innerLoop, ops.size());
1443 newLoop = createLoops(
1444 rewriter, innerLoop.getLoc(), innerLoop.getLowerBound(),
1445 innerLoop.getUpperBound(), innerLoop.getStep(), loopItrArgs, ipType,
1446 opType, blockingFactor, isVnni, vectorOpLhs, vectorOpRhs,
1447 contractOp,
nullptr, innerLoop, ops,
nullptr,
nullptr,
true,
1448 nullptr,
false,
false);
1452 bool isInnerLoopUBLarger =
false;
1453 bool isInnerLoopUBHasOddQuot =
false;
1455 int64_t ubVal = 16 * blockingFactor;
1456 Value ub = innerLoop.getUpperBound();
1458 if (
auto intAttr = dyn_cast<IntegerAttr>(constOp.getValue())) {
1459 ubVal = intAttr.getInt();
1463 isInnerLoopUBLarger = ubVal > 16 * blockingFactor;
1464 isInnerLoopUBHasOddQuot =
1465 (((ubVal / (16 * blockingFactor)) % 2) == 1) && isInnerLoopUBLarger;
1471 int64_t offset = 16 * blockingFactor;
1473 innerLoop.getStep().getDefiningOp<arith::ConstantIndexOp>())
1474 offset = cst.value();
1477 rewriter, innerLoop.getLoc(), offset);
1478 Value spillInnerLoop =
1479 arith::SubIOp::create(rewriter, innerLoop.getLoc(),
1480 innerLoop.getUpperBound(), spillLoopBound);
1483 MemRefType::get({2, 32, (blockingFactor * 16)}, ipType);
1485 memref::AllocaOp::create(rewriter, innerLoop.getLoc(), bufferType);
1488 IRMapping rhsMapping;
1490 vectorOpRhs->getOperand(
1491 getIndexPosition(contractOp.getRhs(), innerLoop) + 1),
1492 innerLoop.getLowerBound());
1493 auto rhsClone = rewriter.
clone(*vectorOpRhs, rhsMapping);
1495 Value quotient_k = arith::DivUIOp::create(rewriter, innerLoop.getLoc(),
1496 innerLoop.getLowerBound(),
1497 innerLoop.getStep());
1500 Value
rem = arith::RemUIOp::create(rewriter, innerLoop.getLoc(),
1503 performShuffle(rewriter, innerLoop.getLoc(), rhsClone->getResult(0),
1504 ipType, blockingFactor, packedBuffer,
rem);
1506 auto newLoopNonSpill = createLoops(
1507 rewriter, innerLoop.getLoc(), innerLoop.getLowerBound(),
1508 spillInnerLoop, innerLoop.getStep(), loopItrArgs, ipType, opType,
1509 blockingFactor, isVnni, vectorOpLhs, vectorOpRhs, contractOp,
1510 nullptr, innerLoop, ops,
nullptr, packedBuffer,
true,
1511 spillLoopBound, isInnerLoopUBLarger, isInnerLoopUBHasOddQuot);
1513 newLoop = createLoops(rewriter, innerLoop.getLoc(), spillInnerLoop,
1514 innerLoop.getUpperBound(), innerLoop.getStep(),
1515 newLoopNonSpill.getResults(), ipType, opType,
1516 blockingFactor, isVnni, vectorOpLhs, vectorOpRhs,
1517 contractOp,
nullptr, innerLoop, ops,
nullptr,
1518 packedBuffer,
false, c0, isInnerLoopUBLarger,
1519 isInnerLoopUBHasOddQuot);
1524 outerLoop = innerLoop;
1529 Location loc = outerLoop.getLoc();
1531 SmallVector<Value> indicesAcc;
1533 if (isAccZeroVectorConstant) {
1534 llvm::TypeSwitch<Operation *>(accWrite)
1535 .Case<vector::TransferWriteOp, vector::StoreOp>([&](
auto writeOp) {
1536 srcBuffAcc = writeOp->getOperand(1);
1538 auto indices = writeOp.getIndices();
1539 indicesAcc.reserve(
indices.size());
1542 indices, std::back_inserter(indicesAcc), [&](OpFoldResult ofr) {
1547 llvm::TypeSwitch<Operation *>(accReadOp).Case<TransferReadOp, LoadOp>(
1549 srcBuffAcc = readOp.getOperand(0);
1551 auto indices = readOp.getIndices();
1552 indicesAcc.reserve(
indices.size());
1554 llvm::transform(
indices, std::back_inserter(indicesAcc),
1555 [&](OpFoldResult ofr) {
1557 rewriter, loc, ofr);
1562 auto outputShapes = cast<MemRefType>(srcBuffAcc.
getType()).getShape();
1563 unsigned int M = outputShapes[outputShapes.size() - 2];
1564 unsigned int N = outputShapes[outputShapes.size() - 1];
1566 SmallVector<Value> dps = newLoop.getResults();
1567 auto bufferType = MemRefType::get({M, N}, opType);
1568 auto resultBuffer = memref::AllocaOp::create(rewriter, loc, bufferType);
1571 for (
unsigned int i = 0, k = 0; i < M; i = i + 16) {
1572 for (
unsigned int j = 0; j < N; j = j + 16) {
1575 amx::TileStoreOp::create(rewriter, loc, resultBuffer,
1587 bool addAccFromMemory = !isAccZeroVectorConstant && carriedAccs.empty();
1589 if (!isVnni || addAccFromMemory) {
1594 rewriter, loc, c0, nBound, one,
ValueRange{},
1595 [&](OpBuilder &nestedBuilder, Location loc, Value iv,
1597 auto row = vector::LoadOp::create(rewriter, loc,
1598 VectorType::get(16, opType),
1601 auto row2 = vector::LoadOp::create(
1602 rewriter, loc, VectorType::get(16, opType), resultBuffer,
1605 Value writeVal1 = row;
1606 Value writeVal2 = row2;
1609 writeVal1 = vector::ShuffleOp::create(
1610 rewriter, loc, VectorType::get(16, opType), row, row2,
1611 ArrayRef<int64_t>{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20,
1614 writeVal2 = vector::ShuffleOp::create(
1615 rewriter, loc, VectorType::get(16, opType), row, row2,
1616 ArrayRef<int64_t>{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14,
1617 15, 28, 29, 30, 31});
1620 if (addAccFromMemory) {
1621 indicesAcc[indicesAcc.size() - 2] = iv;
1622 indicesAcc[indicesAcc.size() - 1] = c0;
1624 Value valueCRow1 = vector::LoadOp::create(
1625 rewriter, loc, VectorType::get(16, opType), srcBuffAcc,
1627 indicesAcc[indicesAcc.size() - 1] = c16;
1629 Value valueCRow2 = vector::LoadOp::create(
1630 rewriter, loc, VectorType::get(16, opType), srcBuffAcc,
1635 arith::AddFOp::create(rewriter, loc, writeVal1, valueCRow1);
1638 arith::AddFOp::create(rewriter, loc, writeVal2, valueCRow2);
1643 arith::AddIOp::create(rewriter, loc, writeVal1, valueCRow1);
1646 arith::AddIOp::create(rewriter, loc, writeVal2, valueCRow2);
1650 vector::StoreOp::create(rewriter, loc, writeVal1, resultBuffer,
1652 vector::StoreOp::create(rewriter, loc, writeVal2, resultBuffer,
1655 scf::YieldOp::create(nestedBuilder, loc);
1659 SmallVector<Value> writeResults;
1660 for (
unsigned int i = 0; i < M; i = i + 16) {
1661 for (
unsigned int j = 0; j < N; j = j + 16) {
1665 auto vectorType = VectorType::get({16, 16}, opType);
1668 (dyn_cast<ShapedType>(resultBuffer.getType())).getRank();
1669 Value padding = ub::PoisonOp::create(rewriter, loc, opType);
1672 SmallVector<bool> inBounds(vectorType.getRank(),
true);
1674 auto vec1 = vector::TransferReadOp::create(
1675 rewriter, loc, vectorType, resultBuffer,
1676 ValueRange{indexOp_i, indexOp_j}, padding, map, inBounds);
1677 writeResults.push_back(vec1);
1681 for (
auto [idx, acc] : carriedAccs) {
1682 Type resultType = writeResults[idx].getType();
1683 if (acc.
getType() != resultType)
1684 acc = vector::ShapeCastOp::create(rewriter, loc, resultType, acc);
1685 if (isa<FloatType>(opType))
1687 arith::AddFOp::create(rewriter, loc, writeResults[idx], acc);
1690 arith::AddIOp::create(rewriter, loc, writeResults[idx], acc);
1694 for (
size_t i = 0; i < ops.size(); i++) {
1695 vector::ContractionOp contOp = ops[i];
1696 Value vecRow = writeResults[i];
1699 if (
auto vecType = dyn_cast<VectorType>(resultWriteOp.
getType()))
1700 vecRow = vector::ShapeCastOp::create(rewriter, loc, vecType,
1714 patterns.
add<VectorContractToAMXDotProduct>(patterns.
getContext());
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static void contract(RootOrderingGraph &graph, ArrayRef< Value > cycle, const DenseMap< Value, unsigned > &parentDepths, DenseMap< Value, Value > &actualSource, DenseMap< Value, Value > &actualTarget)
Contracts the specified cycle in the given graph in-place.
static AffineMap getMinorIdentityMap(unsigned dims, unsigned results, MLIRContext *context)
Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
Attributes are known-constant values of operations.
IntegerAttr getIndexAttr(int64_t value)
FloatType getF8E5M2Type()
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
FloatType getF8E4M3FNType()
This is a utility class for mapping one set of IR entities to another.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
IRValueT get() const
Return the current value being used by this operand.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
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.
This class represents a single result from folding an operation.
This class represents an operand of an operation.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the Operation.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
Block * getBlock()
Returns the operation block that contains this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
unsigned getNumOperands()
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
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.
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,...
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
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...
Type getType() const
Return the type of this value.
user_iterator user_begin() const
unsigned getNumUses() const
This method computes the number of uses of this Value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
use_iterator use_begin() const
Specialization of arith.constant op that returns an integer of index type.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Operation * getOwner() const
Return the owner of this operand.
mlir::x86::AMXTileType TileType
Operation * traceToVectorWriteLikeUserOperation(Value v)
bool isInVnniLayout(Operation *op, llvm::ArrayRef< AffineMap > indexingMaps, std::optional< unsigned > blockingFactor=std::nullopt)
Value contractionUsersAfterYield(Value v)
Operation * traceToVectorReadLikeParentOperation(Value v)
bool validatePairVectorContract(vector::ContractionOp contractOp, vector::ContractionOp pairContOp, bool rhsHasMultipleNonUnitDims, int64_t nonUnitDimValue)
void populateVectorContractToAMXDotProductPatterns(RewritePatternSet &patterns)
Include the generated interface declarations.
OpFoldResult getAsIndexOpFoldResult(MLIRContext *ctx, int64_t val)
Convert int64_t to integer attributes of index type and return them as OpFoldResult.
bool isZeroIntegerOrFloat(OpFoldResult v)
Return "true" if v is an integer/float value/attribute with constant value zero.
bool isZeroInteger(OpFoldResult v)
Return "true" if v is an integer value/attribute with constant value 0.
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
SmallVector< int64_t, 2 > ReassociationIndices
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.