| 23 | } |
| 24 | |
| 25 | void CPUUpsample::submitKernels(const Ref<CancellationToken>& ct) |
| 26 | { |
| 27 | if (!src || !dst) |
| 28 | throw std::logic_error("upsampling source/destination not set"); |
| 29 | |
| 30 | if (srcDesc.layout != TensorLayout::chw) |
| 31 | { |
| 32 | const int blockC = getTensorLayoutInfo(srcDesc.layout).blockC; |
| 33 | |
| 34 | ispc::CPUUpsampleKernel kernel; |
| 35 | kernel.src = *src; |
| 36 | kernel.dst = *dst; |
| 37 | |
| 38 | auto kernelFunc = (src->getDataType() == DataType::Float16) |
| 39 | ? ispc::CPUUpsampleKernel_run_f16 |
| 40 | : ispc::CPUUpsampleKernel_run_f32; |
| 41 | |
| 42 | engine->submitFunc([=] |
| 43 | { |
| 44 | parallel_for(kernel.src.C / blockC, kernel.src.H, [&](int cb, int h) |
| 45 | { |
| 46 | kernelFunc(&kernel, cb, h); |
| 47 | }); |
| 48 | }, ct); |
| 49 | } |
| 50 | else |
| 51 | { |
| 52 | const int C = src->getPaddedC(); |
| 53 | const size_t H = src->getH(); |
| 54 | const size_t W = src->getW(); |
| 55 | const float* srcPtr = (float*)src->getPtr(); |
| 56 | float* dstPtr = (float*)dst->getPtr(); |
| 57 | |
| 58 | engine->submitFunc([=] |
| 59 | { |
| 60 | parallel_for(C, H, [&](int c, size_t h) |
| 61 | { |
| 62 | const size_t offset = (c*H + h) * W; |
| 63 | const float* srcPtr_line = srcPtr + offset; |
| 64 | float* dstPtr_line0 = dstPtr + offset * 4; |
| 65 | float* dstPtr_line1 = dstPtr_line0 + W*2; // next line |
| 66 | |
| 67 | #pragma unroll(16) |
| 68 | for (size_t w = 0; w < W; ++w) |
| 69 | { |
| 70 | // Load value |
| 71 | const float value = srcPtr_line[w]; |
| 72 | |
| 73 | // Store value 2x2 |
| 74 | dstPtr_line0[w*2 ] = value; |
| 75 | dstPtr_line0[w*2+1] = value; |
| 76 | dstPtr_line1[w*2 ] = value; |
| 77 | dstPtr_line1[w*2+1] = value; |
| 78 | } |
| 79 | }); |
| 80 | }, ct); |
| 81 | } |
| 82 | } |
nothing calls this directly
no test coverage detected