• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <audio_utils/intrinsic_utils.h>
18 
19 #include <gtest/gtest.h>
20 #include <random>
21 #include <vector>
22 
23 static constexpr float kFloatTolerance = 1e-3;
24 static constexpr size_t kStandardSize = 8;
25 static constexpr float kRangeMin = -10.f;
26 static constexpr float kRangeMax = 10.f;
27 
28 // see also std::seed_seq
29 static size_t seedCounter = 42;
30 
31 // create uniform distribution
32 template <typename T, typename V>
initUniform(V & v,T rangeMin,T rangeMax)33 static void initUniform(V& v, T rangeMin, T rangeMax) {
34     std::minstd_rand gen(++seedCounter);
35     std::uniform_real_distribution<T> dis(rangeMin, rangeMax);
36 
37     android::audio_utils::intrinsics::vapply([&]() { return dis(gen); }, v);
38 }
39 
40 using android::audio_utils::intrinsics::veval;
41 
42 // constexpr method tests can use static_assert.
43 
44 static constexpr android::audio_utils::intrinsics::internal_array_t<float, 3> xyzzy =
45         { 10, 10, 10 };
46 
47 static_assert(android::audio_utils::intrinsics::internal_array_t<float, 3>(10) ==
48         android::audio_utils::intrinsics::internal_array_t<float, 3>(
49                 { 10, 10, 10 }));
50 
51 static_assert(android::audio_utils::intrinsics::internal_array_t<float, 3>(10) !=
52         android::audio_utils::intrinsics::internal_array_t<float, 3>(
53                 { 10, 10, 20 }));
54 
55 static_assert(android::audio_utils::intrinsics::internal_array_t<float, 3>(10) !=
56         android::audio_utils::intrinsics::internal_array_t<float, 3>(
57                 { 10, 10 })); // implicit zero fill at end.
58 
59 static_assert(android::audio_utils::intrinsics::internal_array_t<float, 3>( { 10, 10, 0 }) ==
60         android::audio_utils::intrinsics::internal_array_t<float, 3>(
61                 { 10, 10 })); // implicit zero fill at end.
62 
63 
64 static_assert(android::audio_utils::intrinsics::internal_array_t<float, 3>(3) ==
__anon182793810202() 65     []() { android::audio_utils::intrinsics::internal_array_t<float, 3>  temp;
66            vapply(3, temp);
67            return temp; }());
68 
TEST(IntrisicUtilsTest,vector_hw_ctor_compatibility)69 TEST(IntrisicUtilsTest, vector_hw_ctor_compatibility) {
70     const android::audio_utils::intrinsics::vector_hw_t<float, 3> a{ 1, 2, 3 };
71     const android::audio_utils::intrinsics::vector_hw_t<float, 3> b(
72         android::audio_utils::intrinsics::internal_array_t<float, 3>{ 1, 2, 3 });
73     const android::audio_utils::intrinsics::vector_hw_t<float, 3> c(
74         android::audio_utils::intrinsics::internal_array_t<float, 3>{ 1, 2, 2 });
75     EXPECT_TRUE(android::audio_utils::intrinsics::veq(a, b));
76     EXPECT_FALSE(android::audio_utils::intrinsics::veq(a, c));
77 }
78 
TEST(IntrisicUtilsTest,veq_nan)79 TEST(IntrisicUtilsTest, veq_nan) {
80     const android::audio_utils::intrinsics::vector_hw_t<float, 3> a(std::nanf(""));
81     EXPECT_EQ(0, std::memcmp(&a, &a, sizeof(a)));  // bitwise equal.
82     EXPECT_FALSE(android::audio_utils::intrinsics::veq(a, a));  // logically nan is not.
83 }
84 
TEST(IntrisicUtilsTest,veq_zero)85 TEST(IntrisicUtilsTest, veq_zero) {
86     int32_t neg = 0x8000'0000;
87     int32_t pos = 0;
88     float negzero, poszero;
89     memcpy(&negzero, &neg, sizeof(neg));  // float negative zero.
90     memcpy(&poszero, &pos, sizeof(pos));  // float positive zero.
91     const android::audio_utils::intrinsics::vector_hw_t<float, 3> a(negzero);
92     const android::audio_utils::intrinsics::vector_hw_t<float, 3> b(poszero);
93     EXPECT_NE(0, std::memcmp(&a, &b, sizeof(a)));  // bitwise not-equal.
94     EXPECT_TRUE(android::audio_utils::intrinsics::veq(a, b));  // logically equal.
95 }
96 
97 template <typename D>
98 class IntrisicUtilsTest : public ::testing::Test {
99 };
100 
101 // Basic intrinsic tests.
102 using FloatTypes = ::testing::Types<float, double,
103         android::audio_utils::intrinsics::internal_array_t<float, kStandardSize>,
104         android::audio_utils::intrinsics::internal_array_t<float, 1>,
105         android::audio_utils::intrinsics::internal_array_t<double, kStandardSize>,
106         android::audio_utils::intrinsics::vector_hw_t<float, kStandardSize>,
107         android::audio_utils::intrinsics::vector_hw_t<float, 1>,
108         android::audio_utils::intrinsics::vector_hw_t<float, 2>,
109         android::audio_utils::intrinsics::vector_hw_t<float, 4>,
110         android::audio_utils::intrinsics::vector_hw_t<float, 7>,
111         android::audio_utils::intrinsics::vector_hw_t<float, 15>
112         >;
113 TYPED_TEST_CASE(IntrisicUtilsTest, FloatTypes);
114 
TYPED_TEST(IntrisicUtilsTest,vector_hw_ctor)115 TYPED_TEST(IntrisicUtilsTest, vector_hw_ctor) {
116     if constexpr (!std::is_arithmetic_v<TypeParam>) {
117         if constexpr(std::is_same_v<float, typename TypeParam::element_t>) {
118             android::audio_utils::intrinsics::vector_hw_t<float, TypeParam::size()>
119                     a(TypeParam(0.5));
120         }
121     }
122 }
123 
TYPED_TEST(IntrisicUtilsTest,vabs_constant)124 TYPED_TEST(IntrisicUtilsTest, vabs_constant) {
125     const TypeParam value(-3.125f);
126     const TypeParam result = veval([](auto v) { return std::abs(v); }, value);
127     ASSERT_EQ(result, android::audio_utils::intrinsics::vabs(value));
128 }
129 
TYPED_TEST(IntrisicUtilsTest,vabs_random)130 TYPED_TEST(IntrisicUtilsTest, vabs_random) {
131     TypeParam value;
132     initUniform(value, kRangeMin, kRangeMax);
133     const TypeParam result = veval([](auto v) { return std::abs(v); }, value);
134     ASSERT_EQ(result, android::audio_utils::intrinsics::vabs(value));
135 }
136 
TYPED_TEST(IntrisicUtilsTest,vadd_constant)137 TYPED_TEST(IntrisicUtilsTest, vadd_constant) {
138     const TypeParam a(0.25f);
139     const TypeParam b(0.5f);
140     const TypeParam result = veval(
141             [](auto x, auto y) { return x + y; }, a, b);
142     EXPECT_EQ(result, android::audio_utils::intrinsics::vadd(a, b));
143 }
144 
TYPED_TEST(IntrisicUtilsTest,vadd_random)145 TYPED_TEST(IntrisicUtilsTest, vadd_random) {
146     TypeParam a, b;
147     initUniform(a, kRangeMin, kRangeMax);
148     initUniform(b, kRangeMin, kRangeMax);
149     const TypeParam result = veval(
150             [](auto x, auto y) { return x + y; }, a, b);
151     EXPECT_EQ(result, android::audio_utils::intrinsics::vadd(a, b));
152 }
153 
TYPED_TEST(IntrisicUtilsTest,vaddv_random)154 TYPED_TEST(IntrisicUtilsTest, vaddv_random) {
155     TypeParam a;
156     initUniform(a, kRangeMin, kRangeMax);
157     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
158     element_t result{};
159     android::audio_utils::intrinsics::vapply([&result] (element_t value) { result += value; }, a);
160     EXPECT_NEAR(result, android::audio_utils::intrinsics::vaddv(a), kFloatTolerance);
161 }
162 
TYPED_TEST(IntrisicUtilsTest,vdupn)163 TYPED_TEST(IntrisicUtilsTest, vdupn) {
164     constexpr float ref = 1.f;
165     const TypeParam value(ref);
166     EXPECT_EQ(value, android::audio_utils::intrinsics::vdupn<TypeParam>(ref));
167 }
168 
TYPED_TEST(IntrisicUtilsTest,vld1)169 TYPED_TEST(IntrisicUtilsTest, vld1) {
170     const TypeParam value(2.f);
171     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(value));
172     EXPECT_EQ(value, android::audio_utils::intrinsics::vld1<TypeParam>(
173             reinterpret_cast<const element_t*>(&value)));
174 }
175 
TYPED_TEST(IntrisicUtilsTest,vmax_constant)176 TYPED_TEST(IntrisicUtilsTest, vmax_constant) {
177     const TypeParam a(0.25f);
178     const TypeParam b(0.5f);
179     const TypeParam result = veval(
180             [](auto x, auto y) { return std::max(x, y); }, a, b);
181     ASSERT_EQ(result, android::audio_utils::intrinsics::vmax(a, b));
182 }
183 
TYPED_TEST(IntrisicUtilsTest,vmax_random)184 TYPED_TEST(IntrisicUtilsTest, vmax_random) {
185     TypeParam a, b;
186     initUniform(a, kRangeMin, kRangeMax);
187     initUniform(b, kRangeMin, kRangeMax);
188     const TypeParam result = veval(
189             [](auto x, auto y) { return std::max(x, y); }, a, b);
190     ASSERT_EQ(result, android::audio_utils::intrinsics::vmax(a, b));
191 }
192 
TYPED_TEST(IntrisicUtilsTest,vmaxv_random)193 TYPED_TEST(IntrisicUtilsTest, vmaxv_random) {
194     TypeParam a;
195     initUniform(a, kRangeMin, kRangeMax);
196     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
197     element_t result = android::audio_utils::intrinsics::first_element_of(a);
198     android::audio_utils::intrinsics::vapply(
199             [&result] (element_t value) { result = std::max(result, value); }, a);
200     ASSERT_EQ(result, android::audio_utils::intrinsics::vmaxv(a));
201 }
202 
TYPED_TEST(IntrisicUtilsTest,vmax_random_scalar)203 TYPED_TEST(IntrisicUtilsTest, vmax_random_scalar) {
204     TypeParam a;
205     initUniform(a, kRangeMin, kRangeMax);
206     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
207     const element_t scalar = 3.f;
208     TypeParam b(scalar);
209     const TypeParam result = veval(
210             [](auto x, auto y) { return std::max(x, y); }, a, b);
211     EXPECT_EQ(result, android::audio_utils::intrinsics::vmax(a, scalar));
212     EXPECT_EQ(result, android::audio_utils::intrinsics::vmax(scalar, a));
213     EXPECT_EQ(result, android::audio_utils::intrinsics::vmax(a, b));
214 }
215 
TYPED_TEST(IntrisicUtilsTest,vmin_constant)216 TYPED_TEST(IntrisicUtilsTest, vmin_constant) {
217     const TypeParam a(0.25f);
218     const TypeParam b(0.5f);
219     const TypeParam result = veval(
220             [](auto x, auto y) { return std::min(x, y); }, a, b);
221     ASSERT_EQ(result, android::audio_utils::intrinsics::vmin(a, b));
222 }
223 
TYPED_TEST(IntrisicUtilsTest,vmin_random)224 TYPED_TEST(IntrisicUtilsTest, vmin_random) {
225     TypeParam a, b;
226     initUniform(a, kRangeMin, kRangeMax);
227     initUniform(b, kRangeMin, kRangeMax);
228     const TypeParam result = veval(
229             [](auto x, auto y) { return std::min(x, y); }, a, b);
230     ASSERT_EQ(result, android::audio_utils::intrinsics::vmin(a, b));
231 }
232 
TYPED_TEST(IntrisicUtilsTest,vminv_random)233 TYPED_TEST(IntrisicUtilsTest, vminv_random) {
234     TypeParam a;
235     initUniform(a, kRangeMin, kRangeMax);
236     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
237     element_t result = android::audio_utils::intrinsics::first_element_of(a);
238     android::audio_utils::intrinsics::vapply(
239             [&result] (element_t value) { result = std::min(result, value); }, a);
240     ASSERT_EQ(result, android::audio_utils::intrinsics::vminv(a));
241 }
242 
TYPED_TEST(IntrisicUtilsTest,vmin_random_scalar)243 TYPED_TEST(IntrisicUtilsTest, vmin_random_scalar) {
244     TypeParam a;
245     initUniform(a, kRangeMin, kRangeMax);
246     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
247     const element_t scalar = 3.f;
248     TypeParam b(scalar);
249     const TypeParam result = veval(
250             [](auto x, auto y) { return std::min(x, y); }, a, b);
251     EXPECT_EQ(result, android::audio_utils::intrinsics::vmin(a, scalar));
252     EXPECT_EQ(result, android::audio_utils::intrinsics::vmin(scalar, a));
253     EXPECT_EQ(result, android::audio_utils::intrinsics::vmin(a, b));
254 }
255 
TYPED_TEST(IntrisicUtilsTest,vmla_constant)256 TYPED_TEST(IntrisicUtilsTest, vmla_constant) {
257     const TypeParam a(2.125f);
258     const TypeParam b(2.25f);
259     const TypeParam c(2.5f);
260     const TypeParam result = veval(
261             [](auto x, auto y, auto z) { return x + y * z; }, a, b, c);
262     EXPECT_EQ(result, android::audio_utils::intrinsics::vmla(a, b, c));
263 }
264 
TYPED_TEST(IntrisicUtilsTest,vmla_random)265 TYPED_TEST(IntrisicUtilsTest, vmla_random) {
266     TypeParam a, b, c;
267     initUniform(a, kRangeMin, kRangeMax);
268     initUniform(b, kRangeMin, kRangeMax);
269     initUniform(c, kRangeMin, kRangeMax);
270     const TypeParam result = veval(
271             [](auto x, auto y, auto z) { return x + y * z; }, a, b, c);
272     EXPECT_EQ(result, android::audio_utils::intrinsics::vmla(a, b, c));
273 }
274 
TYPED_TEST(IntrisicUtilsTest,vmla_random_scalar)275 TYPED_TEST(IntrisicUtilsTest, vmla_random_scalar) {
276     TypeParam a, b;
277     initUniform(a, kRangeMin, kRangeMax);
278     initUniform(b, kRangeMin, kRangeMax);
279     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
280     const element_t scalar = 3.f;
281     const TypeParam c(scalar);
282     const TypeParam result = veval(
283             [](auto x, auto y, auto z) { return x + y * z; }, a, b, c);
284     EXPECT_EQ(result, android::audio_utils::intrinsics::vmla(a, scalar, b));
285     EXPECT_EQ(result, android::audio_utils::intrinsics::vmla(a, b, scalar));
286     EXPECT_EQ(result, android::audio_utils::intrinsics::vmla(a, b, c));
287 }
288 
TYPED_TEST(IntrisicUtilsTest,vmul_constant)289 TYPED_TEST(IntrisicUtilsTest, vmul_constant) {
290     const TypeParam a(2.25f);
291     const TypeParam b(2.5f);
292     const TypeParam result = veval(
293             [](auto x, auto y) { return x * y; }, a, b);
294     EXPECT_EQ(result, android::audio_utils::intrinsics::vmul(a, b));
295 }
296 
TYPED_TEST(IntrisicUtilsTest,vmul_random)297 TYPED_TEST(IntrisicUtilsTest, vmul_random) {
298     TypeParam a, b;
299     initUniform(a, kRangeMin, kRangeMax);
300     initUniform(b, kRangeMin, kRangeMax);
301     const TypeParam result = veval(
302             [](auto x, auto y) { return x * y; }, a, b);
303     EXPECT_EQ(result, android::audio_utils::intrinsics::vmul(a, b));
304 }
305 
TYPED_TEST(IntrisicUtilsTest,vmul_random_scalar)306 TYPED_TEST(IntrisicUtilsTest, vmul_random_scalar) {
307     TypeParam a;
308     initUniform(a, kRangeMin, kRangeMax);
309     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(a));
310     const element_t scalar = 3.f;
311     const TypeParam b(scalar);
312     const TypeParam result = veval(
313             [](auto x, auto y) { return x * y; }, a, b);
314     EXPECT_EQ(result, android::audio_utils::intrinsics::vmul(a, scalar));
315     EXPECT_EQ(result, android::audio_utils::intrinsics::vmul(scalar, a));
316     EXPECT_EQ(result, android::audio_utils::intrinsics::vmul(a, b));
317 }
318 
TYPED_TEST(IntrisicUtilsTest,vneg_constant)319 TYPED_TEST(IntrisicUtilsTest, vneg_constant) {
320     const TypeParam value(3.125f);
321     const TypeParam result = veval([](auto v) { return -v; }, value);
322     EXPECT_EQ(result, android::audio_utils::intrinsics::vneg(value));
323 }
324 
TYPED_TEST(IntrisicUtilsTest,vneg_random)325 TYPED_TEST(IntrisicUtilsTest, vneg_random) {
326     TypeParam value;
327     initUniform(value, kRangeMin, kRangeMax);
328     const TypeParam result = veval([](auto v) { return -v; }, value);
329     EXPECT_EQ(result, android::audio_utils::intrinsics::vneg(value));
330 }
331 
TYPED_TEST(IntrisicUtilsTest,vst1)332 TYPED_TEST(IntrisicUtilsTest, vst1) {
333     constexpr float ref = 2.f;
334     const TypeParam value(ref);
335     TypeParam destination(1.f);
336     using element_t = decltype(android::audio_utils::intrinsics::first_element_of(value));
337     android::audio_utils::intrinsics::vst1(
338             reinterpret_cast<element_t*>(&destination),
339             android::audio_utils::intrinsics::vdupn<TypeParam>(ref));
340     EXPECT_EQ(value, destination);
341 }
342 
TYPED_TEST(IntrisicUtilsTest,vsub_constant)343 TYPED_TEST(IntrisicUtilsTest, vsub_constant) {
344     const TypeParam a(1.25f);
345     const TypeParam b(1.5f);
346     const TypeParam result = veval(
347             [](auto x, auto y) { return x - y; }, a, b);
348     EXPECT_EQ(result, android::audio_utils::intrinsics::vsub(a, b));
349 }
350 
TYPED_TEST(IntrisicUtilsTest,vsub_random)351 TYPED_TEST(IntrisicUtilsTest, vsub_random) {
352     TypeParam a, b;
353     initUniform(a, kRangeMin, kRangeMax);
354     initUniform(b, kRangeMin, kRangeMax);
355     const TypeParam result = veval(
356             [](auto x, auto y) { return x - y; }, a, b);
357     EXPECT_EQ(result, android::audio_utils::intrinsics::vsub(a, b));
358 }
359 
TYPED_TEST(IntrisicUtilsTest,vclamp_constant)360 TYPED_TEST(IntrisicUtilsTest, vclamp_constant) {
361     const TypeParam a(0.25f);
362     const TypeParam b(0.5f);
363     const TypeParam c(1.f);
364     const TypeParam result = veval(
365             [](auto x, auto y, auto z) { if (y > z) {
366                 return std::min(std::max(x, y), z);  // undefined behavior, make defined.
367             } else {
368                 return std::clamp(x, y, z);
369             }
370             }, a, b, c);
371     ASSERT_EQ(result, android::audio_utils::intrinsics::vclamp(a, b, c));
372 }
373 
TYPED_TEST(IntrisicUtilsTest,vclamp_random)374 TYPED_TEST(IntrisicUtilsTest, vclamp_random) {
375     TypeParam a, b, c;
376     initUniform(a, kRangeMin, kRangeMax);
377     initUniform(b, kRangeMin, kRangeMax);
378     initUniform(c, kRangeMin, kRangeMax);
379     const TypeParam result = veval(
380             [](auto x, auto y, auto z) { if (y > z) {
381                 return std::min(std::max(x, y), z);  // undefined behavior, make defined.
382             } else {
383                 return std::clamp(x, y, z);
384             }
385             }, a, b, c);
386     ASSERT_EQ(result, android::audio_utils::intrinsics::vclamp(a, b, c));
387 }
388