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