Version Information [EMAIL PROTECTED] ~]$ arm-elf-gcc -v Using built-in specs. Target: arm-elf Configured with: ../gcc-4.1.1/configure --prefix=/usr/local/armdev-926ej-s-4.1.1 --target=arm-elf --enable-languages=c --with-float=soft --enable-interwork --enable-multilib --with-cpu=arm926ej-s --disable-threads --with-dwarf2 --without-headers Thread model: single gcc version 4.1.1 [EMAIL PROTECTED] ~]$
Introduction This bug was found by building Danger's Java platform using GCC 4.1.1 and running it against the Java ME CLDC TCK 1.1a. The test suite had previously passed when building our Java platform against GCC 3.4.3, so the new test failures constituted a regression. The proposed fix was confirmed to correct the failing tests without introducing other failures in the test suite. The bug should be reproducible using the appended .i file when compiler optimizations are disabled; however, I cannot confirm that because our embedded product requires our supporting OS. If I try to compile this test, I get the following link error: [EMAIL PROTECTED] ~]$ arm-elf-gcc -save-temps -o test test.c /usr/local/armdev-926ej-s-4.1.1/lib/gcc/arm-elf/4.1.1/../../../../arm-elf/bin/ld: crt0.o: No such file: No such file or directory collect2: ld returned 1 exit status Analysis of the bug The test case should simply return; however, on our system it goes into an infinite loop. The cause of the bug is found in the function __adddf3 in gcc/config/arm/ieee754-df.S. In the test case, the inputs to this function are: r0 10000000000000000000000000000000 r1 00000000000000000000000000000001 r2 00000000000000000000000000000000 r3 00000000000000000000000000000000 Hand simulation of the code shows that r4 and r5 are set as follows: r4 00000000000000000000000000000000 r5 00000000000000000000000000000000 __adddf3 correctly identifies that 0.0 is one of the inputs. As a result, we branch to LSYM(Lad_s) and then reach this comment: @ Result is x + 0.0 = x or 0.0 + y = y. It is here that we encounter the bug. The code tries to determine which argument is 0.0 by testing r4. teq r4, #0 If the test passes, the first argument is thought to be 0.0, so the second argument is moved into r0/r1 for return, and the function exits. If the test fails, the function exits directly, returning the first argument. This test is insufficient when the first argument is a very small number. In that case, r4 will be 0, but the first argument overall will be non-zero. As a result, the function returns the second argument when it should have returned the first. To fix the bug, the following line should be inserted after the above line: teqeq xl, #0 This verifies that the entire first argument is indeed 0, not just the high 32 bits. test.i file [EMAIL PROTECTED] ~]$ cat test.i # 1 "test.c" # 1 "<built-in>" # 1 "<command line>" # 1 "test.c" int main() { double x = -4.9E-324; double y = +0.0; double z = x + y; while (z != x) ; return 0; } Full unified patch: --- ieee754-df.S.orig 2006-12-06 14:57:12.000000000 -0800 +++ ieee754-df.S 2006-12-06 14:57:30.000000000 -0800 @@ -327,6 +327,7 @@ @ Result is x + 0.0 = x or 0.0 + y = y. teq r4, #0 + teqeq xl, #0 moveq xh, yh moveq xl, yl RETLDM "r4, r5" -- Summary: Regression in ARM softfloat routine __adddf3 Product: gcc Version: 4.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: regression AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: dpm at danger dot com http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30173