Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/run-tests-aarch64-be.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#
# Copyright 2026 Zetier Inc
#
# This file is part of VOLK
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#

name: Run VOLK tests on big-endian AArch64

on: [push, pull_request]

env:
# Ubuntu has no big-endian AArch64 cross toolchain, so use Arm's.
ARM_TOOLCHAIN: arm-gnu-toolchain-15.3.rel2-x86_64-aarch64_be-none-linux-gnu
ARM_TOOLCHAIN_URL: https://gitlab.arm.com/api/v4/projects/tooling%2Fgnu-toolchains-for-arm/packages/generic/gnu-toolchain/15.3.rel2
ARM_TOOLCHAIN_SHA256: bdf8e9b4c62791c5c3aeeb8ba3791421d73c7d147dd04f0da502716885bcc1d2

jobs:
Tests:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
submodules: "recursive"
- name: Install packages
run: |
sudo DEBIAN_FRONTEND=noninteractive apt-get update -q -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y python3-mako cmake qemu-user curl
- name: Install sccache
shell: bash
run: sudo scripts/ci/install_sccache.bash "aarch64_be tests"
continue-on-error: true
- name: Cache toolchain
id: cache_toolchain
uses: actions/cache@v5
with:
path: ~/${{ env.ARM_TOOLCHAIN }}
key: ${{ env.ARM_TOOLCHAIN }}
- name: Download toolchain
if: steps.cache_toolchain.outputs.cache-hit != 'true'
run: |
cd ~
curl -fsSL -o "$ARM_TOOLCHAIN.tar.xz" "$ARM_TOOLCHAIN_URL/$ARM_TOOLCHAIN.tar.xz"
echo "$ARM_TOOLCHAIN_SHA256 $ARM_TOOLCHAIN.tar.xz" | sha256sum -c -
tar -xJf "$ARM_TOOLCHAIN.tar.xz"
rm "$ARM_TOOLCHAIN.tar.xz"
- name: Add toolchain to PATH
run: echo "$HOME/$ARM_TOOLCHAIN/bin" >> "$GITHUB_PATH"
- name: Prepare sccache usage
id: enable_sccache
run: scripts/ci/setup_cmake_cache_flags.bash "aarch64_be tests"
- name: Configure
run: >
cmake
-S .
-B build
-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/aarch64_be-none-linux-gnu.cmake
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_C_FLAGS="-Werror"
-DCMAKE_CXX_FLAGS="-Werror"
-DBUILD_EXECUTABLE=ON
${{ steps.enable_sccache.outputs.CXX_LAUNCHER }}
${{ steps.enable_sccache.outputs.C_LAUNCHER }}
- name: Build
run: cmake --build build -j$(nproc)
- name: Print info
run: |
sysroot=$(aarch64_be-none-linux-gnu-gcc -print-sysroot)
for opt in --alignment --avail-machines --all-machines --malloc --cc; do
qemu-aarch64_be -L "$sysroot" -E LD_LIBRARY_PATH="$(dirname "$sysroot")/lib64" \
build/apps/volk-config-info $opt
done
- name: Test
run: cd build && ctest -V
- name: Show final sccache and build directory stats
if: always()
continue-on-error: true
shell: bash
run: scripts/ci/build-summary.sh "aarch64_be tests" "./build/"
45 changes: 45 additions & 0 deletions cmake/Toolchains/aarch64_be-none-linux-gnu.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# Copyright 2026 Zetier Inc
#
# This file is part of VOLK
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#

# Big-endian AArch64 with the Arm GNU Toolchain (aarch64_be-none-linux-gnu),
# whose bin directory must be on the PATH. Tests run under qemu-aarch64_be.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64_be)

set(TOOLCHAIN_PREFIX aarch64_be-none-linux-gnu-)

set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)

