[Bug regression/30173] New: Regression in ARM softfloat routine __adddf3

dpm at danger dot com gcc-bugzilla@gcc.gnu.org
Tue Dec 12 16:00:00 GMT 2006


Version Information

[dpm@spenseweed ~]$ 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
[dpm@spenseweed ~]$


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:

[dpm@spenseweed ~]$ 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

[dpm@spenseweed ~]$ 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



More information about the Gcc-bugs mailing list