Merge remote-tracking branch 'origin/cpx_rotate_aarch64' into integration_2025_w36 (!3613)

Speedup complex rotate for aarch64

This is a simple optimization for aarch64 for the "rotate_cpx_vector" used for
the phase_rotation in 5G NR. It provides a speedup of around 1.5 on high-end
aarch64 targets compared to the SIMDe translated version. It is implemented with
native NEON intrinsics and was largely inspired by suggestions from ChatGPT 5 :-)
This commit is contained in:
Jaroslava Fiedlerova
2025-09-02 11:04:44 +02:00
3 changed files with 48 additions and 13 deletions
+1 -1
View File
@@ -170,7 +170,7 @@ endif()
if (NOT CROSS_COMPILE)
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native")
else ()
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a")
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8.2-a")
endif()
# add autotools definitions that were maybe used!
+2 -11
View File
@@ -37,20 +37,11 @@ RUN /bin/sh oaienv && \
mkdir -p log ran_build/build ran_build/build-cross && \
cd ran_build/build && \
cmake ../../.. -GNinja && \
echo "====== Start of log for host-tools ======" && \
ninja ldpc_generators generate_T > ../../log/host-tools.txt 2>&1 && \
echo "====== End of log for host-tools ======" && \
ninja ldpc_generators generate_T && \
cd ../build-cross/ && \
# install missing libyaml-cpp-dev for arm64
apt install -y libyaml-cpp-dev:arm64 && \
cmake ../../.. -GNinja -DENABLE_TELNETSRV=ON \
-DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build \
-DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" && \
echo "====== Start of log for cross-build executables ======" && \
# making always passing so we can analyze the all.txt file
ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv > ../../log/all.txt 2>&1; \
# displaying errors and warnings
grep -E -A3 "warning:|error:" ../../log/all.txt || true && \
# will fail only if string "errors:" is found
grep -E "error:" -vqz ../../log/all.txt && \
echo "====== End of log for cross-build executables ======"
ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv
+45 -1
View File
@@ -828,6 +828,47 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al
// log2_amp - increase the output amplitude by a factor 2^log2_amp (default is 0)
// WARNING: log2_amp>0 can cause overflow!!
#ifdef __aarch64__
if (output_shift == 15) { // allows specific NEON instruction
int16x8_t ar = (int16x8_t)vdupq_n_s16(alpha->r);
int16x8_t ai = (int16x8_t)vdupq_n_s16(alpha->i);
int16x8_t *y_128 = (int16x8_t *)y;
int16x8_t *x_128 = (int16x8_t *)x;
for (uint32_t i = 0; i < (N >> 2); i++) {
// Split interleaved -> separate real/imag
int16x8_t br = vuzp1q_s16(x_128[i], x_128[i]);
int16x8_t bi = vuzp2q_s16(x_128[i], x_128[i]);
// Start with the two “diagonal” products using high-half, doubling, sat:
// x = round( (2*ar*br) / 2^16 ), y = round( (2*ar*bi) / 2^16 )
int16x8_t real = vqdmulhq_s16(ar, br);
int16x8_t imag = vqdmulhq_s16(ar, bi);
// real -= round( (2*ai*bi) / 2^16 )
real = vqrdmlshq_s16(real, ai, bi);
// imag += round( (2*ai*br) / 2^16 )
imag = vqrdmlahq_s16(imag, ai, br);
// Re-interleave [real, imag]
int16x8x2_t z = vzipq_s16(real, imag);
y_128[i] = z.val[0];
/*
printf("y : (%d %d) (%d %d) (%d %d) (%d %d)\n",
vgetq_lane_s16(y_128[i],0),
vgetq_lane_s16(y_128[i],1),
vgetq_lane_s16(y_128[i],2),
vgetq_lane_s16(y_128[i],3),
vgetq_lane_s16(y_128[i],4),
vgetq_lane_s16(y_128[i],5),
vgetq_lane_s16(y_128[i],6),
vgetq_lane_s16(y_128[i],7));*/
}
} else {
#endif
uint32_t i; // loop counter
simd_q15_t *y_128, alpha_128;
@@ -859,7 +900,10 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al
shift));
// print_ints("y_128[0]=", &y_128[0]);
}
#if defined(__x86__) || defined(__x86_64__)
#ifdef __aarch64__
}
#endif //__aarch64__
#if defined(__x86_64__) || defined(__i386__)
}
#endif
}