31#include "llvm/Support/Casting.h"
39enum class CuSparseFormat {
52static void markAsGPUContainer(ModuleOp topModule) {
53 topModule->setDiscardableAttr(gpu::GPUDialect::getContainerModuleAttrName(),
54 UnitAttr::get(topModule->getContext()));
59static gpu::GPUModuleOp genGPUModule(
OpBuilder &builder, ModuleOp topModule) {
60 for (
auto op : topModule.getBodyRegion().getOps<gpu::GPUModuleOp>())
62 markAsGPUContainer(topModule);
64 return gpu::GPUModuleOp::create(builder, topModule->getLoc(),
69static gpu::GPUFuncOp genGPUFunc(
OpBuilder &builder, gpu::GPUModuleOp gpuModule,
73 unsigned kernelNumber = 0;
77 (
"kernel" + Twine(kernelNumber++)).toStringRef(kernelName);
78 }
while (gpuModule.lookupSymbol(kernelName));
83 argsTp.push_back(arg.getType());
84 FunctionType type = FunctionType::get(gpuModule->getContext(), argsTp, {});
86 gpu::GPUFuncOp::create(builder, gpuModule->getLoc(), kernelName, type);
87 gpuFunc.setKernel(
true);
92static Value genLaunchGPUFunc(
OpBuilder &builder, gpu::GPUFuncOp gpuFunc,
95 unsigned numThreads) {
102 return gpu::LaunchFuncOp::create(builder, loc, gpuFunc, gridSize, blckSize,
116 MemRefType memTp = cast<MemRefType>(mem.
getType());
118 UnrankedMemRefType::get(memTp.getElementType(), 0);
119 Value cast = memref::CastOp::create(builder, loc, resTp, mem);
120 gpu::HostRegisterOp::create(builder, loc, cast);
127 gpu::HostUnregisterOp::create(builder, loc, cast);
133 return gpu::WaitOp::create(builder, loc, tokenType,
ValueRange())
140 gpu::WaitOp::create(builder, loc,
Type(), operands);
149 auto tp = cast<ShapedType>(mem.
getType());
150 auto elemTp = tp.getElementType();
151 auto shape = tp.getShape();
152 auto memTp = MemRefType::get(
shape, elemTp);
154 for (
unsigned r = 0, rank = tp.getRank(); r < rank; r++) {
155 if (
shape[r] == ShapedType::kDynamic) {
157 dynamicSizes.push_back(dimOp);
160 return gpu::AllocOp::create(builder, loc,
TypeRange({memTp, token.
getType()}),
167 const auto memTp = MemRefType::get({ShapedType::kDynamic}, type);
168 return memref::AllocOp::create(builder, loc, memTp, size).getResult();
174 const auto memTp = MemRefType::get({ShapedType::kDynamic}, type);
175 return gpu::AllocOp::create(builder, loc,
TypeRange({memTp, token.
getType()}),
182 return genAllocBuffer(builder, loc, builder.
getI8Type(), size, token);
188 return gpu::DeallocOp::create(builder, loc, token.
getType(), token, mem)
195 return gpu::MemcpyOp::create(builder, loc, token.
getType(), token, dst, src)
202 Value firstToken = genFirstWait(builder, loc);
203 auto alloc = genAllocMemRef(builder, loc,
b, firstToken);
204 Value devMem = alloc.getResult(0);
205 Value depToken = alloc.getAsyncToken();
206 tokens.push_back(genCopyMemRef(builder, loc, devMem,
b, depToken));
213 auto tensorType = llvm::cast<ShapedType>(
tensor.getType());
215 MemRefType::get(tensorType.getShape(), tensorType.getElementType());
216 return bufferization::ToBufferOp::create(rewriter, loc, memrefType,
tensor);
228 bool useHostRegistrationForOut) {
231 for (
Value s : scalars)
235 if (useHostRegistrationForOut) {
236 out = genHostRegisterMemref(builder, loc,
b);
238 useHostRegistrationForOut =
false;
241 args.push_back(genAllocCopy(builder, loc,
b, tokens));
259 unsigned base = scalars.size();
264 for (
unsigned i = base, e = args.size(); i < e; i++) {
265 unsigned bufIdx = i - base;
269 if (copyBack[bufIdx]) {
270 if (out && bufIdx == 0) {
271 genHostUnregisterMemref(builder, loc, out);
276 genCopyMemRef(builder, loc, buffers[bufIdx], args[i], kernelToken);
278 firstToken = genFirstWait(builder, loc);
280 tokens.push_back(genDeallocMemRef(builder, loc, args[i], firstToken));
285static void genGPUCode(
PatternRewriter &rewriter, gpu::GPUFuncOp gpuFunc,
286 scf::ParallelOp forallOp,
297 for (
Value c : constants)
299 for (
Value s : scalars)
308 Value bid = gpu::BlockIdOp::create(rewriter, loc, gpu::Dimension::x);
309 Value bsz = gpu::BlockDimOp::create(rewriter, loc, gpu::Dimension::x);
310 Value tid = gpu::ThreadIdOp::create(rewriter, loc, gpu::Dimension::x);
311 Value gsz = gpu::GridDimOp::create(rewriter, loc, gpu::Dimension::x);
312 Value mul = arith::MulIOp::create(rewriter, loc, bid, bsz);
313 Value row = arith::AddIOp::create(rewriter, loc,
mul, tid);
314 Value inc = arith::MulIOp::create(rewriter, loc, bsz, gsz);
322 Value upper = irMap.
lookup(forallOp.getUpperBound()[0]);
323 scf::ForOp forOp = scf::ForOp::create(rewriter, loc, row, upper, inc);
329 forOp.getRegion().begin(), irMap);
336 gpu::ReturnOp::create(rewriter, gpuFunc->getLoc());
344static bool matchAddOfArgs(
Block *block,
Value val) {
346 if (isa<arith::AddFOp, arith::AddIOp>(def)) {
349 return (def->getOperand(0) == a && def->getOperand(1) ==
b) ||
350 (def->getOperand(0) ==
b && def->getOperand(1) == a);
357static bool matchMulOfArgs(
Block *block,
Value val) {
359 if (isa<arith::MulFOp, arith::MulIOp>(def)) {
362 return (def->getOperand(0) == a && def->getOperand(1) ==
b) ||
363 (def->getOperand(0) ==
b && def->getOperand(1) == a);
370static bool matchSumOfMultOfArgs(linalg::GenericOp op) {
371 auto yieldOp = cast<linalg::YieldOp>(op.getRegion().front().getTerminator());
372 if (
auto *def = yieldOp.getOperand(0).getDefiningOp()) {
373 if (isa<arith::AddFOp, arith::AddIOp>(def)) {
374 Value x = op.getBlock()->getArguments()[2];
375 return (def->getOperand(0) == x &&
376 matchMulOfArgs(op.getBlock(), def->getOperand(1))) ||
377 (def->getOperand(1) == x &&
378 matchMulOfArgs(op.getBlock(), def->getOperand(0)));
385static bool matchSumReductionOfMulUnary(linalg::GenericOp op) {
386 auto yieldOp = cast<linalg::YieldOp>(op.getRegion().front().getTerminator());
388 Value s_out = op.getBlock()->getArguments()[2];
390 yieldOp.getOperand(0).getDefiningOp<sparse_tensor::ReduceOp>()) {
393 if (s_out == redOp->getOperand(0))
394 other = redOp->getOperand(1);
395 else if (s_out == redOp->getOperand(1))
396 other = redOp->getOperand(0);
401 if (
auto unOp = other.
getDefiningOp<sparse_tensor::UnaryOp>()) {
402 if (s_out != unOp->getOperand(0) || !unOp.getAbsentRegion().empty())
405 auto yieldUn = cast<sparse_tensor::YieldOp>(
406 unOp.getRegion(0).front().getTerminator());
407 auto yieldRed = cast<sparse_tensor::YieldOp>(
408 redOp.getRegion().front().getTerminator());
409 return matchMulOfArgs(op.getBlock(), yieldUn.getOperand(0)) &&
410 matchAddOfArgs(&redOp.getRegion().front(), yieldRed.getOperand(0));
417static bool isDenseTensor(
Value v) {
419 return sTp.getDimRank() == sTp.getLvlRank() && sTp.isAllDense();
433 isAdmissibleMetaData(aTp);
457 assert(dims.size() == 2);
458 return dims[0] == dims[1] && dims[0] > 1;
470static bool isConversionInto24(
Value v) {
472 Value a = cnv.getResult();
473 Value d = cnv.getSource();
475 return isDenseTensor(d) && isAdmissible24(aTp);
488 return CuSparseFormat::kNone;
490 if (isAdmissibleCOO(aTp))
491#ifdef CUSPARSE_COO_AOS
492 return isMatVec ? CuSparseFormat::kCOO : CuSparseFormat::kNone;
494 return enableRT ? CuSparseFormat::kCOO : CuSparseFormat::kNone;
496 if (isAdmissibleCSR(aTp))
497 return CuSparseFormat::kCSR;
498 if (isAdmissibleCSC(aTp))
499 return CuSparseFormat::kCSC;
500 if (isAdmissibleBSR(aTp))
501 return CuSparseFormat::kBSR;
502 return CuSparseFormat::kNone;
507 CuSparseFormat format,
bool enableRT) {
508 if (format == CuSparseFormat::kCOO) {
511 return ToCoordinatesOp::create(builder, loc, a, 0);
512 return ToCoordinatesBufferOp::create(builder, loc, a);
515 return ToPositionsOp::create(builder, loc, a, 1);
520 CuSparseFormat format,
bool enableRT) {
521 bool isCOO = format == CuSparseFormat::kCOO;
522 if (isCOO && !enableRT)
525 return ToCoordinatesOp::create(builder, loc, a, 1);
533 CuSparseFormat format,
bool enableRT) {
534 if (format == CuSparseFormat::kCOO) {
538 return gpu::CreateCooOp::create(builder, loc, handleTp, tokenTp, token,
539 sz1, sz2, nseA, rowA, colA, valA);
541#ifdef CUSPARSE_COO_AOS
543 return gpu::CreateCooAoSOp::create(builder, loc, handleTp, tokenTp, token,
544 sz1, sz2, nseA, rowA, valA);
546 llvm_unreachable(
"gpu::CreateCooAoSOp is deprecated");
550 if (format == CuSparseFormat::kCSR)
551 return gpu::CreateCsrOp::create(builder, loc, handleTp, tokenTp, token, sz1,
552 sz2, nseA, rowA, colA, valA);
553 if (format == CuSparseFormat::kCSC)
554 return gpu::CreateCscOp::create(builder, loc, handleTp, tokenTp, token, sz1,
555 sz2, nseA, rowA, colA, valA);
559 assert(format == CuSparseFormat::kBSR);
561 assert(dims.size() == 2 && dims[0] == dims[1]);
562 uint64_t
b = dims[0];
564 Value bRows = arith::DivUIOp::create(builder, loc, sz1, bSz);
565 Value bCols = arith::DivUIOp::create(builder, loc, sz2, bSz);
566 Value bNum = arith::DivUIOp::create(builder, loc, nseA,
568 return gpu::CreateBsrOp::create(builder, loc, handleTp, tokenTp, token, bRows,
569 bCols, bNum, bSz, bSz, rowA, colA, valA);
575 case gpu::TransposeMode::NON_TRANSPOSE:
577 case gpu::TransposeMode::TRANSPOSE:
578 case gpu::TransposeMode::CONJUGATE_TRANSPOSE:
581 llvm_unreachable(
"unhandled transpose mode");
586 linalg::GenericOp op,
bool enableRT,
587 gpu::TransposeMode modeA) {
589 Value a = op.getOperand(0);
590 Value x = op.getOperand(1);
591 Value y = op.getOperand(2);
598 auto format = getCuSparseFormat(aTp, xTp, yTp, enableRT,
true);
599 if (format == CuSparseFormat::kNone || format == CuSparseFormat::kBSR)
606 Value nseA = NumberOfEntriesOp::create(rewriter, loc, a);
610 Value szX = isTranspose ? rows : cols;
611 Value szY = isTranspose ? cols : rows;
612 Value memR = genFirstPosOrCrds(rewriter, loc, a, format, enableRT);
613 Value memC = genSecondCrds(rewriter, loc, a, format, enableRT);
614 Value memV = ToValuesOp::create(rewriter, loc, a);
615 Value rowA = genAllocCopy(rewriter, loc, memR, tokens);
616 Value colA = memC ? genAllocCopy(rewriter, loc, memC, tokens) :
Value();
617 Value valA = genAllocCopy(rewriter, loc, memV, tokens);
618 Value memX = genTensorToMemref(rewriter, loc, x);
619 Value vecX = genAllocCopy(rewriter, loc, memX, tokens);
620 Value memY = genTensorToMemref(rewriter, loc, y);
621 Value vecY = genAllocCopy(rewriter, loc, memY, tokens);
622 genBlockingWait(rewriter, loc, tokens);
630 Value token = genFirstWait(rewriter, loc);
632 genSpMat(rewriter, loc, aTp, spmatHandleTp, tokenTp, token, rows, cols,
633 nseA, rowA, colA, valA, format, enableRT);
636 auto dvecX = gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp,
637 tokenTp, token, vecX, szX);
638 Value dnX = dvecX.getResult(0);
639 token = dvecX.getAsyncToken();
640 auto dvecY = gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp,
641 tokenTp, token, vecY, szY);
642 Value dnY = dvecY.getResult(0);
643 token = dvecY.getAsyncToken();
644 auto dnYType = llvm::cast<ShapedType>(y.
getType()).getElementType();
647 auto bufferComp = gpu::SpMVBufferSizeOp::create(
648 rewriter, loc, indexTp, tokenTp, token, modeA, spMatA, dnX, dnY,
650 Value bufferSz = bufferComp.getResult(0);
651 token = bufferComp.getAsyncToken();
652 auto buf = genAllocBuffer(rewriter, loc, bufferSz, token);
653 Value buffer = buf.getResult(0);
654 token = buf.getAsyncToken();
657 auto spmvComp = gpu::SpMVOp::create(rewriter, loc, tokenTp, token, modeA,
660 token = spmvComp.getAsyncToken();
663 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatA)
665 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnX)
667 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnY)
669 token = genDeallocMemRef(rewriter, loc, rowA, token);
671 token = genDeallocMemRef(rewriter, loc, colA, token);
672 token = genDeallocMemRef(rewriter, loc, valA, token);
673 token = genDeallocMemRef(rewriter, loc, buffer, token);
674 token = genDeallocMemRef(rewriter, loc, vecX, token);
675 token = genCopyMemRef(rewriter, loc, memY, vecY, token);
676 token = genDeallocMemRef(rewriter, loc, vecY, token);
677 tokens.push_back(token);
678 genBlockingWait(rewriter, loc, tokens);
688 linalg::GenericOp op,
bool enableRT,
689 gpu::TransposeMode modeA,
690 gpu::TransposeMode modeB) {
692 Value a = op.getOperand(0);
693 Value b = op.getOperand(1);
694 Value c = op.getOperand(2);
701 auto format = getCuSparseFormat(aTp, bTp, cTp, enableRT,
false);
702 if (format == CuSparseFormat::kNone || format == CuSparseFormat::kBSR)
709 Value nseA = NumberOfEntriesOp::create(rewriter, loc, a);
714 Value szm = isTransposeA ? cols : rows;
715 Value szk = isTransposeA ? rows : cols;
719 Value memR = genFirstPosOrCrds(rewriter, loc, a, format, enableRT);
720 Value memC = genSecondCrds(rewriter, loc, a, format, enableRT);
721 Value memV = ToValuesOp::create(rewriter, loc, a);
722 Value rowA = genAllocCopy(rewriter, loc, memR, tokens);
723 Value colA = memC ? genAllocCopy(rewriter, loc, memC, tokens) :
Value();
724 Value valA = genAllocCopy(rewriter, loc, memV, tokens);
725 Value bufB = genTensorToMemref(rewriter, loc,
b);
726 Value matB = genAllocCopy(rewriter, loc, bufB, tokens);
727 Value bufC = genTensorToMemref(rewriter, loc, c);
728 Value matC = genAllocCopy(rewriter, loc, bufC, tokens);
729 genBlockingWait(rewriter, loc, tokens);
737 Value token = genFirstWait(rewriter, loc);
739 genSpMat(rewriter, loc, aTp, spMatHandleTp, tokenTp, token, rows, cols,
740 nseA, rowA, colA, valA, format, enableRT);
743 auto dmatB = gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp,
744 tokenTp, token, matB, bSizes);
745 Value dnB = dmatB.getResult(0);
746 token = dmatB.getAsyncToken();
748 gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp, tokenTp,
750 Value dnC = dmatC.getResult(0);
751 token = dmatC.getAsyncToken();
752 auto dmatCType = llvm::cast<ShapedType>(c.
getType()).getElementType();
755 auto bufferComp = gpu::SpMMBufferSizeOp::create(
756 rewriter, loc, indexTp, tokenTp, token, modeA, modeB, spMatA, dnB, dnC,
758 Value bufferSz = bufferComp.getResult(0);
759 token = bufferComp.getAsyncToken();
760 auto buf = genAllocBuffer(rewriter, loc, bufferSz, token);
761 Value buffer = buf.getResult(0);
762 token = buf.getAsyncToken();
763 auto dnCType = llvm::cast<ShapedType>(c.
getType()).getElementType();
766 auto spmmComp = gpu::SpMMOp::create(rewriter, loc, tokenTp, token, modeA,
767 modeB, spMatA, dnB, dnC,
769 token = spmmComp.getAsyncToken();
772 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatA)
774 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnB)
776 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnC)
778 token = genDeallocMemRef(rewriter, loc, rowA, token);
780 token = genDeallocMemRef(rewriter, loc, colA, token);
781 token = genDeallocMemRef(rewriter, loc, valA, token);
782 token = genDeallocMemRef(rewriter, loc, buffer, token);
783 token = genDeallocMemRef(rewriter, loc, matB, token);
784 token = genCopyMemRef(rewriter, loc, bufC, matC, token);
785 token = genDeallocMemRef(rewriter, loc, matC, token);
786 tokens.push_back(token);
787 genBlockingWait(rewriter, loc, tokens);
797 linalg::GenericOp op,
bool enableRT) {
799 Value a = op.getOperand(0);
800 Value b = op.getOperand(1);
801 Value c = op.getOperand(2);
805 auto format = CuSparseFormat::kCSR;
809 if (!isAdmissibleCSR(aTp) || !isAdmissibleCSR(bTp) || !isAdmissibleCSR(cTp))
817 Value nseA = NumberOfEntriesOp::create(rewriter, loc, a);
818 Value nseB = NumberOfEntriesOp::create(rewriter, loc,
b);
822 Value amemR = genFirstPosOrCrds(rewriter, loc, a, format, enableRT);
823 Value amemC = genSecondCrds(rewriter, loc, a, format, enableRT);
824 Value amemV = ToValuesOp::create(rewriter, loc, a);
825 Value bmemR = genFirstPosOrCrds(rewriter, loc,
b, format, enableRT);
826 Value bmemC = genSecondCrds(rewriter, loc,
b, format, enableRT);
827 Value bmemV = ToValuesOp::create(rewriter, loc,
b);
828 Value rowA = genAllocCopy(rewriter, loc, amemR, tokens);
829 Value colA = genAllocCopy(rewriter, loc, amemC, tokens);
830 Value valA = genAllocCopy(rewriter, loc, amemV, tokens);
831 Value rowB = genAllocCopy(rewriter, loc, bmemR, tokens);
832 Value colB = genAllocCopy(rewriter, loc, bmemC, tokens);
833 Value valB = genAllocCopy(rewriter, loc, bmemV, tokens);
834 genBlockingWait(rewriter, loc, tokens);
842 Value token = genFirstWait(rewriter, loc);
844 genSpMat(rewriter, loc, aTp, spmatHandleTp, tokenTp, token, szm, szk,
845 nseA, rowA, colA, valA, format, enableRT);
849 genSpMat(rewriter, loc, bTp, spmatHandleTp, tokenTp, token, szk, szn,
850 nseB, rowB, colB, valB, format, enableRT);
857 Value mplus1 = arith::AddIOp::create(rewriter, loc, szm, one);
858 auto e1 = genAllocBuffer(rewriter, loc, cTp.
getPosType(), mplus1, token);
859 Value rowC = e1.getResult(0);
860 token = e1.getAsyncToken();
861 auto e2 = genAllocBuffer(rewriter, loc, cTp.
getCrdType(), zero, token);
862 Value colC = e2.getResult(0);
863 token = e2.getAsyncToken();
864 auto e3 = genAllocBuffer(rewriter, loc, dnCType, zero, token);
865 Value valC = e3.getResult(0);
866 token = e3.getAsyncToken();
868 genSpMat(rewriter, loc, cTp, spmatHandleTp, tokenTp, token, szm, szn,
869 zero, rowC, colC, valC, format, enableRT);
875 gpu::SpGEMMCreateDescrOp::create(rewriter, loc, descTp, tokenTp, token);
878 Operation *work1 = gpu::SpGEMMWorkEstimationOrComputeOp::create(
879 rewriter, loc, indexTp, tokenTp, token, desc,
880 gpu::TransposeMode::NON_TRANSPOSE, gpu::TransposeMode::NON_TRANSPOSE,
881 spMatA, spMatB, spMatC, dnCType, zero, valC,
882 gpu::SpGEMMWorkEstimationOrComputeKind::WORK_ESTIMATION);
885 auto buf1 = genAllocBuffer(rewriter, loc, bufferSz1, token);
886 Value buffer1 = buf1.getResult(0);
887 token = buf1.getAsyncToken();
888 Operation *work2 = gpu::SpGEMMWorkEstimationOrComputeOp::create(
889 rewriter, loc, indexTp, tokenTp, token, desc,
890 gpu::TransposeMode::NON_TRANSPOSE, gpu::TransposeMode::NON_TRANSPOSE,
891 spMatA, spMatB, spMatC, dnCType, bufferSz1, buffer1,
892 gpu::SpGEMMWorkEstimationOrComputeKind::WORK_ESTIMATION);
896 Operation *compute1 = gpu::SpGEMMWorkEstimationOrComputeOp::create(
897 rewriter, loc, indexTp, tokenTp, token, desc,
898 gpu::TransposeMode::NON_TRANSPOSE, gpu::TransposeMode::NON_TRANSPOSE,
899 spMatA, spMatB, spMatC, dnCType, zero, valC,
900 gpu::SpGEMMWorkEstimationOrComputeKind::COMPUTE);
903 auto buf2 = genAllocBuffer(rewriter, loc, bufferSz2, token);
904 Value buffer2 = buf2.getResult(0);
905 token = buf2.getAsyncToken();
906 Operation *compute2 = gpu::SpGEMMWorkEstimationOrComputeOp::create(
907 rewriter, loc, indexTp, tokenTp, token, desc,
908 gpu::TransposeMode::NON_TRANSPOSE, gpu::TransposeMode::NON_TRANSPOSE,
909 spMatA, spMatB, spMatC, dnCType, bufferSz2, buffer2,
910 gpu::SpGEMMWorkEstimationOrComputeKind::COMPUTE);
914 Operation *sizes = gpu::SpMatGetSizeOp::create(
915 rewriter, loc, indexTp, indexTp, indexTp, tokenTp, token, spMatC);
918 auto a2 = genAllocBuffer(rewriter, loc, cTp.
getCrdType(), nnz, token);
919 colC = a2.getResult(0);
920 token = a2.getAsyncToken();
921 auto a3 = genAllocBuffer(rewriter, loc, dnCType, nnz, token);
922 valC = a3.getResult(0);
923 token = a3.getAsyncToken();
926 Operation *update = gpu::SetCsrPointersOp::create(
927 rewriter, loc, tokenTp, token, spMatC, rowC, colC, valC);
930 rewriter, loc, tokenTp, token, desc, gpu::TransposeMode::NON_TRANSPOSE,
931 gpu::TransposeMode::NON_TRANSPOSE, spMatA, spMatB, spMatC, dnCType);
932 token =
copy->getResult(0);
937 Value valH = genHostBuffer(rewriter, loc, dnCType, nnz);
940 token = gpu::SpGEMMDestroyDescrOp::create(rewriter, loc, tokenTp, token, desc)
942 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatA)
944 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatB)
946 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatC)
948 token = genCopyMemRef(rewriter, loc, rowH, rowC, token);
949 token = genCopyMemRef(rewriter, loc, colH, colC, token);
950 token = genCopyMemRef(rewriter, loc, valH, valC, token);
951 token = genDeallocMemRef(rewriter, loc, rowA, token);
952 token = genDeallocMemRef(rewriter, loc, colA, token);
953 token = genDeallocMemRef(rewriter, loc, valA, token);
954 token = genDeallocMemRef(rewriter, loc, rowB, token);
955 token = genDeallocMemRef(rewriter, loc, colB, token);
956 token = genDeallocMemRef(rewriter, loc, valB, token);
957 token = genDeallocMemRef(rewriter, loc, rowC, token);
958 token = genDeallocMemRef(rewriter, loc, colC, token);
959 token = genDeallocMemRef(rewriter, loc, valC, token);
960 token = genDeallocMemRef(rewriter, loc, buffer1, token);
961 token = genDeallocMemRef(rewriter, loc, buffer2, token);
962 tokens.push_back(token);
963 genBlockingWait(rewriter, loc, tokens);
967 Value vt = bufferization::ToTensorOp::create(
969 Value rt = bufferization::ToTensorOp::create(
971 Value ct = bufferization::ToTensorOp::create(
980 linalg::GenericOp op) {
982 Value A = op.getOperand(0);
983 Value B = op.getOperand(1);
984 Value C = op.getOperand(2);
992 auto cnv =
A.getDefiningOp<ConvertOp>();
997 if (!isDenseTensor(A) || !isDenseTensor(B) || !isDenseTensor(C))
1004 Value bufA = genTensorToMemref(rewriter, loc, A);
1005 Value matA = genAllocCopy(rewriter, loc, bufA, tokens);
1006 Value bufB = genTensorToMemref(rewriter, loc, B);
1007 Value matB = genAllocCopy(rewriter, loc, bufB, tokens);
1008 Value bufC = genTensorToMemref(rewriter, loc, C);
1009 Value matC = genAllocCopy(rewriter, loc, bufC, tokens);
1010 genBlockingWait(rewriter, loc, tokens);
1021 Value token = genFirstWait(rewriter, loc);
1022 Operation *spGenA = gpu::Create2To4SpMatOp::create(
1023 rewriter, loc, spMatHandleTp, tokenTp, token, szm, szk,
1024 gpu::Prune2To4SpMatFlag::PRUNE_AND_CHECK, matA);
1028 gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp, tokenTp,
1030 Value dnB = dmatB.getResult(0);
1031 token = dmatB.getAsyncToken();
1033 gpu::CreateDnTensorOp::create(rewriter, loc, dnTensorHandleTp, tokenTp,
1035 Value dnC = dmatC.getResult(0);
1036 token = dmatC.getAsyncToken();
1037 auto dmatCType = llvm::cast<ShapedType>(matC.
getType()).getElementType();
1042 auto bufferComp = gpu::SpMMBufferSizeOp::create(
1043 rewriter, loc, bufferTypes, tokenTp, token,
1044 gpu::TransposeMode::NON_TRANSPOSE, gpu::TransposeMode::NON_TRANSPOSE,
1047 token = bufferComp.getAsyncToken();
1050 Value bufferSz1 = bufferComp.getResult(0);
1051 auto buf1 = genAllocBuffer(rewriter, loc, bufferSz1, token);
1052 Value buffer1 = buf1.getResult(0);
1053 token = buf1.getAsyncToken();
1054 Value bufferSz2 = bufferComp.getResult(1);
1055 auto buf2 = genAllocBuffer(rewriter, loc, bufferSz2, token);
1056 Value buffer2 = buf2.getResult(0);
1057 token = buf2.getAsyncToken();
1058 Value bufferSz3 = bufferComp.getResult(2);
1059 auto buf3 = genAllocBuffer(rewriter, loc, bufferSz3, token);
1060 Value buffer3 = buf3.getResult(0);
1061 token = buf3.getAsyncToken();
1064 auto dnCType = llvm::cast<ShapedType>(matC.
getType()).getElementType();
1065 auto spmmComp = gpu::SpMMOp::create(
1066 rewriter, loc, tokenTp, token, spMatA, dnB, dnC, dnCType,
1068 token = spmmComp.getAsyncToken();
1071 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatA)
1073 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnB)
1075 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnC)
1077 token = genDeallocMemRef(rewriter, loc, buffer1, token);
1078 token = genDeallocMemRef(rewriter, loc, buffer2, token);
1079 token = genDeallocMemRef(rewriter, loc, buffer3, token);
1080 token = genDeallocMemRef(rewriter, loc, matA, token);
1081 token = genDeallocMemRef(rewriter, loc, matB, token);
1082 token = genCopyMemRef(rewriter, loc, bufC, matC, token);
1083 token = genDeallocMemRef(rewriter, loc, matC, token);
1084 tokens.push_back(token);
1085 genBlockingWait(rewriter, loc, tokens);
1095 linalg::GenericOp op,
bool enableRT) {
1097 Value a = op.getOperand(0);
1098 Value b = op.getOperand(1);
1099 Value c = op.getOperand(2);
1106 auto format = getCuSparseFormat(cTp, bTp, aTp, enableRT,
false);
1107 if (format == CuSparseFormat::kNone || format == CuSparseFormat::kCOO ||
1108 format == CuSparseFormat::kCSC)
1116 Value nseC = NumberOfEntriesOp::create(rewriter, loc, c);
1120 Value bufA = genTensorToMemref(rewriter, loc, a);
1121 Value matA = genAllocCopy(rewriter, loc, bufA, tokens);
1122 Value bufB = genTensorToMemref(rewriter, loc,
b);
1123 Value matB = genAllocCopy(rewriter, loc, bufB, tokens);
1124 Value memR = genFirstPosOrCrds(rewriter, loc, c, format, enableRT);
1125 Value memC = genSecondCrds(rewriter, loc, c, format, enableRT);
1126 Value memV = ToValuesOp::create(rewriter, loc, c);
1127 Value rowC = genAllocCopy(rewriter, loc, memR, tokens);
1128 Value colC = memC ? genAllocCopy(rewriter, loc, memC, tokens) :
Value();
1129 Value valC = genAllocCopy(rewriter, loc, memV, tokens);
1130 genBlockingWait(rewriter, loc, tokens);
1138 Value token = genFirstWait(rewriter, loc);
1140 gpu::CreateDnTensorOp::create(rewriter, loc, dnMatHandleTp, tokenTp,
1142 Value dnA = dmatA.getResult(0);
1143 token = dmatA.getAsyncToken();
1145 gpu::CreateDnTensorOp::create(rewriter, loc, dnMatHandleTp, tokenTp,
1147 Value dnB = dmatB.getResult(0);
1148 token = dmatB.getAsyncToken();
1150 genSpMat(rewriter, loc, cTp, spMatHandleTp, tokenTp, token, szm, szn,
1151 nseC, rowC, colC, valC, format, enableRT);
1154 auto dnCType = llvm::cast<ShapedType>(c.
getType()).getElementType();
1157 auto bufferComp = gpu::SDDMMBufferSizeOp::create(
1158 rewriter, loc, indexTp, tokenTp, token, dnA, dnB, spMatC, dnCType);
1159 Value bufferSz = bufferComp.getResult(0);
1160 token = bufferComp.getAsyncToken();
1161 auto buf = genAllocBuffer(rewriter, loc, bufferSz, token);
1162 Value buffer = buf.getResult(0);
1163 token = buf.getAsyncToken();
1166 auto sddmmComp = gpu::SDDMMOp::create(rewriter, loc, tokenTp, token, dnA, dnB,
1167 spMatC, dnCType, buffer);
1168 token = sddmmComp.getAsyncToken();
1171 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnA)
1173 token = gpu::DestroyDnTensorOp::create(rewriter, loc, tokenTp, token, dnB)
1175 token = gpu::DestroySpMatOp::create(rewriter, loc, tokenTp, token, spMatC)
1177 token = genDeallocMemRef(rewriter, loc, buffer, token);
1178 token = genDeallocMemRef(rewriter, loc, matA, token);
1179 token = genDeallocMemRef(rewriter, loc, matB, token);
1180 token = genDeallocMemRef(rewriter, loc, rowC, token);
1182 token = genDeallocMemRef(rewriter, loc, colC, token);
1183 token = genCopyMemRef(rewriter, loc, memV, valC, token);
1184 token = genDeallocMemRef(rewriter, loc, valC, token);
1185 tokens.push_back(token);
1186 genBlockingWait(rewriter, loc, tokens);
1203 using OpRewritePattern<scf::ParallelOp>::OpRewritePattern;
1205 ForallRewriter(MLIRContext *context,
unsigned nT)
1206 : OpRewritePattern(context), numThreads(nT) {};
1208 LogicalResult matchAndRewrite(scf::ParallelOp forallOp,
1209 PatternRewriter &rewriter)
const override {
1215 if (!forallOp->hasDiscardableAttr(
1217 forallOp.getNumReductions() != 0 || forallOp.getNumLoops() != 1 ||
1223 forallOp->walk([&](Operation *op) {
1226 Value val = o.get();
1228 if (
auto arg = dyn_cast<BlockArgument>(val))
1229 block = arg.getOwner();
1232 if (!forallOp.getRegion().findAncestorBlockInRegion(*block))
1233 invariants.insert(val);
1238 SmallVector<Value> constants;
1239 SmallVector<Value> scalars;
1240 SmallVector<Value> buffers;
1244 SmallVector<bool> copyBack;
1245 for (Value val : invariants) {
1248 constants.push_back(val);
1250 scalars.push_back(val);
1251 else if (isa<MemRefType>(tp)) {
1252 buffers.push_back(val);
1256 bool isWrite =
false;
1257 for (Operation *user : val.
getUsers()) {
1258 if (isa<memref::StoreOp>(user)) {
1262 if (
auto memInterface = dyn_cast<MemoryEffectOpInterface>(user)) {
1263 if (memInterface.getEffectOnValue<MemoryEffects::Write>(val)) {
1269 copyBack.push_back(isWrite);
1277 Location loc = forallOp->getLoc();
1278 SmallVector<Value> args;
1279 SmallVector<Value> tokens;
1280 Value out = genParametersIn(rewriter, loc, scalars, buffers, args, tokens,
1284 ModuleOp topModule = forallOp->getParentOfType<ModuleOp>();
1285 auto gpuModule = genGPUModule(rewriter, topModule);
1286 auto gpuFunc = genGPUFunc(rewriter, gpuModule, args);
1287 genGPUCode(rewriter, gpuFunc, forallOp, constants, scalars, buffers);
1293 genBlockingWait(rewriter, loc, tokens);
1296 genLaunchGPUFunc(rewriter, gpuFunc, args, tokens, numThreads);
1298 genParametersOut(rewriter, loc, out, kernelToken, scalars, buffers, args,
1300 genBlockingWait(rewriter, loc, tokens);
1306 unsigned numThreads;
1316 using OpRewritePattern<linalg::GenericOp>::OpRewritePattern;
1318 LinalgOpRewriter(MLIRContext *context,
bool rt)
1319 : OpRewritePattern(context), enableRT(rt) {}
1321 LogicalResult matchAndRewrite(linalg::GenericOp op,
1322 PatternRewriter &rewriter)
const override {
1323 if (op.getNumDpsInits() != 1)
1328 if (!op.hasPureTensorSemantics())
1331 const unsigned numLoops = op.getNumLoops();
1332 const unsigned numTensors = op->getNumOperands();
1333 const auto iteratorTypes = op.getIteratorTypesArray();
1334 SmallVector<AffineMap, 4> maps = op.getIndexingMapsArray();
1336 using MapList = ArrayRef<ArrayRef<AffineExpr>>;
1337 auto infer = [&](MapList m) {
1347 if (numLoops == 2 && numTensors == 3 &&
1350 matchSumOfMultOfArgs(op)) {
1351 if (maps == infer({{i, j}, {j}, {i}}))
1352 return rewriteSpMV(rewriter, op, enableRT,
1353 gpu::TransposeMode::NON_TRANSPOSE);
1355 if (maps == infer({{j, i}, {j}, {i}}))
1356 return rewriteSpMV(rewriter, op, enableRT,
1357 gpu::TransposeMode::TRANSPOSE);
1361 if (numLoops == 3 && numTensors == 3 &&
1365 matchSumOfMultOfArgs(op)) {
1366 if (maps == infer({{i, k}, {k, j}, {i, j}})) {
1367 if (!isDenseTensor(op.getOperand(0)) &&
1368 !isDenseTensor(op.getOperand(1)))
1369 return rewriteSpGEMM(rewriter, op, enableRT);
1370 if (isConversionInto24(op.getOperand(0)))
1371 return rewrite2To4SpMM(rewriter, op);
1372 return rewriteSpMM(rewriter, op, enableRT,
1373 gpu::TransposeMode::NON_TRANSPOSE,
1374 gpu::TransposeMode::NON_TRANSPOSE);
1377 if (maps == infer({{k, i}, {k, j}, {i, j}}))
1378 return rewriteSpMM(rewriter, op, enableRT,
1379 gpu::TransposeMode::TRANSPOSE,
1380 gpu::TransposeMode::NON_TRANSPOSE);
1381 if (maps == infer({{i, k}, {j, k}, {i, j}}))
1382 return rewriteSpMM(rewriter, op, enableRT,
1383 gpu::TransposeMode::NON_TRANSPOSE,
1384 gpu::TransposeMode::TRANSPOSE);
1385 if (maps == infer({{k, i}, {j, k}, {i, j}}))
1386 return rewriteSpMM(rewriter, op, enableRT,
1387 gpu::TransposeMode::TRANSPOSE,
1388 gpu::TransposeMode::TRANSPOSE);
1392 if (numLoops == 3 && numTensors == 3 &&
1396 maps == infer({{i, k}, {k, j}, {i, j}}) &&
1397 matchSumReductionOfMulUnary(op)) {
1398 return rewriteSDDMM(rewriter, op, enableRT);
1421 unsigned numThreads) {
1422 patterns.
add<ForallRewriter>(patterns.
getContext(), numThreads);
1427 patterns.
add<LinalgOpRewriter>(patterns.
getContext(), enableRT);
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static FailureOr< bool > isTransposed(vector::TransferReadOp op)
Check if the loaded matrix operand requires transposed.
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...
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
BlockArgListType getArguments()
Ty getType(Args &&...args)
Get or construct an instance of the type Ty with provided arguments.
This is a utility class for mapping one set of IR entities to another.
auto lookup(T from) const
Lookup a mapped value within the map.
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...
This class helps build Operations.
InsertPoint saveInsertionPoint() const
Return a saved insertion point.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void restoreInsertionPoint(InsertPoint ip)
Restore the insert point to a previously saved point.
void cloneRegionBefore(Region ®ion, Region &parent, Region::iterator before, IRMapping &mapping)
Clone the blocks that belong to "region" before the given position in another region "parent".
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Operation is the basic unit of execution within MLIR.
Block * getBlock()
Returns the operation block that contains this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
MutableArrayRef< OpOperand > getOpOperands()
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 eraseBlock(Block *block)
This method erases all operations in a block.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
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 isIntOrIndex() const
Return true if this is an integer (of any signedness) or an index 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...
Type getType() const
Return the type of this value.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static constexpr llvm::StringLiteral getLoopEmitterLoopAttrName()
A wrapper around RankedTensorType, which has three goals:
bool isSingletonLvl(Level l) const
Type getElementType() const
unsigned getCrdWidth() const
Returns the coordinate-overhead bitwidth, defaulting to zero.
bool hasEncoding() const
Returns true for tensors which have an encoding, and false for those which do not.
Dimension getDimRank() const
Returns the dimension-rank.
bool isNOutOfMLvl(Level l) const
Type getCrdType() const
Returns the coordinate-overhead MLIR type, defaulting to IndexType.
bool isIdentity() const
Returns true if the dimToLvl mapping is the identity.
bool isCompressedLvl(Level l) const
Level getLvlRank() const
Returns the level-rank.
unsigned getPosWidth() const
Returns the position-overhead bitwidth, defaulting to zero.
bool isPermutation() const
Returns true if the dimToLvl mapping is a permutation.
bool isDenseLvl(Level l) const
AffineMap getDimToLvl() const
Returns the dimToLvl mapping (or the null-map for the identity).
Type getPosType() const
Returns the position-overhead MLIR type, defaulting to IndexType.
bool isOrderedLvl(Level l) const
bool isUniqueLvl(Level l) const
bool isParallelIterator(utils::IteratorType iteratorType)
Check if iterator type has "parallel" semantics.
bool isReductionIterator(utils::IteratorType iteratorType)
Check if iterator type has "reduction" semantics.
Value createOrFoldDimOp(OpBuilder &b, Location loc, Value val, int64_t dim)
Create one memref::DimOp or tensor::DimOp depending on the type of val.
Type getTensorTypeFromMemRefType(Type type)
Return an unranked/ranked tensor type for the given unranked/ranked memref type.
Value constantIndex(OpBuilder &builder, Location loc, int64_t i)
Generates a constant of index type.
SparseTensorType getSparseTensorType(Value val)
Convenience methods to obtain a SparseTensorType from a Value.
SmallVector< unsigned > getBlockSize(AffineMap dimToLvl)
Given the dimToLvl map, returns the block sizes in a vector.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
void populateSparseGPULibgenPatterns(RewritePatternSet &patterns, bool enableRT)
llvm::SetVector< T, Vector, Set, N > SetVector
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
detail::constant_int_predicate_matcher m_One()
Matches a constant scalar / vector splat / tensor splat integer one.
void populateSparseGPUCodegenPatterns(RewritePatternSet &patterns, unsigned numThreads)
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Utility class for the GPU dialect to represent triples of Values accessible through ....