blob: 55dfab769f2934cf2964f503c250c281a1c0c2d8 [file] [log] [blame] [edit]
// Copyright 2022 Google LLC
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
#pragma once
#include <gtest/gtest.h>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <random>
#include <vector>
#include <xnnpack.h>
#include <xnnpack/aligned-allocator.h>
#include <xnnpack/microfnptr.h>
#include <xnnpack/math.h>
void xnn_cs16_fftr_reference(
size_t samples,
const int16_t* input,
int16_t* output,
const int16_t* twiddle) {
assert(samples >= 2);
assert(samples % 2 == 0);
assert(input != NULL);
assert(output != NULL);
assert(twiddle != NULL);
const int16_t* il = input;
const int16_t* ir = input + samples * 2;
int32_t vdcr = (int32_t) il[0];
int32_t vdci = (int32_t) il[1];
il += 2;
vdcr = math_asr_s32(vdcr * 16383 + 16384, 15);
vdci = math_asr_s32(vdci * 16383 + 16384, 15);
int16_t* outl = output;
int16_t* outr = output + samples * 2;
outl[0] = vdcr + vdci;
outl[1] = 0;
outl += 2;
outr[0] = vdcr - vdci;
outr[1] = 0;
samples >>= 1;
do {
int32_t vilr = il[0];
int32_t vili = il[1];
il += 2;
ir -= 2;
int32_t virr = (int32_t) ir[0];
int32_t viri = -(int32_t) ir[1];
const int32_t vtwr = twiddle[0];
const int32_t vtwi = twiddle[1];
twiddle += 2;
vilr = math_asr_s32(vilr * 16383 + 16384, 15);
vili = math_asr_s32(vili * 16383 + 16384, 15);
virr = math_asr_s32(virr * 16383 + 16384, 15);
viri = math_asr_s32(viri * 16383 + 16384, 15);
const int32_t vacc1r = vilr + virr;
const int32_t vacc1i = vili + viri;
const int32_t vacc2r = vilr - virr;
const int32_t vacc2i = vili - viri;
const int32_t twr = math_asr_s32(vacc2r * vtwr - vacc2i * vtwi + 16384, 15);
const int32_t twi = math_asr_s32(vacc2r * vtwi + vacc2i * vtwr + 16384, 15);
outl[0] = math_asr_s32(vacc1r + twr, 1);
outl[1] = math_asr_s32(vacc1i + twi, 1);
outl += 2;
outr -= 2;
outr[0] = math_asr_s32(vacc1r - twr, 1);
outr[1] = math_asr_s32(twi - vacc1i, 1);
} while (--samples != 0);
}
class FftrMicrokernelTester {
public:
inline FftrMicrokernelTester& samples(size_t samples) {
assert(samples != 0);
this->samples_ = samples;
return *this;
}
inline size_t samples() const {
return this->samples_;
}
inline FftrMicrokernelTester& iterations(size_t iterations) {
this->iterations_ = iterations;
return *this;
}
inline size_t iterations() const {
return this->iterations_;
}
void Test(xnn_cs16_fftr_ukernel_function fftr) const {
std::random_device random_device;
auto rng = std::mt19937(random_device());
auto i16rng = std::bind(std::uniform_int_distribution<int16_t>(), std::ref(rng));
const size_t sample_size = samples() * 2 + 2;
std::vector<int16_t> twiddle(samples());
std::vector<int16_t> y(sample_size);
std::vector<int16_t> y_ref(sample_size);
for (size_t iteration = 0; iteration < iterations(); iteration++) {
std::generate(twiddle.begin(), twiddle.end(), std::ref(i16rng));
std::generate(y.begin(), y.end(), std::ref(i16rng));
std::copy(y.begin(), y.end(), y_ref.begin());
// Compute reference results.
xnn_cs16_fftr_reference(samples(), y_ref.data(), y_ref.data(), twiddle.data());
// Call optimized micro-kernel.
fftr(samples(), y.data(), twiddle.data());
// Verify results.
for (size_t n = 0; n < sample_size; n++) {
ASSERT_EQ(y[n], y_ref[n])
<< "at sample " << n << " / " << samples();
}
}
}
private:
size_t samples_{256};
size_t iterations_{15};
};