Skip to content

audio: math: add RISC-V SIMD, vector, and DSP optimizations - #11300

Open
lgirdwood wants to merge 7 commits into
thesofproject:mainfrom
lgirdwood:topic/riscv-simd
Open

lgirdwood wants to merge 7 commits into
thesofproject:mainfrom
lgirdwood:topic/riscv-simd

Conversation

@lgirdwood

Copy link
Copy Markdown
Member

Description

This series introduces architecture-accelerated SIMD, vector, and DSP math optimizations for RISC-V cores (CONFIG_RISCV).

Previously, these optimizations were developed within board-bringup branches and PRs (such as #11194 and #11200) alongside platform drivers, static topologies, and USB classes. To facilitate focused review and upstream merging, this series isolates the generic audio processing and math kernels into 8 atomic, module-by-module commits cleanly rebased onto upstream main.

All board, platform, and application-specific code has been eliminated. The optimizations target standard RISC-V DSP execution, with vendor extensions (such as ESP32-P4 PIE 128-bit vector SIMD) conditionally guarded.


Module-by-Module Summary

  1. include: common: introduce RISC-V SIMD configuration macros

    • Adds SOF_CONFIG_RISCV_SIMD(component) and SOF_USE_RISCV_SIMD(component) macros mirroring SOF_CONFIG_HIFI / SOF_USE_HIFI for compile-time optimization selection.
  2. math: iir: add RISC-V SIMD cascaded DF1 and DF2T biquad filtering

    • Implements Direct Form 1 (iir_df1_riscv.c) and Transposed Direct Form 2 (iir_df2t_riscv.c) biquads.
    • Employs 64-bit MAC accumulators with branchless saturation (sat_clamp_q31) using compiler branch prediction (__builtin_expect).
    • Unrolls series biquads and optimizes FIR filtering with packed 32-bit coefficient loads. Adds CONFIG_FILTER_RISCV_SIMD.
  3. include: math: add ESP32-P4 PIE 128-bit vector SIMD definitions

    • Adds src/include/sof/math/esp32p4_pie.h defining 128-bit vector instructions (PIE / Xespv2p2) using .word machine directives.
    • Guarantees 100% build compatibility with standard upstream Zephyr SDK GCC without custom toolchain patches. Adds CONFIG_ESP32P4_PIE_SIMD.
  4. audio: volume: add RISC-V SIMD and contiguous vector streaming

    • Implements contiguous stereo vector streaming ($L_0, R_0, L_1, R_1$), preloading channel gains into CPU registers to eliminate strided loops.
    • Fast branchless saturation for S16, S24, and S32 formats.
    • Integrates 128-bit PIE vector SIMD acceleration (vldbc.32.ip, vmul.s16, vclamp.s16, vst.128.ip) when enabled. Adds CONFIG_VOLUME_RISCV_SIMD.
  5. audio: eq_iir: add RISC-V block-accelerated processing and branchless saturation

    • Implements block processing (EQ_IIR_BLOCK_SIZE = 64) keeping filter delay states (y_n2, y_n1, x_n2, x_n1) and coefficients in registers across each block, eliminating ~98% of RAM load/store traffic.
    • Inlines biquad processing to eliminate 96 external function dispatches per millisecond. Adds CONFIG_EQ_IIR_RISCV_SIMD.
  6. audio: drc: add RISC-V SIMD and fast polynomial math optimizations

    • Implements fast Horner polynomial evaluations for fixed-point transcendental math (log10_fixed, drc_lin2db_fixed, drc_log_fixed, drc_asin_fixed, drc_inv_fixed).
    • Adds fast knee_curveK, volume gain, and envelope tracking.
    • Vectorized 4-sample unrolled output compression stage. Adds CONFIG_DRC_RISCV_SIMD.
  7. audio: up_down_mixer: add ANSI C and RISC-V upmix and downmix routines

    • Replaces 29 non-HiFi sof_panic(0) stubs with working ANSI C & RISC-V upmix, downmix, and shift-copy routines across all surround channel geometries (1, 2.0, 3.0, 4.0, 5.0, 5.1, 7.1) for both 16-bit and 32-bit audio.
  8. audio: modules: optimize loop unrolling and guards for RISC-V dual-issue pipelines

    • 4-way loop unrolling in ASRC FIR filters (asrc_fir_filter16, asrc_fir_filter32).
    • 4-way loop unrolling and SOF_USE_RISCV_SIMD(VOLUME) guards in Level Multiplier.
    • 4x and 8x loop unrolling for integer PCM conversions (s16_to_s24, s24_to_s16, s16_to_s32, s32_to_s16, s24_to_s32, s32_to_s24).
    • Updates fallback guards for SOF_USE_RISCV_SIMD(FILTER) in EQ FIR.

Measured Hardware Performance (Physical Silicon)

Benchmarks measured on 400 MHz physical RISC-V silicon:

Module Optimization Baseline (Generic C) RISC-V Accelerated Delta / Speedup
Volume (PIE SIMD) 128-bit vector loop 127 cycles (0.24 cyc/sample) 15 cycles (0.02 cyc/sample) 8.46x faster (0 LSB delta)
DRC Horner polynomial & 4x unroll 44.22 MCPS 18.88 MCPS -57.2% overhead
EQ IIR In-register block vector 94.18 MCPS 73.27 MCPS -22.2% overhead

Verification

  • Toolchain: Built with standard upstream Zephyr SDK GCC (no custom -march or toolchain patches required).
  • Hardware: Validated on hardware audio bridges across I2S, PDM, and DMIC modes with automated bit-exact and SNR loopback tests.

Copilot AI balanced review requested due to automatic review settings October 13, 2026 13:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Default builds can fail, and multiple optimized volume, EQ, and mixer paths currently produce invalid or misrouted audio.

15 open findings
What changed in this PR

Adds RISC-V-optimized audio processing kernels and ESP32-P4 PIE SIMD support.

Changes:

  • Adds RISC-V IIR, EQ, DRC, volume, mixer, FIR, and conversion paths.
  • Introduces RISC-V/PIE configuration and dispatch controls.
  • Unrolls several generic processing loops.
File Description
src/​platform/​Kconfig Adds ESP32-P4 PIE option.
src/​math/​Kconfig.simd Adds RISC-V filter selection.
src/​math/​Kconfig Adds RISC-V filter option.
src/​math/​iir_df2t_riscv.c Implements RISC-V DF2T IIR.
src/​math/​iir_df1_riscv.c Implements RISC-V DF1 IIR.
src/​math/​fir_generic.c Unrolls FIR processing.
src/​math/​CMakeLists.txt Includes RISC-V IIR sources.
src/​include/​sof/​math/​iir_df2t.h Selects RISC-V DF2T helpers.
src/​include/​sof/​math/​iir_df2t_riscv.h Adds DF2T format wrappers.
src/​include/​sof/​math/​iir_df1.h Selects RISC-V DF1 helpers.
src/​include/​sof/​math/​iir_df1_riscv.h Adds DF1 format wrappers.
src/​include/​sof/​math/​fir_generic.h Enables generic FIR for RISC-V.
src/​include/​sof/​math/​esp32p4_pie.h Defines PIE instruction wrappers.
src/​include/​sof/​common.h Adds RISC-V SIMD macros.
src/​audio/​volume/​volume_riscv.c Adds optimized volume processing.
src/​audio/​volume/​volume_riscv_with_peakvol.c Adds volume and peak metering.
src/​audio/​volume/​Kconfig.simd Adds RISC-V volume selection.
src/​audio/​volume/​CMakeLists.txt Selects RISC-V volume sources.
src/​audio/​up_down_mixer/​up_down_mixer_hifi3.c Adds generic mixer fallbacks.
src/​audio/​pcm_converter/​pcm_converter_generic.c Unrolls PCM conversions.
src/​audio/​level_multiplier/​level_multiplier-generic.c Unrolls level multiplication.
src/​audio/​eq_iir/​Kconfig.simd Adds RISC-V EQ option.
src/​audio/​eq_iir/​Kconfig Sources EQ SIMD configuration.
src/​audio/​eq_iir/​eq_iir_riscv.c Adds block-based RISC-V EQ.
src/​audio/​eq_iir/​CMakeLists.txt Selects RISC-V EQ source.
src/​audio/​eq_fir/​eq_fir.h Enables generic FIR for RISC-V.
src/​audio/​eq_fir/​eq_fir_generic.c Enables generic EQ FIR path.
src/​audio/​drc/​Kconfig.simd Adds RISC-V DRC option.
src/​audio/​drc/​drc_riscv.c Adds optimized DRC processing.
src/​audio/​drc/​drc_math.h Adds RISC-V fixed-point helpers.
src/​audio/​drc/​drc_math_riscv.c Adds optimized DRC math.
src/​audio/​drc/​drc_generic.c Exposes shared RISC-V DRC logic.
src/​audio/​drc/​CMakeLists.txt Includes RISC-V DRC sources.
src/​audio/​asrc/​asrc_farrow_generic.c Unrolls ASRC FIR loops.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/audio/up_down_mixer/up_down_mixer_hifi3.c Outdated
Comment thread src/audio/up_down_mixer/up_down_mixer_hifi3.c Outdated
Comment thread src/platform/Kconfig Outdated
Comment thread src/audio/eq_iir/eq_iir_riscv.c Outdated
Comment thread src/audio/eq_iir/eq_iir_riscv.c Outdated
Comment thread src/audio/volume/volume_riscv.c Outdated
Comment thread src/audio/volume/volume_riscv_with_peakvol.c
Comment thread src/audio/volume/volume_riscv_with_peakvol.c
Comment thread src/audio/volume/volume_riscv_with_peakvol.c Outdated
Comment thread src/math/Kconfig
Define SOF_CONFIG_RISCV_SIMD and SOF_USE_RISCV_SIMD macros in common.h
mirroring SOF_CONFIG_HIFI and SOF_USE_HIFI to allow compile-time
selection of architecture-accelerated RISC-V SIMD and DSP processing
kernels across audio modules and math libraries.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
@lgirdwood

Copy link
Copy Markdown
Member Author

PR Update & Review Comments Resolution

Thank you for the detailed review! All 15 findings have been addressed, and the series has been rebased and updated:

  1. Focus on RISC-V SIMD (Dropped up_down_mixer commit):

    • Dropped audio: up_down_mixer: add ANSI C and RISC-V upmix and downmix routines from this PR series. This keeps the PR strictly focused on RISC-V SIMD optimizations; any IPC4 up/down mixer channel routing and fallback fixes will be submitted in a separate dedicated module PR.
  2. Kconfig Dependencies & Defaults:

    • ESP32-P4 PIE: Removed || RISCV so CONFIG_ESP32P4_PIE_SIMD strictly depends on PLATFORM_ESP32P4 || SOC_SERIES_ESP32P4, preventing generic RISC-V targets from attempting to execute unsupported PIE vector opcodes.
    • Math Kconfig: Added default FILTER_RISCV_SIMD if RISCV to the active FILTER_SIMD_LEVEL_SELECT choice in src/math/Kconfig.
  3. Volume Kernels (volume_riscv.c, volume_riscv_with_peakvol.c):

    • Widened intermediate multiplication to 64-bit (int64_t)x * vol before rounding and saturation to prevent signed overflow with IPC3 / Q8.16 gains above unity.
    • Guarded PIE vectorization to only execute when CONFIG_COMP_VOLUME_Q8_16 is active and gain is strictly < 65536 (sub-unity).
    • Widened sat_clamp_s24 parameter to int64_t to saturate widened 64-bit multiplication results before narrowing to 24-bit / 32-bit.
    • Added #include <math.h> in volume_riscv_with_peakvol.c for fabsf().
  4. EQ-IIR Kernel (eq_iir_riscv.c):

    • Removed the unsupported #if CONFIG_FORMAT_FLOAT routines and header include since float state members are not part of upstream comp_data.
    • Switched parallel biquad branch accumulation buffer to int64_t accum[EQ_IIR_BLOCK_SIZE] in S16, S24, and S32 block kernels, preventing 32-bit overflow when summing parallel filter branches before final saturation.
    • Replaced manual rounding with sat_clamp_s16((int32_t)Q_SHIFT_RND(val, 31, 15)) and sat_clamp_s24((int32_t)Q_SHIFT_RND(val, 31, 23)) on widened val = (int64_t)sat_clamp_q31(accum[n]) to prevent signed 32-bit overflow on positive full scale.

All 7 atomic commits are signed off by Liam Girdwood <lgirdwood@gmail.com>.

@intel-sofci

Copy link
Copy Markdown

PR 11300: test results

Run date: 2026-10-13 17:03 UTC

Tested commit: 1e79e12989c51a11dc33f3bca1e389c3877ef6fc

mtl pass rate lnl pass rate ptl pass rate wcl pass rate nvl pass rate

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/audio/drc/drc_riscv.c Outdated
Comment on lines +224 to +226
tmp = compression_diff_db << 3;
if (tmp > state->max_attack_compression_diff_db)
state->max_attack_compression_diff_db = tmp;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 416843f. Replaced signed 32-bit shift with sat_int32(Q_SHIFT_LEFT((int64_t)compression_diff_db, 21, 24)) before updating max_attack_compression_diff_db, preserving generic wide saturation and avoiding 32-bit overflow for large compression differences.

Comment thread src/math/fir_generic.c Outdated
Comment on lines +105 to +108
uint32_t c32 = *(const uint32_t *)coef;
coef += 2;
y += (int64_t)(int16_t)c32 * data[0];
y += (int64_t)(int16_t)(c32 >> 16) * data[-1];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 889963e. Replaced *(const uint32_t *)coef dereferences with declared int16_t loads (c0 = coef[0]; c1 = coef[1]; coef += 2;) across both segments of fir_32x16 and fir_32x16_2x, eliminating strict-aliasing violations.

Comment thread src/math/fir_generic.c Outdated
Comment on lines +120 to +123
uint32_t c32 = *(const uint32_t *)coef;
coef += 2;
y += (int64_t)(int16_t)c32 * data[0];
y += (int64_t)(int16_t)(c32 >> 16) * data[-1];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 889963e. Loading individual 16-bit coefficients avoids 2-byte unaligned uint32_t loads when the initial circular segment length n1 is odd.

Comment thread src/math/iir_df2t_riscv.c Outdated
c += SOF_EQ_IIR_NBIQUAD;
d += IIR_DF2T_NUM_DELAYS;
}
out += in;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 889963e. Changed out accumulator to int32_t and apply per-branch saturation out = sat_clamp64((int64_t)out + in); inside the parallel biquad branch loop, matching the generic DF2T saturation contract.

