| 226 | )"; |
| 227 | |
| 228 | inline KernelCode createMatmul3(const char *shaderTemplate, const size_t M, |
| 229 | const size_t K, const size_t N, const size_t BM, |
| 230 | const size_t BK, const size_t BN, |
| 231 | const size_t TM, |
| 232 | const Shape &workgroupSize = {256, 1, 1}, |
| 233 | NumType precision = kf32, |
| 234 | bool unrolling = false) { |
| 235 | assert(BM % TM == 0); |
| 236 | assert(K % BK == 0); |
| 237 | assert(M % BM == 0); |
| 238 | assert(N % BN == 0); |
| 239 | // # threads = tile A size == tile B size == # threads for computing C |
| 240 | assert(/* tile A size */ BM * BK == /* tile B size */ BK * BN); |
| 241 | assert(/* tile A size */ BM * BK == /* # of threads for C */ BM * BN / TM); |
| 242 | std::string codeString(shaderTemplate); |
| 243 | replaceAll(codeString, {{"{{workgroupSize}}", toString(workgroupSize)}, |
| 244 | {"{{precision}}", toString(precision)}, |
| 245 | {"{{M}}", toString(M)}, |
| 246 | {"{{K}}", toString(K)}, |
| 247 | {"{{N}}", toString(N)}, |
| 248 | {"{{BM}}", toString(BM)}, |
| 249 | {"{{BK}}", toString(BK)}, |
| 250 | {"{{BN}}", toString(BN)}, |
| 251 | {"{{TM}}", toString(TM)}}); |
| 252 | if (unrolling) { |
| 253 | std::string unrolledCode = loopUnrolling(codeString); |
| 254 | // LOG(kDefLog, kInfo, "Unrolled code:\n%s", unrolledCode.c_str()); |
| 255 | return {unrolledCode, workgroupSize, precision}; |
| 256 | } else { |
| 257 | return {codeString, workgroupSize, precision}; |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | /* 2D block-tiling |
| 262 | * |
no test coverage detected