1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 18 нояб. 2018 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <dsp/dsp.h>
23 #include <test/utest.h>
24 #include <test/FloatBuffer.h>
25 
26 namespace native
27 {
28     void limit_saturate1(float *dst, size_t count);
29     void limit_saturate2(float *dst, const float *src, size_t count);
30 }
31 
32 IF_ARCH_X86(
33     namespace sse2
34     {
35         void limit_saturate1(float *dst, size_t count);
36         void limit_saturate2(float *dst, const float *src, size_t count);
37     }
38 
39     namespace avx2
40     {
41         void limit_saturate1(float *dst, size_t count);
42         void limit_saturate2(float *dst, const float *src, size_t count);
43     }
44 )
45 
46 IF_ARCH_ARM(
47     namespace neon_d32
48     {
49         void limit_saturate1(float *dst, size_t count);
50         void limit_saturate2(float *dst, const float *src, size_t count);
51     }
52 )
53 
54 IF_ARCH_AARCH64(
55     namespace asimd
56     {
57         void limit_saturate1(float *dst, size_t count);
58         void limit_saturate2(float *dst, const float *src, size_t count);
59     }
60 )
61 
62 typedef void (* limit_saturate1_t)(float *dst, size_t count);
63 typedef void (* limit_saturate2_t)(float *dst, const float *src, size_t count);
64 
65 UTEST_BEGIN("dsp.float", limit_saturate)
66 
init_buf(FloatBuffer & buf)67     void init_buf(FloatBuffer &buf)
68     {
69         for (size_t i=0; i<buf.size(); ++i)
70         {
71             switch (i%6)
72             {
73                 case 0:
74                     buf[i]          = +INFINITY;
75                     break;
76                 case 1:
77                     buf[i]          = (rand() * 2.0f) / RAND_MAX;
78                     break;
79                 case 2:
80                     buf[i]          = -INFINITY;
81                     break;
82                 case 3:
83                     buf[i]          = - (rand() * 2.0f) / RAND_MAX;
84                     break;
85                 case 4:
86                     buf[i]          = -NAN;
87                     break;
88                 default:
89                     buf[i]          = NAN;
90                     break;
91             }
92         }
93     }
94 
check_buffer(const char * label,FloatBuffer & buf)95     void check_buffer(const char *label, FloatBuffer & buf)
96     {
97         UTEST_ASSERT_MSG(buf.valid(), "Destination buffer '%s' corrupted", label);
98         for (size_t i=0, n=buf.size(); i<n; ++i)
99         {
100             float s = buf.get(i);
101             UTEST_ASSERT_MSG((s >= -1.0f) && (s <= 1.0f), "Invalid buffer contents: %.5f", s);
102         }
103     }
104 
call(const char * label,size_t align,limit_saturate2_t func)105     void call(const char *label, size_t align, limit_saturate2_t func)
106     {
107         if (!UTEST_SUPPORTED(func))
108             return;
109 
110         UTEST_FOREACH(count, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
111                         32, 64, 65, 100, 768, 999, 1024, 0x1fff)
112         {
113             for (size_t mask=0; mask <= 0x03; ++mask)
114             {
115                 printf("Testing %s on input buffer of %d numbers, mask=0x%x...\n", label, int(count), int(mask));
116 
117                 FloatBuffer src(count, align, mask & 0x01);
118                 init_buf(src);
119                 FloatBuffer dst1(count, align, mask & 0x02);
120                 FloatBuffer dst2(dst1);
121 
122                 // Call functions
123                 native::limit_saturate2(dst1, src, count);
124                 func(dst2, src, count);
125 
126                 UTEST_ASSERT_MSG(src.valid(), "Source buffer corrupted");
127 
128                 check_buffer("dst1", dst1);
129                 check_buffer("dst2", dst2);
130 
131                 // Compare buffers
132                 if (!dst1.equals_relative(dst2, 1e-5))
133                 {
134                     src.dump("src ");
135                     dst1.dump("dst1");
136                     dst2.dump("dst2");
137                     UTEST_FAIL_MSG("Output of functions for test '%s' differs", label);
138                 }
139             }
140         }
141     }
142 
call(const char * label,size_t align,limit_saturate1_t func)143     void call(const char *label, size_t align, limit_saturate1_t func)
144     {
145         if (!UTEST_SUPPORTED(func))
146             return;
147 
148         UTEST_FOREACH(count, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
149                 32, 64, 65, 100, 768, 999, 1024, 0x1fff)
150         {
151             for (size_t mask=0; mask <= 0x01; ++mask)
152             {
153                 printf("Testing %s on input buffer of %d numbers, mask=0x%x...\n", label, int(count), int(mask));
154 
155                 FloatBuffer dst1(count, align, mask & 0x02);
156                 init_buf(dst1);
157                 FloatBuffer dst2(dst1);
158                 FloatBuffer src(dst1);
159 
160                 // Call functions
161                 native::limit_saturate1(dst1, count);
162                 func(dst2, count);
163 
164                 check_buffer("dst1", dst1);
165                 check_buffer("dst2", dst2);
166 
167                 // Compare buffers
168                 if (!dst1.equals_relative(dst2, 1e-5))
169                 {
170                     src.dump("src ");
171                     dst1.dump("dst1");
172                     dst2.dump("dst2");
173                     UTEST_FAIL_MSG("Output of functions for test '%s' differs", label);
174                 }
175             }
176         }
177     }
178 
179     UTEST_MAIN
180     {
181         #define CALL(func, align) \
182             call(#func, align, func)
183 
184         IF_ARCH_X86(CALL(sse2::limit_saturate1, 16));
185         IF_ARCH_X86(CALL(sse2::limit_saturate2, 16));
186 
187         IF_ARCH_X86(CALL(avx2::limit_saturate1, 32));
188         IF_ARCH_X86(CALL(avx2::limit_saturate2, 32));
189 
190         IF_ARCH_ARM(CALL(neon_d32::limit_saturate1, 16));
191         IF_ARCH_ARM(CALL(neon_d32::limit_saturate2, 16));
192 
193         IF_ARCH_AARCH64(CALL(asimd::limit_saturate1, 16));
194         IF_ARCH_AARCH64(CALL(asimd::limit_saturate2, 16));
195     }
196 
197 UTEST_END;
198 
199 
200