GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 95.7% 44 / 0 / 46
Functions: 100.0% 4 / 0 / 4
Branches: 33.3% 20 / 0 / 60

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