From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29724 invoked by alias); 16 Jan 2007 16:05:58 -0000 Received: (qmail 29539 invoked by uid 22791); 16 Jan 2007 16:05:56 -0000 X-Spam-Check-By: sourceware.org Received: from igw2.watson.ibm.com (HELO igw2.watson.ibm.com) (129.34.20.6) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 16 Jan 2007 16:05:47 +0000 Received: from sp1n294en1.watson.ibm.com (sp1n294en1.watson.ibm.com [129.34.20.40]) by igw2.watson.ibm.com (8.12.11.20060308/8.13.1/8.13.1-2005-04-25 igw) with ESMTP id l0GG6pL1030923; Tue, 16 Jan 2007 11:06:51 -0500 Received: from sp1n294en1.watson.ibm.com (localhost [127.0.0.1]) by sp1n294en1.watson.ibm.com (AIX5.2/8.11.6p2/8.11.7/01-14-2004_2) with ESMTP id l0GG5ex118398; Tue, 16 Jan 2007 11:05:40 -0500 Received: from mgsmtp00.watson.ibm.com (mgsmtp00.watson.ibm.com [9.2.40.58]) by sp1n294en1.watson.ibm.com (AIX5.2/8.11.6p2/8.11.7/01-14-2004_1) with ESMTP id l0GG5dC118396; Tue, 16 Jan 2007 11:05:39 -0500 Received: from makai.watson.ibm.com (makai.watson.ibm.com [9.2.216.144]) by mgsmtp00.watson.ibm.com (8.12.11/8.12.11/2005/09/01) with ESMTP id l0GFwggK005030; Tue, 16 Jan 2007 10:58:43 -0500 Received: from watson.ibm.com (localhost [127.0.0.1]) by makai.watson.ibm.com (AIX5.3/8.11.6p2/8.11.0/03-06-2002) with ESMTP id l0GG5a834214; Tue, 16 Jan 2007 11:05:37 -0500 Message-Id: <200701161605.l0GG5a834214@makai.watson.ibm.com> To: "Joseph S. Myers" cc: gcc-patches@gcc.gnu.org Subject: Re: soft-fp updated In-Reply-To: Message from "Joseph S. Myers" of "Tue, 16 Jan 2007 00:03:09 GMT." References: Date: Tue, 16 Jan 2007 16:05:00 -0000 From: David Edelsohn Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2007-01/txt/msg01334.txt.bz2 With the soft-fp fixes imported from Glibc, I have committed the long double 128 soft-fp support for PowerPC. Assuming no problems on mainline, I will backport to GCC 4.2. David * config/rs6000/darwin-ldouble.c: Build file for SOFT_FLOAT. (strong_alias): Define. (__gcc_qmul): Provide non-FMA for soft-float. (__gcc_qdiv): Same. (__gcc_qneg): New. (__gcc_qeq): New. (__gcc_qle): New. (__gcc_qge): New. (__gcc_qunord): New. (__gcc_stoq): New. (__gcc_dtoq): New. (__gcc_qtos): New. (__gcc_qtod): New. (__gcc_qtoi): New. (__gcc_qtou): New. (__gcc_itoq): New. (__gcc_utoq): New. (fmsub): New. * config/rs6000/rs6000.c (rs6000_init_libfuncs): Initialize soft-float functions. * config/rs6000/libgcc-ppc-glibc.ver: Version soft-float symbols. * config/rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Do not warn about long double soft float. Index: darwin-ldouble.c =================================================================== --- darwin-ldouble.c (revision 120219) +++ darwin-ldouble.c (working copy) @@ -49,7 +49,8 @@ This code currently assumes big-endian. */ -#if (!defined (__NO_FPRS__) && !defined (__LITTLE_ENDIAN__) \ +#if ((!defined (__NO_FPRS__) || defined (_SOFT_FLOAT)) \ + && !defined (__LITTLE_ENDIAN__) \ && (defined (__MACH__) || defined (__powerpc__) || defined (_AIX))) #define fabs(x) __builtin_fabs(x) @@ -60,14 +61,19 @@ #define nonfinite(a) unlikely (! isless (fabs (a), inf ())) +/* Define ALIASNAME as a strong alias for NAME. */ +# define strong_alias(name, aliasname) _strong_alias(name, aliasname) +# define _strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))); + /* All these routines actually take two long doubles as parameters, but GCC currently generates poor code when a union is used to turn a long double into a pair of doubles. */ -extern long double __gcc_qadd (double, double, double, double); -extern long double __gcc_qsub (double, double, double, double); -extern long double __gcc_qmul (double, double, double, double); -extern long double __gcc_qdiv (double, double, double, double); +long double __gcc_qadd (double, double, double, double); +long double __gcc_qsub (double, double, double, double); +long double __gcc_qmul (double, double, double, double); +long double __gcc_qdiv (double, double, double, double); #if defined __ELF__ && defined SHARED \ && (defined __powerpc64__ || !(defined __linux__ || defined __gnu_hurd__)) @@ -139,6 +145,10 @@ return __gcc_qadd (a, b, -c, -d); } +#ifdef _SOFT_FLOAT +static double fmsub (double, double, double); +#endif + long double __gcc_qmul (double a, double b, double c, double d) { @@ -154,7 +164,11 @@ /* Sum terms of two highest orders. */ /* Use fused multiply-add to get low part of a * c. */ +#ifndef _SOFT_FLOAT asm ("fmsub %0,%1,%2,%3" : "=f"(tau) : "f"(a), "f"(c), "f"(t)); +#else + tau = fmsub (a, c, t); +#endif v = a*d; w = b*c; tau += v + w; /* Add in other second-order terms. */ @@ -187,7 +201,11 @@ numerically necessary. */ /* Use fused multiply-add to get low part of c * t. */ +#ifndef _SOFT_FLOAT asm ("fmsub %0,%1,%2,%3" : "=f"(sigma) : "f"(c), "f"(t), "f"(s)); +#else + sigma = fmsub (c, t, s); +#endif v = a - s; tau = ((v-sigma)+w)/c; /* Correction to t. */ @@ -201,4 +219,220 @@ return z.ldval; } +#ifdef _SOFT_FLOAT + +long double __gcc_qneg (double, double); +int __gcc_qeq (double, double, double, double); +int __gcc_qne (double, double, double, double); +int __gcc_qge (double, double, double, double); +int __gcc_qle (double, double, double, double); +int __gcc_qunord (double, double, double, double); +long double __gcc_stoq (float); +long double __gcc_dtoq (double); +float __gcc_qtos (double, double); +double __gcc_qtod (double, double); +int __gcc_qtoi (double, double); +unsigned int __gcc_qtou (double, double); +long double __gcc_itoq (int); +long double __gcc_utoq (unsigned int); + +extern int __eqdf2 (double, double); +extern int __ledf2 (double, double); +extern int __gedf2 (double, double); +extern int __unorddf2 (double, double); + +/* Negate 'long double' value and return the result. */ +long double +__gcc_qneg (double a, double aa) +{ + longDblUnion x; + + x.dval[0] = -a; + x.dval[1] = -aa; + return x.ldval; +} + +/* Compare two 'long double' values for equality. */ +int +__gcc_qeq (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __eqdf2 (aa, cc); + return 1; +} + +strong_alias (__gcc_qeq, __gcc_qne); + +/* Compare two 'long double' values for less than or equal. */ +int +__gcc_qle (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __ledf2 (aa, cc); + return __ledf2 (a, c); +} + +strong_alias (__gcc_qle, __gcc_qlt); + +/* Compare two 'long double' values for greater than or equal. */ +int +__gcc_qge (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __gedf2 (aa, cc); + return __gedf2 (a, c); +} + +strong_alias (__gcc_qge, __gcc_qgt); + +/* Compare two 'long double' values for unordered. */ +int +__gcc_qunord (double a, double aa, double c, double cc) +{ + if (__eqdf2 (a, c) == 0) + return __unorddf2 (aa, cc); + return __unorddf2 (a, c); +} + +/* Convert single to long double. */ +long double +__gcc_stoq (float a) +{ + longDblUnion x; + + x.dval[0] = (double) a; + x.dval[1] = 0.0; + + return x.ldval; +} + +/* Convert double to long double. */ +long double +__gcc_dtoq (double a) +{ + longDblUnion x; + + x.dval[0] = a; + x.dval[1] = 0.0; + + return x.ldval; +} + +/* Convert long double to single. */ +float +__gcc_qtos (double a, double aa __attribute__ ((__unused__))) +{ + return (float) a; +} + +/* Convert long double to double. */ +double +__gcc_qtod (double a, double aa __attribute__ ((__unused__))) +{ + return a; +} + +/* Convert long double to int. */ +int +__gcc_qtoi (double a, double aa) +{ + double z = a + aa; + return (int) z; +} + +/* Convert long double to unsigned int. */ +unsigned int +__gcc_qtou (double a, double aa) +{ + double z = a + aa; + return (unsigned int) z; +} + +/* Convert int to long double. */ +long double +__gcc_itoq (int a) +{ + return __gcc_dtoq ((double) a); +} + +/* Convert unsigned int to long double. */ +long double +__gcc_utoq (unsigned int a) +{ + return __gcc_dtoq ((double) a); +} + +#include "config/soft-fp/soft-fp.h" +#include "config/soft-fp/double.h" +#include "config/soft-fp/quad.h" + +/* Compute floating point multiply-subtract with higher (quad) precision. */ +static double +fmsub (double a, double b, double c) +{ + FP_DECL_EX; + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_Q(X); + FP_DECL_Q(Y); + FP_DECL_Q(Z); + FP_DECL_Q(U); + FP_DECL_Q(V); + FP_DECL_D(R); + double r; + long double u, v, x, y, z; + + FP_INIT_ROUNDMODE; + FP_UNPACK_RAW_D (A, a); + FP_UNPACK_RAW_D (B, b); + FP_UNPACK_RAW_D (C, c); + + /* Extend double to quad. */ +#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q + FP_EXTEND(Q,D,4,2,X,A); + FP_EXTEND(Q,D,4,2,Y,B); + FP_EXTEND(Q,D,4,2,Z,C); +#else + FP_EXTEND(Q,D,2,1,X,A); + FP_EXTEND(Q,D,2,1,Y,B); + FP_EXTEND(Q,D,2,1,Z,C); +#endif + FP_PACK_RAW_Q(x,X); + FP_PACK_RAW_Q(y,Y); + FP_PACK_RAW_Q(z,Z); + FP_HANDLE_EXCEPTIONS; + + /* Multiply. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_Q(X,x); + FP_UNPACK_Q(Y,y); + FP_MUL_Q(U,X,Y); + FP_PACK_Q(u,U); + FP_HANDLE_EXCEPTIONS; + + /* Subtract. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_Q(U,u); + FP_UNPACK_SEMIRAW_Q(Z,z); + FP_SUB_Q(V,U,Z); + FP_PACK_SEMIRAW_Q(v,V); + FP_HANDLE_EXCEPTIONS; + + /* Truncate quad to double. */ + FP_INIT_ROUNDMODE; + FP_UNPACK_SEMIRAW_Q(V,v); +#if (2 * _FP_W_TYPE_SIZE) < _FP_FRACBITS_Q + FP_TRUNC(D,Q,2,4,R,V); +#else + FP_TRUNC(D,Q,1,2,R,V); +#endif + FP_PACK_SEMIRAW_D(r,R); + FP_HANDLE_EXCEPTIONS; + + return r; +} + +#endif + #endif Index: rs6000.c =================================================================== --- rs6000.c (revision 120219) +++ rs6000.c (working copy) @@ -9402,9 +9402,6 @@ static void rs6000_init_libfuncs (void) { - if (!TARGET_HARD_FLOAT) - return; - if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF && !TARGET_POWER2 && !TARGET_POWERPC) { @@ -9423,6 +9420,27 @@ set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub"); set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul"); set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv"); + + if (TARGET_SOFT_FLOAT) + { + set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg"); + set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq"); + set_optab_libfunc (ne_optab, TFmode, "__gcc_qne"); + set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt"); + set_optab_libfunc (ge_optab, TFmode, "__gcc_qge"); + set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt"); + set_optab_libfunc (le_optab, TFmode, "__gcc_qle"); + set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord"); + + set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq"); + set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq"); + set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos"); + set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod"); + set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi"); + set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou"); + set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq"); + set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq"); + } } else { Index: libgcc-ppc-glibc.ver =================================================================== --- libgcc-ppc-glibc.ver (revision 120219) +++ libgcc-ppc-glibc.ver (working copy) @@ -21,11 +21,32 @@ %else GCC_3.4.4 { %endif +%else +GCC_4.2.0 { +%endif # long double support __gcc_qadd __gcc_qsub __gcc_qmul __gcc_qdiv -} + +%ifdef _SOFT_FLOAT + __gcc_qneg + __gcc_qeq + __gcc_qne + __gcc_ggt + __gcc_qge + __gcc_qlt + __gcc_qle + __gcc_qunord + __gcc_stoq + __gcc_dtoq + __gcc_qtos + __gcc_qtod + __gcc_qtoi + __gcc_qtou + __gcc_itoq + __gcc_utoq %endif +} Index: sysv4.h =================================================================== --- sysv4.h (revision 120219) +++ sysv4.h (working copy) @@ -215,10 +215,6 @@ error ("-msecure-plt not supported by your assembler"); \ } \ \ - if (TARGET_SOFT_FLOAT && TARGET_LONG_DOUBLE_128 \ - && rs6000_explicit_options.long_double) \ - warning (0, "-msoft-float and -mlong-double-128 not supported"); \ - \ /* Treat -fPIC the same as -mrelocatable. */ \ if (flag_pic > 1 && DEFAULT_ABI != ABI_AIX) \ { \