fix(none.h): widen SMLALD/SMLALDX products to 64-bit before summing#320
Open
saikumar-mandaji wants to merge 1 commit into
Open
fix(none.h): widen SMLALD/SMLALDX products to 64-bit before summing#320saikumar-mandaji wants to merge 1 commit into
saikumar-mandaji wants to merge 1 commit into
Conversation
The software fallback __SMLALD/__SMLALDX in Include/dsp/none.h (used on cores without the hardware DSP extension, e.g. Cortex-M0/M0+/M3/M23) computed both 16x16 products as 32-bit q31_t and summed them before widening to the 64-bit accumulator. Two same-sign near-full-scale products (each up to 2^30) sum to 2^31, overflowing signed 32-bit and wrapping negative before the (q63_t)sum widening ever applies. This silently produces wrong results in every Q15 function that hits this fallback on a non-DSP core, including arm_fir_q15, arm_mat_vec_mult_q15, arm_lms_q15, arm_lms_norm_q15, arm_conv_opt_q15/arm_conv_partial_opt_q15, and arm_correlate_opt_q15 -- directly contradicting the documented guarantee that the 64-bit accumulator carries no risk of internal overflow. Minimal repro (from the issue): x = y = 0x80008000 (both 16-bit halves = -32768). Each product is (-32768)*(-32768) = 2^30; their 32-bit sum 2^31 wraps to -2^31 under the old code. The true value is +2^31. Fix: cast one operand of each product to q63_t before multiplying, so C's usual arithmetic conversions promote the whole product (and the sum) to 64-bit, matching the fix already suggested in the issue. Verified by hand against the issue's worked arithmetic; no C compiler was available in the environment this patch was authored in to run the reproduction directly, so please double check against CI/local build before merging. Fixes ARM-software#319 Signed-off-by: Saikumar Mandaji <mandajisaikumar@gmail.com>
Contributor
|
Waiting for some feedback on #319 because although I agree with the fix, I also want to understand in which conditions the problem occurs since I have not been able to reproduce it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #319
Problem
The software fallback
__SMLALD/__SMLALDXinInclude/dsp/none.h— used on cores without the hardware DSP extension (Cortex-M0/M0+/M3/M23) — computed both 16x16 products as 32-bitq31_tand summed them before widening to the 64-bit accumulator. Two same-sign near-full-scale products (each up to 2^30) sum to 2^31, overflowing signed 32-bit and wrapping negative before the(q63_t)sumwidening ever applies.This silently produces wrong results in every Q15 function that hits this fallback on a non-DSP core, including
arm_fir_q15,arm_mat_vec_mult_q15,arm_lms_q15,arm_lms_norm_q15,arm_conv_opt_q15/arm_conv_partial_opt_q15, andarm_correlate_opt_q15— directly contradicting the documented guarantee that the 64-bit accumulator carries "no risk of internal overflow."Minimal repro (from the issue):
x = y = 0x80008000(both 16-bit halves = -32768). Each product is(-32768)*(-32768) = 2^30; their 32-bit sum2^31wraps to-2^31under the old code. The true value is+2^31.Fix
Cast one operand of each product to
q63_tbefore multiplying, so C's usual arithmetic conversions promote the whole product (and the sum) to 64-bit. Same shape for both__SMLALDand__SMLALDX, matching the fix already suggested in the issue.Verification
Verified by hand against the issue's worked arithmetic (the minimal-isolation case and the
arm_fir_q15accumulation trace). No C compiler was available in the environment this patch was authored in, so I was not able to run the reproduction or the test suite directly -- please double-check against CI/local build before merging, and let me know if you'd like a test case added.