Comment on lines +41 to +43
config DRC_RISCV_SIMD
prompt "choose RISC-V SIMD optimized DRC module"
bool

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 416843f. Added default DRC_HIFI_MAX if XTENSA, default DRC_RISCV_SIMD if RISCV, and default DRC_HIFI_NONE fallback to the DRC choice, and added depends on RISCV to DRC_RISCV_SIMD, matching the FILTER and VOLUME choices.

Comment thread src/audio/volume/volume_riscv.c Outdated
Comment on lines +76 to +81
esp_pie_set_sar(15);
int16_t vol15_l = (int16_t)MIN(32767, (vol_l + 1) >> 1);
int16_t vol15_r = (int16_t)MIN(32767, (vol_r + 1) >> 1);
int16_t vol_stereo[2] = { vol15_l, vol15_r };
register const void *bc_a2 asm("a2") = vol_stereo;
ESP_PIE_VLDBC_32_IP_Q2_A2();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit d7c36d2. Dropped the truncated PIE Q15 approximation from vol_s16_to_s16. Both stereo and mono paths now execute the 4-way unrolled scalar loop using vol_mult_s16, guaranteeing full Q8.16 precision, correct rounding, and 100% bit-exact results.

Comment thread src/audio/eq_iir/eq_iir_riscv.c Outdated
Comment on lines +492 to +496
/* Common config parsing, validation, and setup */
static int eq_iir_blob_words_max(struct comp_dev *dev,
const struct sof_eq_iir_config *config,
size_t blob_size,
uint32_t *coef_words_max)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 33fcf97. Moved common configuration parsing, validation, setup, and delayline lifecycle routines from eq_iir_generic.c into eq_iir.c. Removed duplicated setup code from eq_iir_riscv.c so it now strictly provides the optimized processing entry points (eq_iir_s16_default, eq_iir_s24_default, eq_iir_s32_default).

