From a0367d039fbe78a81398b24ebb98f7ac1680f359 Mon Sep 17 00:00:00 2001 From: sadko4u Date: Fri, 29 Nov 2024 00:40:15 +0300 Subject: [PATCH] ARM NEON sign_minmax function --- .../dsp/arch/arm/neon-d32/search/minmax.h | 124 ++++++++++++++++++ src/main/arm/neon-d32.cpp | 1 + src/test/ptest/search/sign_minmax.cpp | 4 +- src/test/utest/search/sign_minmax.cpp | 4 +- 4 files changed, 129 insertions(+), 4 deletions(-) diff --git a/include/private/dsp/arch/arm/neon-d32/search/minmax.h b/include/private/dsp/arch/arm/neon-d32/search/minmax.h index ce6c026d..d4fc9e77 100644 --- a/include/private/dsp/arch/arm/neon-d32/search/minmax.h +++ b/include/private/dsp/arch/arm/neon-d32/search/minmax.h @@ -420,6 +420,130 @@ namespace lsp #undef SEL_NONE #undef SEL_ABS + #undef MINMAX2_SEARCH_CORE + + void sign_minmax(const float *src, size_t count, float *min, float *max) + { + ARCH_ARM_ASM( + __ASM_EMIT("veor q0, q0") \ + __ASM_EMIT("veor q1, q0") \ + __ASM_EMIT("cmp %[count], #0") \ + __ASM_EMIT("bls 8f") \ + __ASM_EMIT("vld1.32 {d0[], d1[]}, [%[src]]") /* q0 = min */ \ + __ASM_EMIT("vabs.f32 q2, q0") /* q2 = abs(min) */ \ + __ASM_EMIT("vmov q1, q0") /* q1 = max */ \ + __ASM_EMIT("vmov q3, q2") /* q3 = abs(max) */ \ + __ASM_EMIT("subs %[count], #16") \ + __ASM_EMIT("blt 2f") \ + /* x16 blocks */ \ + __ASM_EMIT("1:") \ + __ASM_EMIT("vldm %[src]!, {q8-q11}") /* q8 = x0, q9 = x1, q10 = x2, q11 = x3 */ \ + __ASM_EMIT("vabs.f32 q12, q8") /* q12 = abs(x0) */ \ + __ASM_EMIT("vabs.f32 q13, q9") /* q13 = abs(x1) */ \ + __ASM_EMIT("vabs.f32 q14, q10") /* q14 = abs(x2) */ \ + __ASM_EMIT("vabs.f32 q15, q11") /* q15 = abs(x3) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q13") /* q4 = [abs(min) < abs(x1) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q13") /* q4 = [abs(max) > abs(x1) ] */ \ + __ASM_EMIT("vbif q0, q9, q4") /* q0 = [abs(min) < abs(x1) ] ? min : x1 */ \ + __ASM_EMIT("vbif q1, q9, q5") /* q1 = [abs(max) > abs(x1) ] ? res : x1 */ \ + __ASM_EMIT("vbif q2, q13, q4") /* q12 = [abs(min) < abs(x1) ] ? abs(min) : abs(x1) */ \ + __ASM_EMIT("vbif q3, q13, q5") /* q13 = [abs(max) > abs(x1) ] ? abs(max) : abs(x1) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q14") /* q4 = [abs(min) < abs(x1) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q14") /* q4 = [abs(max) > abs(x1) ] */ \ + __ASM_EMIT("vbif q0, q10, q4") /* q0 = [abs(min) < abs(x2) ] ? min : x2 */ \ + __ASM_EMIT("vbif q1, q10, q5") /* q1 = [abs(max) > abs(x2) ] ? res : x2 */ \ + __ASM_EMIT("vbif q2, q14, q4") /* q12 = [abs(min) < abs(x2) ] ? abs(min) : abs(x2) */ \ + __ASM_EMIT("vbif q3, q14, q5") /* q13 = [abs(max) > abs(x2) ] ? abs(max) : abs(x2) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q15") /* q4 = [abs(min) < abs(x1) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q15") /* q4 = [abs(max) > abs(x1) ] */ \ + __ASM_EMIT("vbif q0, q11, q4") /* q0 = [abs(min) < abs(x3) ] ? min : x3 */ \ + __ASM_EMIT("vbif q1, q11, q5") /* q1 = [abs(max) > abs(x3) ] ? res : x3 */ \ + __ASM_EMIT("vbif q2, q15, q4") /* q12 = [abs(min) < abs(x3) ] ? abs(min) : abs(x3) */ \ + __ASM_EMIT("vbif q3, q15, q5") /* q13 = [abs(max) > abs(x3) ] ? abs(max) : abs(x3) */ \ + __ASM_EMIT("subs %[count], #16") \ + __ASM_EMIT("bhs 1b") \ + __ASM_EMIT("2:") \ + /* x8 block */ \ + __ASM_EMIT("adds %[count], #8") \ + __ASM_EMIT("blt 4f") \ + __ASM_EMIT("vldm %[src]!, {q8-q9}") /* q8 = x0, q9 = x1 */ \ + __ASM_EMIT("vabs.f32 q12, q8") /* q12 = abs(x0) */ \ + __ASM_EMIT("vabs.f32 q13, q9") /* q13 = abs(x1) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q13") /* q4 = [abs(min) < abs(x1) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q13") /* q4 = [abs(max) > abs(x1) ] */ \ + __ASM_EMIT("vbif q0, q9, q4") /* q0 = [abs(min) < abs(x1) ] ? min : x1 */ \ + __ASM_EMIT("vbif q1, q9, q5") /* q1 = [abs(max) > abs(x1) ] ? res : x1 */ \ + __ASM_EMIT("vbif q2, q13, q4") /* q12 = [abs(min) < abs(x1) ] ? abs(min) : abs(x1) */ \ + __ASM_EMIT("vbif q3, q13, q5") /* q13 = [abs(max) > abs(x1) ] ? abs(max) : abs(x1) */ \ + __ASM_EMIT("sub %[count], #8") \ + __ASM_EMIT("4:") \ + /* x4 block */ \ + __ASM_EMIT("adds %[count], #4") \ + __ASM_EMIT("blt 6f") \ + __ASM_EMIT("vldm %[src]!, {q8}") /* q8 = x0, q9 = x1 */ \ + __ASM_EMIT("vabs.f32 q12, q8") /* q12 = abs(x0) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + __ASM_EMIT("sub %[count], #4") \ + __ASM_EMIT("6:") \ + __ASM_EMIT("vext.32 q8, q0, q0, #2") /* q8 = x0 */ \ + __ASM_EMIT("vext.32 q12, q2, q2, #2") /* q12 = abs(x0) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + __ASM_EMIT("vext.32 q8, q0, q0, #1") /* q8 = x0 */ \ + __ASM_EMIT("vext.32 q12, q2, q2, #1") /* q12 = abs(x0) */ \ + __ASM_EMIT(OP " q4, q2, q12") /* q4 = [abs(res0) <=> abs(x0) ] */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + /* x1 block */ \ + __ASM_EMIT("adds %[count], #3") \ + __ASM_EMIT("blt 8f") \ + __ASM_EMIT("7:") \ + __ASM_EMIT("vld1.32 {d16[], d17[]}, [%[src]]!") \ + __ASM_EMIT("vabs.f32 q12, q8") /* q12 = abs(x0) */ \ + __ASM_EMIT("fclt.f32 q4, q2, q12") /* q4 = [abs(min) < abs(x0) ] */ \ + __ASM_EMIT("fcgt.f32 q5, q3, q12") /* q4 = [abs(max) > abs(x0) ] */ \ + __ASM_EMIT("vbif q0, q8, q4") /* q0 = [abs(min) < abs(x0) ] ? min : x0 */ \ + __ASM_EMIT("vbif q1, q8, q5") /* q1 = [abs(max) > abs(x0) ] ? res : x0 */ \ + __ASM_EMIT("vbif q2, q12, q4") /* q12 = [abs(min) < abs(x0) ] ? abs(min) : abs(x0) */ \ + __ASM_EMIT("vbif q3, q12, q5") /* q13 = [abs(max) > abs(x0) ] ? abs(max) : abs(x0) */ \ + __ASM_EMIT("subs %[count], #1") \ + __ASM_EMIT("bge 7b") \ + __ASM_EMIT("8:") \ + /* end */ \ + __ASM_EMIT("vst1.32 {d0[0]}, [%[min]]") \ + __ASM_EMIT("vst1.32 {d2[0]}, [%[max]]") + : [count] "+r" (count), [src] "+r" (src) + : [min] "r" (min), [max] "r" (max) + : "cc", + "q1", "q2", "q3", "q4", "q5", + "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" + ); + } } /* namespace neon_d32 */ } /* namespace lsp */ diff --git a/src/main/arm/neon-d32.cpp b/src/main/arm/neon-d32.cpp index 96b1459c..9dcb918b 100644 --- a/src/main/arm/neon-d32.cpp +++ b/src/main/arm/neon-d32.cpp @@ -367,6 +367,7 @@ EXPORT1(abs_minmax); EXPORT1(sign_min); EXPORT1(sign_max); + EXPORT1(sign_minmax); EXPORT1(min_index); EXPORT1(max_index); diff --git a/src/test/ptest/search/sign_minmax.cpp b/src/test/ptest/search/sign_minmax.cpp index 8f722e11..991e4556 100644 --- a/src/test/ptest/search/sign_minmax.cpp +++ b/src/test/ptest/search/sign_minmax.cpp @@ -54,7 +54,7 @@ namespace lsp IF_ARCH_ARM( namespace neon_d32 { -// void sign_minmax(const float *src, size_t count, float *min, float *max); + void sign_minmax(const float *src, size_t count, float *min, float *max); } ) @@ -106,7 +106,7 @@ PTEST_BEGIN("dsp.search", sign_minmax, 5, 1000) IF_ARCH_X86(CALL(sse::sign_minmax)); IF_ARCH_X86(CALL(avx::sign_minmax)); IF_ARCH_X86(CALL(avx512::sign_minmax)); -// IF_ARCH_ARM(CALL(neon_d32::sign_minmax)); + IF_ARCH_ARM(CALL(neon_d32::sign_minmax)); // IF_ARCH_AARCH64(CALL(asimd::sign_minmax)); PTEST_SEPARATOR; } diff --git a/src/test/utest/search/sign_minmax.cpp b/src/test/utest/search/sign_minmax.cpp index 4e69e511..4ef4f8a7 100644 --- a/src/test/utest/search/sign_minmax.cpp +++ b/src/test/utest/search/sign_minmax.cpp @@ -51,7 +51,7 @@ namespace lsp IF_ARCH_ARM( namespace neon_d32 { -// void sign_minmax(const float *src, size_t count, float *min, float *max); + void sign_minmax(const float *src, size_t count, float *min, float *max); } ) @@ -109,7 +109,7 @@ UTEST_BEGIN("dsp.search", sign_minmax) IF_ARCH_X86(CALL(sse::sign_minmax, 16)); IF_ARCH_X86(CALL(avx::sign_minmax, 32)); IF_ARCH_X86(CALL(avx512::sign_minmax, 64)); -// IF_ARCH_ARM(CALL(neon_d32::sign_minmax, 16)); + IF_ARCH_ARM(CALL(neon_d32::sign_minmax, 16)); // IF_ARCH_AARCH64(CALL(asimd::sign_minmax, 16)); } UTEST_END