1 // Copyright 2022 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 #pragma once
7
8 #include <gtest/gtest.h>
9
10 #include <algorithm>
11 #include <cassert>
12 #include <cmath>
13 #include <cstddef>
14 #include <cstdlib>
15 #include <random>
16 #include <vector>
17
18 #include <xnnpack.h>
19 #include <xnnpack/aligned-allocator.h>
20 #include <xnnpack/microfnptr.h>
21 #include <xnnpack/math.h>
22
23
xnn_cs16_fftr_reference(size_t samples,const int16_t * input,int16_t * output,const int16_t * twiddle)24 void xnn_cs16_fftr_reference(
25 size_t samples,
26 const int16_t* input,
27 int16_t* output,
28 const int16_t* twiddle) {
29
30 assert(samples >= 2);
31 assert(samples % 2 == 0);
32 assert(input != NULL);
33 assert(output != NULL);
34 assert(twiddle != NULL);
35
36 const int16_t* il = input;
37 const int16_t* ir = input + samples * 2;
38 int32_t vdcr = (int32_t) il[0];
39 int32_t vdci = (int32_t) il[1];
40 il += 2;
41 vdcr = math_asr_s32(vdcr * 16383 + 16384, 15);
42 vdci = math_asr_s32(vdci * 16383 + 16384, 15);
43
44 int16_t* outl = output;
45 int16_t* outr = output + samples * 2;
46 outl[0] = vdcr + vdci;
47 outl[1] = 0;
48 outl += 2;
49 outr[0] = vdcr - vdci;
50 outr[1] = 0;
51
52 samples >>= 1;
53
54 do {
55 int32_t vilr = il[0];
56 int32_t vili = il[1];
57 il += 2;
58 ir -= 2;
59 int32_t virr = (int32_t) ir[0];
60 int32_t viri = -(int32_t) ir[1];
61 const int32_t vtwr = twiddle[0];
62 const int32_t vtwi = twiddle[1];
63 twiddle += 2;
64
65 vilr = math_asr_s32(vilr * 16383 + 16384, 15);
66 vili = math_asr_s32(vili * 16383 + 16384, 15);
67 virr = math_asr_s32(virr * 16383 + 16384, 15);
68 viri = math_asr_s32(viri * 16383 + 16384, 15);
69 const int32_t vacc1r = vilr + virr;
70 const int32_t vacc1i = vili + viri;
71 const int32_t vacc2r = vilr - virr;
72 const int32_t vacc2i = vili - viri;
73
74 const int32_t twr = math_asr_s32(vacc2r * vtwr - vacc2i * vtwi + 16384, 15);
75 const int32_t twi = math_asr_s32(vacc2r * vtwi + vacc2i * vtwr + 16384, 15);
76
77 outl[0] = math_asr_s32(vacc1r + twr, 1);
78 outl[1] = math_asr_s32(vacc1i + twi, 1);
79 outl += 2;
80 outr -= 2;
81 outr[0] = math_asr_s32(vacc1r - twr, 1);
82 outr[1] = math_asr_s32(twi - vacc1i, 1);
83
84 } while (--samples != 0);
85 }
86
87 class FftrMicrokernelTester {
88 public:
samples(size_t samples)89 inline FftrMicrokernelTester& samples(size_t samples) {
90 assert(samples != 0);
91 this->samples_ = samples;
92 return *this;
93 }
94
samples()95 inline size_t samples() const {
96 return this->samples_;
97 }
98
iterations(size_t iterations)99 inline FftrMicrokernelTester& iterations(size_t iterations) {
100 this->iterations_ = iterations;
101 return *this;
102 }
103
iterations()104 inline size_t iterations() const {
105 return this->iterations_;
106 }
107
Test(xnn_cs16_fftr_ukernel_function fftr)108 void Test(xnn_cs16_fftr_ukernel_function fftr) const {
109 std::random_device random_device;
110 auto rng = std::mt19937(random_device());
111 auto i16rng = std::bind(std::uniform_int_distribution<int16_t>(), std::ref(rng));
112 const size_t sample_size = samples() * 2 + 2;
113
114 std::vector<int16_t> twiddle(samples());
115 std::vector<int16_t> y(sample_size);
116 std::vector<int16_t> y_ref(sample_size);
117
118 for (size_t iteration = 0; iteration < iterations(); iteration++) {
119 std::generate(twiddle.begin(), twiddle.end(), std::ref(i16rng));
120 std::generate(y.begin(), y.end(), std::ref(i16rng));
121 std::copy(y.begin(), y.end(), y_ref.begin());
122
123 // Compute reference results.
124 xnn_cs16_fftr_reference(samples(), y_ref.data(), y_ref.data(), twiddle.data());
125
126 // Call optimized micro-kernel.
127 fftr(samples(), y.data(), twiddle.data());
128
129 // Verify results.
130 for (size_t n = 0; n < sample_size; n++) {
131 ASSERT_EQ(y[n], y_ref[n])
132 << "at sample " << n << " / " << samples();
133 }
134 }
135 }
136
137 private:
138 size_t samples_{256};
139 size_t iterations_{15};
140 };
141