GCC Code Coverage Report


Directory: brotensor/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.3% 290 / 0 / 301
Functions: 100.0% 26 / 0 / 26
Branches: 32.5% 264 / 0 / 812

src/api/native_tensor_conv.cpp
Line Branch Exec Source
1 // native_tensor_conv.cpp — the restored `conv` group, ported from the QuickJS
2 // binding (bro's old src/js/tensor_bindings_conv.cpp). Argument order, optional
3 // arguments and defaults are the old ones; the brotensor call each body makes
4 // is today's `brotensor::` signature, not the old `nngpu::` one.
5 //
6 // Everything here is a free function on `bro.tensor`; js/tensor_conv.js is the
7 // wrapper half that validates arguments and reads the error slot back.
8
9 #include "native_tensor_conv_decl.h"
10 #include "api_internal.h"
11 #include "native_register.h"
12
13 #include <cstring>
14 #include <stdexcept>
15 #include <string>
16
17 using namespace brotensor::api;
18 using brotensor::Tensor;
19 using brotensor::Dtype;
20
21 // Every body checks its operands against the dims first (api_internal.h
22 // "input-size contract"); accumulated gradients are checked like inputs.
23
24 namespace {
25
26 142 Tensor* T(void* p) { return toTensor(p); }
27
28 // Transposed-conv geometry (torch ConvTranspose2d): positive kernel, stride,
29 // dilation and groups dividing both channel counts; the output extent is
30 // (in-1)*s - 2p + d*(k-1) + op + 1.
31 10 bool convTGeom(const char* L, int64_t C_in, int64_t C_out, int64_t H, int64_t W, int64_t kH, int64_t kW,
32 int64_t sH, int64_t sW, int64_t pH, int64_t pW, int64_t opH, int64_t opW, int64_t dH, int64_t dW,
33 int64_t groups, int64_t& H_out, int64_t& W_out) {
34
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!needPositive(L, {kH, kW, sH, sW, dH, dW, groups})) return false;
35
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!needNonNegative(L, {C_in, C_out, H, W, pH, pW, opH, opW})) return false;
36
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (C_in % groups != 0 || C_out % groups != 0) {
37 ✗ setError(std::string(L) + ": groups must divide C_in and C_out");
38 ✗ return false;
39 }
40 10 H_out = (H - 1) * sH - 2 * pH + dH * (kH - 1) + opH + 1;
41 10 W_out = (W - 1) * sW - 2 * pW + dW * (kW - 1) + opW + 1;
42
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (H_out < 0) H_out = 0;
43
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (W_out < 0) W_out = 0;
44 10 return true;
45 10 }
46
47 // Idx values address the per-channel H*W input plane on the device: read
48 // them back and range-check them (-1 = "all padding" is skipped by the op).
49 2 bool needPoolIndices(const char* L, const Tensor* idx, int64_t n, int64_t plane) {
50
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (idx->dtype != Dtype::INT32) {
51 ✗ setError(std::string(L) + ": Idx must be INT32 (the forward's output)");
52 ✗ return false;
53 }
54
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!needElems(L, "Idx", idx, n)) return false;
55
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (n == 0) return true;
56 2 auto host = idx->to(brotensor::Device::CPU);
57
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 const auto* v = static_cast<const int32_t*>(host.host_raw());
58
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (int64_t i = 0; i < n; ++i) {
59
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (v[i] < -1 || v[i] >= plane) {
60 ✗ setError(std::string(L) + ": Idx[" + std::to_string(i) + "] = " + std::to_string(v[i]) +
61 ✗ " is outside the " + std::to_string(plane) + "-pixel input plane");
62 ✗ return false;
63 }
64 2 }
65 2 return true;
66 2 }
67
68 } // namespace
69
70 extern "C" {
71
72 // ---- interp2d backward -----------------------------------------------------
73
74 2 void bro_tensor_interp2dBackward(void* dY, int32_t N, int32_t C, int32_t H_in, int32_t W_in,
75 int32_t H_out, int32_t W_out, int32_t mode, void* dX) {
76 2 const char* L = "interp2dBackward";
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {dY, dX})) return;
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needNonNegative(L, {N, C, H_in, W_in})) return;
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return;
80 BROTENSOR_API_TRY
81
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::interp2d_backward(*toTensor(dY), N, C, H_in, W_in, H_out, W_out, mode, *toTensor(dX));
82
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
83 2 }
84
85 // ---- pad2d / slice2d -------------------------------------------------------
86
87 4 void bro_tensor_pad2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
88 int32_t padT, int32_t padB, int32_t padL, int32_t padR,
89 int32_t mode, void* Y) {
90 4 const char* L = "pad2dForward";
91
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!need(L, {X, Y}) || !needNonNegative(L, {padT, padB, padL, padR})) return;
92
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
93 BROTENSOR_API_TRY
94
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::pad2d_forward(*toTensor(X), N, C, H, W, padT, padB, padL, padR, mode, *toTensor(Y));
95
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
96 4 }
97
98 2 void bro_tensor_pad2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W,
99 int32_t padT, int32_t padB, int32_t padL, int32_t padR,
100 int32_t mode, void* dX) {
101 2 const char* L = "pad2dBackward";
102
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!need(L, {dY, dX}) || !needNonNegative(L, {N, C, H, W, padT, padB, padL, padR})) return;
103
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (!needElems(L, "dY", T(dY), elems({N, C, static_cast<int64_t>(H) + padT + padB,
104 2 static_cast<int64_t>(W) + padL + padR}))) return;
105 BROTENSOR_API_TRY
106
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::pad2d_backward(*toTensor(dY), N, C, H, W, padT, padB, padL, padR, mode, *toTensor(dX));
107
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
108 2 }
109
110 2 void bro_tensor_slice2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
111 int32_t h0, int32_t w0, int32_t H_out, int32_t W_out, void* Y) {
112 2 const char* L = "slice2dForward";
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {X, Y})) return;
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
115 BROTENSOR_API_TRY
116
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::slice2d_forward(*toTensor(X), N, C, H, W, h0, w0, H_out, W_out, *toTensor(Y));
117
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
118 2 }
119
120 2 void bro_tensor_slice2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W,
121 int32_t h0, int32_t w0, int32_t H_out, int32_t W_out, void* dX) {
122 2 const char* L = "slice2dBackward";
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {dY, dX})) return;
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return;
125 BROTENSOR_API_TRY
126
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::slice2d_backward(*toTensor(dY), N, C, H, W, h0, w0, H_out, W_out, *toTensor(dX));
127
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
128 2 }
129
130 // ---- max pool / adaptive average pool --------------------------------------
131
132 6 void bro_tensor_maxPool2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
133 int32_t kH, int32_t kW, int32_t sH, int32_t sW,
134 int32_t padH, int32_t padW, void* Y, void* Idx) {
135 6 const char* L = "maxPool2dForward";
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!need(L, {X, Y, Idx})) return;
137
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!needPositive(L, {kH, kW, sH, sW}) || !needNonNegative(L, {padH, padW})) return;
138
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
139 BROTENSOR_API_TRY
140
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 brotensor::max_pool2d_forward(*toTensor(X), N, C, H, W, kH, kW, sH, sW, padH, padW,
141
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 *toTensor(Y), *toTensor(Idx));
142
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH(L)
143 6 }
144
145 2 void bro_tensor_maxPool2dBackward(void* dY, void* Idx, int32_t N, int32_t C, int32_t H, int32_t W,
146 int32_t H_out, int32_t W_out, void* dX) {
147 2 const char* L = "maxPool2dBackward";
148
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!need(L, {dY, Idx, dX}) || !needNonNegative(L, {N, C, H, W})) return;
149 2 const int64_t n = elems({N, C, H_out, W_out});
150
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!needElems(L, "dY", T(dY), n)) return;
151 BROTENSOR_API_TRY
152
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (!needPoolIndices(L, T(Idx), n, elems({H, W}))) return;
153
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 brotensor::max_pool2d_backward(*toTensor(dY), *toTensor(Idx), N, C, H, W, H_out, W_out, *toTensor(dX));
154
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
155 2 }
156
157 4 void bro_tensor_adaptiveAvgPool2dForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
158 int32_t H_out, int32_t W_out, void* Y) {
159 4 const char* L = "adaptiveAvgPool2dForward";
160
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 if (!need(L, {X, Y}) || !needPositive(L, {H_out, W_out})) return;
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
162 BROTENSOR_API_TRY
163
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::adaptive_avg_pool2d_forward(*toTensor(X), N, C, H, W, H_out, W_out, *toTensor(Y));
164
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
165 4 }
166
167 2 void bro_tensor_adaptiveAvgPool2dBackward(void* dY, int32_t N, int32_t C, int32_t H, int32_t W,
168 int32_t H_out, int32_t W_out, void* dX) {
169 2 const char* L = "adaptiveAvgPool2dBackward";
170
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
2 if (!need(L, {dY, dX}) || !needPositive(L, {H_out, W_out}) || !needNonNegative(L, {N, C, H, W})) return;
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needElems(L, "dY", T(dY), elems({N, C, H_out, W_out}))) return;
172 BROTENSOR_API_TRY
173
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 brotensor::adaptive_avg_pool2d_backward(*toTensor(dY), N, C, H, W, H_out, W_out, *toTensor(dX));
174
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH(L)
175 2 }
176
177 // ---- transposed conv2d -----------------------------------------------------
178
179 6 void bro_tensor_convTranspose2dForward(void* X, void* Wt, uint64_t bias_bits,
180 int32_t N, int32_t C_in, int32_t H, int32_t W,
181 int32_t C_out, int32_t kH, int32_t kW,
182 int32_t sH, int32_t sW, int32_t pH, int32_t pW,
183 int32_t opH, int32_t opW, int32_t dH, int32_t dW,
184 int32_t groups, void* Y) {
185 6 const char* L = "convTranspose2dForward";
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!need(L, {X, Wt, Y})) return;
187 6 int64_t H_out = 0, W_out = 0;
188
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return;
189
6/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
18 if (!needOperands(L, T(X), {{"X", T(X), elems({N, C_in, H, W})},
190 6 {"Wt", T(Wt), elems({C_in, C_out / groups, kH, kW})},
191 6 {"bias", tensorFromValue(bias_bits), C_out}})) return;
192 BROTENSOR_API_TRY
193
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8 brotensor::conv_transpose2d_forward(*toTensor(X), *toTensor(Wt), tensorFromValue(bias_bits),
194 4 N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW,
195
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 opH, opW, dH, dW, groups, *toTensor(Y));
196
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("convTranspose2dForward")
197 6 }
198
199 2 void bro_tensor_convTranspose2dBackwardInput(void* Wt, void* dY,
200 int32_t N, int32_t C_in, int32_t H, int32_t W,
201 int32_t C_out, int32_t kH, int32_t kW,
202 int32_t sH, int32_t sW, int32_t pH, int32_t pW,
203 int32_t opH, int32_t opW, int32_t dH, int32_t dW,
204 int32_t groups, void* dX) {
205 2 const char* L = "convTranspose2dBackwardInput";
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {Wt, dY, dX})) return;
207 2 int64_t H_out = 0, W_out = 0;
208
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return;
209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needNonNegative(L, {N})) return;
210
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (!needOperands(L, T(Wt), {{"Wt", T(Wt), elems({C_in, C_out / groups, kH, kW})},
211 2 {"dY", T(dY), elems({N, C_out, H_out, W_out})}})) return;
212 BROTENSOR_API_TRY
213
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 brotensor::conv_transpose2d_backward_input(*toTensor(Wt), *toTensor(dY),
214 2 N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW,
215
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 opH, opW, dH, dW, groups, *toTensor(dX));
216
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH("convTranspose2dBackwardInput")
217 2 }
218
219 2 void bro_tensor_convTranspose2dBackwardWeight(void* X, void* dY,
220 int32_t N, int32_t C_in, int32_t H, int32_t W,
221 int32_t C_out, int32_t kH, int32_t kW,
222 int32_t sH, int32_t sW, int32_t pH, int32_t pW,
223 int32_t opH, int32_t opW, int32_t dH, int32_t dW,
224 int32_t groups, void* dWt) {
225 2 const char* L = "convTranspose2dBackwardWeight";
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {X, dY, dWt})) return;
227 2 int64_t H_out = 0, W_out = 0;
228
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!convTGeom(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, opH, opW, dH, dW, groups, H_out, W_out)) return;
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needNonNegative(L, {N})) return;
230 // dWt accumulates — "pre-zeroed by caller".
231
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
6 if (!needOperands(L, T(X), {{"X", T(X), elems({N, C_in, H, W})},
232 2 {"dY", T(dY), elems({N, C_out, H_out, W_out})},
233 2 {"dWt", T(dWt), elems({C_in, C_out / groups, kH, kW})}})) return;
234 BROTENSOR_API_TRY
235
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 brotensor::conv_transpose2d_backward_weight(*toTensor(X), *toTensor(dY),
236 2 N, C_in, H, W, C_out, kH, kW, sH, sW, pH, pW,
237
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 opH, opW, dH, dW, groups, *toTensor(dWt));
238
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH("convTranspose2dBackwardWeight")
239 2 }
240
241 4 void bro_tensor_convTranspose2dBackwardBias(void* dY, int32_t N, int32_t C_out,
242 int32_t H_out, int32_t W_out, void* dB) {
243 4 const char* L = "convTranspose2dBackwardBias";
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!need(L, {dY, dB})) return;
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!needOperands(L, T(dY), {{"dY", T(dY), elems({N, C_out, H_out, W_out})}, {"dB", T(dB), C_out}})) return;
246 BROTENSOR_API_TRY
247
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 brotensor::conv_transpose2d_backward_bias(*toTensor(dY), N, C_out, H_out, W_out, *toTensor(dB));
248
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("convTranspose2dBackwardBias")
249 4 }
250
251 // ---- conv3d (NCTHW) --------------------------------------------------------
252
253 6 void bro_tensor_conv3dForward(void* X, void* Wt, uint64_t bias_bits,
254 int32_t N, int32_t C_in, int32_t T, int32_t H, int32_t W,
255 int32_t C_out, int32_t kT, int32_t kH, int32_t kW,
256 int32_t sT, int32_t sH, int32_t sW,
257 int32_t pT, int32_t pH, int32_t pW,
258 int32_t dT, int32_t dH, int32_t dW,
259 int32_t groups, void* Y) {
260 6 const char* L = "conv3dForward";
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!need(L, {X, Wt, Y})) return;
262 // conv2d's geometry on (H, W) plus the same rules on T.
263 6 int64_t H_out = 0, W_out = 0;
264
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!convGeom2d(L, C_in, C_out, H, W, kH, kW, sH, sW, pH, pW, dH, dW, groups, H_out, W_out)) return;
265
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!needPositive(L, {kT, sT, dT}) || !needNonNegative(L, {N, T, pT})) return;
266
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
18 if (!needOperands(L, toTensor(X), {{"X", toTensor(X), elems({N, C_in, T, H, W})},
267 6 {"Wt", toTensor(Wt), elems({C_out, C_in / groups, kT, kH, kW})},
268 6 {"bias", tensorFromValue(bias_bits), C_out}})) return;
269 BROTENSOR_API_TRY
270
4/8
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
12 brotensor::conv3d_forward(*toTensor(X), *toTensor(Wt), tensorFromValue(bias_bits),
271 6 N, C_in, T, H, W, C_out, kT, kH, kW,
272
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 sT, sH, sW, pT, pH, pW, dT, dH, dW, groups, *toTensor(Y));
273
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
6 BROTENSOR_API_CATCH("conv3dForward")
274 6 }
275
276 // ---- window partition / reverse / 2x2 spatial merge ------------------------
277
278 4 void bro_tensor_windowPartitionForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
279 int32_t window, void* Y) {
280 4 const char* L = "windowPartitionForward";
281
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!need(L, {X, Y}) || !needPositive(L, {window})) return;
282
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (H % window != 0 || W % window != 0) { setError("windowPartitionForward: H and W must be multiples of window"); return; }
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
284 BROTENSOR_API_TRY
285
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 brotensor::window_partition_forward(*toTensor(X), N, C, H, W, window, *toTensor(Y));
286
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("windowPartitionForward")
287 4 }
288
289 4 void bro_tensor_windowReverseForward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
290 int32_t window, void* Y) {
291 4 const char* L = "windowReverseForward";
292
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!need(L, {X, Y}) || !needPositive(L, {window})) return;
293
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (H % window != 0 || W % window != 0) { setError("windowReverseForward: H and W must be multiples of window"); return; }
294 // The windowed batch holds the same N*C*H*W elements, re-tiled.
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
296 BROTENSOR_API_TRY
297
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 brotensor::window_reverse_forward(*toTensor(X), N, C, H, W, window, *toTensor(Y));
298
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("windowReverseForward")
299 4 }
300
301 // channelMajor false (the old binding's default) = block-major
302 // c_out = block*C + c_in (Qwen-VL); true = torch pixel_unshuffle ordering.
303 4 void bro_tensor_spatialMerge2x2Forward(void* X, int32_t N, int32_t C, int32_t H, int32_t W,
304 void* Y, bool channelMajor) {
305 4 const char* L = "spatialMerge2x2Forward";
306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!need(L, {X, Y})) return;
307
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (H % 2 != 0 || W % 2 != 0) { setError("spatialMerge2x2Forward: H and W must be even"); return; }
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!needElems(L, "X", T(X), elems({N, C, H, W}))) return;
309 BROTENSOR_API_TRY
310
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 brotensor::spatial_merge_2x2_forward(*toTensor(X), N, C, H, W, channelMajor, *toTensor(Y));
311
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("spatialMerge2x2Forward")
312 4 }
313
314 // ---- batch norm ------------------------------------------------------------
315
316 2 void bro_tensor_batchNormForward(void* X, void* gamma, void* beta, void* runningMean, void* runningVar,
317 int32_t N, int32_t C, int32_t H, int32_t W,
318 double eps, double momentum, void* Y, void* savedMean, void* savedRstd) {
319 2 const char* L = "batchNormForward";
320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {X, gamma, beta, runningMean, runningVar, Y, savedMean, savedRstd})) return;
321
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
6 if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"gamma", T(gamma), C}, {"beta", T(beta), C},
322 4 {"runningMean", T(runningMean), C}, {"runningVar", T(runningVar), C}})) return;
323 BROTENSOR_API_TRY
324
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
4 brotensor::batch_norm_forward(*toTensor(X), *toTensor(gamma), *toTensor(beta),
325
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 *toTensor(runningMean), *toTensor(runningVar),
326 2 N, C, H, W, static_cast<float>(eps), static_cast<float>(momentum),
327
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 *toTensor(Y), *toTensor(savedMean), *toTensor(savedRstd));
328
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH("batchNormForward")
329 2 }
330
331 2 void bro_tensor_batchNormBackward(void* X, void* gamma, void* savedMean, void* savedRstd, void* dY,
332 int32_t N, int32_t C, int32_t H, int32_t W,
333 void* dX, void* dGamma, void* dBeta) {
334 2 const char* L = "batchNormBackward";
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {X, gamma, savedMean, savedRstd, dY, dX, dGamma, dBeta})) return;
336 2 const int64_t n = elems({N, C, H, W});
337 // savedMean/savedRstd are the forward's FP32 caches; dGamma/dBeta accumulate.
338
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
6 if (!needOperands(L, T(X), {{"X", T(X), n}, {"dY", T(dY), n}, {"gamma", T(gamma), C},
339 4 {"dGamma", T(dGamma), C}, {"dBeta", T(dBeta), C}})) return;
340
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!needMask(L, T(savedMean), C, "savedMean") || !needMask(L, T(savedRstd), C, "savedRstd")) return;
341 BROTENSOR_API_TRY
342
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
4 brotensor::batch_norm_backward(*toTensor(X), *toTensor(gamma), *toTensor(savedMean),
343
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 *toTensor(savedRstd), *toTensor(dY), N, C, H, W,
344
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 *toTensor(dX), *toTensor(dGamma), *toTensor(dBeta));
345
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH("batchNormBackward")
346 2 }
347
348 4 void bro_tensor_batchNormInference(void* X, void* gamma, void* beta, void* runningMean, void* runningVar,
349 int32_t N, int32_t C, int32_t H, int32_t W, double eps, void* Y) {
350 4 const char* L = "batchNormInference";
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!need(L, {X, gamma, beta, runningMean, runningVar, Y})) return;
352
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
12 if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"gamma", T(gamma), C}, {"beta", T(beta), C},
353 8 {"runningMean", T(runningMean), C}, {"runningVar", T(runningVar), C}})) return;
354 BROTENSOR_API_TRY
355
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8 brotensor::batch_norm_inference(*toTensor(X), *toTensor(gamma), *toTensor(beta),
356
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 *toTensor(runningMean), *toTensor(runningVar),
357
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 N, C, H, W, static_cast<float>(eps), *toTensor(Y));
358
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4 BROTENSOR_API_CATCH("batchNormInference")
359 4 }
360
361 // ---- image preprocessing ---------------------------------------------------
362
363 2 void bro_tensor_imageNormalize(void* X, void* mean, void* std_,
364 int32_t N, int32_t C, int32_t H, int32_t W, void* Y) {
365 2 const char* L = "imageNormalize";
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!need(L, {X, mean, std_, Y})) return;
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!needOperands(L, T(X), {{"X", T(X), elems({N, C, H, W})}, {"mean", T(mean), C}, {"std", T(std_), C}})) return;
368 BROTENSOR_API_TRY
369
5/10
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 brotensor::image_normalize(*toTensor(X), *toTensor(mean), *toTensor(std_), N, C, H, W, *toTensor(Y));
370
0/12
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
2 BROTENSOR_API_CATCH("imageNormalize")
371 2 }
372
373 // The op reads `src` from the SAME device as Y (the CUDA kernel dereferences
374 // it directly), but a Uint8Array is host memory. On a GPU backend the bytes
375 // are staged through an INT8 device tensor (size_bytes == element count, the
376 // contents uninterpreted) and its device pointer is what the op sees.
377 10 void bro_tensor_imageU8ToF32NhwcToNchw(const uint8_t* src, uint32_t src_len,
378 int32_t N, int32_t H, int32_t W, int32_t C,
379 double scale, double bias, void* Y) {
380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!need("imageU8ToF32NhwcToNchw", {Y})) return;
381 BROTENSOR_API_TRY
382
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (N < 0 || H < 0 || W < 0 || C < 0) {
383 ✗ throw std::runtime_error("negative dimension");
384 }
385 10 const int64_t want = static_cast<int64_t>(N) * H * W * C;
386
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (static_cast<int64_t>(src_len) < want) {
387
6/12
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 throw std::runtime_error("src holds " + std::to_string(src_len) + " bytes, need " +
388
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::to_string(want));
389 }
390
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 auto* yt = toTensor(Y);
391
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8 const brotensor::Device dev = yt->data ? yt->device : brotensor::default_device();
392
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 if (dev == brotensor::Device::CPU || want == 0) {
393 ✗ brotensor::image_u8_to_f32_nhwc_to_nchw(src, N, H, W, C, static_cast<float>(scale),
394 ✗ static_cast<float>(bias), *yt);
395 ✗ } else {
396
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 brotensor::Tensor staged = brotensor::Tensor::zeros_on(
397 8 brotensor::Device::CPU, static_cast<int>(want), 1, brotensor::Dtype::INT8);
398
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 std::memcpy(staged.host_raw_mut(), src, static_cast<size_t>(want));
399
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 staged = staged.to(dev);
400
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 brotensor::image_u8_to_f32_nhwc_to_nchw(static_cast<const uint8_t*>(staged.data),
401 8 N, H, W, C, static_cast<float>(scale),
402 8 static_cast<float>(bias), *yt);
403 8 }
404
5/12
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
10 BROTENSOR_API_CATCH("imageU8ToF32NhwcToNchw")
405 12 }
406
407 } // extern "C"
408
409 namespace brotensor::api {
410
411 3 bool registerTensorNatives_conv(std::string* error) {
412 using namespace brotensor::api::reg;
413 3 bool ok =
414 6 fn("__bro_native.tensor.interp2dBackward", p(&bro_tensor_interp2dBackward), "void",
415
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
416 6 fn("__bro_native.tensor.pad2dForward", p(&bro_tensor_pad2dForward), "void",
417
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
418 6 fn("__bro_native.tensor.pad2dBackward", p(&bro_tensor_pad2dBackward), "void",
419
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
420 6 fn("__bro_native.tensor.slice2dForward", p(&bro_tensor_slice2dForward), "void",
421
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
422 6 fn("__bro_native.tensor.slice2dBackward", p(&bro_tensor_slice2dBackward), "void",
423
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
424 6 fn("__bro_native.tensor.maxPool2dForward", p(&bro_tensor_maxPool2dForward), "void",
425
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls, kTensorCls}, error) &&
426 6 fn("__bro_native.tensor.maxPool2dBackward", p(&bro_tensor_maxPool2dBackward), "void",
427
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
428 6 fn("__bro_native.tensor.adaptiveAvgPool2dForward", p(&bro_tensor_adaptiveAvgPool2dForward), "void",
429
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
430 6 fn("__bro_native.tensor.adaptiveAvgPool2dBackward", p(&bro_tensor_adaptiveAvgPool2dBackward), "void",
431
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
432 6 fn("__bro_native.tensor.convTranspose2dForward", p(&bro_tensor_convTranspose2dForward), "void",
433 3 {kTensorCls, kTensorCls, kDyn, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32",
434
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
435 6 fn("__bro_native.tensor.convTranspose2dBackwardInput", p(&bro_tensor_convTranspose2dBackwardInput), "void",
436 3 {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32",
437
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
438 6 fn("__bro_native.tensor.convTranspose2dBackwardWeight", p(&bro_tensor_convTranspose2dBackwardWeight), "void",
439 3 {kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32",
440
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
441 6 fn("__bro_native.tensor.convTranspose2dBackwardBias", p(&bro_tensor_convTranspose2dBackwardBias), "void",
442
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", kTensorCls}, error) &&
443 6 fn("__bro_native.tensor.conv3dForward", p(&bro_tensor_conv3dForward), "void",
444 3 {kTensorCls, kTensorCls, kDyn, "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32",
445
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
446 6 fn("__bro_native.tensor.windowPartitionForward", p(&bro_tensor_windowPartitionForward), "void",
447
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
448 6 fn("__bro_native.tensor.windowReverseForward", p(&bro_tensor_windowReverseForward), "void",
449
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", "i32", kTensorCls}, error) &&
450 6 fn("__bro_native.tensor.spatialMerge2x2Forward", p(&bro_tensor_spatialMerge2x2Forward), "void",
451
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 {kTensorCls, "i32", "i32", "i32", "i32", kTensorCls, "bool"}, error) &&
452 6 fn("__bro_native.tensor.batchNormForward", p(&bro_tensor_batchNormForward), "void",
453 3 {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32",
454
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "f64", "f64", kTensorCls, kTensorCls, kTensorCls}, error) &&
455 6 fn("__bro_native.tensor.batchNormBackward", p(&bro_tensor_batchNormBackward), "void",
456 3 {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32",
457
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 kTensorCls, kTensorCls, kTensorCls}, error) &&
458 6 fn("__bro_native.tensor.batchNormInference", p(&bro_tensor_batchNormInference), "void",
459 3 {kTensorCls, kTensorCls, kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32",
460
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 "f64", kTensorCls}, error) &&
461 6 fn("__bro_native.tensor.imageNormalize", p(&bro_tensor_imageNormalize), "void",
462
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 {kTensorCls, kTensorCls, kTensorCls, "i32", "i32", "i32", "i32", kTensorCls}, error) &&
463 6 fn("__bro_native.tensor.imageU8ToF32NhwcToNchw", p(&bro_tensor_imageU8ToF32NhwcToNchw), "void",
464 3 {"u8[]", "i32", "i32", "i32", "i32", "f64", "f64", kTensorCls}, error);
465 3 return ok;
466 }
467
468 } // namespace brotensor::api
469