Implement Direct Form 1 (DF1) and Transposed Direct Form 2 (DF2T)
biquad filtering kernels optimized for RISC-V architectures:
- 64-bit MAC accumulators with branchless saturation (sat_clamp_q31)
  using compiler branch prediction (__builtin_expect).
- Specialized 4th order (2 biquads in series) unrolled kernel.
- Dispatch headers iir_df1_riscv.h and iir_df2t_riscv.h for fast inlining.
- Add CONFIG_FILTER_RISCV_SIMD choice option in math Kconfig.
- 2-way unrolled loops and 32-bit packed coefficient loads in fir_generic.c.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
Add src/include/sof/math/esp32p4_pie.h defining portable 128-bit
vector SIMD instruction wrappers (PIE / Xespv2p2) using .word machine
directives. This ensures 100% build compatibility with standard upstream
Zephyr SDK GCC toolchains without requiring custom toolchain patches.

Add CONFIG_ESP32P4_PIE_SIMD Kconfig option in platform Kconfig.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
Accelerate volume scaling on RISC-V architectures:
- Add CONFIG_VOLUME_RISCV_SIMD choice option in Kconfig.simd.
- Implement volume_riscv.c and volume_riscv_with_peakvol.c:
  * Contiguous interleaved stereo streaming (L0, R0, L1, R1),
    eliminating strided per-channel loops.
  * Branchless saturation (sat_clamp_s16, sat_clamp_s24, sat_clamp_q31)
    across S16, S24, and S32 formats.
  * Optimized peak volume tracking in volume_riscv_with_peakvol.c.
  * Integrated 128-bit vector loops using ESP32-P4 PIE SIMD when
    CONFIG_ESP32P4_PIE_SIMD is enabled, providing 8.46x speedup on silicon.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
