https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128155
Bug ID: 128155
Summary: arm: wrong code: _Sat unsigned _Accum multiplication
returns 0 instead of saturating to the maximum
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: yuki.tanaka at defaultcase dot de
Target Milestone: ---
typedef _Sat unsigned _Accum T;
__attribute__((noipa)) T a(T x, T y)
{
return x * y;
}
int main(void)
{
if (a(50000uk, 50000uk) != __UACCUM_MAX__)
__builtin_abort();
return 0;
}
$ arm-none-eabi-gcc -O2 -march=armv7-a -mthumb --specs=rdimon.specs
-Wl,-Ttext-segment=0x400000 usmul.c -o usmul
$ qemu-arm ./usmul; echo $?
1
50000 * 50000 is larger than the maximum of _Sat unsigned _Accum
(65535.9999847412109375), so the result must saturate to the maximum. Instead a
returns 0 and main aborts.
Compiler Explorer:
https://godbolt.org/z/W4o3Tfjav
GCC 17:
a:
umull r2, r3, r0, r1
mov r1, #0
msr APSR_nzcvq, r1
usat r3, #16, r3
mrs r1, APSR
tst r1, #1<<27
it ne
sbfxne r2, r3, #15, #1
lsr r0, r2, #16
orr r0, r0, r3, asl #16
bx lr
The usat applied to the high word of the 64-bit umull product treats it as
signed, so a high word of 0x80000000 or more gives 0 instead of 0xffff. GCC
16.1 emits the same code. usat is also used at -O0 and with -mcpu=cortex-m4 or
-march=armv7-a.