| 579 | )"; |
| 580 | |
| 581 | inline KernelCode createMatmulWithTranspose(const char *shaderTemplate, const size_t M, |
| 582 | const size_t K, const size_t N, const size_t BM, |
| 583 | const size_t BK, const size_t BN, |
| 584 | const size_t TM, const size_t TN, |
| 585 | const Shape &workgroupSize = {256, 1, 1}, |
| 586 | NumType precision = kf32) { |
| 587 | assert(BM % TM == 0); |
| 588 | assert(BN % TN == 0); |
| 589 | assert(K % BK == 0); |
| 590 | assert(M % BM == 0); |
| 591 | assert(N % BN == 0); |
| 592 | // # threads = tile A size == tile B size == # threads for computing C |
| 593 | int num_threads = BM * BN / (TM * TN); |
| 594 | std::string codeString(shaderTemplate); |
| 595 | replaceAll(codeString, {{"{{workgroupSize}}", toString(workgroupSize)}, |
| 596 | {"{{precision}}", toString(precision)}, |
| 597 | {"{{M}}", toString(M)}, |
| 598 | {"{{K}}", toString(K)}, |
| 599 | {"{{N}}", toString(N)}, |
| 600 | {"{{BM}}", toString(BM)}, |
| 601 | {"{{BK}}", toString(BK)}, |
| 602 | {"{{BN}}", toString(BN)}, |
| 603 | {"{{TM}}", toString(TM)}, |
| 604 | {"{{TN}}", toString(TN)}, |
| 605 | {"{{NUM_TILEA}}", toString(BM * BK / num_threads)}, |
| 606 | {"{{NUM_TILEB}}", toString(BN * BK / num_threads)}, |
| 607 | {"{{TN4}}", toString(TN / 4)}, |
| 608 | {"{{N4}}", toString(N / 4)}, |
| 609 | {"{{BN4}}", toString(BN / 4)}, |
| 610 | }); |
| 611 | std::string unrolledCode = loopUnrolling(codeString); |
| 612 | // LOG(kDefLog, kInfo, "Unrolled code:\n%s", unrolledCode.c_str()); |
| 613 | return {unrolledCode, workgroupSize, precision}; |
| 614 | } |
| 615 | |
| 616 | /** |
| 617 | * @brief No-Op shader with matmul bindings for performance testing |
no test coverage detected