Coverage Report

Created: 2026-07-12 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Simd/src/Simd/SimdBaseWinograd2.cpp
Line
Count
Source
1
/*
2
* Simd Library (http://ermig1979.github.io/Simd).
3
*
4
* Copyright (c) 2011-2021 Yermalayeu Ihar.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
#include "Simd/SimdMemory.h"
25
#include "Simd/SimdWinograd.h"
26
27
namespace Simd
28
{
29
#if defined(SIMD_SYNET_ENABLE)
30
    namespace Base
31
    {
32
        void WinogradKernel2x2Block2x2SetFilter(const float* src, size_t size, float* dst, SimdBool trans)
33
0
        {
34
0
            if (trans)
35
0
            {
36
0
                for (size_t i = 0; i < size; i += 1)
37
0
                    Base::WinogradKernel2x2Block2x2SetFilter1t(src + i, dst + i, size);
38
0
            }
39
0
            else
40
0
            {
41
0
                for (size_t i = 0; i < size; i += 1, src += 4, dst += 1)
42
0
                    Base::WinogradKernel2x2Block2x2SetFilter1n(src, dst, size);
43
0
            }
44
0
        }
45
46
        //-----------------------------------------------------------------------
47
48
        SIMD_INLINE void WinogradKernel2x2Block2x2SetInput1(const float src[16], float* dst, size_t stride)
49
0
        {
50
0
            dst[0 * stride] = src[0] - src[1] - src[3] + src[4];
51
0
            dst[1 * stride] = src[1] - src[4];
52
0
            dst[2 * stride] = src[2] - src[1] + src[4] - src[5];
53
0
            dst[3 * stride] = src[3] - src[4];
54
0
            dst[4 * stride] = src[4];
55
0
            dst[5 * stride] = src[5] - src[4];
56
0
            dst[6 * stride] = src[4] - src[3] + src[6] - src[7];
57
0
            dst[7 * stride] = src[7] - src[4];
58
0
            dst[8 * stride] = src[4] - src[5] + src[8] - src[7];
59
0
        }
60
61
        SIMD_INLINE void WinogradKernel2x2Block2x2SetInput1n(const float* src, size_t srcStride, float* dst, size_t dstStride)
62
0
        {
63
0
            float tmp[9];
64
0
            tmp[0] = src[0 * srcStride + 0];
65
0
            tmp[1] = src[0 * srcStride + 1];
66
0
            tmp[2] = src[0 * srcStride + 2];
67
0
            tmp[3] = src[1 * srcStride + 0];
68
0
            tmp[4] = src[1 * srcStride + 1];
69
0
            tmp[5] = src[1 * srcStride + 2];
70
0
            tmp[6] = src[2 * srcStride + 0];
71
0
            tmp[7] = src[2 * srcStride + 1];
72
0
            tmp[8] = src[2 * srcStride + 2];
73
74
0
            WinogradKernel2x2Block2x2SetInput1(tmp, dst, dstStride);
75
0
        }
76
77
        SIMD_INLINE void WinogradKernel2x2Block2x2SetInput1n(const float* src, size_t srcStride, size_t rowB, size_t rowE, size_t colB, size_t colE, float* dst, size_t dstStride)
78
0
        {
79
0
            float tmp[9] = { 0 };
80
0
            for (size_t row = rowB; row < rowE; ++row)
81
0
                for (size_t col = colB; col < colE; ++col)
82
0
                    tmp[row * 3 + col] = src[row * srcStride + col];
83
0
            WinogradKernel2x2Block2x2SetInput1(tmp, dst, dstStride);
84
0
        }
85
86
        SIMD_INLINE void WinogradKernel2x2Block2x2SetInput1t(const float* src, size_t srcW, size_t srcC, float* dst, size_t dstStride)
87
0
        {
88
0
            size_t srcS = srcW * srcC;
89
0
            for (size_t c = 0; c < srcC; ++c, src++, dst++)
90
0
            {
91
0
                float tmp[9];
92
0
                tmp[0] = src[0 * srcS + 0 * srcC];
93
0
                tmp[1] = src[0 * srcS + 1 * srcC];
94
0
                tmp[2] = src[0 * srcS + 2 * srcC];
95
0
                tmp[3] = src[1 * srcS + 0 * srcC];
96
0
                tmp[4] = src[1 * srcS + 1 * srcC];
97
0
                tmp[5] = src[1 * srcS + 2 * srcC];
98
0
                tmp[6] = src[2 * srcS + 0 * srcC];
99
0
                tmp[7] = src[2 * srcS + 1 * srcC];
100
0
                tmp[8] = src[2 * srcS + 2 * srcC];
101
0
                WinogradKernel2x2Block2x2SetInput1(tmp, dst, dstStride);
102
0
            }
103
0
        }
104
105
        SIMD_INLINE void WinogradKernel2x2Block2x2SetInput1t(const float* src, size_t srcW, size_t srcC, size_t rowB, size_t rowE, size_t colB, size_t colE, float* dst, size_t dstStride)
106
0
        {
107
0
            size_t srcS = srcW * srcC;
108
0
            for (size_t c = 0; c < srcC; ++c, src++, dst++)
109
0
            {
110
0
                float tmp[9] = { 0 };
111
0
                for (size_t row = rowB; row < rowE; ++row)
112
0
                    for (size_t col = colB; col < colE; ++col)
113
0
                        tmp[row * 3 + col] = src[row * srcS + col * srcC];
114
0
                WinogradKernel2x2Block2x2SetInput1(tmp, dst, dstStride);
115
0
            }
116
0
        }
117
118
        void WinogradKernel2x2Block2x2SetInput(const float* src, size_t srcChannels, size_t srcHeight, size_t srcWidth,
119
            size_t padY, size_t padX, size_t padH, size_t padW, float* dst, size_t dstStride, SimdBool trans)
120
0
        {
121
0
            assert(padY == padX && padW == padH && (padY + padH == 0 || padY + padH == 1));
122
0
            size_t dstHeight = srcHeight - 1 + padY + padH;
123
0
            size_t dstWidth = srcWidth - 1 + padX + padW;
124
0
            size_t dstHeightFull = AlignLo(dstHeight, 2);
125
0
            size_t dstWidthFull = AlignLo(dstWidth, 2);
126
0
            size_t noseW = Simd::Min<size_t>(3, dstWidth + 1);
127
0
            size_t noseH = Simd::Min<size_t>(3, dstHeight + 1);
128
0
            size_t startY = padY ? 2 : 0;
129
0
            size_t startX = padX ? 2 : 0;
130
0
            if (padY || padH)
131
0
            {
132
0
                if (dstHeight == dstHeightFull)
133
0
                    dstHeightFull -= 2;
134
0
                if (dstWidth == dstWidthFull)
135
0
                    dstWidthFull -= 2;
136
0
                if(padY)
137
0
                    src -= (srcWidth + 1) * (trans ? srcChannels : 1);
138
0
            }
139
0
            size_t tailW = dstWidth - dstWidthFull + (padW ? 0 : 1);
140
0
            size_t tailH = dstHeight - dstHeightFull + (padH ? 0 : 1);
141
0
            if (trans)
142
0
            {
143
0
                size_t row = 0, col = 0;
144
0
                if (padY)
145
0
                {
146
0
                    if (padX)
147
0
                        WinogradKernel2x2Block2x2SetInput1t(src, srcWidth, srcChannels, 1, noseH, 1, noseW, dst, dstStride), dst += srcChannels;
148
0
                    for (col = startX; col < dstWidthFull; col += 2)
149
0
                        WinogradKernel2x2Block2x2SetInput1t(src + col * srcChannels, srcWidth, srcChannels, 1, noseH, 0, 3, dst, dstStride), dst += srcChannels;
150
0
                    if (col < dstWidth)
151
0
                        WinogradKernel2x2Block2x2SetInput1t(src + col * srcChannels, srcWidth, srcChannels, 1, noseH, 0, tailW, dst, dstStride), dst += srcChannels;
152
0
                }
153
0
                for (row = startY; row < dstHeightFull; row += 2)
154
0
                {
155
0
                    if (padX)
156
0
                        WinogradKernel2x2Block2x2SetInput1t(src + row * srcWidth * srcChannels, srcWidth, srcChannels, 0, 3, 1, noseW, dst, dstStride), dst += srcChannels;
157
0
                    for (col = startX; col < dstWidthFull; col += 2)
158
0
                        WinogradKernel2x2Block2x2SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, dst, dstStride), dst += srcChannels;
159
0
                    if (col < dstWidth)
160
0
                        WinogradKernel2x2Block2x2SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, 3, 0, tailW, dst, dstStride), dst += srcChannels;
161
0
                }
162
0
                if (row < dstHeight)
163
0
                {
164
0
                    if (padX)
165
0
                        WinogradKernel2x2Block2x2SetInput1t(src + row * srcWidth * srcChannels, srcWidth, srcChannels, 0, tailH, 1, noseW, dst, dstStride), dst += srcChannels;
166
0
                    for (col = startX; col < dstWidthFull; col += 2)
167
0
                        WinogradKernel2x2Block2x2SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, tailH, 0, 3, dst, dstStride), dst += srcChannels;
168
0
                    if (col < dstWidth)
169
0
                        WinogradKernel2x2Block2x2SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, tailH, 0, tailW, dst, dstStride), dst += srcChannels;
170
0
                }
171
0
            }
172
0
            else
173
0
            {
174
0
                for (size_t c = 0; c < srcChannels; ++c)
175
0
                {
176
0
                    size_t row = 0, col = 0;
177
0
                    if (padY)
178
0
                    {
179
0
                        if (padX)
180
0
                            WinogradKernel2x2Block2x2SetInput1n(src, srcWidth, 1, noseH, 1, noseW, dst++, dstStride);
181
0
                        for (col = startX; col < dstWidthFull; col += 2)
182
0
                            WinogradKernel2x2Block2x2SetInput1n(src + col, srcWidth, 1, noseH, 0, 3, dst++, dstStride);
183
0
                        if (col < dstWidth)
184
0
                            WinogradKernel2x2Block2x2SetInput1n(src + col, srcWidth, 1, noseH, 0, tailW, dst++, dstStride);
185
0
                    }
186
0
                    for (row = startY; row < dstHeightFull; row += 2)
187
0
                    {
188
0
                        if (padX)
189
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth, srcWidth, 0, 3, 1, noseW, dst++, dstStride);
190
0
                        for (col = startX; col < dstWidthFull; col += 2)
191
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth + col, srcWidth, dst++, dstStride);
192
0
                        if (col < dstWidth)
193
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth + col, srcWidth, 0, 3, 0, tailW, dst++, dstStride);
194
0
                    }
195
0
                    if (row < dstHeight)
196
0
                    {
197
0
                        if (padX)
198
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth, srcWidth, 0, tailH, 1, noseW, dst++, dstStride);
199
0
                        for (col = startX; col < dstWidthFull; col += 2)
200
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth + col, srcWidth, 0, tailH, 0, 3, dst++, dstStride);
201
0
                        if (col < dstWidth)
202
0
                            WinogradKernel2x2Block2x2SetInput1n(src + row * srcWidth + col, srcWidth, 0, tailH, 0, tailW, dst++, dstStride);
203
0
                    }
204
0
                    src += srcWidth * srcHeight;
205
0
                }
206
0
            }
207
0
        }
208
209
        //-----------------------------------------------------------------------
210
211
        SIMD_INLINE void WinogradKernel2x2Block2x2SetOutput1(const float* src, size_t stride, float dst[4])
212
0
        {
213
0
            float s[9];
214
0
            s[0] = src[0 * stride];
215
0
            s[1] = src[1 * stride];
216
0
            s[2] = src[2 * stride];
217
0
            s[3] = src[3 * stride];
218
0
            s[4] = src[4 * stride];
219
0
            s[5] = src[5 * stride];
220
0
            s[6] = src[6 * stride];
221
0
            s[7] = src[7 * stride];
222
0
            s[8] = src[8 * stride];
223
224
0
            dst[0] = s[0] + s[1] + s[3] + s[4];
225
0
            dst[1] = s[1] + s[2] + s[4] + s[5];
226
0
            dst[2] = s[3] + s[4] + s[6] + s[7];
227
0
            dst[3] = s[4] + s[5] + s[7] + s[8];
228
0
        }
229
230
        SIMD_INLINE void WinogradKernel2x2Block2x2SetOutput1n(const float* src, size_t srcStride, float* dst, size_t dstStride)
231
0
        {
232
0
            float tmp[4];
233
0
            WinogradKernel2x2Block2x2SetOutput1(src, srcStride, tmp);
234
0
            dst[0 * dstStride + 0] = tmp[0];
235
0
            dst[0 * dstStride + 1] = tmp[1];
236
0
            dst[1 * dstStride + 0] = tmp[2];
237
0
            dst[1 * dstStride + 1] = tmp[3];
238
0
        }
239
240
        SIMD_INLINE void WinogradKernel2x2Block2x2SetOutput1n(const float* src, size_t srcStride, float* dst, size_t dstStride, size_t rowE, size_t colE)
241
0
        {
242
0
            float tmp[4];
243
0
            WinogradKernel2x2Block2x2SetOutput1(src, srcStride, tmp);
244
0
            for (size_t row = 0; row < rowE; ++row)
245
0
                for (size_t col = 0; col < colE; ++col)
246
0
                    dst[row * dstStride + col] = tmp[row * 2 + col];
247
0
        }
248
249
        SIMD_INLINE void WinogradKernel2x2Block2x2SetOutput1t(const float* src, size_t srcStride, float* dst, size_t dstW, size_t dstC)
250
0
        {
251
0
            size_t dstS = dstW * dstC;
252
0
            for (size_t d = 0; d < dstC; ++d, src++, dst++)
253
0
            {
254
0
                float tmp[4];
255
0
                WinogradKernel2x2Block2x2SetOutput1(src, srcStride, tmp);
256
0
                dst[0 * dstS + 0 * dstC] = tmp[0];
257
0
                dst[0 * dstS + 1 * dstC] = tmp[1];
258
0
                dst[1 * dstS + 0 * dstC] = tmp[2];
259
0
                dst[1 * dstS + 1 * dstC] = tmp[3];
260
0
            }
261
0
        }
262
263
        SIMD_INLINE void WinogradKernel2x2Block2x2SetOutput1t(const float* src, size_t srcStride, float* dst, size_t dstW, size_t dstC, size_t rowE, size_t colE)
264
0
        {
265
0
            size_t dstS = dstW * dstC;
266
0
            for (size_t d = 0; d < dstC; ++d, src++, dst++)
267
0
            {
268
0
                float tmp[4];
269
0
                WinogradKernel2x2Block2x2SetOutput1(src, srcStride, tmp);
270
0
                for (size_t row = 0; row < rowE; ++row)
271
0
                    for (size_t col = 0; col < colE; ++col)
272
0
                        dst[row * dstS + col * dstC] = tmp[row * 2 + col];
273
0
            }
274
0
        }
275
276
        void WinogradKernel2x2Block2x2SetOutput(const float* src, size_t srcStride, float* dst, size_t dstChannels, size_t dstHeight, size_t dstWidth, SimdBool trans)
277
0
        {
278
0
            size_t dstHeightFull = AlignLo(dstHeight, 2);
279
0
            size_t dstWidthFull = AlignLo(dstWidth, 2);
280
0
            if (trans)
281
0
            {
282
0
                size_t row, col;
283
0
                for (row = 0; row < dstHeightFull; row += 2)
284
0
                {
285
0
                    for (col = 0; col < dstWidthFull; col += 2)
286
0
                        WinogradKernel2x2Block2x2SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels), src += dstChannels;
287
0
                    if (col < dstWidth)
288
0
                        WinogradKernel2x2Block2x2SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, 2, dstWidth - col), src += dstChannels;
289
0
                }
290
0
                if (row < dstHeight)
291
0
                {
292
0
                    for (col = 0; col < dstWidthFull; col += 2)
293
0
                        WinogradKernel2x2Block2x2SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, dstHeight - row, 2), src += dstChannels;
294
0
                    if (col < dstWidth)
295
0
                        WinogradKernel2x2Block2x2SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, dstHeight - row, dstWidth - col), src += dstChannels;
296
0
                }
297
0
            }
298
0
            else
299
0
            {
300
0
                for (size_t c = 0; c < dstChannels; ++c)
301
0
                {
302
0
                    size_t row, col;
303
0
                    for (row = 0; row < dstHeightFull; row += 2)
304
0
                    {
305
0
                        for (col = 0; col < dstWidthFull; col += 2)
306
0
                            WinogradKernel2x2Block2x2SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth);
307
0
                        if (col < dstWidth)
308
0
                            WinogradKernel2x2Block2x2SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, 2, dstWidth - col);
309
0
                    }
310
0
                    if (row < dstHeight)
311
0
                    {
312
0
                        for (col = 0; col < dstWidthFull; col += 2)
313
0
                            WinogradKernel2x2Block2x2SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, dstHeight - row, 2);
314
0
                        if (col < dstWidth)
315
0
                            WinogradKernel2x2Block2x2SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, dstHeight - row, dstWidth - col);
316
0
                    }
317
0
                    dst += dstHeight * dstWidth;
318
0
                }
319
0
            }
320
0
        }
321
322
        //-----------------------------------------------------------------------
323
324
        void WinogradKernel2x2Block4x4SetFilter(const float* src, size_t size, float* dst, SimdBool trans)
325
0
        {
326
0
            if (trans)
327
0
            {
328
0
                for (size_t i = 0; i < size; i += 1)
329
0
                    Base::WinogradKernel2x2Block4x4SetFilter1t(src + i, dst + i, size);
330
0
            }
331
0
            else
332
0
            {
333
0
                for (size_t i = 0; i < size; i += 1, src += 4, dst += 1)
334
0
                    Base::WinogradKernel2x2Block4x4SetFilter1n(src, dst, size);
335
0
            }
336
0
        }
337
338
        //-----------------------------------------------------------------------
339
340
        SIMD_INLINE void WinogradKernel2x2Block4x4SetInput1(const float src[25], float* dst, size_t stride)
341
0
        {
342
0
            float tmp[25];
343
0
            tmp[0] = 2 * src[0] - src[5] - 2 * src[10] + src[15];
344
0
            tmp[1] = 2 * src[1] - src[6] - 2 * src[11] + src[16];
345
0
            tmp[2] = 2 * src[2] - src[7] - 2 * src[12] + src[17];
346
0
            tmp[3] = 2 * src[3] - src[8] - 2 * src[13] + src[18];
347
0
            tmp[4] = 2 * src[4] - src[9] - 2 * src[14] + src[19];
348
0
            tmp[5] = src[15] - 2 * src[5] - src[10];
349
0
            tmp[6] = src[16] - 2 * src[6] - src[11];
350
0
            tmp[7] = src[17] - 2 * src[7] - src[12];
351
0
            tmp[8] = src[18] - 2 * src[8] - src[13];
352
0
            tmp[9] = src[19] - 2 * src[9] - src[14];
353
0
            tmp[10] = 2 * src[5] - 3 * src[10] + src[15];
354
0
            tmp[11] = 2 * src[6] - 3 * src[11] + src[16];
355
0
            tmp[12] = 2 * src[7] - 3 * src[12] + src[17];
356
0
            tmp[13] = 2 * src[8] - 3 * src[13] + src[18];
357
0
            tmp[14] = 2 * src[9] - 3 * src[14] + src[19];
358
0
            tmp[15] = src[15] - src[5];
359
0
            tmp[16] = src[16] - src[6];
360
0
            tmp[17] = src[17] - src[7];
361
0
            tmp[18] = src[18] - src[8];
362
0
            tmp[19] = src[19] - src[9];
363
0
            tmp[20] = 2 * src[5] - src[10] - 2 * src[15] + src[20];
364
0
            tmp[21] = 2 * src[6] - src[11] - 2 * src[16] + src[21];
365
0
            tmp[22] = 2 * src[7] - src[12] - 2 * src[17] + src[22];
366
0
            tmp[23] = 2 * src[8] - src[13] - 2 * src[18] + src[23];
367
0
            tmp[24] = 2 * src[9] - src[14] - 2 * src[19] + src[24];
368
369
0
            dst[0 * stride] = 2 * tmp[0] - tmp[1] - 2 * tmp[2] + tmp[3];
370
0
            dst[1 * stride] = tmp[3] - 2 * tmp[1] - tmp[2];
371
0
            dst[2 * stride] = 2 * tmp[1] - 3 * tmp[2] + tmp[3];
372
0
            dst[3 * stride] = tmp[3] - tmp[1];
373
0
            dst[4 * stride] = 2 * tmp[1] - tmp[2] - 2 * tmp[3] + tmp[4];
374
0
            dst[5 * stride] = 2 * tmp[5] - tmp[6] - 2 * tmp[7] + tmp[8];
375
0
            dst[6 * stride] = tmp[8] - 2 * tmp[6] - tmp[7];
376
0
            dst[7 * stride] = 2 * tmp[6] - 3 * tmp[7] + tmp[8];
377
0
            dst[8 * stride] = tmp[8] - tmp[6];
378
0
            dst[9 * stride] = 2 * tmp[6] - tmp[7] - 2 * tmp[8] + tmp[9];
379
0
            dst[10 * stride] = 2 * tmp[10] - tmp[11] - 2 * tmp[12] + tmp[13];
380
0
            dst[11 * stride] = tmp[13] - 2 * tmp[11] - tmp[12];
381
0
            dst[12 * stride] = 2 * tmp[11] - 3 * tmp[12] + tmp[13];
382
0
            dst[13 * stride] = tmp[13] - tmp[11];
383
0
            dst[14 * stride] = 2 * tmp[11] - tmp[12] - 2 * tmp[13] + tmp[14];
384
0
            dst[15 * stride] = 2 * tmp[15] - tmp[16] - 2 * tmp[17] + tmp[18];
385
0
            dst[16 * stride] = tmp[18] - 2 * tmp[16] - tmp[17];
386
0
            dst[17 * stride] = 2 * tmp[16] - 3 * tmp[17] + tmp[18];
387
0
            dst[18 * stride] = tmp[18] - tmp[16];
388
0
            dst[19 * stride] = 2 * tmp[16] - tmp[17] - 2 * tmp[18] + tmp[19];
389
0
            dst[20 * stride] = 2 * tmp[20] - tmp[21] - 2 * tmp[22] + tmp[23];
390
0
            dst[21 * stride] = tmp[23] - 2 * tmp[21] - tmp[22];
391
0
            dst[22 * stride] = 2 * tmp[21] - 3 * tmp[22] + tmp[23];
392
0
            dst[23 * stride] = tmp[23] - tmp[21];
393
0
            dst[24 * stride] = 2 * tmp[21] - tmp[22] - 2 * tmp[23] + tmp[24];
394
0
        }
395
396
        SIMD_INLINE void WinogradKernel2x2Block4x4SetInput1n(const float* src, size_t srcStride, float* dst, size_t dstStride)
397
0
        {
398
0
            float tmp[25];
399
0
            tmp[0] = src[0 * srcStride + 0];
400
0
            tmp[1] = src[0 * srcStride + 1];
401
0
            tmp[2] = src[0 * srcStride + 2];
402
0
            tmp[3] = src[0 * srcStride + 3];
403
0
            tmp[4] = src[0 * srcStride + 4];
404
0
            tmp[5] = src[1 * srcStride + 0];
405
0
            tmp[6] = src[1 * srcStride + 1];
406
0
            tmp[7] = src[1 * srcStride + 2];
407
0
            tmp[8] = src[1 * srcStride + 3];
408
0
            tmp[9] = src[1 * srcStride + 4];
409
0
            tmp[10] = src[2 * srcStride + 0];
410
0
            tmp[11] = src[2 * srcStride + 1];
411
0
            tmp[12] = src[2 * srcStride + 2];
412
0
            tmp[13] = src[2 * srcStride + 3];
413
0
            tmp[14] = src[2 * srcStride + 4];
414
0
            tmp[15] = src[3 * srcStride + 0];
415
0
            tmp[16] = src[3 * srcStride + 1];
416
0
            tmp[17] = src[3 * srcStride + 2];
417
0
            tmp[18] = src[3 * srcStride + 3];
418
0
            tmp[19] = src[3 * srcStride + 4];
419
0
            tmp[20] = src[4 * srcStride + 0];
420
0
            tmp[21] = src[4 * srcStride + 1];
421
0
            tmp[22] = src[4 * srcStride + 2];
422
0
            tmp[23] = src[4 * srcStride + 3];
423
0
            tmp[24] = src[4 * srcStride + 4];
424
0
            WinogradKernel2x2Block4x4SetInput1(tmp, dst, dstStride);
425
0
        }
426
427
        SIMD_INLINE void WinogradKernel2x2Block4x4SetInput1n(const float* src, size_t srcStride, size_t rowB, size_t rowE, size_t colB, size_t colE, float* dst, size_t dstStride)
428
0
        {
429
0
            float tmp[25] = { 0 };
430
0
            for (size_t row = rowB; row < rowE; ++row)
431
0
                for (size_t col = colB; col < colE; ++col)
432
0
                    tmp[row * 5 + col] = src[row * srcStride + col];
433
0
            WinogradKernel2x2Block4x4SetInput1(tmp, dst, dstStride);
434
0
        }
435
436
        SIMD_INLINE void WinogradKernel2x2Block4x4SetInput1t(const float* src, size_t srcW, size_t srcC, float* dst, size_t dstStride)
437
0
        {
438
0
            size_t srcS = srcW * srcC;
439
0
            for (size_t c = 0; c < srcC; ++c, src++, dst++)
440
0
            {
441
0
                float tmp[25];
442
0
                tmp[0] = src[0 * srcS + 0 * srcC];
443
0
                tmp[1] = src[0 * srcS + 1 * srcC];
444
0
                tmp[2] = src[0 * srcS + 2 * srcC];
445
0
                tmp[3] = src[0 * srcS + 3 * srcC];
446
0
                tmp[4] = src[0 * srcS + 4 * srcC];
447
0
                tmp[5] = src[1 * srcS + 0 * srcC];
448
0
                tmp[6] = src[1 * srcS + 1 * srcC];
449
0
                tmp[7] = src[1 * srcS + 2 * srcC];
450
0
                tmp[8] = src[1 * srcS + 3 * srcC];
451
0
                tmp[9] = src[1 * srcS + 4 * srcC];
452
0
                tmp[10] = src[2 * srcS + 0 * srcC];
453
0
                tmp[11] = src[2 * srcS + 1 * srcC];
454
0
                tmp[12] = src[2 * srcS + 2 * srcC];
455
0
                tmp[13] = src[2 * srcS + 3 * srcC];
456
0
                tmp[14] = src[2 * srcS + 4 * srcC];
457
0
                tmp[15] = src[3 * srcS + 0 * srcC];
458
0
                tmp[16] = src[3 * srcS + 1 * srcC];
459
0
                tmp[17] = src[3 * srcS + 2 * srcC];
460
0
                tmp[18] = src[3 * srcS + 3 * srcC];
461
0
                tmp[19] = src[3 * srcS + 4 * srcC];
462
0
                tmp[20] = src[4 * srcS + 0 * srcC];
463
0
                tmp[21] = src[4 * srcS + 1 * srcC];
464
0
                tmp[22] = src[4 * srcS + 2 * srcC];
465
0
                tmp[23] = src[4 * srcS + 3 * srcC];
466
0
                tmp[24] = src[4 * srcS + 4 * srcC];
467
0
                WinogradKernel2x2Block4x4SetInput1(tmp, dst, dstStride);
468
0
            }
469
0
        }
470
471
        SIMD_INLINE void WinogradKernel2x2Block4x4SetInput1t(const float* src, size_t srcW, size_t srcC, size_t rowB, size_t rowE, size_t colB, size_t colE, float* dst, size_t dstStride)
472
0
        {
473
0
            size_t srcS = srcW * srcC;
474
0
            for (size_t c = 0; c < srcC; ++c, src++, dst++)
475
0
            {
476
0
                float tmp[25] = { 0 };
477
0
                for (size_t row = rowB; row < rowE; ++row)
478
0
                    for (size_t col = colB; col < colE; ++col)
479
0
                        tmp[row * 5 + col] = src[row * srcS + col * srcC];
480
0
                WinogradKernel2x2Block4x4SetInput1(tmp, dst, dstStride);
481
0
            }
482
0
        }
483
484
        void WinogradKernel2x2Block4x4SetInput(const float* src, size_t srcChannels, size_t srcHeight, size_t srcWidth,
485
            size_t padY, size_t padX, size_t padH, size_t padW, float* dst, size_t dstStride, SimdBool trans)
486
0
        {
487
0
            assert(padY == padX && padW == padH && (padY + padH == 0 || padY + padH == 1));
488
0
            size_t dstHeight = srcHeight - 1 + padY + padH;
489
0
            size_t dstWidth = srcWidth - 1 + padX + padW;
490
0
            size_t dstHeightFull = AlignLo(dstHeight, 4);
491
0
            size_t dstWidthFull = AlignLo(dstWidth, 4);
492
0
            size_t noseW = Simd::Min<size_t>(5, dstWidth + 1);
493
0
            size_t noseH = Simd::Min<size_t>(5, dstHeight + 1);
494
0
            size_t startY = padY ? 4 : 0;
495
0
            size_t startX = padX ? 4 : 0;
496
0
            if (padY || padH)
497
0
            {
498
0
                if (dstHeight == dstHeightFull)
499
0
                    dstHeightFull -= 4;
500
0
                if (dstWidth == dstWidthFull)
501
0
                    dstWidthFull -= 4;
502
0
                if (padY)
503
0
                    src -= (srcWidth + 1) * (trans ? srcChannels : 1);
504
0
            }
505
0
            size_t tailW = dstWidth - dstWidthFull + (padW ? 0 : 1);
506
0
            size_t tailH = dstHeight - dstHeightFull + (padH ? 0 : 1);
507
0
            if (trans)
508
0
            {
509
0
                size_t row = 0, col = 0;
510
0
                if (padY)
511
0
                {
512
0
                    if (padX)
513
0
                        WinogradKernel2x2Block4x4SetInput1t(src, srcWidth, srcChannels, 1, noseH, 1, noseW, dst, dstStride), dst += srcChannels;
514
0
                    for (col = startX; col < dstWidthFull; col += 4)
515
0
                        WinogradKernel2x2Block4x4SetInput1t(src + col * srcChannels, srcWidth, srcChannels, 1, noseH, 0, 5, dst, dstStride), dst += srcChannels;
516
0
                    if (col < dstWidth)
517
0
                        WinogradKernel2x2Block4x4SetInput1t(src + col * srcChannels, srcWidth, srcChannels, 1, noseH, 0, tailW, dst, dstStride), dst += srcChannels;
518
0
                }
519
0
                for (row = startY; row < dstHeightFull; row += 4)
520
0
                {
521
0
                    if (padX)
522
0
                        WinogradKernel2x2Block4x4SetInput1t(src + row * srcWidth * srcChannels, srcWidth, srcChannels, 0, 5, 1, noseW, dst, dstStride), dst += srcChannels;
523
0
                    for (col = startX; col < dstWidthFull; col += 4)
524
0
                        WinogradKernel2x2Block4x4SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, dst, dstStride), dst += srcChannels;
525
0
                    if (col < dstWidth)
526
0
                        WinogradKernel2x2Block4x4SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, 5, 0, tailW, dst, dstStride), dst += srcChannels;
527
0
                }
528
0
                if (row < dstHeight)
529
0
                {
530
0
                    if (padX)
531
0
                        WinogradKernel2x2Block4x4SetInput1t(src + row * srcWidth * srcChannels, srcWidth, srcChannels, 0, tailH, 1, noseW, dst, dstStride), dst += srcChannels;
532
0
                    for (col = startX; col < dstWidthFull; col += 4)
533
0
                        WinogradKernel2x2Block4x4SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, tailH, 0, 5, dst, dstStride), dst += srcChannels;
534
0
                    if (col < dstWidth)
535
0
                        WinogradKernel2x2Block4x4SetInput1t(src + (row * srcWidth + col) * srcChannels, srcWidth, srcChannels, 0, tailH, 0, tailW, dst, dstStride), dst += srcChannels;
536
0
                }
537
0
            }
538
0
            else
539
0
            {
540
0
                for (size_t c = 0; c < srcChannels; ++c)
541
0
                {
542
0
                    size_t row = 0, col = 0;
543
0
                    if (padY)
544
0
                    {
545
0
                        if (padX)
546
0
                            WinogradKernel2x2Block4x4SetInput1n(src, srcWidth, 1, noseH, 1, noseW, dst++, dstStride);
547
0
                        for (col = startX; col < dstWidthFull; col += 4)
548
0
                            WinogradKernel2x2Block4x4SetInput1n(src + col, srcWidth, 1, noseH, 0, 5, dst++, dstStride);
549
0
                        if (col < dstWidth)
550
0
                            WinogradKernel2x2Block4x4SetInput1n(src + col, srcWidth, 1, noseH, 0, tailW, dst++, dstStride);
551
0
                    }
552
0
                    for (row = startY; row < dstHeightFull; row += 4)
553
0
                    {
554
0
                        if (padX)
555
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth, srcWidth, 0, 5, 1, noseW, dst++, dstStride);
556
0
                        for (col = startX; col < dstWidthFull; col += 4)
557
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth + col, srcWidth, dst++, dstStride);
558
0
                        if (col < dstWidth)
559
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth + col, srcWidth, 0, 5, 0, tailW, dst++, dstStride);
560
0
                    }
561
0
                    if (row < dstHeight)
562
0
                    {
563
0
                        if (padX)
564
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth, srcWidth, 0, tailH, 1, noseW, dst++, dstStride);
565
0
                        for (col = startX; col < dstWidthFull; col += 4)
566
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth + col, srcWidth, 0, tailH, 0, 5, dst++, dstStride);
567
0
                        if (col < dstWidth)
568
0
                            WinogradKernel2x2Block4x4SetInput1n(src + row * srcWidth + col, srcWidth, 0, tailH, 0, tailW, dst++, dstStride);
569
0
                    }
570
0
                    src += srcWidth * srcHeight;
571
0
                }
572
0
            }
573
0
        }
574
575
        //-----------------------------------------------------------------------
576
577
        SIMD_INLINE void WinogradKernel2x2Block4x4SetOutput1(const float* src, size_t stride, float dst[4])
578
0
        {
579
0
            float s[25];
580
0
            s[0] = src[0 * stride];
581
0
            s[1] = src[1 * stride];
582
0
            s[2] = src[2 * stride];
583
0
            s[3] = src[3 * stride];
584
0
            s[4] = src[4 * stride];
585
0
            s[5] = src[5 * stride];
586
0
            s[6] = src[6 * stride];
587
0
            s[7] = src[7 * stride];
588
0
            s[8] = src[8 * stride];
589
0
            s[9] = src[9 * stride];
590
0
            s[10] = src[10 * stride];
591
0
            s[11] = src[11 * stride];
592
0
            s[12] = src[12 * stride];
593
0
            s[13] = src[13 * stride];
594
0
            s[14] = src[14 * stride];
595
0
            s[15] = src[15 * stride];
596
0
            s[16] = src[16 * stride];
597
0
            s[17] = src[17 * stride];
598
0
            s[18] = src[18 * stride];
599
0
            s[19] = src[19 * stride];
600
0
            s[20] = src[20 * stride];
601
0
            s[21] = src[21 * stride];
602
0
            s[22] = src[22 * stride];
603
0
            s[23] = src[23 * stride];
604
0
            s[24] = src[24 * stride];
605
606
0
            float t[20];
607
0
            t[0] = s[0] + s[5] + s[10] + s[15];
608
0
            t[1] = s[1] + s[6] + s[11] + s[16];
609
0
            t[2] = s[2] + s[7] + s[12] + s[17];
610
0
            t[3] = s[3] + s[8] + s[13] + s[18];
611
0
            t[4] = s[4] + s[9] + s[14] + s[19];
612
0
            t[5] = s[5] - s[10] + 2 * s[15];
613
0
            t[6] = s[6] - s[11] + 2 * s[16];
614
0
            t[7] = s[7] - s[12] + 2 * s[17];
615
0
            t[8] = s[8] - s[13] + 2 * s[18];
616
0
            t[9] = s[9] - s[14] + 2 * s[19];
617
0
            t[10] = s[5] + s[10] + 4 * s[15];
618
0
            t[11] = s[6] + s[11] + 4 * s[16];
619
0
            t[12] = s[7] + s[12] + 4 * s[17];
620
0
            t[13] = s[8] + s[13] + 4 * s[18];
621
0
            t[14] = s[9] + s[14] + 4 * s[19];
622
0
            t[15] = s[5] - s[10] + 8 * s[15] + s[20];
623
0
            t[16] = s[6] - s[11] + 8 * s[16] + s[21];
624
0
            t[17] = s[7] - s[12] + 8 * s[17] + s[22];
625
0
            t[18] = s[8] - s[13] + 8 * s[18] + s[23];
626
0
            t[19] = s[9] - s[14] + 8 * s[19] + s[24];
627
628
0
            dst[0] = t[0] + t[1] + t[2] + t[3];
629
0
            dst[1] = t[1] - t[2] + 2 * t[3];
630
0
            dst[2] = t[1] + t[2] + 4 * t[3];
631
0
            dst[3] = t[1] - t[2] + 8 * t[3] + t[4];
632
0
            dst[4] = t[5] + t[6] + t[7] + t[8];
633
0
            dst[5] = t[6] - t[7] + 2 * t[8];
634
0
            dst[6] = t[6] + t[7] + 4 * t[8];
635
0
            dst[7] = t[6] - t[7] + 8 * t[8] + t[9];
636
0
            dst[8] = t[10] + t[11] + t[12] + t[13];
637
0
            dst[9] = t[11] - t[12] + 2 * t[13];
638
0
            dst[10] = t[11] + t[12] + 4 * t[13];
639
0
            dst[11] = t[11] - t[12] + 8 * t[13] + t[14];
640
0
            dst[12] = t[15] + t[16] + t[17] + t[18];
641
0
            dst[13] = t[16] - t[17] + 2 * t[18];
642
0
            dst[14] = t[16] + t[17] + 4 * t[18];
643
0
            dst[15] = t[16] - t[17] + 8 * t[18] + t[19];
644
0
        }
645
646
        SIMD_INLINE void WinogradKernel2x2Block4x4SetOutput1n(const float* src, size_t srcStride, float* dst, size_t dstStride)
647
0
        {
648
0
            float tmp[16];
649
0
            WinogradKernel2x2Block4x4SetOutput1(src, srcStride, tmp);
650
0
            dst[0 * dstStride + 0] = tmp[0];
651
0
            dst[0 * dstStride + 1] = tmp[1];
652
0
            dst[0 * dstStride + 2] = tmp[2];
653
0
            dst[0 * dstStride + 3] = tmp[3];
654
0
            dst[1 * dstStride + 0] = tmp[4];
655
0
            dst[1 * dstStride + 1] = tmp[5];
656
0
            dst[1 * dstStride + 2] = tmp[6];
657
0
            dst[1 * dstStride + 3] = tmp[7];
658
0
            dst[2 * dstStride + 0] = tmp[8];
659
0
            dst[2 * dstStride + 1] = tmp[9];
660
0
            dst[2 * dstStride + 2] = tmp[10];
661
0
            dst[2 * dstStride + 3] = tmp[11];
662
0
            dst[3 * dstStride + 0] = tmp[12];
663
0
            dst[3 * dstStride + 1] = tmp[13];
664
0
            dst[3 * dstStride + 2] = tmp[14];
665
0
            dst[3 * dstStride + 3] = tmp[15];
666
0
        }
667
668
        SIMD_INLINE void WinogradKernel2x2Block4x4SetOutput1n(const float* src, size_t srcStride, float* dst, size_t dstStride, size_t rowE, size_t colE)
669
0
        {
670
0
            float tmp[16];
671
0
            WinogradKernel2x2Block4x4SetOutput1(src, srcStride, tmp);
672
0
            for (size_t row = 0; row < rowE; ++row)
673
0
                for (size_t col = 0; col < colE; ++col)
674
0
                    dst[row * dstStride + col] = tmp[row * 4 + col];
675
0
        }
676
677
        SIMD_INLINE void WinogradKernel2x2Block4x4SetOutput1t(const float* src, size_t srcStride, float* dst, size_t dstW, size_t dstC)
678
0
        {
679
0
            size_t dstS = dstW * dstC;
680
0
            for (size_t d = 0; d < dstC; ++d, src++, dst++)
681
0
            {
682
0
                float tmp[16];
683
0
                WinogradKernel2x2Block4x4SetOutput1(src, srcStride, tmp);
684
0
                dst[0 * dstS + 0 * dstC] = tmp[0];
685
0
                dst[0 * dstS + 1 * dstC] = tmp[1];
686
0
                dst[0 * dstS + 2 * dstC] = tmp[2];
687
0
                dst[0 * dstS + 3 * dstC] = tmp[3];
688
0
                dst[1 * dstS + 0 * dstC] = tmp[4];
689
0
                dst[1 * dstS + 1 * dstC] = tmp[5];
690
0
                dst[1 * dstS + 2 * dstC] = tmp[6];
691
0
                dst[1 * dstS + 3 * dstC] = tmp[7];
692
0
                dst[2 * dstS + 0 * dstC] = tmp[8];
693
0
                dst[2 * dstS + 1 * dstC] = tmp[9];
694
0
                dst[2 * dstS + 2 * dstC] = tmp[10];
695
0
                dst[2 * dstS + 3 * dstC] = tmp[11];
696
0
                dst[3 * dstS + 0 * dstC] = tmp[12];
697
0
                dst[3 * dstS + 1 * dstC] = tmp[13];
698
0
                dst[3 * dstS + 2 * dstC] = tmp[14];
699
0
                dst[3 * dstS + 3 * dstC] = tmp[15];
700
0
            }
701
0
        }
702
703
        SIMD_INLINE void WinogradKernel2x2Block4x4SetOutput1t(const float* src, size_t srcStride, float* dst, size_t dstW, size_t dstC, size_t rowE, size_t colE)
704
0
        {
705
0
            size_t dstS = dstW * dstC;
706
0
            for (size_t d = 0; d < dstC; ++d, src++, dst++)
707
0
            {
708
0
                float tmp[16];
709
0
                WinogradKernel2x2Block4x4SetOutput1(src, srcStride, tmp);
710
0
                for (size_t row = 0; row < rowE; ++row)
711
0
                    for (size_t col = 0; col < colE; ++col)
712
0
                        dst[row * dstS + col * dstC] = tmp[row * 4 + col];
713
0
            }
714
0
        }
715
716
        void WinogradKernel2x2Block4x4SetOutput(const float* src, size_t srcStride, float* dst, size_t dstChannels, size_t dstHeight, size_t dstWidth, SimdBool trans)
717
0
        {
718
0
            size_t dstHeightFull = AlignLo(dstHeight, 4);
719
0
            size_t dstWidthFull = AlignLo(dstWidth, 4);
720
0
            if (trans)
721
0
            {
722
0
                size_t row, col;
723
0
                for (row = 0; row < dstHeightFull; row += 4)
724
0
                {
725
0
                    for (col = 0; col < dstWidthFull; col += 4)
726
0
                        WinogradKernel2x2Block4x4SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels), src += dstChannels;
727
0
                    if (col < dstWidth)
728
0
                        WinogradKernel2x2Block4x4SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, 4, dstWidth - col), src += dstChannels;
729
0
                }
730
0
                if (row < dstHeight)
731
0
                {
732
0
                    for (col = 0; col < dstWidthFull; col += 4)
733
0
                        WinogradKernel2x2Block4x4SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, dstHeight - row, 4), src += dstChannels;
734
0
                    if (col < dstWidth)
735
0
                        WinogradKernel2x2Block4x4SetOutput1t(src, srcStride, dst + (row * dstWidth + col) * dstChannels, dstWidth, dstChannels, dstHeight - row, dstWidth - col), src += dstChannels;
736
0
                }
737
0
            }
738
0
            else
739
0
            {
740
0
                for (size_t c = 0; c < dstChannels; ++c)
741
0
                {
742
0
                    size_t row, col;
743
0
                    for (row = 0; row < dstHeightFull; row += 4)
744
0
                    {
745
0
                        for (col = 0; col < dstWidthFull; col += 4)
746
0
                            WinogradKernel2x2Block4x4SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth);
747
0
                        if (col < dstWidth)
748
0
                            WinogradKernel2x2Block4x4SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, 4, dstWidth - col);
749
0
                    }
750
0
                    if (row < dstHeight)
751
0
                    {
752
0
                        for (col = 0; col < dstWidthFull; col += 4)
753
0
                            WinogradKernel2x2Block4x4SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, dstHeight - row, 4);
754
0
                        if (col < dstWidth)
755
0
                            WinogradKernel2x2Block4x4SetOutput1n(src++, srcStride, dst + row * dstWidth + col, dstWidth, dstHeight - row, dstWidth - col);
756
0
                    }
757
0
                    dst += dstHeight * dstWidth;
758
0
                }
759
0
            }
760
0
        }
761
    }
762
#endif
763
}