Hello,

I found a problem in GCC on MIPS r5900: When printf() is used with type float, 
the converter function __extendsfdf2() is called. Parameters to printf() are 
always passed as double and not float. The function __extendsfdf2() calls 
itself to convert 32 bit float to 64 bit float. With Linux the __extendsfdf2() 
leads to a segfault when the stack limit is reached.
Here is the wrong code (mipsel-linux-gnu):

00402af0 <__extendsfdf2>:
  402af0:       3c1c0002        lui     gp,0x2
  402af4:       279c9b30        addiu   gp,gp,-25808
  402af8:       0399e021        addu    gp,gp,t9
  402afc:       8f9980a0        lw      t9,-32608(gp)  # Load pointer to 
__extendsfdf2 into t9
  402b00:       27bdffe0        addiu   sp,sp,-32
  402b04:       afbf001c        sw      ra,28(sp)
  402b08:       0320f809        jalr    t9             # Calls __extendsfdf2 
(itself)
  402b0c:       afbc0010        sw      gp,16(sp)
  402b10:       8fbf001c        lw      ra,28(sp)
  402b14:       03e00008        jr      ra
  402b18:       27bd0020        addiu   sp,sp,32
  402b1c:       00000000        nop

The problem happens with the r5900 hard float configurations, e.g.:
configure --target=mipsel-linux-gnu --with-float=hard --with-fpu=single 
--with-arch=r5900
I created the attached patch which fixes this problem for r5900 and another 
problem explained later.
The fixed code generates the following code which should be correct 
(mipsr5900el-ps2-elf):

00105440 <__extendsfdf2>:
  105440:       27bdffc8        addiu   sp,sp,-56
  105444:       27a40028        addiu   a0,sp,40
  105448:       27a50018        addiu   a1,sp,24
  10544c:       afbf0034        sw      ra,52(sp)
  105450:       0c0417b5        jal     105ed4 <__unpack_f>
  105454:       e7ac0028        swc1    $f12,40(sp)
  105458:       8fa20024        lw      v0,36(sp)
  10545c:       8fa40018        lw      a0,24(sp)
  105460:       8fa5001c        lw      a1,28(sp)
  105464:       8fa60020        lw      a2,32(sp)
  105468:       00021882        srl     v1,v0,0x2
  10546c:       00021780        sll     v0,v0,0x1e
  105470:       afa20010        sw      v0,16(sp)
  105474:       0c041789        jal     105e24 <__make_dp>
  105478:       afa30014        sw      v1,20(sp)
  10547c:       8fbf0034        lw      ra,52(sp)
  105480:       03e00008        jr      ra
  105484:       27bd0038        addiu   sp,sp,56

The default targets mipsr5900el and mips64r5900el are not affected by the 
problem, because soft float is the default.

It also seems that the same problem occurs with the following configuration:
configure --target=mipsel-linux-gnu --with-float=hard --with-fpu=single
I expected that this combination should work and a problem should already be 
detected. Can somebody confirm that the problem also occurs with default mipsel?

The second part of the patch fixes the following configuration:
configure --target=mipsel-linux-gnu --with-arch=r5900
It disables the mips16 stuff in the libgcc. This can't be compiled on r5900. 
This was already disabled for targets mipsr5900*el. I detected the problem, 
because the buildroot project uses this style which leads to less problems with 
existing software (because "mipsel" or "mips64el" is hardcoded in most 
configure scripts and don't expect "mipsr5900el" or "mips64r5900el").

Can someone please add the patch to the official GCC repository?

I am not sure whether I fixed all self-calling implementations. Does somebody 
know a way of finding selfcalling implementations?

I tried to find a FPU testsuite, but the testsuites are not designed to test 
non-standard FPUs or use double instead of float. So there can be more problems 
with FPU on r5900 which I don't see at the moment.

Best regards
Jürgen Urban
--- gcc-4.9.0/libgcc/config/t-hardfp-sf	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.9.0-patched/libgcc/config/t-hardfp-sf	2014-05-07 00:14:27.093320928 +0200
@@ -0,0 +1,32 @@
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+hardfp_float_modes := sf
+# di and ti are provided by libgcc2.c where needed.
+hardfp_int_modes := si
+hardfp_extensions :=
+hardfp_truncations :=
+
+# Emulate 64 bit float:
+FPBIT = true
+DPBIT = true
+# Don't build functions handled by 32 bit hardware:
+LIB2FUNCS_EXCLUDE = _addsub_sf _mul_sf _div_sf \
+    _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
+    _lt_sf _le_sf _unord_sf _si_to_sf _sf_to_si _negate_sf \
+    _thenan_sf _sf_to_usi _usi_to_sf
--- gcc-4.9.0/libgcc/config.host	2014-03-27 16:40:31.000000000 +0100
+++ gcc-4.9.0-patched/libgcc/config.host	2014-05-07 00:10:16.565329373 +0200
@@ -140,11 +140,24 @@ microblaze*-*-*)
 	cpu_type=microblaze
 	;;
 mips*-*-*)
-	# All MIPS targets provide a full set of FP routines.
+	# All MIPS targets provide a full set of FP routines except r5900.
 	cpu_type=mips
 	tmake_file="mips/t-mips"
 	if test "${libgcc_cv_mips_hard_float}" = yes; then
-		tmake_file="${tmake_file} t-hardfp-sfdf t-hardfp"
+	    case ${host} in
+	      mips64r5900* | mipsr5900*)
+	        # r5900 doesn't support df.
+		tmake_file="${tmake_file} t-hardfp-sf t-hardfp"
+	        ;;
+	      *)
+	        if test x$with_arch = xr5900; then
+	            # r5900 doesn't support df.
+		    tmake_file="${tmake_file} t-hardfp-sf t-hardfp"
+		else
+		    tmake_file="${tmake_file} t-hardfp-sfdf t-hardfp"
+	        fi
+	        ;;
+	    esac
 	else
 		tmake_file="${tmake_file} t-softfp-sfdf"
 	fi
@@ -794,7 +807,9 @@ mips*-*-linux*)				# Linux MIPS, either
 	    # instructions that are not supported on r5900.
 	    ;;
 	  *)
-	    tmake_file="${tmake_file} mips/t-mips16 t-slibgcc-libgcc"
+	    if test x$with_arch != xr5900; then
+		tmake_file="${tmake_file} mips/t-mips16 t-slibgcc-libgcc"
+	    fi
 	    ;;
 	esac
 	md_unwind_header=mips/linux-unwind.h

Reply via email to