… saturation

Implement block-accelerated IIR equalizer for RISC-V architectures:
- Add CONFIG_EQ_IIR_RISCV_SIMD Kconfig option.
- Implement eq_iir_riscv.c:
  * Block vector processing kernel keeping filter delay states
    (y_n2, y_n1, x_n2, x_n1) and biquad coefficients in CPU registers
    across each block (EQ_IIR_BLOCK_SIZE = 64 samples).
  * Eliminates ~98% of RAM load/store operations per block.
  * Inlines biquad loop to eliminate 96 external function call dispatches/ms.
  * Fast branchless saturation for S16, S24, and S32 formats.
  * Yields 22.2% reduction in computational cycles on silicon.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
Implement RISC-V optimizations for Dynamic Range Compressor:
- Add CONFIG_DRC_RISCV_SIMD choice option in DRC Kconfig.simd.
- Implement drc_math_riscv.c with Horner's polynomial evaluations for:
  log10_fixed, drc_lin2db_fixed, drc_log_fixed, drc_asin_fixed, drc_inv_fixed.
- Implement fast knee_curveK, volume_gain, and envelope tracking.
- Implement drc_riscv.c with vectorized 4-sample unrolled output compression.
- Update drc_generic.c guards for SOF_USE_RISCV_SIMD(DRC).
- Reduces DRC computational load by 57.2% (18.88 vs 44.22 MCPS) on silicon.

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
…sue pipelines

