xref: /aosp_15_r20/external/XNNPACK/test/fftr-microkernel-tester.h (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
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