diff --git a/openair1/PHY/TOOLS/oai_arith_operations.c b/openair1/PHY/TOOLS/oai_arith_operations.c index 84a6352070..5c37b2637f 100644 --- a/openair1/PHY/TOOLS/oai_arith_operations.c +++ b/openair1/PHY/TOOLS/oai_arith_operations.c @@ -21,54 +21,76 @@ #include +#define SHUFFLE_MASK SIMDE_MM_SHUFFLE(3, 1, 2, 0) // 0xD8 + +// Helper function for 128-bit vectors +static inline simde__m128i +simde_mm_presort_complex(simde__m128i x) { + return simde_mm_shuffle_epi32(simde_mm_shufflehi_epi16(simde_mm_shufflelo_epi16(x, SHUFFLE_MASK), SHUFFLE_MASK), SHUFFLE_MASK); +} + +// Helper function for 256-bit vectors +static inline simde__m256i +simde_mm256_presort_complex(simde__m256i x) { + return simde_mm256_shuffle_epi32(simde_mm256_shufflehi_epi16(simde_mm256_shufflelo_epi16(x, SHUFFLE_MASK), SHUFFLE_MASK), SHUFFLE_MASK); +} + void simde_mm_separate_real_imag_parts(simde__m128i *out_re, simde__m128i *out_im, simde__m128i in0, simde__m128i in1) { - #define SHUFFLE_MASK SIMDE_MM_SHUFFLE(3, 1, 2, 0) // 0xD8 - - // Put in0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)] - in0 = simde_mm_shufflelo_epi16(in0, SHUFFLE_MASK); - in0 = simde_mm_shufflehi_epi16(in0, SHUFFLE_MASK); - in0 = simde_mm_shuffle_epi32(in0, SHUFFLE_MASK); - - // Put xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)] - in1 = simde_mm_shufflelo_epi16(in1, SHUFFLE_MASK); - in1 = simde_mm_shufflehi_epi16(in1, SHUFFLE_MASK); - in1 = simde_mm_shuffle_epi32(in1, SHUFFLE_MASK); + // presort real and imag part + simde__m128i xmm0 = simde_mm_presort_complex(in0); + simde__m128i xmm1 = simde_mm_presort_complex(in1); - if (out_re != NULL) - *out_re = simde_mm_unpacklo_epi64(in0, in1); + if (out_re) + *out_re = simde_mm_unpacklo_epi64(xmm0, xmm1); - if (out_im != NULL) - *out_im = simde_mm_unpackhi_epi64(in0, in1); + if (out_im) + *out_im = simde_mm_unpackhi_epi64(xmm0, xmm1); - #undef SHUFFLE_MASK } void simde_mm256_separate_real_imag_parts(simde__m256i *out_re, simde__m256i *out_im, simde__m256i in0, simde__m256i in1) { - #define SHUFFLE_MASK SIMDE_MM_SHUFFLE(3, 1, 2, 0) // 0xD8 - - // Put in0 = [Re(0,1,2,3) Im(0,1,2,3) Re(4,5,6,7) Im(4,5,6,7)] - in0 = simde_mm256_shufflelo_epi16(in0, SHUFFLE_MASK); - in0 = simde_mm256_shufflehi_epi16(in0, SHUFFLE_MASK); - in0 = simde_mm256_shuffle_epi32(in0, SHUFFLE_MASK); - - // Put in1 = [Re(8,9,10,11) Im(8,9,10,11) Re(12,13,14,15) Im(12,13,14,15)] - in1 = simde_mm256_shufflelo_epi16(in1, SHUFFLE_MASK); - in1 = simde_mm256_shufflehi_epi16(in1, SHUFFLE_MASK); - in1 = simde_mm256_shuffle_epi32(in1, SHUFFLE_MASK); - - // Put tmp0 = [Re(0,1,2,3) Re(8,9,10,11) Re(4,5,6,7) Re(12,13,14,15)] - simde__m256i tmp0 = simde_mm256_unpacklo_epi64(in0, in1); - - // Put tmp1 = [Im(0,1,2,3) Im(8,9,10,11) Im(4,5,6,7) Im(12,13,14,15)] - simde__m256i tmp1 = simde_mm256_unpackhi_epi64(in0, in1); - if (out_re != NULL) - *out_re = simde_mm256_permute4x64_epi64(tmp0, SHUFFLE_MASK); + // presort + simde__m256i xmm0 = simde_mm256_presort_complex(in0); + simde__m256i xmm1 = simde_mm256_presort_complex(in1); + + if (out_re) + *out_re = simde_mm256_permute4x64_epi64(simde_mm256_unpacklo_epi64(xmm0, xmm1), SHUFFLE_MASK); - if (out_im != NULL) - *out_im = simde_mm256_permute4x64_epi64(tmp1, SHUFFLE_MASK); + if (out_im) + *out_im = simde_mm256_permute4x64_epi64(simde_mm256_unpackhi_epi64(xmm0, xmm1), SHUFFLE_MASK); - #undef SHUFFLE_MASK } + +// Function to separate the real and imaginary parts from the combined 256-bit vector +//__attribute__((always_inline)) static inline +void simde_mm256_separate_vectors(simde__m256i combined, simde__m128i *re, simde__m128i *im) { + + // presort + simde__m256i xmm0 = simde_mm256_presort_complex(combined); + + // Unpack the low and high parts of the combined vector to extract real and imaginary parts + simde__m128i lo = simde_mm256_extractf128_si256(xmm0, 0); // Extract the lower 128 bits (real part) + simde__m128i hi = simde_mm256_extractf128_si256(xmm0, 1); // Extract the higher 128 bits (imaginary part) + + // Now we need to separate the real and imaginary parts within each 128-bit part. + simde__m128i xmmre = simde_mm_unpacklo_epi16(lo, hi); // Real part of the low half + simde__m128i xmmim = simde_mm_unpackhi_epi16(lo, hi); // Imaginary part of the high half + + *re = simde_mm_presort_complex(xmmre); + *im = simde_mm_presort_complex(xmmim); + +} + +// Function to perform interleaving and combining re and im to a complex vector +//__attribute__((always_inline)) static inline +void simde_mm256_combine_vectors(simde__m128i re, simde__m128i im, simde__m256i *combined) { + *combined = simde_mm256_set_m128i( + simde_mm_unpackhi_epi16(re, im), + simde_mm_unpacklo_epi16(re, im) + ); +} + +#undef SHUFFLE_MASK diff --git a/openair1/PHY/TOOLS/tests/CMakeLists.txt b/openair1/PHY/TOOLS/tests/CMakeLists.txt index f5bdf24421..7211fc7baa 100644 --- a/openair1/PHY/TOOLS/tests/CMakeLists.txt +++ b/openair1/PHY/TOOLS/tests/CMakeLists.txt @@ -16,7 +16,6 @@ add_dependencies(tests test_log2_approx) add_test(NAME test_log2_approx COMMAND ./test_log2_approx --gtest_filter=-log2_approx.complete) - add_executable(dft_test test_dft.c ../dfts_load.c) target_link_libraries(dft_test minimal_lib shlib_loader SIMU m) add_dependencies(tests dft_test) @@ -28,3 +27,15 @@ target_link_libraries(test_vector_op PRIVATE LOG minimal_lib) add_dependencies(tests test_vector_op) add_test(NAME test_vector_op COMMAND test_vector_op) + +add_executable(test_simde_operations test_simde_operations.cpp ../simde_operations.c) +target_link_libraries(test_simde_operations PRIVATE GTest::gtest LOG minimal_lib) +add_dependencies(tests test_simde_operations) +add_test(NAME test_simde_operations + COMMAND ./test_simde_operations) + +add_executable(test_sse_intrinsics test_sse_intrinsics.cpp) +target_link_libraries(test_sse_intrinsics PRIVATE GTest::gtest LOG minimal_lib) +add_dependencies(tests test_sse_intrinsics) +add_test(NAME test_sse_intrinsics + COMMAND ./test_sse_intrinsics) \ No newline at end of file diff --git a/openair1/PHY/TOOLS/tests/test_simde_operations.cpp b/openair1/PHY/TOOLS/tests/test_simde_operations.cpp new file mode 100644 index 0000000000..ea726b87ce --- /dev/null +++ b/openair1/PHY/TOOLS/tests/test_simde_operations.cpp @@ -0,0 +1,122 @@ +#include +#include +#include + +// Deklaration der zu testenden Funktionen +extern "C" { + void simde_mm_separate_real_imag_parts(simde__m128i *out_re, simde__m128i *out_im, simde__m128i in0, simde__m128i in1); + void simde_mm256_separate_real_imag_parts(simde__m256i *out_re, simde__m256i *out_im, simde__m256i in0, simde__m256i in1); + void simde_mm256_separate_vectors(simde__m256i combined, simde__m128i *re, simde__m128i *im); + void simde_mm256_combine_vectors(simde__m128i re, simde__m128i im, simde__m256i *combined); +} + +TEST(separate_real_imag_parts, 128) { + + // Create two 128-bit input vectosr with 8 16-bit integers + simde__m128i in0 = simde_mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7); + simde__m128i in1 = simde_mm_setr_epi16(8, 9, 10, 11, 12, 13, 14, 15); + + // Create two 128-bit output vectors + simde__m128i out_re, out_im; + + // Call function to test + simde_mm_separate_real_imag_parts(&out_re, &out_im, in0, in1); + + // Store the results for comparison + int16_t re_result[8], im_result[8]; + simde_mm_storeu_si128(reinterpret_cast(re_result), out_re); + simde_mm_storeu_si128(reinterpret_cast(im_result), out_im); + + // Create the expected vectors + int16_t re_expected[8] = {0, 2, 4, 6, 8, 10, 12, 14}; + int16_t im_expected[8] = {1, 3, 5, 7, 9, 11, 13, 15}; + + for (int i = 0; i < 8; i++) { + EXPECT_EQ(re_result[i], re_expected[i]) << "Real part mismatch on index " << i; + EXPECT_EQ(im_result[i], im_expected[i]) << "Imag part mismatch on index " << i; + } +} + +TEST(separate_real_imag_parts, 256) { + + // Create two 256-bit input vectosr with 16 16-bit integers + simde__m256i in0 = simde_mm256_setr_epi16( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + simde__m256i in1 = simde_mm256_setr_epi16(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + + // Create two 256-bit output vectors + simde__m256i out_re, out_im; + + // Call function to test + simde_mm256_separate_real_imag_parts(&out_re, &out_im, in0, in1); + + // Store the results for comparison + int16_t re_result[16], im_result[16]; + simde_mm256_storeu_si256(reinterpret_cast(re_result), out_re); + simde_mm256_storeu_si256(reinterpret_cast(im_result), out_im); + + // Create the expected vectors + int16_t re_expected[16] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; + int16_t im_expected[16] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}; + + for (int i = 0; i < 16; i++) { + EXPECT_EQ(re_result[i], re_expected[i]) << "Real part mismatch on index " << i; + EXPECT_EQ(im_result[i], im_expected[i]) << "Imag part mismatch on index " << i; + } +} + +TEST(complex_vectors, separate) { + + // Create a 256-bit input vector with 16 16-bit integers in natural order. + simde__m256i combined = simde_mm256_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + + // Create two 128-bit output vectors + simde__m128i re, im; + + // Call function to test + simde_mm256_separate_vectors(combined, &re, &im); + + // Store the results for comparison + int16_t re_result[8], im_result[8]; + simde_mm_storeu_si128((simde__m128i*)re_result, re); + simde_mm_storeu_si128((simde__m128i*)im_result, im); + + // Create the expected vectors + int16_t re_expected[8] = {0, 2, 4, 6, 8, 10, 12, 14}; + int16_t im_expected[8] = {1, 3, 5, 7, 9, 11, 13, 15}; + + for (int i = 0; i < 8; i++) { + EXPECT_EQ(re_result[i], re_expected[i]) << "Real part mismatch on index " << i; + EXPECT_EQ(im_result[i], im_expected[i]) << "Imag part mismatch on index " << i; + } +} + +TEST(complex_vectors, combine) { + + // Create two 128-bit input vectosr with 8 16-bit integers + simde__m128i re = simde_mm_setr_epi16(0, 2, 4, 6, 8, 10, 12, 14); + simde__m128i im = simde_mm_setr_epi16(1, 3, 5, 7, 9, 11, 13, 15); + + // Create 256-bit output vector + simde__m256i c; + + // Call function to test + simde_mm256_combine_vectors(re, im, &c); + + // Store the results for comparison + int16_t c_result[16]; + simde_mm256_storeu_si256((simde__m256i*)c_result, c); + + // Create the expected vector + int16_t c_expected[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + for (int i = 0; i < 8; i++) { + EXPECT_EQ(c_result[2*i+0], c_expected[2*i+0]) << "Real part mismatch on index " << 2*i+0; + EXPECT_EQ(c_result[2*i+1], c_expected[2*i+1]) << "Imag part mismatch on index " << 2*i+1; + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/openair1/PHY/TOOLS/tests/test_sse_intrinsics.cpp b/openair1/PHY/TOOLS/tests/test_sse_intrinsics.cpp new file mode 100644 index 0000000000..33cee22e71 --- /dev/null +++ b/openair1/PHY/TOOLS/tests/test_sse_intrinsics.cpp @@ -0,0 +1,374 @@ +#include +#include +#include "../../sse_intrin.h" + +TEST(conj_vectors, 128) { + + // Create a 128-bit input vector with 8 16-bit integers in natural order. + simde__m128i in = simde_mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7); + + // Call function to test + simde__m128i out = oai_mm_conj(in); + + // Store the results for comparison + int16_t out_result[8]; + simde_mm_storeu_si128((simde__m128i*)out_result, out); + + // Create the expected vectors + int16_t out_expected[8] = {0, -1, 2, -3, 4, -5, 6, -7}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(out_result[i], out_expected[i]) << "Conjugate mismatch on index " << i; + } +} + +TEST(conj_vectors, 256) { + + // Create a 256-bit input vector with 16 16-bit integers in natural order. + simde__m256i in = simde_mm256_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + + // Call function to test + simde__m256i out = oai_mm256_conj(in); + + // Store the results for comparison + int16_t out_result[16]; + simde_mm256_storeu_si256((simde__m256i*)out_result, out); + + // Create the expected vectors + int16_t out_expected[16] = {0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15}; + + // Check for mismatch + for (int i = 0; i < 16; i++) { + EXPECT_EQ(out_result[i], out_expected[i]) << "Conjugate mismatch on index " << i; + } +} + +TEST(swap_vectors, 128) { + + // Create a 128-bit input vector with 8 16-bit integers in natural order. + simde__m128i in = simde_mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7); + + // Call function to test + simde__m128i out = oai_mm_swap(in); + + // Store the results for comparison + int16_t out_result[8]; + simde_mm_storeu_si128((simde__m128i*)out_result, out); + + // Create the expected vectors + int16_t out_expected[8] = {1, 0, 3, 2, 5, 4, 7, 6}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(out_result[i], out_expected[i]) << "IQ swap mismatch on index " << i; + } +} + +TEST(swap_vectors, 256) { + + // Create a 256-bit input vector with 16 16-bit integers in natural order. + simde__m256i in = simde_mm256_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + + // Call function to test + simde__m256i out = oai_mm256_swap(in); + + // Store the results for comparison + int16_t out_result[16]; + simde_mm256_storeu_si256((simde__m256i*)out_result, out); + + // Create the expected vector + int16_t out_expected[16] = {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}; + + // Check for mismatch + for (int i = 0; i < 16; i++) { + EXPECT_EQ(out_result[i], out_expected[i]) << "Conjugate mismatch on index " << i; + } +} + +TEST(ShiftedMultiplyAndAdd, 128) { + + // Set up two 128-bit vectors with 8 16-bit elements each. + simde__m128i vec1 = simde_mm_setr_epi16( 1, 2, 3, 4, -5, -6, 7, 8); + simde__m128i vec2 = simde_mm_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80); + + // Call function to test + int shift = 1; + simde__m128i res = oai_mm_smadd(vec1, vec2, shift); + + // Store the results for comparison + int32_t output[4]; + simde_mm_storeu_si128((simde__m128i*)output, res); + + // Create the expected vector + // Pair 0: 1*10 + 2*20 = 10 + 40 = 50>>1 = 25 + // Pair 1: 3*30 + 4*40 = 90 + 160 = 250>>1 = 125 + // Pair 2: -5*50 + -6*60 = -250 + -360 = -610>>1 = -305 + // Pair 3: 7*70 + 8*80 = 490 + 640 = 1130>>1 = 565 + int32_t expected[4] = {25, 125, -305, 565}; + + // Check for mismatch + for (int i = 0; i < 4; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(ShiftedMultiplyAndAdd, 256) { + + // Set up two 128-bit vectors with 16 16-bit elements each. + simde__m256i vec1 = simde_mm256_setr_epi16( 1, 2, 3, 4, 5, 6, -7, -8, 9, 10, 11, 12, 13, 14, 15, 16); + simde__m256i vec2 = simde_mm256_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160); + + // Call function to test + int shift = 1; + simde__m256i res = oai_mm256_smadd(vec1, vec2, shift); + + // Store the results for comparison + int32_t output[8]; + simde_mm256_storeu_si256((simde__m256i*)output, res); + + // Create the expected vector + // Pair 0: 1* 10 + 2* 20 = 50>>1 = 25 + // Pair 1: 3* 30 + 4* 40 = 250>>1 = 125 + // Pair 2: 5* 50 + 6* 60 = 610>>1 = 305 + // Pair 3: -7* 70 + -8* 80 = -1130>>1 = -565 + // Pair 4: 9* 90 + 10*100 = 1810>>1 = 905 + // Pair 5: 11*110 + 12*120 = 2650>>1 = 1325 + // Pair 6: 13*130 + 14*140 = 3650>>1 = 1825 + // Pair 7: 15*150 + 16*160 = 4810>>1 = 2405 + int32_t expected[8] = {25, 125, 305, -565, 905, 1325, 1825, 2405}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(Pack, 128normal) { + + // Set up two 128-bit vectors containing 4 32-bit integers each. + simde__m128i a = simde_mm_setr_epi32(1000, 2000, 3000, 4000); + simde__m128i b = simde_mm_setr_epi32(5000, 6000, 7000, 8000); + + // Call function to test + simde__m128i res = oai_mm_pack(a, b); + + // Store the results for comparison + int16_t result[8]; + simde_mm_storeu_si128((simde__m128i*) result, res); + + // Create the expected vector (here without saturation) + int16_t expected[8] = {1000, 5000, 2000, 6000, 3000, 7000, 4000, 8000}; + + for (int i = 0; i < 8; i++) { + EXPECT_EQ(result[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(Pack, 128saturation) { + + // Set up two 128-bit vectors containing 4 32-bit integers each. + simde__m128i a = simde_mm_setr_epi32(-40000, 40000, -1000, 1000); + simde__m128i b = simde_mm_setr_epi32(-50000, 50000, -2000, 2000); + + // Call function to test + simde__m128i res = oai_mm_pack(a, b); + + // Store the results for comparison + int16_t result[8]; + simde_mm_storeu_si128((simde__m128i*) result, res); + + // Create the expected vector (here saturation occours) + int16_t expected[8] = { + -32768, -32768, 32767, 32767, // saturation applied to the first unpacked vector + -1000, -2000, 1000, 2000 // values remain unchanged for the second unpacked vector + }; + + for (int i = 0; i < 8; i++) { + EXPECT_EQ(result[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(Pack, 256normal) { + + // Set up two 256-bit vectors with 16 16-bit values each. + simde__m256i vec1 = simde_mm256_setr_epi16( 1, 2, 3, 4, 5, 6, -7, -8, 9, 10, 11, 12, 13, 14, 15, 16); + simde__m256i vec2 = simde_mm256_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m256i res = oai_mm256_smadd(vec1, vec2, shift); + + // Store the results for comparison + int32_t output[8]; + simde_mm256_storeu_si256((simde__m256i*)output, res); + + // The expected results are calculated as follows: + // Pair 0: 1* 10 + 2* 20 = 50>>1 = 25 + // Pair 1: 3* 30 + 4* 40 = 250>>1 = 125 + // Pair 2: 5* 50 + 6* 60 = 610>>1 = 305 + // Pair 3: -7* 70 + -8* 80 = -1130>>1 = -565 + // Pair 4: 9* 90 + 10*100 = 1810>>1 = 905 + // Pair 5: 11*110 + 12*120 = 2650>>1 = 1325 + // Pair 6: 13*130 + 14*140 = 3650>>1 = 1825 + // Pair 7: 15*150 + 16*160 = 4810>>1 = 2405 + int32_t expected[8] = {25, 125, 305, -565, 905, 1325, 1825, 2405}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(Pack, 256saturation) { + + // Set up two 256-bit vectors with 16 16-bit values each. + simde__m256i vec1 = simde_mm256_setr_epi16(-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16); + simde__m256i vec2 = simde_mm256_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m256i res = oai_mm256_smadd(vec1, vec2, shift); + + // Store the results for comparison + int32_t output[8]; + simde_mm256_storeu_si256((simde__m256i*)output, res); + + // The expected results are calculated as follows: + // Pair 0: -1* 10 + -2* 20 = -50>>1 = -25 + // Pair 1: -3* 30 + -4* 40 = -250>>1 = -125 + // Pair 2: -5* 50 + -6* 60 = -610>>1 = -305 + // Pair 3: -7* 70 + -8* 80 = -1130>>1 = -565 + // Pair 4: -9* 90 + -10*100 = -1810>>1 = -905 + // Pair 5: -11*110 + -12*120 = -2650>>1 = -1325 + // Pair 6: -13*130 + -14*140 = -3650>>1 = -1825 + // Pair 7: -15*150 + -16*160 = -4810>>1 = -2405 + int32_t expected[8] = {-25, -125, -305, -565, -905, -1325, -1825, -2405}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(ComplexMultiply, 128) { + + // Set up two 128-bit vectors with 8 16-bit elements each. + simde__m128i z1 = simde_mm_setr_epi16( 3, 4, 5, 6, 7, 8, 9, 10); + simde__m128i z2 = simde_mm_setr_epi16(11, 12, 13, 14, 15, 16, 17, 18); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m128i result = oai_mm_cpx_mult(z1, z2, shift); + + // Store the results for comparison + int16_t output[8]; + simde_mm_storeu_si128((simde__m128i*)output, result); + + // Expected results calculated manually: + // Pair 0: (3 + 4i) * (11 + 12i) = (-15 + 80i)>>1 = -8 + 40i + // Pair 1: (5 + 6i) * (13 + 14i) = (-19 + 148i)>>1 = -10 + 74i + // Pair 2: (7 + 8i) * (15 + 16i) = (-23 + 232i)>>1 = -12 + 116i + // Pair 3: (9 + 10i) * (17 + 18i) = (-27 + 332i)>>1 = -14 + 166i + int16_t expected[8] = { -8, 40, -10, 74, -12, 116, -14, 166 }; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(ComplexMultiply, 256) { + + // Set up two 256-bit vectors with 16 16-bit elements each. + simde__m256i z1 = simde_mm256_setr_epi16( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); + simde__m256i z2 = simde_mm256_setr_epi16(19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m256i result = oai_mm256_cpx_mult(z1, z2, shift); + + // Store the results for comparison + int16_t output[16]; + simde_mm256_storeu_si256((simde__m256i*)output, result); + + // Expected results calculated manually: + // Pair 0: ( 3 + 4i) * (19 + 20i) = (-23 + 136i)>>1 = -12 + 68i + // Pair 1: ( 5 + 6i) * (21 + 22i) = (-27 + 236i)>>1 = -14 + 118i + // Pair 2: ( 7 + 8i) * (23 + 24i) = (-31 + 352i)>>1 = -16 + 176i + // Pair 3: ( 9 + 10i) * (25 + 26i) = (-35 + 484i)>>1 = -18 + 242i + // Pair 4: (11 + 12i) * (27 + 28i) = (-39 + 632i)>>1 = -20 + 316i + // Pair 5: (13 + 14i) * (29 + 30i) = (-43 + 796i)>>1 = -22 + 398i + // Pair 6: (15 + 16i) * (31 + 32i) = (-47 + 976i)>>1 = -24 + 488i + // Pair 7: (17 + 18i) * (33 + 34i) = (-51 + 1172i)>>1 = -26 + 586i + int16_t expected[16] = {-12, 68, -14, 118, -16, 176, -18, 242, -20, 316, -22, 398, -24, 488, -26, 586}; + + // Check for mismatch + for (int i = 0; i < 16; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(ComplexMultiplyConjugatedInput, 128) { + + // Set up two 128-bit vectors with 8 16-bit elements each. + simde__m128i a = simde_mm_setr_epi16( 3, 4, 5, 6, 7, 8, 9, 10); + simde__m128i b = simde_mm_setr_epi16(11, 12, 13, 14, 15, 16, 17, 18); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m128i result = oai_mm_cpx_mult_conj(a, b, shift); + + // Store the results for comparison + int16_t output[8]; + simde_mm_storeu_si128((simde__m128i*)output, result); + + // Expected results calculated manually: + // Pair 0: ( 3 - 4i) * (11 + 12i) = ( 81 - 8i)>>1 = 40 - 4i + // Pair 1: ( 5 - 6i) * (13 + 14i) = (149 - 8i)>>1 = 74 - 4i + // Pair 2: ( 7 - 8i) * (15 + 16i) = (233 - 8i)>>1 = 116 - 4i + // Pair 3: ( 9 - 10i) * (17 + 18i) = (333 - 8i)>>1 = 166 - 4i + int16_t expected[8] = {40, -4, 74, -4, 116, -4, 166, -4}; + + // Check for mismatch + for (int i = 0; i < 8; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +TEST(ComplexMultiplyConjugatedInput, 256) { + + // Set up two 256-bit vectors with 16 16-bit elements each. + simde__m256i a = simde_mm256_setr_epi16( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); + simde__m256i b = simde_mm256_setr_epi16(19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34); + + // Call function to test with arithmetic shift by 1 (i.e. divide by 2). + int shift = 1; + simde__m256i result = oai_mm256_cpx_mult_conj(a, b, shift); + + // Store the results for comparison + int16_t output[16]; + simde_mm256_storeu_si256((simde__m256i*)output, result); + + // Expected results calculated manually: + // Pair 0: ( 3 - 4i) * (19 + 20i) = ( 137 - 16i)>>1 = 68 - 8i + // Pair 1: ( 5 - 6i) * (21 + 22i) = ( 237 - 16i)>>1 = 118 - 8i + // Pair 2: ( 7 - 8i) * (23 + 24i) = ( 353 - 16i)>>1 = 176 - 8i + // Pair 3: ( 9 - 10i) * (25 + 26i) = ( 485 - 16i)>>1 = 242 - 8i + // Pair 4: (11 - 12i) * (27 + 28i) = ( 633 - 16i)>>1 = 316 - 8i + // Pair 5: (13 - 14i) * (29 + 30i) = ( 797 - 16i)>>1 = 398 - 8i + // Pair 6: (15 - 16i) * (31 + 32i) = ( 977 - 16i)>>1 = 488 - 8i + // Pair 7: (17 - 18i) * (33 + 34i) = (1173 - 16i)>>1 = 586 - 8i + int16_t expected[16] = {68, -8, 118, -8, 176, -8, 242, -8, 316, -8, 398, -8, 488, -8, 586, -8}; + + // Check for mismatch + for (int i = 0; i < 16; i++) { + EXPECT_EQ(output[i], expected[i]) << "Mismatch at index " << i; + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/openair1/PHY/sse_intrin.h b/openair1/PHY/sse_intrin.h index 79c9e0b9f7..e39f141c3f 100644 --- a/openair1/PHY/sse_intrin.h +++ b/openair1/PHY/sse_intrin.h @@ -252,7 +252,7 @@ __attribute__((always_inline)) static inline simde__m128i oai_mm_cpx_mult_conj(simde__m128i a, simde__m128i b, int shift) { simde__m128i re = oai_mm_smadd(a, b, shift); - simde__m128i im = oai_mm_smadd(oai_mm_swap(oai_mm_conj(a)), b, shift); + simde__m128i im = oai_mm_smadd(oai_mm_swap(oai_mm_conj(a)), b, shift); return oai_mm_pack(re, im); } @@ -349,41 +349,10 @@ __attribute__((always_inline)) static inline simde__m256i oai_mm256_cpx_mult_conj(simde__m256i a, simde__m256i b, int shift) { simde__m256i re = oai_mm256_smadd(a, b, shift); - simde__m256i im = oai_mm256_smadd(oai_mm256_swap(oai_mm256_conj(a)), b, shift); + simde__m256i im = oai_mm256_smadd(oai_mm256_swap(oai_mm256_conj(a)), b, shift); return oai_mm256_pack(re, im); } -// Function to perform interleaving and combining re and im to a complex vector -__attribute__((always_inline)) static inline -void oai_mm256_combine_vectors(simde__m128i a_re, simde__m128i a_im, simde__m256i *a) { - *a = simde_mm256_set_m128i( - simde_mm_unpackhi_epi16(a_re, a_im), - simde_mm_unpacklo_epi16(a_re, a_im) - ); -} - -// Function to separate the real and imaginary parts from the combined 256-bit vector -__attribute__((always_inline)) static inline -void oai_mm256_separate_vectors(simde__m256i combined, simde__m128i *re, simde__m128i *im) { - - #define SHUFFLE_MASK SIMDE_MM_SHUFFLE(3, 1, 2, 0) // 0xD8 - - simde__m256i xmm0 = simde_mm256_shuffle_epi32(simde_mm256_shufflehi_epi16(simde_mm256_shufflelo_epi16(combined, SHUFFLE_MASK), SHUFFLE_MASK), SHUFFLE_MASK); - - // Unpack the low and high parts of the combined vector to extract real and imaginary parts - simde__m128i lo = simde_mm256_extractf128_si256(xmm0, 0); // Extract the lower 128 bits (real part) - simde__m128i hi = simde_mm256_extractf128_si256(xmm0, 1); // Extract the higher 128 bits (imaginary part) - - // Now we need to separate the real and imaginary parts within each 128-bit part. - simde__m128i xmmre = simde_mm_unpacklo_epi16(lo, hi); // Real part of the low half - simde__m128i xmmim = simde_mm_unpackhi_epi16(lo, hi); // Imaginary part of the high half - - *re = simde_mm_shuffle_epi32(simde_mm_shufflehi_epi16(simde_mm_shufflelo_epi16(xmmre, SHUFFLE_MASK), SHUFFLE_MASK), SHUFFLE_MASK); - *im = simde_mm_shuffle_epi32(simde_mm_shufflehi_epi16(simde_mm_shufflelo_epi16(xmmim, SHUFFLE_MASK), SHUFFLE_MASK), SHUFFLE_MASK); - - #undef SHUFFLE_MASK -} - #ifdef __cplusplus } #endif