# The toolchain ships its own glibc sysroot; libstdc++ and libgcc_s sit
# outside it, next to the sysroot in the toolchain's target directory.
execute_process(
COMMAND ${CMAKE_C_COMPILER} -print-sysroot
RESULT_VARIABLE TOOLCHAIN_SYSROOT_RESULT
OUTPUT_VARIABLE TOOLCHAIN_SYSROOT
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT TOOLCHAIN_SYSROOT_RESULT EQUAL 0 OR TOOLCHAIN_SYSROOT STREQUAL "")
message(FATAL_ERROR "Could not run ${CMAKE_C_COMPILER} -print-sysroot; "
"put the toolchain's bin directory on the PATH")
endif()
get_filename_component(TOOLCHAIN_SYSROOT "${TOOLCHAIN_SYSROOT}" REALPATH)
get_filename_component(TOOLCHAIN_TARGET_DIR "${TOOLCHAIN_SYSROOT}" DIRECTORY)

set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# One string, as VolkAddTest pastes it into each test's shell script. The -E
# replaces the scripts' LD_LIBRARY_PATH; the build tree's RPATH still finds
# libvolk.
set(CMAKE_CROSSCOMPILING_EMULATOR
"qemu-aarch64_be -L ${TOOLCHAIN_SYSROOT} -E LD_LIBRARY_PATH=${TOOLCHAIN_TARGET_DIR}/lib64")
10 changes: 8 additions & 2 deletions kernels/volk/volk_32f_index_max_16u.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@ volk_32f_index_max_16u_neon(uint16_t* target, const float* src0, uint32_t num_po
const float* inputPtr = src0;

// Use integer indices directly
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(-FLT_MAX);
Expand Down Expand Up @@ -345,7 +348,10 @@ volk_32f_index_max_16u_neonv8(uint16_t* target, const float* src0, uint32_t num_
const float* inputPtr = src0;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(-FLT_MAX);
Expand Down
5 changes: 4 additions & 1 deletion kernels/volk/volk_32f_index_max_32u.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,10 @@ volk_32f_index_max_32u_neonv8(uint32_t* target, const float* src0, uint32_t num_
const float* inputPtr = src0;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(-FLT_MAX);
Expand Down
10 changes: 8 additions & 2 deletions kernels/volk/volk_32f_index_min_16u.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,10 @@ volk_32f_index_min_16u_neon(uint16_t* target, const float* source, uint32_t num_
const float* inputPtr = source;

// Use integer indices directly
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down Expand Up @@ -337,7 +340,10 @@ volk_32f_index_min_16u_neonv8(uint16_t* target, const float* source, uint32_t nu
const float* inputPtr = source;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down
5 changes: 4 additions & 1 deletion kernels/volk/volk_32f_index_min_32u.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ volk_32f_index_min_32u_neonv8(uint32_t* target, const float* source, uint32_t nu
const float* inputPtr = source;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down
7 changes: 4 additions & 3 deletions kernels/volk/volk_32fc_conjugate_32fc.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,10 @@ static inline void volk_32fc_conjugate_32fc_neonv8(lv_32fc_t* cVector,
lv_32fc_t* c = cVector;
const lv_32fc_t* a = aVector;

/* Sign mask to flip imaginary parts: [0, -0, 0, -0] */
const uint32x4_t sign_mask =
vreinterpretq_u32_f32((float32x4_t){ 0.0f, -0.0f, 0.0f, -0.0f });
/* Sign mask to flip imaginary parts: [0, -0, 0, -0], loaded from memory
* because a brace-initialized vector is lane-reversed on big-endian GCC */
static const float sign_bits[4] = { 0.0f, -0.0f, 0.0f, -0.0f };
const uint32x4_t sign_mask = vreinterpretq_u32_f32(vld1q_f32(sign_bits));

/* Process 4 complex numbers per iteration (2x unroll) */
while (n >= 4) {
Expand Down
10 changes: 8 additions & 2 deletions kernels/volk/volk_32fc_index_max_16u.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,10 @@ volk_32fc_index_max_16u_neon(uint16_t* target, const lv_32fc_t* src0, uint32_t n
const lv_32fc_t* inputPtr = src0;

// Use integer indices directly
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(0.0f);
Expand Down Expand Up @@ -404,7 +407,10 @@ static inline void volk_32fc_index_max_16u_neonv8(uint16_t* target,
const lv_32fc_t* inputPtr = src0;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(0.0f);
Expand Down
5 changes: 4 additions & 1 deletion kernels/volk/volk_32fc_index_max_32u.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,10 @@ static inline void volk_32fc_index_max_32u_neonv8(uint32_t* target,
const lv_32fc_t* inputPtr = src0;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_max = vdupq_n_f32(0.0f);
Expand Down
10 changes: 8 additions & 2 deletions kernels/volk/volk_32fc_index_min_16u.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ static inline void volk_32fc_index_min_16u_neon(uint16_t* target,
const lv_32fc_t* inputPtr = source;

// Use integer indices directly
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down Expand Up @@ -403,7 +406,10 @@ static inline void volk_32fc_index_min_16u_neonv8(uint16_t* target,
const lv_32fc_t* inputPtr = source;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down
5 changes: 4 additions & 1 deletion kernels/volk/volk_32fc_index_min_32u.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,10 @@ static inline void volk_32fc_index_min_32u_neonv8(uint32_t* target,
const lv_32fc_t* inputPtr = source;

// Use integer indices directly (no float conversion overhead)
uint32x4_t vec_indices = { 0, 1, 2, 3 };
// Load from an array to avoid GCC filling a brace-initialized vector like
// { 0, 1, 2, 3 } in reverse lane order on big-endian targets
static const uint32_t init_indices[4] = { 0, 1, 2, 3 };
uint32x4_t vec_indices = vld1q_u32(init_indices);
const uint32x4_t vec_incr = vdupq_n_u32(4);

float32x4_t vec_min = vdupq_n_f32(FLT_MAX);
Expand Down
5 changes: 2 additions & 3 deletions kernels/volk/volk_32u_byteswap.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,17 @@ static inline void volk_32u_byteswap_neonv8(uint32_t* intsToSwap, unsigned int n
uint32_t* inputPtr = (uint32_t*)intsToSwap;
const unsigned int n8points = num_points / 8;
uint8x16_t input;
uint8x16_t idx = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };

unsigned int number = 0;
for (number = 0; number < n8points; ++number) {
__VOLK_PREFETCH(inputPtr + 8);
input = vld1q_u8((uint8_t*)inputPtr);
input = vqtbl1q_u8(input, idx);
input = vrev32q_u8(input);
vst1q_u8((uint8_t*)inputPtr, input);
inputPtr += 4;

input = vld1q_u8((uint8_t*)inputPtr);
input = vqtbl1q_u8(input, idx);
input = vrev32q_u8(input);
vst1q_u8((uint8_t*)inputPtr, input);
inputPtr += 4;
}
Expand Down
4 changes: 1 addition & 3 deletions kernels/volk/volk_32u_reverse_32u.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,13 @@ volk_32u_reverse_32u_neonv8(uint32_t* out, const uint32_t* in, unsigned int num_
const uint32_t* in_ptr = in;
uint32_t* out_ptr = out;

const uint8x16_t idx = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };

const unsigned int quarterPoints = num_points / 4;
unsigned int number = 0;
for (; number < quarterPoints; ++number) {
__VOLK_PREFETCH(in_ptr + 4);
uint32x4_t x = vld1q_u32(in_ptr);
uint32x4_t z =
vreinterpretq_u32_u8(vqtbl1q_u8(vrbitq_u8(vreinterpretq_u8_u32(x)), idx));
vreinterpretq_u32_u8(vrev32q_u8(vrbitq_u8(vreinterpretq_u8_u32(x))));
vst1q_u32(out_ptr, z);
in_ptr += 4;
out_ptr += 4;
Expand Down
Loading