| 2103 | |
| 2104 | template <typename T> |
| 2105 | void ShuffleArrayTemplate(const Shape& input_shape, AxesOrder input_axes_order, |
| 2106 | AxesOrder output_axes_order, |
| 2107 | const Shape& output_shape, const T* input_data, |
| 2108 | T* output_data) { |
| 2109 | if (input_axes_order == AxesOrder::kHWIM && |
| 2110 | output_axes_order == AxesOrder::k1HWO) { |
| 2111 | // This special case isn't just a permutation, the IM pair of dims get |
| 2112 | // merged into the O dim, so we have to special-case it. Fortunately, |
| 2113 | // as far as array shuffling is concerned, it's just the identity |
| 2114 | // transformation. |
| 2115 | memcpy(output_data, input_data, |
| 2116 | RequiredBufferSizeForShape(input_shape) * sizeof(output_data[0])); |
| 2117 | return; |
| 2118 | } |
| 2119 | CHECK(input_shape.dimensions_count() == output_shape.dimensions_count()); |
| 2120 | const int dim = input_shape.dimensions_count(); |
| 2121 | CHECK_LE(dim, 4); |
| 2122 | std::vector<int> shuffle; |
| 2123 | GetShuffleShape(input_axes_order, output_axes_order, &shuffle); |
| 2124 | CHECK(shuffle.size() >= dim); |
| 2125 | for (int i = 0; i < dim; i++) { |
| 2126 | CHECK(shuffle[i] >= 0 && shuffle[i] < dim); |
| 2127 | CHECK(input_shape.dims(shuffle[i]) == output_shape.dims(i)); |
| 2128 | } |
| 2129 | Shape extended_input_shape = input_shape; |
| 2130 | ExtendShape(&extended_input_shape, 4); |
| 2131 | Shape extended_output_shape = output_shape; |
| 2132 | ExtendShape(&extended_output_shape, 4); |
| 2133 | std::vector<int> extended_shuffle; |
| 2134 | ExtendShuffle(shuffle, 4, &extended_shuffle); |
| 2135 | |
| 2136 | const std::vector<int>& extended_input_dims = extended_input_shape.dims(); |
| 2137 | const std::vector<int>& extended_output_dims = extended_output_shape.dims(); |
| 2138 | |
| 2139 | // TODO(starka): Rework to handle different numbers of dimensions. |
| 2140 | int input_strides[4]; |
| 2141 | input_strides[3] = 1; |
| 2142 | input_strides[2] = extended_input_dims[3]; |
| 2143 | input_strides[1] = input_strides[2] * extended_input_dims[2]; |
| 2144 | input_strides[0] = input_strides[1] * extended_input_dims[1]; |
| 2145 | const int input_stride_0 = input_strides[extended_shuffle[3]]; |
| 2146 | const int input_stride_1 = input_strides[extended_shuffle[2]]; |
| 2147 | const int input_stride_2 = input_strides[extended_shuffle[1]]; |
| 2148 | const int input_stride_3 = input_strides[extended_shuffle[0]]; |
| 2149 | |
| 2150 | const int output_size_0 = extended_output_dims[3]; |
| 2151 | const int output_size_1 = extended_output_dims[2]; |
| 2152 | const int output_size_2 = extended_output_dims[1]; |
| 2153 | const int output_size_3 = extended_output_dims[0]; |
| 2154 | const int output_stride_0 = 1; |
| 2155 | const int output_stride_1 = output_size_0; |
| 2156 | const int output_stride_2 = output_stride_1 * output_size_1; |
| 2157 | const int output_stride_3 = output_stride_2 * output_size_2; |
| 2158 | |
| 2159 | for (int i3 = 0; i3 < output_size_3; i3++) { |
| 2160 | const T* const input_ptr_3 = input_data + i3 * input_stride_3; |
| 2161 | T* const output_ptr_3 = output_data + i3 * output_stride_3; |
| 2162 | for (int i2 = 0; i2 < output_size_2; i2++) { |
nothing calls this directly
no test coverage detected