src/cpu/transpose.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ─── CPU NCHW <-> sequence transposes (CHUNK 4) ──────────────────────────── | ||
| 2 | // | ||
| 3 | // FP32 scalar host implementations. Ports src/cuda/transpose.cu — FP32 path | ||
| 4 | // only (CPU is FP32-only). Pure gathers — no arithmetic, no rounding. | ||
| 5 | // | ||
| 6 | // Layout convention (matches the GPU verbatim): | ||
| 7 | // NCHW form : X[((n*C + c) * H + h) * W + w], shape (N, C*H*W). | ||
| 8 | // sequence form : Y[(n*HW + p) * C + c], shape (N*HW, C), | ||
| 9 | // where HW = H*W and p = h*W + w. | ||
| 10 | // | ||
| 11 | // nchw_to_sequence : (N, C*H*W) -> (N*HW, C) | ||
| 12 | // sequence_to_nchw : (N*HW, C) -> (N, C*H*W) (exact inverse) | ||
| 13 | // | ||
| 14 | // Both ops simply OVERWRITE the output tensor. | ||
| 15 | |||
| 16 | #include <brotensor/tensor.h> | ||
| 17 | |||
| 18 | #include <stdexcept> | ||
| 19 | #include <string> | ||
| 20 | |||
| 21 | namespace brotensor::detail::cpu { | ||
| 22 | |||
| 23 | namespace { | ||
| 24 | |||
| 25 | 22 | inline void check_fp32(const ::brotensor::Tensor& t, | |
| 26 | const char* op, const char* name) { | ||
| 27 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (t.dtype != Dtype::FP32) { |
| 28 | ✗ | throw std::runtime_error(std::string(op) + ": " + name + | |
| 29 | " must be FP32 (CPU backend is FP32-only)"); | ||
| 30 | } | ||
| 31 | 22 | } | |
| 32 | |||
| 33 | 22 | inline void check_dims(const char* op, int N, int C, int H, int W) { | |
| 34 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (N < 0 || C < 0 || H < 0 || W < 0) { |
| 35 | ✗ | throw std::runtime_error(std::string(op) + ": negative dimension"); | |
| 36 | } | ||
| 37 | 22 | } | |
| 38 | |||
| 39 | } // namespace | ||
| 40 | |||
| 41 | 11 | void nchw_to_sequence(const ::brotensor::Tensor& X, | |
| 42 | int N, int C, int H, int W, | ||
| 43 | ::brotensor::Tensor& Y) { | ||
| 44 | 11 | check_fp32(X, "nchw_to_sequence", "X"); | |
| 45 | 11 | check_dims("nchw_to_sequence", N, C, H, W); | |
| 46 | 11 | const int HW = H * W; | |
| 47 | 11 | const int rows = N * HW; | |
| 48 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
11 | if (Y.rows != rows || Y.cols != C || Y.dtype != Dtype::FP32) { |
| 49 | 11 | Y.resize(rows, C, Dtype::FP32); | |
| 50 | 11 | } | |
| 51 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (rows == 0 || C == 0) return; |
| 52 | |||
| 53 | 11 | const float* Xp = X.host_f32(); | |
| 54 | 11 | float* Yp = Y.host_f32_mut(); | |
| 55 | |||
| 56 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 14 times.
|
25 | for (int n = 0; n < N; ++n) { |
| 57 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 14 times.
|
174 | for (int c = 0; c < C; ++c) { |
| 58 |
2/2✓ Branch 0 taken 7012 times.
✓ Branch 1 taken 160 times.
|
7172 | for (int p = 0; p < HW; ++p) { |
| 59 | 7012 | Yp[(n * HW + p) * C + c] = Xp[(n * C + c) * HW + p]; | |
| 60 | 7012 | } | |
| 61 | 160 | } | |
| 62 | 14 | } | |
| 63 | 11 | } | |
| 64 | |||
| 65 | 11 | void sequence_to_nchw(const ::brotensor::Tensor& X, | |
| 66 | int N, int C, int H, int W, | ||
| 67 | ::brotensor::Tensor& Y) { | ||
| 68 | 11 | check_fp32(X, "sequence_to_nchw", "X"); | |
| 69 | 11 | check_dims("sequence_to_nchw", N, C, H, W); | |
| 70 | 11 | const int HW = H * W; | |
| 71 | 11 | const int cols = C * HW; | |
| 72 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
11 | if (Y.rows != N || Y.cols != cols || Y.dtype != Dtype::FP32) { |
| 73 | 11 | Y.resize(N, cols, Dtype::FP32); | |
| 74 | 11 | } | |
| 75 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (N == 0 || cols == 0) return; |
| 76 | |||
| 77 | 11 | const float* Xp = X.host_f32(); | |
| 78 | 11 | float* Yp = Y.host_f32_mut(); | |
| 79 | |||
| 80 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 14 times.
|
25 | for (int n = 0; n < N; ++n) { |
| 81 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 14 times.
|
174 | for (int c = 0; c < C; ++c) { |
| 82 |
2/2✓ Branch 0 taken 7012 times.
✓ Branch 1 taken 160 times.
|
7172 | for (int p = 0; p < HW; ++p) { |
| 83 | 7012 | Yp[(n * C + c) * HW + p] = Xp[(n * HW + p) * C + c]; | |
| 84 | 7012 | } | |
| 85 | 160 | } | |
| 86 | 14 | } | |
| 87 | 11 | } | |
| 88 | |||
| 89 | } // namespace brotensor::detail::cpu | ||
| 90 |