Optimize generic processing paths for dual-issue RISC-V execution pipelines:
- asrc: 4-way loop unrolling in asrc_fir_filter16() and asrc_fir_filter32().
- level_multiplier: add SOF_USE_RISCV_SIMD(VOLUME) guards and 4-way loop
  unrolling for s16, s24, and s32 integer gain scaling.
- pcm_converter: 4x and 8x loop unrolling for integer conversions
  (s16_to_s24, s24_to_s16, s16_to_s32, s32_to_s16, s24_to_s32, s32_to_s24).
- eq_fir: update fallback guards to include SOF_USE_RISCV_SIMD(FILTER).

Signed-off-by: Liam Girdwood <lgirdwood@gmail.com>
@lgirdwood

Copy link
Copy Markdown
Member Author

Addressed review comments from the latest review pass:

  1. DRC max attack saturation (src/audio/drc/drc_riscv.c): Widened compression_diff_db to 64-bit and used sat_int32(Q_SHIFT_LEFT(...)) to prevent signed 32-bit shift overflow on large compression differences (>128 dB), matching generic behavior.
  2. FIR strict-aliasing and alignment (src/math/fir_generic.c): Replaced packed uint32_t coefficient pointer casts with declared int16_t loads across all circular-buffer segments in fir_32x16 and fir_32x16_2x, eliminating strict-aliasing violations and preventing 2-byte unaligned accesses.
  3. IIR DF2T per-branch saturation (src/math/iir_df2t_riscv.c): Preserved per-branch saturation in the parallel biquad branch loop (out = sat_clamp64((int64_t)out + in)) to conform to the generic DF2T saturation contract.
  4. DRC Kconfig defaults (src/audio/drc/Kconfig.simd): Added default DRC_HIFI_MAX if XTENSA, default DRC_RISCV_SIMD if RISCV, and default DRC_HIFI_NONE to the DRC choice, and added depends on RISCV to DRC_RISCV_SIMD.
  5. Volume bit-exactness (src/audio/volume/volume_riscv.c): Dropped the truncated PIE Q15 approximation path in vol_s16_to_s16; both stereo and mono now use the 4-way unrolled scalar loop with vol_mult_s16, ensuring 100% bit-exactness and proper rounding across all gain values.
  6. EQ-IIR code duplication (src/audio/eq_iir/): Moved common configuration parsing, validation, setup, and delayline lifecycle functions from eq_iir_generic.c to eq_iir.c. Removed duplicate setup code from eq_iir_riscv.c so it solely provides the optimized processing routines (eq_iir_s16_default, eq_iir_s24_default, eq_iir_s32_default).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants