TODO(jiawen): We can implement BroadcastAdd on buffers of arbitrary dimensionality if the runtime code does a single loop over one dimension that handles broadcasting as the base case. The code generator would then generate max(D1, D2) nested for loops. TODO(benoitjacob): BroadcastAdd is intentionally duplicated from reference_ops.h. Once an optimized version is implemented and NdArrayDesc is n
| 176 | // is no longer referenced in this file, move NdArrayDesc<T> from types.h to |
| 177 | // reference_ops.h. |
| 178 | inline void BroadcastAdd4DSlow(const ArithmeticParams& params, |
| 179 | const RuntimeShape& input1_shape, |
| 180 | const float* input1_data, |
| 181 | const RuntimeShape& input2_shape, |
| 182 | const float* input2_data, |
| 183 | const RuntimeShape& output_shape, |
| 184 | float* output_data) { |
| 185 | NdArrayDesc<4> desc1; |
| 186 | NdArrayDesc<4> desc2; |
| 187 | NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, |
| 188 | &desc2); |
| 189 | const RuntimeShape extended_output_shape = |
| 190 | RuntimeShape::ExtendedShape(4, output_shape); |
| 191 | |
| 192 | // In Tensorflow, the dimensions are canonically named (batch_number, row, |
| 193 | // col, channel), with extents (batches, height, width, depth), with the |
| 194 | // trailing dimension changing most rapidly (channels has the smallest stride, |
| 195 | // typically 1 element). |
| 196 | // |
| 197 | // In generated C code, we store arrays with the dimensions reversed. The |
| 198 | // first dimension has smallest stride. |
| 199 | // |
| 200 | // We name our variables by their Tensorflow convention, but generate C code |
| 201 | // nesting loops such that the innermost loop has the smallest stride for the |
| 202 | // best cache behavior. |
| 203 | for (int b = 0; b < extended_output_shape.Dims(0); ++b) { |
| 204 | for (int y = 0; y < extended_output_shape.Dims(1); ++y) { |
| 205 | for (int x = 0; x < extended_output_shape.Dims(2); ++x) { |
| 206 | for (int c = 0; c < extended_output_shape.Dims(3); ++c) { |
| 207 | output_data[Offset(extended_output_shape, b, y, x, c)] = |
| 208 | ActivationFunctionWithMinMax( |
| 209 | input1_data[SubscriptToIndex(desc1, b, y, x, c)] + |
| 210 | input2_data[SubscriptToIndex(desc2, b, y, x, c)], |
| 211 | params.float_activation_min, params.float_activation_max); |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | inline void BroadcastAdd4DSlow(const ArithmeticParams& params, |
| 219 | const RuntimeShape& input1_shape, |
no test coverage detected