1*660662f8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Linux/PA-RISC Project (http://www.parisc-linux.org/)
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Floating-point emulation code
61da177e4SLinus Torvalds * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds * BEGIN_DESC
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * File:
121da177e4SLinus Torvalds * @(#) pa/spmath/fmpyfadd.c $Revision: 1.1 $
131da177e4SLinus Torvalds *
141da177e4SLinus Torvalds * Purpose:
151da177e4SLinus Torvalds * Double Floating-point Multiply Fused Add
161da177e4SLinus Torvalds * Double Floating-point Multiply Negate Fused Add
171da177e4SLinus Torvalds * Single Floating-point Multiply Fused Add
181da177e4SLinus Torvalds * Single Floating-point Multiply Negate Fused Add
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * External Interfaces:
211da177e4SLinus Torvalds * dbl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
221da177e4SLinus Torvalds * dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
231da177e4SLinus Torvalds * sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
241da177e4SLinus Torvalds * sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
251da177e4SLinus Torvalds *
261da177e4SLinus Torvalds * Internal Interfaces:
271da177e4SLinus Torvalds *
281da177e4SLinus Torvalds * Theory:
291da177e4SLinus Torvalds * <<please update with a overview of the operation of this file>>
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * END_DESC
321da177e4SLinus Torvalds */
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds #include "float.h"
361da177e4SLinus Torvalds #include "sgl_float.h"
371da177e4SLinus Torvalds #include "dbl_float.h"
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds /*
411da177e4SLinus Torvalds * Double Floating-point Multiply Fused Add
421da177e4SLinus Torvalds */
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds int
dbl_fmpyfadd(dbl_floating_point * src1ptr,dbl_floating_point * src2ptr,dbl_floating_point * src3ptr,unsigned int * status,dbl_floating_point * dstptr)451da177e4SLinus Torvalds dbl_fmpyfadd(
461da177e4SLinus Torvalds dbl_floating_point *src1ptr,
471da177e4SLinus Torvalds dbl_floating_point *src2ptr,
481da177e4SLinus Torvalds dbl_floating_point *src3ptr,
491da177e4SLinus Torvalds unsigned int *status,
501da177e4SLinus Torvalds dbl_floating_point *dstptr)
511da177e4SLinus Torvalds {
521da177e4SLinus Torvalds unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
531da177e4SLinus Torvalds register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
541da177e4SLinus Torvalds unsigned int rightp1, rightp2, rightp3, rightp4;
551da177e4SLinus Torvalds unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
561da177e4SLinus Torvalds register int mpy_exponent, add_exponent, count;
571da177e4SLinus Torvalds boolean inexact = FALSE, is_tiny = FALSE;
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds unsigned int signlessleft1, signlessright1, save;
601da177e4SLinus Torvalds register int result_exponent, diff_exponent;
611da177e4SLinus Torvalds int sign_save, jumpsize;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
641da177e4SLinus Torvalds Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
651da177e4SLinus Torvalds Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /*
681da177e4SLinus Torvalds * set sign bit of result of multiply
691da177e4SLinus Torvalds */
701da177e4SLinus Torvalds if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
711da177e4SLinus Torvalds Dbl_setnegativezerop1(resultp1);
721da177e4SLinus Torvalds else Dbl_setzerop1(resultp1);
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds /*
751da177e4SLinus Torvalds * Generate multiply exponent
761da177e4SLinus Torvalds */
771da177e4SLinus Torvalds mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds /*
801da177e4SLinus Torvalds * check first operand for NaN's or infinity
811da177e4SLinus Torvalds */
821da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd1p1)) {
831da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
841da177e4SLinus Torvalds if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
851da177e4SLinus Torvalds Dbl_isnotnan(opnd3p1,opnd3p2)) {
861da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds * invalid since operands are infinity
891da177e4SLinus Torvalds * and zero
901da177e4SLinus Torvalds */
911da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
921da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
931da177e4SLinus Torvalds Set_invalidflag();
941da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
951da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
961da177e4SLinus Torvalds return(NOEXCEPTION);
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds * Check third operand for infinity with a
1001da177e4SLinus Torvalds * sign opposite of the multiply result
1011da177e4SLinus Torvalds */
1021da177e4SLinus Torvalds if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
1031da177e4SLinus Torvalds (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
1041da177e4SLinus Torvalds /*
1051da177e4SLinus Torvalds * invalid since attempting a magnitude
1061da177e4SLinus Torvalds * subtraction of infinities
1071da177e4SLinus Torvalds */
1081da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
1091da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
1101da177e4SLinus Torvalds Set_invalidflag();
1111da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
1121da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
1131da177e4SLinus Torvalds return(NOEXCEPTION);
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds /*
1171da177e4SLinus Torvalds * return infinity
1181da177e4SLinus Torvalds */
1191da177e4SLinus Torvalds Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
1201da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
1211da177e4SLinus Torvalds return(NOEXCEPTION);
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds else {
1251da177e4SLinus Torvalds /*
1261da177e4SLinus Torvalds * is NaN; signaling or quiet?
1271da177e4SLinus Torvalds */
1281da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd1p1)) {
1291da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
1301da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
1311da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
1321da177e4SLinus Torvalds /* make NaN quiet */
1331da177e4SLinus Torvalds Set_invalidflag();
1341da177e4SLinus Torvalds Dbl_set_quiet(opnd1p1);
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds /*
1371da177e4SLinus Torvalds * is second operand a signaling NaN?
1381da177e4SLinus Torvalds */
1391da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd2p1)) {
1401da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
1411da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
1421da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
1431da177e4SLinus Torvalds /* make NaN quiet */
1441da177e4SLinus Torvalds Set_invalidflag();
1451da177e4SLinus Torvalds Dbl_set_quiet(opnd2p1);
1461da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
1471da177e4SLinus Torvalds return(NOEXCEPTION);
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds /*
1501da177e4SLinus Torvalds * is third operand a signaling NaN?
1511da177e4SLinus Torvalds */
1521da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd3p1)) {
1531da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
1541da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
1551da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
1561da177e4SLinus Torvalds /* make NaN quiet */
1571da177e4SLinus Torvalds Set_invalidflag();
1581da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
1591da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
1601da177e4SLinus Torvalds return(NOEXCEPTION);
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds /*
1631da177e4SLinus Torvalds * return quiet NaN
1641da177e4SLinus Torvalds */
1651da177e4SLinus Torvalds Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
1661da177e4SLinus Torvalds return(NOEXCEPTION);
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds * check second operand for NaN's or infinity
1721da177e4SLinus Torvalds */
1731da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd2p1)) {
1741da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
1751da177e4SLinus Torvalds if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
1761da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds * invalid since multiply operands are
1791da177e4SLinus Torvalds * zero & infinity
1801da177e4SLinus Torvalds */
1811da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
1821da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
1831da177e4SLinus Torvalds Set_invalidflag();
1841da177e4SLinus Torvalds Dbl_makequietnan(opnd2p1,opnd2p2);
1851da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
1861da177e4SLinus Torvalds return(NOEXCEPTION);
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds /*
1901da177e4SLinus Torvalds * Check third operand for infinity with a
1911da177e4SLinus Torvalds * sign opposite of the multiply result
1921da177e4SLinus Torvalds */
1931da177e4SLinus Torvalds if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
1941da177e4SLinus Torvalds (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
1951da177e4SLinus Torvalds /*
1961da177e4SLinus Torvalds * invalid since attempting a magnitude
1971da177e4SLinus Torvalds * subtraction of infinities
1981da177e4SLinus Torvalds */
1991da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
2001da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
2011da177e4SLinus Torvalds Set_invalidflag();
2021da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
2031da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
2041da177e4SLinus Torvalds return(NOEXCEPTION);
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds /*
2081da177e4SLinus Torvalds * return infinity
2091da177e4SLinus Torvalds */
2101da177e4SLinus Torvalds Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
2111da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
2121da177e4SLinus Torvalds return(NOEXCEPTION);
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds else {
2161da177e4SLinus Torvalds /*
2171da177e4SLinus Torvalds * is NaN; signaling or quiet?
2181da177e4SLinus Torvalds */
2191da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd2p1)) {
2201da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
2211da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
2221da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
2231da177e4SLinus Torvalds /* make NaN quiet */
2241da177e4SLinus Torvalds Set_invalidflag();
2251da177e4SLinus Torvalds Dbl_set_quiet(opnd2p1);
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds /*
2281da177e4SLinus Torvalds * is third operand a signaling NaN?
2291da177e4SLinus Torvalds */
2301da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd3p1)) {
2311da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
2321da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
2331da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
2341da177e4SLinus Torvalds /* make NaN quiet */
2351da177e4SLinus Torvalds Set_invalidflag();
2361da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
2371da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
2381da177e4SLinus Torvalds return(NOEXCEPTION);
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds /*
2411da177e4SLinus Torvalds * return quiet NaN
2421da177e4SLinus Torvalds */
2431da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
2441da177e4SLinus Torvalds return(NOEXCEPTION);
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds
2481da177e4SLinus Torvalds /*
2491da177e4SLinus Torvalds * check third operand for NaN's or infinity
2501da177e4SLinus Torvalds */
2511da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd3p1)) {
2521da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
2531da177e4SLinus Torvalds /* return infinity */
2541da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
2551da177e4SLinus Torvalds return(NOEXCEPTION);
2561da177e4SLinus Torvalds } else {
2571da177e4SLinus Torvalds /*
2581da177e4SLinus Torvalds * is NaN; signaling or quiet?
2591da177e4SLinus Torvalds */
2601da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd3p1)) {
2611da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
2621da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
2631da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
2641da177e4SLinus Torvalds /* make NaN quiet */
2651da177e4SLinus Torvalds Set_invalidflag();
2661da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds /*
2691da177e4SLinus Torvalds * return quiet NaN
2701da177e4SLinus Torvalds */
2711da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
2721da177e4SLinus Torvalds return(NOEXCEPTION);
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds /*
2771da177e4SLinus Torvalds * Generate multiply mantissa
2781da177e4SLinus Torvalds */
2791da177e4SLinus Torvalds if (Dbl_isnotzero_exponent(opnd1p1)) {
2801da177e4SLinus Torvalds /* set hidden bit */
2811da177e4SLinus Torvalds Dbl_clear_signexponent_set_hidden(opnd1p1);
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds else {
2841da177e4SLinus Torvalds /* check for zero */
2851da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
2861da177e4SLinus Torvalds /*
2871da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
2881da177e4SLinus Torvalds */
2891da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
2901da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
2911da177e4SLinus Torvalds Dbl_or_signs(opnd3p1,resultp1);
2921da177e4SLinus Torvalds } else {
2931da177e4SLinus Torvalds Dbl_and_signs(opnd3p1,resultp1);
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds /*
2971da177e4SLinus Torvalds * Now let's check for trapped underflow case.
2981da177e4SLinus Torvalds */
2991da177e4SLinus Torvalds else if (Dbl_iszero_exponent(opnd3p1) &&
3001da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
3011da177e4SLinus Torvalds /* need to normalize results mantissa */
3021da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1);
3031da177e4SLinus Torvalds result_exponent = 0;
3041da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
3051da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
3061da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,/*using*/sign_save);
3071da177e4SLinus Torvalds Dbl_setwrapped_exponent(opnd3p1,result_exponent,
3081da177e4SLinus Torvalds unfl);
3091da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
3101da177e4SLinus Torvalds /* inexact = FALSE */
3111da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
3141da177e4SLinus Torvalds return(NOEXCEPTION);
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds /* is denormalized, adjust exponent */
3171da177e4SLinus Torvalds Dbl_clear_signexponent(opnd1p1);
3181da177e4SLinus Torvalds Dbl_leftshiftby1(opnd1p1,opnd1p2);
3191da177e4SLinus Torvalds Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds /* opnd2 needs to have hidden bit set with msb in hidden bit */
3221da177e4SLinus Torvalds if (Dbl_isnotzero_exponent(opnd2p1)) {
3231da177e4SLinus Torvalds Dbl_clear_signexponent_set_hidden(opnd2p1);
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds else {
3261da177e4SLinus Torvalds /* check for zero */
3271da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
3281da177e4SLinus Torvalds /*
3291da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
3301da177e4SLinus Torvalds */
3311da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
3321da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
3331da177e4SLinus Torvalds Dbl_or_signs(opnd3p1,resultp1);
3341da177e4SLinus Torvalds } else {
3351da177e4SLinus Torvalds Dbl_and_signs(opnd3p1,resultp1);
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds }
3381da177e4SLinus Torvalds /*
3391da177e4SLinus Torvalds * Now let's check for trapped underflow case.
3401da177e4SLinus Torvalds */
3411da177e4SLinus Torvalds else if (Dbl_iszero_exponent(opnd3p1) &&
3421da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
3431da177e4SLinus Torvalds /* need to normalize results mantissa */
3441da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1);
3451da177e4SLinus Torvalds result_exponent = 0;
3461da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
3471da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
3481da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,/*using*/sign_save);
3491da177e4SLinus Torvalds Dbl_setwrapped_exponent(opnd3p1,result_exponent,
3501da177e4SLinus Torvalds unfl);
3511da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
3521da177e4SLinus Torvalds /* inexact = FALSE */
3531da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
3561da177e4SLinus Torvalds return(NOEXCEPTION);
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds /* is denormalized; want to normalize */
3591da177e4SLinus Torvalds Dbl_clear_signexponent(opnd2p1);
3601da177e4SLinus Torvalds Dbl_leftshiftby1(opnd2p1,opnd2p2);
3611da177e4SLinus Torvalds Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds /* Multiply the first two source mantissas together */
3651da177e4SLinus Torvalds
3661da177e4SLinus Torvalds /*
3671da177e4SLinus Torvalds * The intermediate result will be kept in tmpres,
3681da177e4SLinus Torvalds * which needs enough room for 106 bits of mantissa,
3691da177e4SLinus Torvalds * so lets call it a Double extended.
3701da177e4SLinus Torvalds */
3711da177e4SLinus Torvalds Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds /*
3741da177e4SLinus Torvalds * Four bits at a time are inspected in each loop, and a
3751da177e4SLinus Torvalds * simple shift and add multiply algorithm is used.
3761da177e4SLinus Torvalds */
3771da177e4SLinus Torvalds for (count = DBL_P-1; count >= 0; count -= 4) {
3781da177e4SLinus Torvalds Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
3791da177e4SLinus Torvalds if (Dbit28p2(opnd1p2)) {
3801da177e4SLinus Torvalds /* Fourword_add should be an ADD followed by 3 ADDC's */
3811da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
3821da177e4SLinus Torvalds opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds if (Dbit29p2(opnd1p2)) {
3851da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
3861da177e4SLinus Torvalds opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
3871da177e4SLinus Torvalds }
3881da177e4SLinus Torvalds if (Dbit30p2(opnd1p2)) {
3891da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
3901da177e4SLinus Torvalds opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds if (Dbit31p2(opnd1p2)) {
3931da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
3941da177e4SLinus Torvalds opnd2p1, opnd2p2, 0, 0);
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds Dbl_rightshiftby4(opnd1p1,opnd1p2);
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds if (Is_dexthiddenoverflow(tmpresp1)) {
3991da177e4SLinus Torvalds /* result mantissa >= 2 (mantissa overflow) */
4001da177e4SLinus Torvalds mpy_exponent++;
4011da177e4SLinus Torvalds Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds
4041da177e4SLinus Torvalds /*
4051da177e4SLinus Torvalds * Restore the sign of the mpy result which was saved in resultp1.
4061da177e4SLinus Torvalds * The exponent will continue to be kept in mpy_exponent.
4071da177e4SLinus Torvalds */
4081da177e4SLinus Torvalds Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
4091da177e4SLinus Torvalds
4101da177e4SLinus Torvalds /*
4111da177e4SLinus Torvalds * No rounding is required, since the result of the multiply
4121da177e4SLinus Torvalds * is exact in the extended format.
4131da177e4SLinus Torvalds */
4141da177e4SLinus Torvalds
4151da177e4SLinus Torvalds /*
4161da177e4SLinus Torvalds * Now we are ready to perform the add portion of the operation.
4171da177e4SLinus Torvalds *
4181da177e4SLinus Torvalds * The exponents need to be kept as integers for now, since the
4191da177e4SLinus Torvalds * multiply result might not fit into the exponent field. We
4201da177e4SLinus Torvalds * can't overflow or underflow because of this yet, since the
4211da177e4SLinus Torvalds * add could bring the final result back into range.
4221da177e4SLinus Torvalds */
4231da177e4SLinus Torvalds add_exponent = Dbl_exponent(opnd3p1);
4241da177e4SLinus Torvalds
4251da177e4SLinus Torvalds /*
4261da177e4SLinus Torvalds * Check for denormalized or zero add operand.
4271da177e4SLinus Torvalds */
4281da177e4SLinus Torvalds if (add_exponent == 0) {
4291da177e4SLinus Torvalds /* check for zero */
4301da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
4311da177e4SLinus Torvalds /* right is zero */
4321da177e4SLinus Torvalds /* Left can't be zero and must be result.
4331da177e4SLinus Torvalds *
4341da177e4SLinus Torvalds * The final result is now in tmpres and mpy_exponent,
4351da177e4SLinus Torvalds * and needs to be rounded and squeezed back into
4361da177e4SLinus Torvalds * double precision format from double extended.
4371da177e4SLinus Torvalds */
4381da177e4SLinus Torvalds result_exponent = mpy_exponent;
4391da177e4SLinus Torvalds Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
4401da177e4SLinus Torvalds resultp1,resultp2,resultp3,resultp4);
4411da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
4421da177e4SLinus Torvalds goto round;
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds /*
4461da177e4SLinus Torvalds * Neither are zeroes.
4471da177e4SLinus Torvalds * Adjust exponent and normalize add operand.
4481da177e4SLinus Torvalds */
4491da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1); /* save sign */
4501da177e4SLinus Torvalds Dbl_clear_signexponent(opnd3p1);
4511da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
4521da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
4531da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,sign_save); /* restore sign */
4541da177e4SLinus Torvalds } else {
4551da177e4SLinus Torvalds Dbl_clear_exponent_set_hidden(opnd3p1);
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds /*
4581da177e4SLinus Torvalds * Copy opnd3 to the double extended variable called right.
4591da177e4SLinus Torvalds */
4601da177e4SLinus Torvalds Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
4611da177e4SLinus Torvalds
4621da177e4SLinus Torvalds /*
4631da177e4SLinus Torvalds * A zero "save" helps discover equal operands (for later),
4641da177e4SLinus Torvalds * and is used in swapping operands (if needed).
4651da177e4SLinus Torvalds */
4661da177e4SLinus Torvalds Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds /*
4691da177e4SLinus Torvalds * Compare magnitude of operands.
4701da177e4SLinus Torvalds */
4711da177e4SLinus Torvalds Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
4721da177e4SLinus Torvalds Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
4731da177e4SLinus Torvalds if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
4741da177e4SLinus Torvalds Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
4751da177e4SLinus Torvalds /*
4761da177e4SLinus Torvalds * Set the left operand to the larger one by XOR swap.
4771da177e4SLinus Torvalds * First finish the first word "save".
4781da177e4SLinus Torvalds */
4791da177e4SLinus Torvalds Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
4801da177e4SLinus Torvalds Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
4811da177e4SLinus Torvalds Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
4821da177e4SLinus Torvalds rightp2,rightp3,rightp4);
4831da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
4841da177e4SLinus Torvalds diff_exponent = add_exponent - mpy_exponent;
4851da177e4SLinus Torvalds result_exponent = add_exponent;
4861da177e4SLinus Torvalds } else {
4871da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
4881da177e4SLinus Torvalds diff_exponent = mpy_exponent - add_exponent;
4891da177e4SLinus Torvalds result_exponent = mpy_exponent;
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds /* Invariant: left is not smaller than right. */
4921da177e4SLinus Torvalds
4931da177e4SLinus Torvalds /*
4941da177e4SLinus Torvalds * Special case alignment of operands that would force alignment
4951da177e4SLinus Torvalds * beyond the extent of the extension. A further optimization
4961da177e4SLinus Torvalds * could special case this but only reduces the path length for
4971da177e4SLinus Torvalds * this infrequent case.
4981da177e4SLinus Torvalds */
4991da177e4SLinus Torvalds if (diff_exponent > DBLEXT_THRESHOLD) {
5001da177e4SLinus Torvalds diff_exponent = DBLEXT_THRESHOLD;
5011da177e4SLinus Torvalds }
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds /* Align right operand by shifting it to the right */
5041da177e4SLinus Torvalds Dblext_clear_sign(rightp1);
5051da177e4SLinus Torvalds Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
5061da177e4SLinus Torvalds /*shifted by*/diff_exponent);
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds /* Treat sum and difference of the operands separately. */
5091da177e4SLinus Torvalds if ((int)save < 0) {
5101da177e4SLinus Torvalds /*
5111da177e4SLinus Torvalds * Difference of the two operands. Overflow can occur if the
5121da177e4SLinus Torvalds * multiply overflowed. A borrow can occur out of the hidden
5131da177e4SLinus Torvalds * bit and force a post normalization phase.
5141da177e4SLinus Torvalds */
5151da177e4SLinus Torvalds Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
5161da177e4SLinus Torvalds rightp1,rightp2,rightp3,rightp4,
5171da177e4SLinus Torvalds resultp1,resultp2,resultp3,resultp4);
5181da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);
5191da177e4SLinus Torvalds if (Dbl_iszero_hidden(resultp1)) {
5201da177e4SLinus Torvalds /* Handle normalization */
52125985edcSLucas De Marchi /* A straightforward algorithm would now shift the
5221da177e4SLinus Torvalds * result and extension left until the hidden bit
5231da177e4SLinus Torvalds * becomes one. Not all of the extension bits need
5241da177e4SLinus Torvalds * participate in the shift. Only the two most
5251da177e4SLinus Torvalds * significant bits (round and guard) are needed.
5261da177e4SLinus Torvalds * If only a single shift is needed then the guard
5271da177e4SLinus Torvalds * bit becomes a significant low order bit and the
5281da177e4SLinus Torvalds * extension must participate in the rounding.
5291da177e4SLinus Torvalds * If more than a single shift is needed, then all
5301da177e4SLinus Torvalds * bits to the right of the guard bit are zeros,
5311da177e4SLinus Torvalds * and the guard bit may or may not be zero. */
5321da177e4SLinus Torvalds Dblext_leftshiftby1(resultp1,resultp2,resultp3,
5331da177e4SLinus Torvalds resultp4);
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvalds /* Need to check for a zero result. The sign and
5361da177e4SLinus Torvalds * exponent fields have already been zeroed. The more
5371da177e4SLinus Torvalds * efficient test of the full object can be used.
5381da177e4SLinus Torvalds */
5391da177e4SLinus Torvalds if(Dblext_iszero(resultp1,resultp2,resultp3,resultp4)){
5401da177e4SLinus Torvalds /* Must have been "x-x" or "x+(-x)". */
5411da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS))
5421da177e4SLinus Torvalds Dbl_setone_sign(resultp1);
5431da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
5441da177e4SLinus Torvalds return(NOEXCEPTION);
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds result_exponent--;
5471da177e4SLinus Torvalds
5481da177e4SLinus Torvalds /* Look to see if normalization is finished. */
5491da177e4SLinus Torvalds if (Dbl_isone_hidden(resultp1)) {
5501da177e4SLinus Torvalds /* No further normalization is needed */
5511da177e4SLinus Torvalds goto round;
5521da177e4SLinus Torvalds }
5531da177e4SLinus Torvalds
5541da177e4SLinus Torvalds /* Discover first one bit to determine shift amount.
5551da177e4SLinus Torvalds * Use a modified binary search. We have already
5561da177e4SLinus Torvalds * shifted the result one position right and still
5571da177e4SLinus Torvalds * not found a one so the remainder of the extension
5581da177e4SLinus Torvalds * must be zero and simplifies rounding. */
5591da177e4SLinus Torvalds /* Scan bytes */
5601da177e4SLinus Torvalds while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
5611da177e4SLinus Torvalds Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
5621da177e4SLinus Torvalds result_exponent -= 8;
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds /* Now narrow it down to the nibble */
5651da177e4SLinus Torvalds if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
5661da177e4SLinus Torvalds /* The lower nibble contains the
5671da177e4SLinus Torvalds * normalizing one */
5681da177e4SLinus Torvalds Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
5691da177e4SLinus Torvalds result_exponent -= 4;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds /* Select case where first bit is set (already
5721da177e4SLinus Torvalds * normalized) otherwise select the proper shift. */
5731da177e4SLinus Torvalds jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
5741da177e4SLinus Torvalds if (jumpsize <= 7) switch(jumpsize) {
5751da177e4SLinus Torvalds case 1:
5761da177e4SLinus Torvalds Dblext_leftshiftby3(resultp1,resultp2,resultp3,
5771da177e4SLinus Torvalds resultp4);
5781da177e4SLinus Torvalds result_exponent -= 3;
5791da177e4SLinus Torvalds break;
5801da177e4SLinus Torvalds case 2:
5811da177e4SLinus Torvalds case 3:
5821da177e4SLinus Torvalds Dblext_leftshiftby2(resultp1,resultp2,resultp3,
5831da177e4SLinus Torvalds resultp4);
5841da177e4SLinus Torvalds result_exponent -= 2;
5851da177e4SLinus Torvalds break;
5861da177e4SLinus Torvalds case 4:
5871da177e4SLinus Torvalds case 5:
5881da177e4SLinus Torvalds case 6:
5891da177e4SLinus Torvalds case 7:
5901da177e4SLinus Torvalds Dblext_leftshiftby1(resultp1,resultp2,resultp3,
5911da177e4SLinus Torvalds resultp4);
5921da177e4SLinus Torvalds result_exponent -= 1;
5931da177e4SLinus Torvalds break;
5941da177e4SLinus Torvalds }
5951da177e4SLinus Torvalds } /* end if (hidden...)... */
5961da177e4SLinus Torvalds /* Fall through and round */
5971da177e4SLinus Torvalds } /* end if (save < 0)... */
5981da177e4SLinus Torvalds else {
5991da177e4SLinus Torvalds /* Add magnitudes */
6001da177e4SLinus Torvalds Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
6011da177e4SLinus Torvalds rightp1,rightp2,rightp3,rightp4,
6021da177e4SLinus Torvalds /*to*/resultp1,resultp2,resultp3,resultp4);
6031da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);
6041da177e4SLinus Torvalds if (Dbl_isone_hiddenoverflow(resultp1)) {
6051da177e4SLinus Torvalds /* Prenormalization required. */
6061da177e4SLinus Torvalds Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
6071da177e4SLinus Torvalds resultp4);
6081da177e4SLinus Torvalds result_exponent++;
6091da177e4SLinus Torvalds } /* end if hiddenoverflow... */
6101da177e4SLinus Torvalds } /* end else ...add magnitudes... */
6111da177e4SLinus Torvalds
6121da177e4SLinus Torvalds /* Round the result. If the extension and lower two words are
6131da177e4SLinus Torvalds * all zeros, then the result is exact. Otherwise round in the
6141da177e4SLinus Torvalds * correct direction. Underflow is possible. If a postnormalization
6151da177e4SLinus Torvalds * is necessary, then the mantissa is all zeros so no shift is needed.
6161da177e4SLinus Torvalds */
6171da177e4SLinus Torvalds round:
6181da177e4SLinus Torvalds if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
6191da177e4SLinus Torvalds Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
6201da177e4SLinus Torvalds result_exponent,is_tiny);
6211da177e4SLinus Torvalds }
6221da177e4SLinus Torvalds Dbl_set_sign(resultp1,/*using*/sign_save);
6231da177e4SLinus Torvalds if (Dblext_isnotzero_mantissap3(resultp3) ||
6241da177e4SLinus Torvalds Dblext_isnotzero_mantissap4(resultp4)) {
6251da177e4SLinus Torvalds inexact = TRUE;
6261da177e4SLinus Torvalds switch(Rounding_mode()) {
6271da177e4SLinus Torvalds case ROUNDNEAREST: /* The default. */
6281da177e4SLinus Torvalds if (Dblext_isone_highp3(resultp3)) {
6291da177e4SLinus Torvalds /* at least 1/2 ulp */
6301da177e4SLinus Torvalds if (Dblext_isnotzero_low31p3(resultp3) ||
6311da177e4SLinus Torvalds Dblext_isnotzero_mantissap4(resultp4) ||
6321da177e4SLinus Torvalds Dblext_isone_lowp2(resultp2)) {
6331da177e4SLinus Torvalds /* either exactly half way and odd or
6341da177e4SLinus Torvalds * more than 1/2ulp */
6351da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds }
6381da177e4SLinus Torvalds break;
6391da177e4SLinus Torvalds
6401da177e4SLinus Torvalds case ROUNDPLUS:
6411da177e4SLinus Torvalds if (Dbl_iszero_sign(resultp1)) {
6421da177e4SLinus Torvalds /* Round up positive results */
6431da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds break;
6461da177e4SLinus Torvalds
6471da177e4SLinus Torvalds case ROUNDMINUS:
6481da177e4SLinus Torvalds if (Dbl_isone_sign(resultp1)) {
6491da177e4SLinus Torvalds /* Round down negative results */
6501da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds case ROUNDZERO:;
6541da177e4SLinus Torvalds /* truncate is simple */
6551da177e4SLinus Torvalds } /* end switch... */
6561da177e4SLinus Torvalds if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds if (result_exponent >= DBL_INFINITY_EXPONENT) {
6591da177e4SLinus Torvalds /* trap if OVERFLOWTRAP enabled */
6601da177e4SLinus Torvalds if (Is_overflowtrap_enabled()) {
6611da177e4SLinus Torvalds /*
6621da177e4SLinus Torvalds * Adjust bias of result
6631da177e4SLinus Torvalds */
6641da177e4SLinus Torvalds Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
6651da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
6661da177e4SLinus Torvalds if (inexact)
6671da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
6681da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION |
6691da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
6701da177e4SLinus Torvalds else Set_inexactflag();
6711da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION);
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds inexact = TRUE;
6741da177e4SLinus Torvalds Set_overflowflag();
6751da177e4SLinus Torvalds /* set result to infinity or largest number */
6761da177e4SLinus Torvalds Dbl_setoverflow(resultp1,resultp2);
6771da177e4SLinus Torvalds
6781da177e4SLinus Torvalds } else if (result_exponent <= 0) { /* underflow case */
6791da177e4SLinus Torvalds if (Is_underflowtrap_enabled()) {
6801da177e4SLinus Torvalds /*
6811da177e4SLinus Torvalds * Adjust bias of result
6821da177e4SLinus Torvalds */
6831da177e4SLinus Torvalds Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
6841da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
6851da177e4SLinus Torvalds if (inexact)
6861da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
6871da177e4SLinus Torvalds return (OPC_2E_UNDERFLOWEXCEPTION |
6881da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
6891da177e4SLinus Torvalds else Set_inexactflag();
6901da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
6911da177e4SLinus Torvalds }
6921da177e4SLinus Torvalds else if (inexact && is_tiny) Set_underflowflag();
6931da177e4SLinus Torvalds }
6941da177e4SLinus Torvalds else Dbl_set_exponent(resultp1,result_exponent);
6951da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
6961da177e4SLinus Torvalds if (inexact)
6971da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
6981da177e4SLinus Torvalds else Set_inexactflag();
6991da177e4SLinus Torvalds return(NOEXCEPTION);
7001da177e4SLinus Torvalds }
7011da177e4SLinus Torvalds
7021da177e4SLinus Torvalds /*
7031da177e4SLinus Torvalds * Double Floating-point Multiply Negate Fused Add
7041da177e4SLinus Torvalds */
7051da177e4SLinus Torvalds
dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)7061da177e4SLinus Torvalds dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
7071da177e4SLinus Torvalds
7081da177e4SLinus Torvalds dbl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
7091da177e4SLinus Torvalds unsigned int *status;
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
7121da177e4SLinus Torvalds register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
7131da177e4SLinus Torvalds unsigned int rightp1, rightp2, rightp3, rightp4;
7141da177e4SLinus Torvalds unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
7151da177e4SLinus Torvalds register int mpy_exponent, add_exponent, count;
7161da177e4SLinus Torvalds boolean inexact = FALSE, is_tiny = FALSE;
7171da177e4SLinus Torvalds
7181da177e4SLinus Torvalds unsigned int signlessleft1, signlessright1, save;
7191da177e4SLinus Torvalds register int result_exponent, diff_exponent;
7201da177e4SLinus Torvalds int sign_save, jumpsize;
7211da177e4SLinus Torvalds
7221da177e4SLinus Torvalds Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
7231da177e4SLinus Torvalds Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
7241da177e4SLinus Torvalds Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
7251da177e4SLinus Torvalds
7261da177e4SLinus Torvalds /*
7271da177e4SLinus Torvalds * set sign bit of result of multiply
7281da177e4SLinus Torvalds */
7291da177e4SLinus Torvalds if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
7301da177e4SLinus Torvalds Dbl_setzerop1(resultp1);
7311da177e4SLinus Torvalds else
7321da177e4SLinus Torvalds Dbl_setnegativezerop1(resultp1);
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds /*
7351da177e4SLinus Torvalds * Generate multiply exponent
7361da177e4SLinus Torvalds */
7371da177e4SLinus Torvalds mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
7381da177e4SLinus Torvalds
7391da177e4SLinus Torvalds /*
7401da177e4SLinus Torvalds * check first operand for NaN's or infinity
7411da177e4SLinus Torvalds */
7421da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd1p1)) {
7431da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
7441da177e4SLinus Torvalds if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
7451da177e4SLinus Torvalds Dbl_isnotnan(opnd3p1,opnd3p2)) {
7461da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
7471da177e4SLinus Torvalds /*
7481da177e4SLinus Torvalds * invalid since operands are infinity
7491da177e4SLinus Torvalds * and zero
7501da177e4SLinus Torvalds */
7511da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
7521da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
7531da177e4SLinus Torvalds Set_invalidflag();
7541da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
7551da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
7561da177e4SLinus Torvalds return(NOEXCEPTION);
7571da177e4SLinus Torvalds }
7581da177e4SLinus Torvalds /*
7591da177e4SLinus Torvalds * Check third operand for infinity with a
7601da177e4SLinus Torvalds * sign opposite of the multiply result
7611da177e4SLinus Torvalds */
7621da177e4SLinus Torvalds if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
7631da177e4SLinus Torvalds (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
7641da177e4SLinus Torvalds /*
7651da177e4SLinus Torvalds * invalid since attempting a magnitude
7661da177e4SLinus Torvalds * subtraction of infinities
7671da177e4SLinus Torvalds */
7681da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
7691da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
7701da177e4SLinus Torvalds Set_invalidflag();
7711da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
7721da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
7731da177e4SLinus Torvalds return(NOEXCEPTION);
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds
7761da177e4SLinus Torvalds /*
7771da177e4SLinus Torvalds * return infinity
7781da177e4SLinus Torvalds */
7791da177e4SLinus Torvalds Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
7801da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
7811da177e4SLinus Torvalds return(NOEXCEPTION);
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds else {
7851da177e4SLinus Torvalds /*
7861da177e4SLinus Torvalds * is NaN; signaling or quiet?
7871da177e4SLinus Torvalds */
7881da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd1p1)) {
7891da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
7901da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
7911da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
7921da177e4SLinus Torvalds /* make NaN quiet */
7931da177e4SLinus Torvalds Set_invalidflag();
7941da177e4SLinus Torvalds Dbl_set_quiet(opnd1p1);
7951da177e4SLinus Torvalds }
7961da177e4SLinus Torvalds /*
7971da177e4SLinus Torvalds * is second operand a signaling NaN?
7981da177e4SLinus Torvalds */
7991da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd2p1)) {
8001da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
8011da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8021da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8031da177e4SLinus Torvalds /* make NaN quiet */
8041da177e4SLinus Torvalds Set_invalidflag();
8051da177e4SLinus Torvalds Dbl_set_quiet(opnd2p1);
8061da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
8071da177e4SLinus Torvalds return(NOEXCEPTION);
8081da177e4SLinus Torvalds }
8091da177e4SLinus Torvalds /*
8101da177e4SLinus Torvalds * is third operand a signaling NaN?
8111da177e4SLinus Torvalds */
8121da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd3p1)) {
8131da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
8141da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8151da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8161da177e4SLinus Torvalds /* make NaN quiet */
8171da177e4SLinus Torvalds Set_invalidflag();
8181da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
8191da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
8201da177e4SLinus Torvalds return(NOEXCEPTION);
8211da177e4SLinus Torvalds }
8221da177e4SLinus Torvalds /*
8231da177e4SLinus Torvalds * return quiet NaN
8241da177e4SLinus Torvalds */
8251da177e4SLinus Torvalds Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
8261da177e4SLinus Torvalds return(NOEXCEPTION);
8271da177e4SLinus Torvalds }
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds
8301da177e4SLinus Torvalds /*
8311da177e4SLinus Torvalds * check second operand for NaN's or infinity
8321da177e4SLinus Torvalds */
8331da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd2p1)) {
8341da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
8351da177e4SLinus Torvalds if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
8361da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
8371da177e4SLinus Torvalds /*
8381da177e4SLinus Torvalds * invalid since multiply operands are
8391da177e4SLinus Torvalds * zero & infinity
8401da177e4SLinus Torvalds */
8411da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8421da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8431da177e4SLinus Torvalds Set_invalidflag();
8441da177e4SLinus Torvalds Dbl_makequietnan(opnd2p1,opnd2p2);
8451da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
8461da177e4SLinus Torvalds return(NOEXCEPTION);
8471da177e4SLinus Torvalds }
8481da177e4SLinus Torvalds
8491da177e4SLinus Torvalds /*
8501da177e4SLinus Torvalds * Check third operand for infinity with a
8511da177e4SLinus Torvalds * sign opposite of the multiply result
8521da177e4SLinus Torvalds */
8531da177e4SLinus Torvalds if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
8541da177e4SLinus Torvalds (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
8551da177e4SLinus Torvalds /*
8561da177e4SLinus Torvalds * invalid since attempting a magnitude
8571da177e4SLinus Torvalds * subtraction of infinities
8581da177e4SLinus Torvalds */
8591da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8601da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8611da177e4SLinus Torvalds Set_invalidflag();
8621da177e4SLinus Torvalds Dbl_makequietnan(resultp1,resultp2);
8631da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
8641da177e4SLinus Torvalds return(NOEXCEPTION);
8651da177e4SLinus Torvalds }
8661da177e4SLinus Torvalds
8671da177e4SLinus Torvalds /*
8681da177e4SLinus Torvalds * return infinity
8691da177e4SLinus Torvalds */
8701da177e4SLinus Torvalds Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
8711da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
8721da177e4SLinus Torvalds return(NOEXCEPTION);
8731da177e4SLinus Torvalds }
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds else {
8761da177e4SLinus Torvalds /*
8771da177e4SLinus Torvalds * is NaN; signaling or quiet?
8781da177e4SLinus Torvalds */
8791da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd2p1)) {
8801da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
8811da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8821da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8831da177e4SLinus Torvalds /* make NaN quiet */
8841da177e4SLinus Torvalds Set_invalidflag();
8851da177e4SLinus Torvalds Dbl_set_quiet(opnd2p1);
8861da177e4SLinus Torvalds }
8871da177e4SLinus Torvalds /*
8881da177e4SLinus Torvalds * is third operand a signaling NaN?
8891da177e4SLinus Torvalds */
8901da177e4SLinus Torvalds else if (Dbl_is_signalingnan(opnd3p1)) {
8911da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
8921da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
8931da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
8941da177e4SLinus Torvalds /* make NaN quiet */
8951da177e4SLinus Torvalds Set_invalidflag();
8961da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
8971da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
8981da177e4SLinus Torvalds return(NOEXCEPTION);
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds /*
9011da177e4SLinus Torvalds * return quiet NaN
9021da177e4SLinus Torvalds */
9031da177e4SLinus Torvalds Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
9041da177e4SLinus Torvalds return(NOEXCEPTION);
9051da177e4SLinus Torvalds }
9061da177e4SLinus Torvalds }
9071da177e4SLinus Torvalds
9081da177e4SLinus Torvalds /*
9091da177e4SLinus Torvalds * check third operand for NaN's or infinity
9101da177e4SLinus Torvalds */
9111da177e4SLinus Torvalds if (Dbl_isinfinity_exponent(opnd3p1)) {
9121da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
9131da177e4SLinus Torvalds /* return infinity */
9141da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
9151da177e4SLinus Torvalds return(NOEXCEPTION);
9161da177e4SLinus Torvalds } else {
9171da177e4SLinus Torvalds /*
9181da177e4SLinus Torvalds * is NaN; signaling or quiet?
9191da177e4SLinus Torvalds */
9201da177e4SLinus Torvalds if (Dbl_isone_signaling(opnd3p1)) {
9211da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
9221da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
9231da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
9241da177e4SLinus Torvalds /* make NaN quiet */
9251da177e4SLinus Torvalds Set_invalidflag();
9261da177e4SLinus Torvalds Dbl_set_quiet(opnd3p1);
9271da177e4SLinus Torvalds }
9281da177e4SLinus Torvalds /*
9291da177e4SLinus Torvalds * return quiet NaN
9301da177e4SLinus Torvalds */
9311da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
9321da177e4SLinus Torvalds return(NOEXCEPTION);
9331da177e4SLinus Torvalds }
9341da177e4SLinus Torvalds }
9351da177e4SLinus Torvalds
9361da177e4SLinus Torvalds /*
9371da177e4SLinus Torvalds * Generate multiply mantissa
9381da177e4SLinus Torvalds */
9391da177e4SLinus Torvalds if (Dbl_isnotzero_exponent(opnd1p1)) {
9401da177e4SLinus Torvalds /* set hidden bit */
9411da177e4SLinus Torvalds Dbl_clear_signexponent_set_hidden(opnd1p1);
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds else {
9441da177e4SLinus Torvalds /* check for zero */
9451da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
9461da177e4SLinus Torvalds /*
9471da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
9481da177e4SLinus Torvalds */
9491da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
9501da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
9511da177e4SLinus Torvalds Dbl_or_signs(opnd3p1,resultp1);
9521da177e4SLinus Torvalds } else {
9531da177e4SLinus Torvalds Dbl_and_signs(opnd3p1,resultp1);
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds /*
9571da177e4SLinus Torvalds * Now let's check for trapped underflow case.
9581da177e4SLinus Torvalds */
9591da177e4SLinus Torvalds else if (Dbl_iszero_exponent(opnd3p1) &&
9601da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
9611da177e4SLinus Torvalds /* need to normalize results mantissa */
9621da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1);
9631da177e4SLinus Torvalds result_exponent = 0;
9641da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
9651da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
9661da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,/*using*/sign_save);
9671da177e4SLinus Torvalds Dbl_setwrapped_exponent(opnd3p1,result_exponent,
9681da177e4SLinus Torvalds unfl);
9691da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
9701da177e4SLinus Torvalds /* inexact = FALSE */
9711da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
9721da177e4SLinus Torvalds }
9731da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
9741da177e4SLinus Torvalds return(NOEXCEPTION);
9751da177e4SLinus Torvalds }
9761da177e4SLinus Torvalds /* is denormalized, adjust exponent */
9771da177e4SLinus Torvalds Dbl_clear_signexponent(opnd1p1);
9781da177e4SLinus Torvalds Dbl_leftshiftby1(opnd1p1,opnd1p2);
9791da177e4SLinus Torvalds Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
9801da177e4SLinus Torvalds }
9811da177e4SLinus Torvalds /* opnd2 needs to have hidden bit set with msb in hidden bit */
9821da177e4SLinus Torvalds if (Dbl_isnotzero_exponent(opnd2p1)) {
9831da177e4SLinus Torvalds Dbl_clear_signexponent_set_hidden(opnd2p1);
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds else {
9861da177e4SLinus Torvalds /* check for zero */
9871da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
9881da177e4SLinus Torvalds /*
9891da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
9901da177e4SLinus Torvalds */
9911da177e4SLinus Torvalds if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
9921da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
9931da177e4SLinus Torvalds Dbl_or_signs(opnd3p1,resultp1);
9941da177e4SLinus Torvalds } else {
9951da177e4SLinus Torvalds Dbl_and_signs(opnd3p1,resultp1);
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds /*
9991da177e4SLinus Torvalds * Now let's check for trapped underflow case.
10001da177e4SLinus Torvalds */
10011da177e4SLinus Torvalds else if (Dbl_iszero_exponent(opnd3p1) &&
10021da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
10031da177e4SLinus Torvalds /* need to normalize results mantissa */
10041da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1);
10051da177e4SLinus Torvalds result_exponent = 0;
10061da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
10071da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
10081da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,/*using*/sign_save);
10091da177e4SLinus Torvalds Dbl_setwrapped_exponent(opnd3p1,result_exponent,
10101da177e4SLinus Torvalds unfl);
10111da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
10121da177e4SLinus Torvalds /* inexact = FALSE */
10131da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
10161da177e4SLinus Torvalds return(NOEXCEPTION);
10171da177e4SLinus Torvalds }
10181da177e4SLinus Torvalds /* is denormalized; want to normalize */
10191da177e4SLinus Torvalds Dbl_clear_signexponent(opnd2p1);
10201da177e4SLinus Torvalds Dbl_leftshiftby1(opnd2p1,opnd2p2);
10211da177e4SLinus Torvalds Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds
10241da177e4SLinus Torvalds /* Multiply the first two source mantissas together */
10251da177e4SLinus Torvalds
10261da177e4SLinus Torvalds /*
10271da177e4SLinus Torvalds * The intermediate result will be kept in tmpres,
10281da177e4SLinus Torvalds * which needs enough room for 106 bits of mantissa,
10291da177e4SLinus Torvalds * so lets call it a Double extended.
10301da177e4SLinus Torvalds */
10311da177e4SLinus Torvalds Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
10321da177e4SLinus Torvalds
10331da177e4SLinus Torvalds /*
10341da177e4SLinus Torvalds * Four bits at a time are inspected in each loop, and a
10351da177e4SLinus Torvalds * simple shift and add multiply algorithm is used.
10361da177e4SLinus Torvalds */
10371da177e4SLinus Torvalds for (count = DBL_P-1; count >= 0; count -= 4) {
10381da177e4SLinus Torvalds Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
10391da177e4SLinus Torvalds if (Dbit28p2(opnd1p2)) {
10401da177e4SLinus Torvalds /* Fourword_add should be an ADD followed by 3 ADDC's */
10411da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
10421da177e4SLinus Torvalds opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
10431da177e4SLinus Torvalds }
10441da177e4SLinus Torvalds if (Dbit29p2(opnd1p2)) {
10451da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
10461da177e4SLinus Torvalds opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds if (Dbit30p2(opnd1p2)) {
10491da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
10501da177e4SLinus Torvalds opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
10511da177e4SLinus Torvalds }
10521da177e4SLinus Torvalds if (Dbit31p2(opnd1p2)) {
10531da177e4SLinus Torvalds Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
10541da177e4SLinus Torvalds opnd2p1, opnd2p2, 0, 0);
10551da177e4SLinus Torvalds }
10561da177e4SLinus Torvalds Dbl_rightshiftby4(opnd1p1,opnd1p2);
10571da177e4SLinus Torvalds }
10581da177e4SLinus Torvalds if (Is_dexthiddenoverflow(tmpresp1)) {
10591da177e4SLinus Torvalds /* result mantissa >= 2 (mantissa overflow) */
10601da177e4SLinus Torvalds mpy_exponent++;
10611da177e4SLinus Torvalds Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
10621da177e4SLinus Torvalds }
10631da177e4SLinus Torvalds
10641da177e4SLinus Torvalds /*
10651da177e4SLinus Torvalds * Restore the sign of the mpy result which was saved in resultp1.
10661da177e4SLinus Torvalds * The exponent will continue to be kept in mpy_exponent.
10671da177e4SLinus Torvalds */
10681da177e4SLinus Torvalds Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
10691da177e4SLinus Torvalds
10701da177e4SLinus Torvalds /*
10711da177e4SLinus Torvalds * No rounding is required, since the result of the multiply
10721da177e4SLinus Torvalds * is exact in the extended format.
10731da177e4SLinus Torvalds */
10741da177e4SLinus Torvalds
10751da177e4SLinus Torvalds /*
10761da177e4SLinus Torvalds * Now we are ready to perform the add portion of the operation.
10771da177e4SLinus Torvalds *
10781da177e4SLinus Torvalds * The exponents need to be kept as integers for now, since the
10791da177e4SLinus Torvalds * multiply result might not fit into the exponent field. We
10801da177e4SLinus Torvalds * can't overflow or underflow because of this yet, since the
10811da177e4SLinus Torvalds * add could bring the final result back into range.
10821da177e4SLinus Torvalds */
10831da177e4SLinus Torvalds add_exponent = Dbl_exponent(opnd3p1);
10841da177e4SLinus Torvalds
10851da177e4SLinus Torvalds /*
10861da177e4SLinus Torvalds * Check for denormalized or zero add operand.
10871da177e4SLinus Torvalds */
10881da177e4SLinus Torvalds if (add_exponent == 0) {
10891da177e4SLinus Torvalds /* check for zero */
10901da177e4SLinus Torvalds if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
10911da177e4SLinus Torvalds /* right is zero */
10921da177e4SLinus Torvalds /* Left can't be zero and must be result.
10931da177e4SLinus Torvalds *
10941da177e4SLinus Torvalds * The final result is now in tmpres and mpy_exponent,
10951da177e4SLinus Torvalds * and needs to be rounded and squeezed back into
10961da177e4SLinus Torvalds * double precision format from double extended.
10971da177e4SLinus Torvalds */
10981da177e4SLinus Torvalds result_exponent = mpy_exponent;
10991da177e4SLinus Torvalds Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
11001da177e4SLinus Torvalds resultp1,resultp2,resultp3,resultp4);
11011da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
11021da177e4SLinus Torvalds goto round;
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds
11051da177e4SLinus Torvalds /*
11061da177e4SLinus Torvalds * Neither are zeroes.
11071da177e4SLinus Torvalds * Adjust exponent and normalize add operand.
11081da177e4SLinus Torvalds */
11091da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(opnd3p1); /* save sign */
11101da177e4SLinus Torvalds Dbl_clear_signexponent(opnd3p1);
11111da177e4SLinus Torvalds Dbl_leftshiftby1(opnd3p1,opnd3p2);
11121da177e4SLinus Torvalds Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
11131da177e4SLinus Torvalds Dbl_set_sign(opnd3p1,sign_save); /* restore sign */
11141da177e4SLinus Torvalds } else {
11151da177e4SLinus Torvalds Dbl_clear_exponent_set_hidden(opnd3p1);
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds /*
11181da177e4SLinus Torvalds * Copy opnd3 to the double extended variable called right.
11191da177e4SLinus Torvalds */
11201da177e4SLinus Torvalds Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
11211da177e4SLinus Torvalds
11221da177e4SLinus Torvalds /*
11231da177e4SLinus Torvalds * A zero "save" helps discover equal operands (for later),
11241da177e4SLinus Torvalds * and is used in swapping operands (if needed).
11251da177e4SLinus Torvalds */
11261da177e4SLinus Torvalds Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
11271da177e4SLinus Torvalds
11281da177e4SLinus Torvalds /*
11291da177e4SLinus Torvalds * Compare magnitude of operands.
11301da177e4SLinus Torvalds */
11311da177e4SLinus Torvalds Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
11321da177e4SLinus Torvalds Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
11331da177e4SLinus Torvalds if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
11341da177e4SLinus Torvalds Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
11351da177e4SLinus Torvalds /*
11361da177e4SLinus Torvalds * Set the left operand to the larger one by XOR swap.
11371da177e4SLinus Torvalds * First finish the first word "save".
11381da177e4SLinus Torvalds */
11391da177e4SLinus Torvalds Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
11401da177e4SLinus Torvalds Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
11411da177e4SLinus Torvalds Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
11421da177e4SLinus Torvalds rightp2,rightp3,rightp4);
11431da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
11441da177e4SLinus Torvalds diff_exponent = add_exponent - mpy_exponent;
11451da177e4SLinus Torvalds result_exponent = add_exponent;
11461da177e4SLinus Torvalds } else {
11471da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
11481da177e4SLinus Torvalds diff_exponent = mpy_exponent - add_exponent;
11491da177e4SLinus Torvalds result_exponent = mpy_exponent;
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds /* Invariant: left is not smaller than right. */
11521da177e4SLinus Torvalds
11531da177e4SLinus Torvalds /*
11541da177e4SLinus Torvalds * Special case alignment of operands that would force alignment
11551da177e4SLinus Torvalds * beyond the extent of the extension. A further optimization
11561da177e4SLinus Torvalds * could special case this but only reduces the path length for
11571da177e4SLinus Torvalds * this infrequent case.
11581da177e4SLinus Torvalds */
11591da177e4SLinus Torvalds if (diff_exponent > DBLEXT_THRESHOLD) {
11601da177e4SLinus Torvalds diff_exponent = DBLEXT_THRESHOLD;
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds
11631da177e4SLinus Torvalds /* Align right operand by shifting it to the right */
11641da177e4SLinus Torvalds Dblext_clear_sign(rightp1);
11651da177e4SLinus Torvalds Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
11661da177e4SLinus Torvalds /*shifted by*/diff_exponent);
11671da177e4SLinus Torvalds
11681da177e4SLinus Torvalds /* Treat sum and difference of the operands separately. */
11691da177e4SLinus Torvalds if ((int)save < 0) {
11701da177e4SLinus Torvalds /*
11711da177e4SLinus Torvalds * Difference of the two operands. Overflow can occur if the
11721da177e4SLinus Torvalds * multiply overflowed. A borrow can occur out of the hidden
11731da177e4SLinus Torvalds * bit and force a post normalization phase.
11741da177e4SLinus Torvalds */
11751da177e4SLinus Torvalds Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
11761da177e4SLinus Torvalds rightp1,rightp2,rightp3,rightp4,
11771da177e4SLinus Torvalds resultp1,resultp2,resultp3,resultp4);
11781da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);
11791da177e4SLinus Torvalds if (Dbl_iszero_hidden(resultp1)) {
11801da177e4SLinus Torvalds /* Handle normalization */
118125985edcSLucas De Marchi /* A straightforward algorithm would now shift the
11821da177e4SLinus Torvalds * result and extension left until the hidden bit
11831da177e4SLinus Torvalds * becomes one. Not all of the extension bits need
11841da177e4SLinus Torvalds * participate in the shift. Only the two most
11851da177e4SLinus Torvalds * significant bits (round and guard) are needed.
11861da177e4SLinus Torvalds * If only a single shift is needed then the guard
11871da177e4SLinus Torvalds * bit becomes a significant low order bit and the
11881da177e4SLinus Torvalds * extension must participate in the rounding.
11891da177e4SLinus Torvalds * If more than a single shift is needed, then all
11901da177e4SLinus Torvalds * bits to the right of the guard bit are zeros,
11911da177e4SLinus Torvalds * and the guard bit may or may not be zero. */
11921da177e4SLinus Torvalds Dblext_leftshiftby1(resultp1,resultp2,resultp3,
11931da177e4SLinus Torvalds resultp4);
11941da177e4SLinus Torvalds
11951da177e4SLinus Torvalds /* Need to check for a zero result. The sign and
11961da177e4SLinus Torvalds * exponent fields have already been zeroed. The more
11971da177e4SLinus Torvalds * efficient test of the full object can be used.
11981da177e4SLinus Torvalds */
11991da177e4SLinus Torvalds if (Dblext_iszero(resultp1,resultp2,resultp3,resultp4)) {
12001da177e4SLinus Torvalds /* Must have been "x-x" or "x+(-x)". */
12011da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS))
12021da177e4SLinus Torvalds Dbl_setone_sign(resultp1);
12031da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
12041da177e4SLinus Torvalds return(NOEXCEPTION);
12051da177e4SLinus Torvalds }
12061da177e4SLinus Torvalds result_exponent--;
12071da177e4SLinus Torvalds
12081da177e4SLinus Torvalds /* Look to see if normalization is finished. */
12091da177e4SLinus Torvalds if (Dbl_isone_hidden(resultp1)) {
12101da177e4SLinus Torvalds /* No further normalization is needed */
12111da177e4SLinus Torvalds goto round;
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds
12141da177e4SLinus Torvalds /* Discover first one bit to determine shift amount.
12151da177e4SLinus Torvalds * Use a modified binary search. We have already
12161da177e4SLinus Torvalds * shifted the result one position right and still
12171da177e4SLinus Torvalds * not found a one so the remainder of the extension
12181da177e4SLinus Torvalds * must be zero and simplifies rounding. */
12191da177e4SLinus Torvalds /* Scan bytes */
12201da177e4SLinus Torvalds while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
12211da177e4SLinus Torvalds Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
12221da177e4SLinus Torvalds result_exponent -= 8;
12231da177e4SLinus Torvalds }
12241da177e4SLinus Torvalds /* Now narrow it down to the nibble */
12251da177e4SLinus Torvalds if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
12261da177e4SLinus Torvalds /* The lower nibble contains the
12271da177e4SLinus Torvalds * normalizing one */
12281da177e4SLinus Torvalds Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
12291da177e4SLinus Torvalds result_exponent -= 4;
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds /* Select case where first bit is set (already
12321da177e4SLinus Torvalds * normalized) otherwise select the proper shift. */
12331da177e4SLinus Torvalds jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
12341da177e4SLinus Torvalds if (jumpsize <= 7) switch(jumpsize) {
12351da177e4SLinus Torvalds case 1:
12361da177e4SLinus Torvalds Dblext_leftshiftby3(resultp1,resultp2,resultp3,
12371da177e4SLinus Torvalds resultp4);
12381da177e4SLinus Torvalds result_exponent -= 3;
12391da177e4SLinus Torvalds break;
12401da177e4SLinus Torvalds case 2:
12411da177e4SLinus Torvalds case 3:
12421da177e4SLinus Torvalds Dblext_leftshiftby2(resultp1,resultp2,resultp3,
12431da177e4SLinus Torvalds resultp4);
12441da177e4SLinus Torvalds result_exponent -= 2;
12451da177e4SLinus Torvalds break;
12461da177e4SLinus Torvalds case 4:
12471da177e4SLinus Torvalds case 5:
12481da177e4SLinus Torvalds case 6:
12491da177e4SLinus Torvalds case 7:
12501da177e4SLinus Torvalds Dblext_leftshiftby1(resultp1,resultp2,resultp3,
12511da177e4SLinus Torvalds resultp4);
12521da177e4SLinus Torvalds result_exponent -= 1;
12531da177e4SLinus Torvalds break;
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds } /* end if (hidden...)... */
12561da177e4SLinus Torvalds /* Fall through and round */
12571da177e4SLinus Torvalds } /* end if (save < 0)... */
12581da177e4SLinus Torvalds else {
12591da177e4SLinus Torvalds /* Add magnitudes */
12601da177e4SLinus Torvalds Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
12611da177e4SLinus Torvalds rightp1,rightp2,rightp3,rightp4,
12621da177e4SLinus Torvalds /*to*/resultp1,resultp2,resultp3,resultp4);
12631da177e4SLinus Torvalds sign_save = Dbl_signextendedsign(resultp1);
12641da177e4SLinus Torvalds if (Dbl_isone_hiddenoverflow(resultp1)) {
12651da177e4SLinus Torvalds /* Prenormalization required. */
12661da177e4SLinus Torvalds Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
12671da177e4SLinus Torvalds resultp4);
12681da177e4SLinus Torvalds result_exponent++;
12691da177e4SLinus Torvalds } /* end if hiddenoverflow... */
12701da177e4SLinus Torvalds } /* end else ...add magnitudes... */
12711da177e4SLinus Torvalds
12721da177e4SLinus Torvalds /* Round the result. If the extension and lower two words are
12731da177e4SLinus Torvalds * all zeros, then the result is exact. Otherwise round in the
12741da177e4SLinus Torvalds * correct direction. Underflow is possible. If a postnormalization
12751da177e4SLinus Torvalds * is necessary, then the mantissa is all zeros so no shift is needed.
12761da177e4SLinus Torvalds */
12771da177e4SLinus Torvalds round:
12781da177e4SLinus Torvalds if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
12791da177e4SLinus Torvalds Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
12801da177e4SLinus Torvalds result_exponent,is_tiny);
12811da177e4SLinus Torvalds }
12821da177e4SLinus Torvalds Dbl_set_sign(resultp1,/*using*/sign_save);
12831da177e4SLinus Torvalds if (Dblext_isnotzero_mantissap3(resultp3) ||
12841da177e4SLinus Torvalds Dblext_isnotzero_mantissap4(resultp4)) {
12851da177e4SLinus Torvalds inexact = TRUE;
12861da177e4SLinus Torvalds switch(Rounding_mode()) {
12871da177e4SLinus Torvalds case ROUNDNEAREST: /* The default. */
12881da177e4SLinus Torvalds if (Dblext_isone_highp3(resultp3)) {
12891da177e4SLinus Torvalds /* at least 1/2 ulp */
12901da177e4SLinus Torvalds if (Dblext_isnotzero_low31p3(resultp3) ||
12911da177e4SLinus Torvalds Dblext_isnotzero_mantissap4(resultp4) ||
12921da177e4SLinus Torvalds Dblext_isone_lowp2(resultp2)) {
12931da177e4SLinus Torvalds /* either exactly half way and odd or
12941da177e4SLinus Torvalds * more than 1/2ulp */
12951da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
12961da177e4SLinus Torvalds }
12971da177e4SLinus Torvalds }
12981da177e4SLinus Torvalds break;
12991da177e4SLinus Torvalds
13001da177e4SLinus Torvalds case ROUNDPLUS:
13011da177e4SLinus Torvalds if (Dbl_iszero_sign(resultp1)) {
13021da177e4SLinus Torvalds /* Round up positive results */
13031da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds break;
13061da177e4SLinus Torvalds
13071da177e4SLinus Torvalds case ROUNDMINUS:
13081da177e4SLinus Torvalds if (Dbl_isone_sign(resultp1)) {
13091da177e4SLinus Torvalds /* Round down negative results */
13101da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
13111da177e4SLinus Torvalds }
13121da177e4SLinus Torvalds
13131da177e4SLinus Torvalds case ROUNDZERO:;
13141da177e4SLinus Torvalds /* truncate is simple */
13151da177e4SLinus Torvalds } /* end switch... */
13161da177e4SLinus Torvalds if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
13171da177e4SLinus Torvalds }
13181da177e4SLinus Torvalds if (result_exponent >= DBL_INFINITY_EXPONENT) {
13191da177e4SLinus Torvalds /* Overflow */
13201da177e4SLinus Torvalds if (Is_overflowtrap_enabled()) {
13211da177e4SLinus Torvalds /*
13221da177e4SLinus Torvalds * Adjust bias of result
13231da177e4SLinus Torvalds */
13241da177e4SLinus Torvalds Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
13251da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
13261da177e4SLinus Torvalds if (inexact)
13271da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
13281da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION |
13291da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
13301da177e4SLinus Torvalds else Set_inexactflag();
13311da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION);
13321da177e4SLinus Torvalds }
13331da177e4SLinus Torvalds inexact = TRUE;
13341da177e4SLinus Torvalds Set_overflowflag();
13351da177e4SLinus Torvalds Dbl_setoverflow(resultp1,resultp2);
13361da177e4SLinus Torvalds } else if (result_exponent <= 0) { /* underflow case */
13371da177e4SLinus Torvalds if (Is_underflowtrap_enabled()) {
13381da177e4SLinus Torvalds /*
13391da177e4SLinus Torvalds * Adjust bias of result
13401da177e4SLinus Torvalds */
13411da177e4SLinus Torvalds Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
13421da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
13431da177e4SLinus Torvalds if (inexact)
13441da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
13451da177e4SLinus Torvalds return (OPC_2E_UNDERFLOWEXCEPTION |
13461da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
13471da177e4SLinus Torvalds else Set_inexactflag();
13481da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
13491da177e4SLinus Torvalds }
13501da177e4SLinus Torvalds else if (inexact && is_tiny) Set_underflowflag();
13511da177e4SLinus Torvalds }
13521da177e4SLinus Torvalds else Dbl_set_exponent(resultp1,result_exponent);
13531da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
13541da177e4SLinus Torvalds if (inexact)
13551da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
13561da177e4SLinus Torvalds else Set_inexactflag();
13571da177e4SLinus Torvalds return(NOEXCEPTION);
13581da177e4SLinus Torvalds }
13591da177e4SLinus Torvalds
13601da177e4SLinus Torvalds /*
13611da177e4SLinus Torvalds * Single Floating-point Multiply Fused Add
13621da177e4SLinus Torvalds */
13631da177e4SLinus Torvalds
sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)13641da177e4SLinus Torvalds sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
13651da177e4SLinus Torvalds
13661da177e4SLinus Torvalds sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
13671da177e4SLinus Torvalds unsigned int *status;
13681da177e4SLinus Torvalds {
13691da177e4SLinus Torvalds unsigned int opnd1, opnd2, opnd3;
13701da177e4SLinus Torvalds register unsigned int tmpresp1, tmpresp2;
13711da177e4SLinus Torvalds unsigned int rightp1, rightp2;
13721da177e4SLinus Torvalds unsigned int resultp1, resultp2 = 0;
13731da177e4SLinus Torvalds register int mpy_exponent, add_exponent, count;
13741da177e4SLinus Torvalds boolean inexact = FALSE, is_tiny = FALSE;
13751da177e4SLinus Torvalds
13761da177e4SLinus Torvalds unsigned int signlessleft1, signlessright1, save;
13771da177e4SLinus Torvalds register int result_exponent, diff_exponent;
13781da177e4SLinus Torvalds int sign_save, jumpsize;
13791da177e4SLinus Torvalds
13801da177e4SLinus Torvalds Sgl_copyfromptr(src1ptr,opnd1);
13811da177e4SLinus Torvalds Sgl_copyfromptr(src2ptr,opnd2);
13821da177e4SLinus Torvalds Sgl_copyfromptr(src3ptr,opnd3);
13831da177e4SLinus Torvalds
13841da177e4SLinus Torvalds /*
13851da177e4SLinus Torvalds * set sign bit of result of multiply
13861da177e4SLinus Torvalds */
13871da177e4SLinus Torvalds if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2))
13881da177e4SLinus Torvalds Sgl_setnegativezero(resultp1);
13891da177e4SLinus Torvalds else Sgl_setzero(resultp1);
13901da177e4SLinus Torvalds
13911da177e4SLinus Torvalds /*
13921da177e4SLinus Torvalds * Generate multiply exponent
13931da177e4SLinus Torvalds */
13941da177e4SLinus Torvalds mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
13951da177e4SLinus Torvalds
13961da177e4SLinus Torvalds /*
13971da177e4SLinus Torvalds * check first operand for NaN's or infinity
13981da177e4SLinus Torvalds */
13991da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd1)) {
14001da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd1)) {
14011da177e4SLinus Torvalds if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
14021da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd2)) {
14031da177e4SLinus Torvalds /*
14041da177e4SLinus Torvalds * invalid since operands are infinity
14051da177e4SLinus Torvalds * and zero
14061da177e4SLinus Torvalds */
14071da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14081da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14091da177e4SLinus Torvalds Set_invalidflag();
14101da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
14111da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
14121da177e4SLinus Torvalds return(NOEXCEPTION);
14131da177e4SLinus Torvalds }
14141da177e4SLinus Torvalds /*
14151da177e4SLinus Torvalds * Check third operand for infinity with a
14161da177e4SLinus Torvalds * sign opposite of the multiply result
14171da177e4SLinus Torvalds */
14181da177e4SLinus Torvalds if (Sgl_isinfinity(opnd3) &&
14191da177e4SLinus Torvalds (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
14201da177e4SLinus Torvalds /*
14211da177e4SLinus Torvalds * invalid since attempting a magnitude
14221da177e4SLinus Torvalds * subtraction of infinities
14231da177e4SLinus Torvalds */
14241da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14251da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14261da177e4SLinus Torvalds Set_invalidflag();
14271da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
14281da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
14291da177e4SLinus Torvalds return(NOEXCEPTION);
14301da177e4SLinus Torvalds }
14311da177e4SLinus Torvalds
14321da177e4SLinus Torvalds /*
14331da177e4SLinus Torvalds * return infinity
14341da177e4SLinus Torvalds */
14351da177e4SLinus Torvalds Sgl_setinfinity_exponentmantissa(resultp1);
14361da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
14371da177e4SLinus Torvalds return(NOEXCEPTION);
14381da177e4SLinus Torvalds }
14391da177e4SLinus Torvalds }
14401da177e4SLinus Torvalds else {
14411da177e4SLinus Torvalds /*
14421da177e4SLinus Torvalds * is NaN; signaling or quiet?
14431da177e4SLinus Torvalds */
14441da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd1)) {
14451da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
14461da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14471da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14481da177e4SLinus Torvalds /* make NaN quiet */
14491da177e4SLinus Torvalds Set_invalidflag();
14501da177e4SLinus Torvalds Sgl_set_quiet(opnd1);
14511da177e4SLinus Torvalds }
14521da177e4SLinus Torvalds /*
14531da177e4SLinus Torvalds * is second operand a signaling NaN?
14541da177e4SLinus Torvalds */
14551da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd2)) {
14561da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
14571da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14581da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14591da177e4SLinus Torvalds /* make NaN quiet */
14601da177e4SLinus Torvalds Set_invalidflag();
14611da177e4SLinus Torvalds Sgl_set_quiet(opnd2);
14621da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
14631da177e4SLinus Torvalds return(NOEXCEPTION);
14641da177e4SLinus Torvalds }
14651da177e4SLinus Torvalds /*
14661da177e4SLinus Torvalds * is third operand a signaling NaN?
14671da177e4SLinus Torvalds */
14681da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd3)) {
14691da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
14701da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14711da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14721da177e4SLinus Torvalds /* make NaN quiet */
14731da177e4SLinus Torvalds Set_invalidflag();
14741da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
14751da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
14761da177e4SLinus Torvalds return(NOEXCEPTION);
14771da177e4SLinus Torvalds }
14781da177e4SLinus Torvalds /*
14791da177e4SLinus Torvalds * return quiet NaN
14801da177e4SLinus Torvalds */
14811da177e4SLinus Torvalds Sgl_copytoptr(opnd1,dstptr);
14821da177e4SLinus Torvalds return(NOEXCEPTION);
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds
14861da177e4SLinus Torvalds /*
14871da177e4SLinus Torvalds * check second operand for NaN's or infinity
14881da177e4SLinus Torvalds */
14891da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd2)) {
14901da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd2)) {
14911da177e4SLinus Torvalds if (Sgl_isnotnan(opnd3)) {
14921da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd1)) {
14931da177e4SLinus Torvalds /*
14941da177e4SLinus Torvalds * invalid since multiply operands are
14951da177e4SLinus Torvalds * zero & infinity
14961da177e4SLinus Torvalds */
14971da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
14981da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
14991da177e4SLinus Torvalds Set_invalidflag();
15001da177e4SLinus Torvalds Sgl_makequietnan(opnd2);
15011da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
15021da177e4SLinus Torvalds return(NOEXCEPTION);
15031da177e4SLinus Torvalds }
15041da177e4SLinus Torvalds
15051da177e4SLinus Torvalds /*
15061da177e4SLinus Torvalds * Check third operand for infinity with a
15071da177e4SLinus Torvalds * sign opposite of the multiply result
15081da177e4SLinus Torvalds */
15091da177e4SLinus Torvalds if (Sgl_isinfinity(opnd3) &&
15101da177e4SLinus Torvalds (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
15111da177e4SLinus Torvalds /*
15121da177e4SLinus Torvalds * invalid since attempting a magnitude
15131da177e4SLinus Torvalds * subtraction of infinities
15141da177e4SLinus Torvalds */
15151da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
15161da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
15171da177e4SLinus Torvalds Set_invalidflag();
15181da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
15191da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
15201da177e4SLinus Torvalds return(NOEXCEPTION);
15211da177e4SLinus Torvalds }
15221da177e4SLinus Torvalds
15231da177e4SLinus Torvalds /*
15241da177e4SLinus Torvalds * return infinity
15251da177e4SLinus Torvalds */
15261da177e4SLinus Torvalds Sgl_setinfinity_exponentmantissa(resultp1);
15271da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
15281da177e4SLinus Torvalds return(NOEXCEPTION);
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds }
15311da177e4SLinus Torvalds else {
15321da177e4SLinus Torvalds /*
15331da177e4SLinus Torvalds * is NaN; signaling or quiet?
15341da177e4SLinus Torvalds */
15351da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd2)) {
15361da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
15371da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
15381da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
15391da177e4SLinus Torvalds /* make NaN quiet */
15401da177e4SLinus Torvalds Set_invalidflag();
15411da177e4SLinus Torvalds Sgl_set_quiet(opnd2);
15421da177e4SLinus Torvalds }
15431da177e4SLinus Torvalds /*
15441da177e4SLinus Torvalds * is third operand a signaling NaN?
15451da177e4SLinus Torvalds */
15461da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd3)) {
15471da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
15481da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
15491da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
15501da177e4SLinus Torvalds /* make NaN quiet */
15511da177e4SLinus Torvalds Set_invalidflag();
15521da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
15531da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
15541da177e4SLinus Torvalds return(NOEXCEPTION);
15551da177e4SLinus Torvalds }
15561da177e4SLinus Torvalds /*
15571da177e4SLinus Torvalds * return quiet NaN
15581da177e4SLinus Torvalds */
15591da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
15601da177e4SLinus Torvalds return(NOEXCEPTION);
15611da177e4SLinus Torvalds }
15621da177e4SLinus Torvalds }
15631da177e4SLinus Torvalds
15641da177e4SLinus Torvalds /*
15651da177e4SLinus Torvalds * check third operand for NaN's or infinity
15661da177e4SLinus Torvalds */
15671da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd3)) {
15681da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd3)) {
15691da177e4SLinus Torvalds /* return infinity */
15701da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
15711da177e4SLinus Torvalds return(NOEXCEPTION);
15721da177e4SLinus Torvalds } else {
15731da177e4SLinus Torvalds /*
15741da177e4SLinus Torvalds * is NaN; signaling or quiet?
15751da177e4SLinus Torvalds */
15761da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd3)) {
15771da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
15781da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
15791da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
15801da177e4SLinus Torvalds /* make NaN quiet */
15811da177e4SLinus Torvalds Set_invalidflag();
15821da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
15831da177e4SLinus Torvalds }
15841da177e4SLinus Torvalds /*
15851da177e4SLinus Torvalds * return quiet NaN
15861da177e4SLinus Torvalds */
15871da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
15881da177e4SLinus Torvalds return(NOEXCEPTION);
15891da177e4SLinus Torvalds }
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds
15921da177e4SLinus Torvalds /*
15931da177e4SLinus Torvalds * Generate multiply mantissa
15941da177e4SLinus Torvalds */
15951da177e4SLinus Torvalds if (Sgl_isnotzero_exponent(opnd1)) {
15961da177e4SLinus Torvalds /* set hidden bit */
15971da177e4SLinus Torvalds Sgl_clear_signexponent_set_hidden(opnd1);
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds else {
16001da177e4SLinus Torvalds /* check for zero */
16011da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd1)) {
16021da177e4SLinus Torvalds /*
16031da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
16041da177e4SLinus Torvalds */
16051da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd3)) {
16061da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
16071da177e4SLinus Torvalds Sgl_or_signs(opnd3,resultp1);
16081da177e4SLinus Torvalds } else {
16091da177e4SLinus Torvalds Sgl_and_signs(opnd3,resultp1);
16101da177e4SLinus Torvalds }
16111da177e4SLinus Torvalds }
16121da177e4SLinus Torvalds /*
16131da177e4SLinus Torvalds * Now let's check for trapped underflow case.
16141da177e4SLinus Torvalds */
16151da177e4SLinus Torvalds else if (Sgl_iszero_exponent(opnd3) &&
16161da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
16171da177e4SLinus Torvalds /* need to normalize results mantissa */
16181da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3);
16191da177e4SLinus Torvalds result_exponent = 0;
16201da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
16211da177e4SLinus Torvalds Sgl_normalize(opnd3,result_exponent);
16221da177e4SLinus Torvalds Sgl_set_sign(opnd3,/*using*/sign_save);
16231da177e4SLinus Torvalds Sgl_setwrapped_exponent(opnd3,result_exponent,
16241da177e4SLinus Torvalds unfl);
16251da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
16261da177e4SLinus Torvalds /* inexact = FALSE */
16271da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
16281da177e4SLinus Torvalds }
16291da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
16301da177e4SLinus Torvalds return(NOEXCEPTION);
16311da177e4SLinus Torvalds }
16321da177e4SLinus Torvalds /* is denormalized, adjust exponent */
16331da177e4SLinus Torvalds Sgl_clear_signexponent(opnd1);
16341da177e4SLinus Torvalds Sgl_leftshiftby1(opnd1);
16351da177e4SLinus Torvalds Sgl_normalize(opnd1,mpy_exponent);
16361da177e4SLinus Torvalds }
16371da177e4SLinus Torvalds /* opnd2 needs to have hidden bit set with msb in hidden bit */
16381da177e4SLinus Torvalds if (Sgl_isnotzero_exponent(opnd2)) {
16391da177e4SLinus Torvalds Sgl_clear_signexponent_set_hidden(opnd2);
16401da177e4SLinus Torvalds }
16411da177e4SLinus Torvalds else {
16421da177e4SLinus Torvalds /* check for zero */
16431da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd2)) {
16441da177e4SLinus Torvalds /*
16451da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
16461da177e4SLinus Torvalds */
16471da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd3)) {
16481da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
16491da177e4SLinus Torvalds Sgl_or_signs(opnd3,resultp1);
16501da177e4SLinus Torvalds } else {
16511da177e4SLinus Torvalds Sgl_and_signs(opnd3,resultp1);
16521da177e4SLinus Torvalds }
16531da177e4SLinus Torvalds }
16541da177e4SLinus Torvalds /*
16551da177e4SLinus Torvalds * Now let's check for trapped underflow case.
16561da177e4SLinus Torvalds */
16571da177e4SLinus Torvalds else if (Sgl_iszero_exponent(opnd3) &&
16581da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
16591da177e4SLinus Torvalds /* need to normalize results mantissa */
16601da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3);
16611da177e4SLinus Torvalds result_exponent = 0;
16621da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
16631da177e4SLinus Torvalds Sgl_normalize(opnd3,result_exponent);
16641da177e4SLinus Torvalds Sgl_set_sign(opnd3,/*using*/sign_save);
16651da177e4SLinus Torvalds Sgl_setwrapped_exponent(opnd3,result_exponent,
16661da177e4SLinus Torvalds unfl);
16671da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
16681da177e4SLinus Torvalds /* inexact = FALSE */
16691da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
16721da177e4SLinus Torvalds return(NOEXCEPTION);
16731da177e4SLinus Torvalds }
16741da177e4SLinus Torvalds /* is denormalized; want to normalize */
16751da177e4SLinus Torvalds Sgl_clear_signexponent(opnd2);
16761da177e4SLinus Torvalds Sgl_leftshiftby1(opnd2);
16771da177e4SLinus Torvalds Sgl_normalize(opnd2,mpy_exponent);
16781da177e4SLinus Torvalds }
16791da177e4SLinus Torvalds
16801da177e4SLinus Torvalds /* Multiply the first two source mantissas together */
16811da177e4SLinus Torvalds
16821da177e4SLinus Torvalds /*
16831da177e4SLinus Torvalds * The intermediate result will be kept in tmpres,
16841da177e4SLinus Torvalds * which needs enough room for 106 bits of mantissa,
16851da177e4SLinus Torvalds * so lets call it a Double extended.
16861da177e4SLinus Torvalds */
16871da177e4SLinus Torvalds Sglext_setzero(tmpresp1,tmpresp2);
16881da177e4SLinus Torvalds
16891da177e4SLinus Torvalds /*
16901da177e4SLinus Torvalds * Four bits at a time are inspected in each loop, and a
16911da177e4SLinus Torvalds * simple shift and add multiply algorithm is used.
16921da177e4SLinus Torvalds */
16931da177e4SLinus Torvalds for (count = SGL_P-1; count >= 0; count -= 4) {
16941da177e4SLinus Torvalds Sglext_rightshiftby4(tmpresp1,tmpresp2);
16951da177e4SLinus Torvalds if (Sbit28(opnd1)) {
16961da177e4SLinus Torvalds /* Twoword_add should be an ADD followed by 2 ADDC's */
16971da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
16981da177e4SLinus Torvalds }
16991da177e4SLinus Torvalds if (Sbit29(opnd1)) {
17001da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
17011da177e4SLinus Torvalds }
17021da177e4SLinus Torvalds if (Sbit30(opnd1)) {
17031da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
17041da177e4SLinus Torvalds }
17051da177e4SLinus Torvalds if (Sbit31(opnd1)) {
17061da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
17071da177e4SLinus Torvalds }
17081da177e4SLinus Torvalds Sgl_rightshiftby4(opnd1);
17091da177e4SLinus Torvalds }
17101da177e4SLinus Torvalds if (Is_sexthiddenoverflow(tmpresp1)) {
17111da177e4SLinus Torvalds /* result mantissa >= 2 (mantissa overflow) */
17121da177e4SLinus Torvalds mpy_exponent++;
17131da177e4SLinus Torvalds Sglext_rightshiftby4(tmpresp1,tmpresp2);
17141da177e4SLinus Torvalds } else {
17151da177e4SLinus Torvalds Sglext_rightshiftby3(tmpresp1,tmpresp2);
17161da177e4SLinus Torvalds }
17171da177e4SLinus Torvalds
17181da177e4SLinus Torvalds /*
17191da177e4SLinus Torvalds * Restore the sign of the mpy result which was saved in resultp1.
17201da177e4SLinus Torvalds * The exponent will continue to be kept in mpy_exponent.
17211da177e4SLinus Torvalds */
17221da177e4SLinus Torvalds Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
17231da177e4SLinus Torvalds
17241da177e4SLinus Torvalds /*
17251da177e4SLinus Torvalds * No rounding is required, since the result of the multiply
17261da177e4SLinus Torvalds * is exact in the extended format.
17271da177e4SLinus Torvalds */
17281da177e4SLinus Torvalds
17291da177e4SLinus Torvalds /*
17301da177e4SLinus Torvalds * Now we are ready to perform the add portion of the operation.
17311da177e4SLinus Torvalds *
17321da177e4SLinus Torvalds * The exponents need to be kept as integers for now, since the
17331da177e4SLinus Torvalds * multiply result might not fit into the exponent field. We
17341da177e4SLinus Torvalds * can't overflow or underflow because of this yet, since the
17351da177e4SLinus Torvalds * add could bring the final result back into range.
17361da177e4SLinus Torvalds */
17371da177e4SLinus Torvalds add_exponent = Sgl_exponent(opnd3);
17381da177e4SLinus Torvalds
17391da177e4SLinus Torvalds /*
17401da177e4SLinus Torvalds * Check for denormalized or zero add operand.
17411da177e4SLinus Torvalds */
17421da177e4SLinus Torvalds if (add_exponent == 0) {
17431da177e4SLinus Torvalds /* check for zero */
17441da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd3)) {
17451da177e4SLinus Torvalds /* right is zero */
17461da177e4SLinus Torvalds /* Left can't be zero and must be result.
17471da177e4SLinus Torvalds *
17481da177e4SLinus Torvalds * The final result is now in tmpres and mpy_exponent,
17491da177e4SLinus Torvalds * and needs to be rounded and squeezed back into
17501da177e4SLinus Torvalds * double precision format from double extended.
17511da177e4SLinus Torvalds */
17521da177e4SLinus Torvalds result_exponent = mpy_exponent;
17531da177e4SLinus Torvalds Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
17541da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
17551da177e4SLinus Torvalds goto round;
17561da177e4SLinus Torvalds }
17571da177e4SLinus Torvalds
17581da177e4SLinus Torvalds /*
17591da177e4SLinus Torvalds * Neither are zeroes.
17601da177e4SLinus Torvalds * Adjust exponent and normalize add operand.
17611da177e4SLinus Torvalds */
17621da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3); /* save sign */
17631da177e4SLinus Torvalds Sgl_clear_signexponent(opnd3);
17641da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
17651da177e4SLinus Torvalds Sgl_normalize(opnd3,add_exponent);
17661da177e4SLinus Torvalds Sgl_set_sign(opnd3,sign_save); /* restore sign */
17671da177e4SLinus Torvalds } else {
17681da177e4SLinus Torvalds Sgl_clear_exponent_set_hidden(opnd3);
17691da177e4SLinus Torvalds }
17701da177e4SLinus Torvalds /*
17711da177e4SLinus Torvalds * Copy opnd3 to the double extended variable called right.
17721da177e4SLinus Torvalds */
17731da177e4SLinus Torvalds Sgl_copyto_sglext(opnd3,rightp1,rightp2);
17741da177e4SLinus Torvalds
17751da177e4SLinus Torvalds /*
17761da177e4SLinus Torvalds * A zero "save" helps discover equal operands (for later),
17771da177e4SLinus Torvalds * and is used in swapping operands (if needed).
17781da177e4SLinus Torvalds */
17791da177e4SLinus Torvalds Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
17801da177e4SLinus Torvalds
17811da177e4SLinus Torvalds /*
17821da177e4SLinus Torvalds * Compare magnitude of operands.
17831da177e4SLinus Torvalds */
17841da177e4SLinus Torvalds Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
17851da177e4SLinus Torvalds Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
17861da177e4SLinus Torvalds if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
17871da177e4SLinus Torvalds Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
17881da177e4SLinus Torvalds /*
17891da177e4SLinus Torvalds * Set the left operand to the larger one by XOR swap.
17901da177e4SLinus Torvalds * First finish the first word "save".
17911da177e4SLinus Torvalds */
17921da177e4SLinus Torvalds Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
17931da177e4SLinus Torvalds Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
17941da177e4SLinus Torvalds Sglext_swap_lower(tmpresp2,rightp2);
17951da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
17961da177e4SLinus Torvalds diff_exponent = add_exponent - mpy_exponent;
17971da177e4SLinus Torvalds result_exponent = add_exponent;
17981da177e4SLinus Torvalds } else {
17991da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
18001da177e4SLinus Torvalds diff_exponent = mpy_exponent - add_exponent;
18011da177e4SLinus Torvalds result_exponent = mpy_exponent;
18021da177e4SLinus Torvalds }
18031da177e4SLinus Torvalds /* Invariant: left is not smaller than right. */
18041da177e4SLinus Torvalds
18051da177e4SLinus Torvalds /*
18061da177e4SLinus Torvalds * Special case alignment of operands that would force alignment
18071da177e4SLinus Torvalds * beyond the extent of the extension. A further optimization
18081da177e4SLinus Torvalds * could special case this but only reduces the path length for
18091da177e4SLinus Torvalds * this infrequent case.
18101da177e4SLinus Torvalds */
18111da177e4SLinus Torvalds if (diff_exponent > SGLEXT_THRESHOLD) {
18121da177e4SLinus Torvalds diff_exponent = SGLEXT_THRESHOLD;
18131da177e4SLinus Torvalds }
18141da177e4SLinus Torvalds
18151da177e4SLinus Torvalds /* Align right operand by shifting it to the right */
18161da177e4SLinus Torvalds Sglext_clear_sign(rightp1);
18171da177e4SLinus Torvalds Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
18181da177e4SLinus Torvalds
18191da177e4SLinus Torvalds /* Treat sum and difference of the operands separately. */
18201da177e4SLinus Torvalds if ((int)save < 0) {
18211da177e4SLinus Torvalds /*
18221da177e4SLinus Torvalds * Difference of the two operands. Overflow can occur if the
18231da177e4SLinus Torvalds * multiply overflowed. A borrow can occur out of the hidden
18241da177e4SLinus Torvalds * bit and force a post normalization phase.
18251da177e4SLinus Torvalds */
18261da177e4SLinus Torvalds Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
18271da177e4SLinus Torvalds resultp1,resultp2);
18281da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);
18291da177e4SLinus Torvalds if (Sgl_iszero_hidden(resultp1)) {
18301da177e4SLinus Torvalds /* Handle normalization */
183125985edcSLucas De Marchi /* A straightforward algorithm would now shift the
18321da177e4SLinus Torvalds * result and extension left until the hidden bit
18331da177e4SLinus Torvalds * becomes one. Not all of the extension bits need
18341da177e4SLinus Torvalds * participate in the shift. Only the two most
18351da177e4SLinus Torvalds * significant bits (round and guard) are needed.
18361da177e4SLinus Torvalds * If only a single shift is needed then the guard
18371da177e4SLinus Torvalds * bit becomes a significant low order bit and the
18381da177e4SLinus Torvalds * extension must participate in the rounding.
18391da177e4SLinus Torvalds * If more than a single shift is needed, then all
18401da177e4SLinus Torvalds * bits to the right of the guard bit are zeros,
18411da177e4SLinus Torvalds * and the guard bit may or may not be zero. */
18421da177e4SLinus Torvalds Sglext_leftshiftby1(resultp1,resultp2);
18431da177e4SLinus Torvalds
18441da177e4SLinus Torvalds /* Need to check for a zero result. The sign and
18451da177e4SLinus Torvalds * exponent fields have already been zeroed. The more
18461da177e4SLinus Torvalds * efficient test of the full object can be used.
18471da177e4SLinus Torvalds */
18481da177e4SLinus Torvalds if (Sglext_iszero(resultp1,resultp2)) {
18491da177e4SLinus Torvalds /* Must have been "x-x" or "x+(-x)". */
18501da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS))
18511da177e4SLinus Torvalds Sgl_setone_sign(resultp1);
18521da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
18531da177e4SLinus Torvalds return(NOEXCEPTION);
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds result_exponent--;
18561da177e4SLinus Torvalds
18571da177e4SLinus Torvalds /* Look to see if normalization is finished. */
18581da177e4SLinus Torvalds if (Sgl_isone_hidden(resultp1)) {
18591da177e4SLinus Torvalds /* No further normalization is needed */
18601da177e4SLinus Torvalds goto round;
18611da177e4SLinus Torvalds }
18621da177e4SLinus Torvalds
18631da177e4SLinus Torvalds /* Discover first one bit to determine shift amount.
18641da177e4SLinus Torvalds * Use a modified binary search. We have already
18651da177e4SLinus Torvalds * shifted the result one position right and still
18661da177e4SLinus Torvalds * not found a one so the remainder of the extension
18671da177e4SLinus Torvalds * must be zero and simplifies rounding. */
18681da177e4SLinus Torvalds /* Scan bytes */
18691da177e4SLinus Torvalds while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
18701da177e4SLinus Torvalds Sglext_leftshiftby8(resultp1,resultp2);
18711da177e4SLinus Torvalds result_exponent -= 8;
18721da177e4SLinus Torvalds }
18731da177e4SLinus Torvalds /* Now narrow it down to the nibble */
18741da177e4SLinus Torvalds if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
18751da177e4SLinus Torvalds /* The lower nibble contains the
18761da177e4SLinus Torvalds * normalizing one */
18771da177e4SLinus Torvalds Sglext_leftshiftby4(resultp1,resultp2);
18781da177e4SLinus Torvalds result_exponent -= 4;
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds /* Select case where first bit is set (already
18811da177e4SLinus Torvalds * normalized) otherwise select the proper shift. */
18821da177e4SLinus Torvalds jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
18831da177e4SLinus Torvalds if (jumpsize <= 7) switch(jumpsize) {
18841da177e4SLinus Torvalds case 1:
18851da177e4SLinus Torvalds Sglext_leftshiftby3(resultp1,resultp2);
18861da177e4SLinus Torvalds result_exponent -= 3;
18871da177e4SLinus Torvalds break;
18881da177e4SLinus Torvalds case 2:
18891da177e4SLinus Torvalds case 3:
18901da177e4SLinus Torvalds Sglext_leftshiftby2(resultp1,resultp2);
18911da177e4SLinus Torvalds result_exponent -= 2;
18921da177e4SLinus Torvalds break;
18931da177e4SLinus Torvalds case 4:
18941da177e4SLinus Torvalds case 5:
18951da177e4SLinus Torvalds case 6:
18961da177e4SLinus Torvalds case 7:
18971da177e4SLinus Torvalds Sglext_leftshiftby1(resultp1,resultp2);
18981da177e4SLinus Torvalds result_exponent -= 1;
18991da177e4SLinus Torvalds break;
19001da177e4SLinus Torvalds }
19011da177e4SLinus Torvalds } /* end if (hidden...)... */
19021da177e4SLinus Torvalds /* Fall through and round */
19031da177e4SLinus Torvalds } /* end if (save < 0)... */
19041da177e4SLinus Torvalds else {
19051da177e4SLinus Torvalds /* Add magnitudes */
19061da177e4SLinus Torvalds Sglext_addition(tmpresp1,tmpresp2,
19071da177e4SLinus Torvalds rightp1,rightp2, /*to*/resultp1,resultp2);
19081da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);
19091da177e4SLinus Torvalds if (Sgl_isone_hiddenoverflow(resultp1)) {
19101da177e4SLinus Torvalds /* Prenormalization required. */
19111da177e4SLinus Torvalds Sglext_arithrightshiftby1(resultp1,resultp2);
19121da177e4SLinus Torvalds result_exponent++;
19131da177e4SLinus Torvalds } /* end if hiddenoverflow... */
19141da177e4SLinus Torvalds } /* end else ...add magnitudes... */
19151da177e4SLinus Torvalds
19161da177e4SLinus Torvalds /* Round the result. If the extension and lower two words are
19171da177e4SLinus Torvalds * all zeros, then the result is exact. Otherwise round in the
19181da177e4SLinus Torvalds * correct direction. Underflow is possible. If a postnormalization
19191da177e4SLinus Torvalds * is necessary, then the mantissa is all zeros so no shift is needed.
19201da177e4SLinus Torvalds */
19211da177e4SLinus Torvalds round:
19221da177e4SLinus Torvalds if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
19231da177e4SLinus Torvalds Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
19241da177e4SLinus Torvalds }
19251da177e4SLinus Torvalds Sgl_set_sign(resultp1,/*using*/sign_save);
19261da177e4SLinus Torvalds if (Sglext_isnotzero_mantissap2(resultp2)) {
19271da177e4SLinus Torvalds inexact = TRUE;
19281da177e4SLinus Torvalds switch(Rounding_mode()) {
19291da177e4SLinus Torvalds case ROUNDNEAREST: /* The default. */
19301da177e4SLinus Torvalds if (Sglext_isone_highp2(resultp2)) {
19311da177e4SLinus Torvalds /* at least 1/2 ulp */
19321da177e4SLinus Torvalds if (Sglext_isnotzero_low31p2(resultp2) ||
19331da177e4SLinus Torvalds Sglext_isone_lowp1(resultp1)) {
19341da177e4SLinus Torvalds /* either exactly half way and odd or
19351da177e4SLinus Torvalds * more than 1/2ulp */
19361da177e4SLinus Torvalds Sgl_increment(resultp1);
19371da177e4SLinus Torvalds }
19381da177e4SLinus Torvalds }
19391da177e4SLinus Torvalds break;
19401da177e4SLinus Torvalds
19411da177e4SLinus Torvalds case ROUNDPLUS:
19421da177e4SLinus Torvalds if (Sgl_iszero_sign(resultp1)) {
19431da177e4SLinus Torvalds /* Round up positive results */
19441da177e4SLinus Torvalds Sgl_increment(resultp1);
19451da177e4SLinus Torvalds }
19461da177e4SLinus Torvalds break;
19471da177e4SLinus Torvalds
19481da177e4SLinus Torvalds case ROUNDMINUS:
19491da177e4SLinus Torvalds if (Sgl_isone_sign(resultp1)) {
19501da177e4SLinus Torvalds /* Round down negative results */
19511da177e4SLinus Torvalds Sgl_increment(resultp1);
19521da177e4SLinus Torvalds }
19531da177e4SLinus Torvalds
19541da177e4SLinus Torvalds case ROUNDZERO:;
19551da177e4SLinus Torvalds /* truncate is simple */
19561da177e4SLinus Torvalds } /* end switch... */
19571da177e4SLinus Torvalds if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds if (result_exponent >= SGL_INFINITY_EXPONENT) {
19601da177e4SLinus Torvalds /* Overflow */
19611da177e4SLinus Torvalds if (Is_overflowtrap_enabled()) {
19621da177e4SLinus Torvalds /*
19631da177e4SLinus Torvalds * Adjust bias of result
19641da177e4SLinus Torvalds */
19651da177e4SLinus Torvalds Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
19661da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
19671da177e4SLinus Torvalds if (inexact)
19681da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
19691da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION |
19701da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
19711da177e4SLinus Torvalds else Set_inexactflag();
19721da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION);
19731da177e4SLinus Torvalds }
19741da177e4SLinus Torvalds inexact = TRUE;
19751da177e4SLinus Torvalds Set_overflowflag();
19761da177e4SLinus Torvalds Sgl_setoverflow(resultp1);
19771da177e4SLinus Torvalds } else if (result_exponent <= 0) { /* underflow case */
19781da177e4SLinus Torvalds if (Is_underflowtrap_enabled()) {
19791da177e4SLinus Torvalds /*
19801da177e4SLinus Torvalds * Adjust bias of result
19811da177e4SLinus Torvalds */
19821da177e4SLinus Torvalds Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
19831da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
19841da177e4SLinus Torvalds if (inexact)
19851da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
19861da177e4SLinus Torvalds return (OPC_2E_UNDERFLOWEXCEPTION |
19871da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
19881da177e4SLinus Torvalds else Set_inexactflag();
19891da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
19901da177e4SLinus Torvalds }
19911da177e4SLinus Torvalds else if (inexact && is_tiny) Set_underflowflag();
19921da177e4SLinus Torvalds }
19931da177e4SLinus Torvalds else Sgl_set_exponent(resultp1,result_exponent);
19941da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
19951da177e4SLinus Torvalds if (inexact)
19961da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
19971da177e4SLinus Torvalds else Set_inexactflag();
19981da177e4SLinus Torvalds return(NOEXCEPTION);
19991da177e4SLinus Torvalds }
20001da177e4SLinus Torvalds
20011da177e4SLinus Torvalds /*
20021da177e4SLinus Torvalds * Single Floating-point Multiply Negate Fused Add
20031da177e4SLinus Torvalds */
20041da177e4SLinus Torvalds
sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)20051da177e4SLinus Torvalds sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
20061da177e4SLinus Torvalds
20071da177e4SLinus Torvalds sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
20081da177e4SLinus Torvalds unsigned int *status;
20091da177e4SLinus Torvalds {
20101da177e4SLinus Torvalds unsigned int opnd1, opnd2, opnd3;
20111da177e4SLinus Torvalds register unsigned int tmpresp1, tmpresp2;
20121da177e4SLinus Torvalds unsigned int rightp1, rightp2;
20131da177e4SLinus Torvalds unsigned int resultp1, resultp2 = 0;
20141da177e4SLinus Torvalds register int mpy_exponent, add_exponent, count;
20151da177e4SLinus Torvalds boolean inexact = FALSE, is_tiny = FALSE;
20161da177e4SLinus Torvalds
20171da177e4SLinus Torvalds unsigned int signlessleft1, signlessright1, save;
20181da177e4SLinus Torvalds register int result_exponent, diff_exponent;
20191da177e4SLinus Torvalds int sign_save, jumpsize;
20201da177e4SLinus Torvalds
20211da177e4SLinus Torvalds Sgl_copyfromptr(src1ptr,opnd1);
20221da177e4SLinus Torvalds Sgl_copyfromptr(src2ptr,opnd2);
20231da177e4SLinus Torvalds Sgl_copyfromptr(src3ptr,opnd3);
20241da177e4SLinus Torvalds
20251da177e4SLinus Torvalds /*
20261da177e4SLinus Torvalds * set sign bit of result of multiply
20271da177e4SLinus Torvalds */
20281da177e4SLinus Torvalds if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2))
20291da177e4SLinus Torvalds Sgl_setzero(resultp1);
20301da177e4SLinus Torvalds else
20311da177e4SLinus Torvalds Sgl_setnegativezero(resultp1);
20321da177e4SLinus Torvalds
20331da177e4SLinus Torvalds /*
20341da177e4SLinus Torvalds * Generate multiply exponent
20351da177e4SLinus Torvalds */
20361da177e4SLinus Torvalds mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
20371da177e4SLinus Torvalds
20381da177e4SLinus Torvalds /*
20391da177e4SLinus Torvalds * check first operand for NaN's or infinity
20401da177e4SLinus Torvalds */
20411da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd1)) {
20421da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd1)) {
20431da177e4SLinus Torvalds if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
20441da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd2)) {
20451da177e4SLinus Torvalds /*
20461da177e4SLinus Torvalds * invalid since operands are infinity
20471da177e4SLinus Torvalds * and zero
20481da177e4SLinus Torvalds */
20491da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
20501da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
20511da177e4SLinus Torvalds Set_invalidflag();
20521da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
20531da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
20541da177e4SLinus Torvalds return(NOEXCEPTION);
20551da177e4SLinus Torvalds }
20561da177e4SLinus Torvalds /*
20571da177e4SLinus Torvalds * Check third operand for infinity with a
20581da177e4SLinus Torvalds * sign opposite of the multiply result
20591da177e4SLinus Torvalds */
20601da177e4SLinus Torvalds if (Sgl_isinfinity(opnd3) &&
20611da177e4SLinus Torvalds (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
20621da177e4SLinus Torvalds /*
20631da177e4SLinus Torvalds * invalid since attempting a magnitude
20641da177e4SLinus Torvalds * subtraction of infinities
20651da177e4SLinus Torvalds */
20661da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
20671da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
20681da177e4SLinus Torvalds Set_invalidflag();
20691da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
20701da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
20711da177e4SLinus Torvalds return(NOEXCEPTION);
20721da177e4SLinus Torvalds }
20731da177e4SLinus Torvalds
20741da177e4SLinus Torvalds /*
20751da177e4SLinus Torvalds * return infinity
20761da177e4SLinus Torvalds */
20771da177e4SLinus Torvalds Sgl_setinfinity_exponentmantissa(resultp1);
20781da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
20791da177e4SLinus Torvalds return(NOEXCEPTION);
20801da177e4SLinus Torvalds }
20811da177e4SLinus Torvalds }
20821da177e4SLinus Torvalds else {
20831da177e4SLinus Torvalds /*
20841da177e4SLinus Torvalds * is NaN; signaling or quiet?
20851da177e4SLinus Torvalds */
20861da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd1)) {
20871da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
20881da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
20891da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
20901da177e4SLinus Torvalds /* make NaN quiet */
20911da177e4SLinus Torvalds Set_invalidflag();
20921da177e4SLinus Torvalds Sgl_set_quiet(opnd1);
20931da177e4SLinus Torvalds }
20941da177e4SLinus Torvalds /*
20951da177e4SLinus Torvalds * is second operand a signaling NaN?
20961da177e4SLinus Torvalds */
20971da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd2)) {
20981da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
20991da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21001da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21011da177e4SLinus Torvalds /* make NaN quiet */
21021da177e4SLinus Torvalds Set_invalidflag();
21031da177e4SLinus Torvalds Sgl_set_quiet(opnd2);
21041da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
21051da177e4SLinus Torvalds return(NOEXCEPTION);
21061da177e4SLinus Torvalds }
21071da177e4SLinus Torvalds /*
21081da177e4SLinus Torvalds * is third operand a signaling NaN?
21091da177e4SLinus Torvalds */
21101da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd3)) {
21111da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
21121da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21131da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21141da177e4SLinus Torvalds /* make NaN quiet */
21151da177e4SLinus Torvalds Set_invalidflag();
21161da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
21171da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
21181da177e4SLinus Torvalds return(NOEXCEPTION);
21191da177e4SLinus Torvalds }
21201da177e4SLinus Torvalds /*
21211da177e4SLinus Torvalds * return quiet NaN
21221da177e4SLinus Torvalds */
21231da177e4SLinus Torvalds Sgl_copytoptr(opnd1,dstptr);
21241da177e4SLinus Torvalds return(NOEXCEPTION);
21251da177e4SLinus Torvalds }
21261da177e4SLinus Torvalds }
21271da177e4SLinus Torvalds
21281da177e4SLinus Torvalds /*
21291da177e4SLinus Torvalds * check second operand for NaN's or infinity
21301da177e4SLinus Torvalds */
21311da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd2)) {
21321da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd2)) {
21331da177e4SLinus Torvalds if (Sgl_isnotnan(opnd3)) {
21341da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd1)) {
21351da177e4SLinus Torvalds /*
21361da177e4SLinus Torvalds * invalid since multiply operands are
21371da177e4SLinus Torvalds * zero & infinity
21381da177e4SLinus Torvalds */
21391da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21401da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21411da177e4SLinus Torvalds Set_invalidflag();
21421da177e4SLinus Torvalds Sgl_makequietnan(opnd2);
21431da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
21441da177e4SLinus Torvalds return(NOEXCEPTION);
21451da177e4SLinus Torvalds }
21461da177e4SLinus Torvalds
21471da177e4SLinus Torvalds /*
21481da177e4SLinus Torvalds * Check third operand for infinity with a
21491da177e4SLinus Torvalds * sign opposite of the multiply result
21501da177e4SLinus Torvalds */
21511da177e4SLinus Torvalds if (Sgl_isinfinity(opnd3) &&
21521da177e4SLinus Torvalds (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
21531da177e4SLinus Torvalds /*
21541da177e4SLinus Torvalds * invalid since attempting a magnitude
21551da177e4SLinus Torvalds * subtraction of infinities
21561da177e4SLinus Torvalds */
21571da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21581da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21591da177e4SLinus Torvalds Set_invalidflag();
21601da177e4SLinus Torvalds Sgl_makequietnan(resultp1);
21611da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
21621da177e4SLinus Torvalds return(NOEXCEPTION);
21631da177e4SLinus Torvalds }
21641da177e4SLinus Torvalds
21651da177e4SLinus Torvalds /*
21661da177e4SLinus Torvalds * return infinity
21671da177e4SLinus Torvalds */
21681da177e4SLinus Torvalds Sgl_setinfinity_exponentmantissa(resultp1);
21691da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
21701da177e4SLinus Torvalds return(NOEXCEPTION);
21711da177e4SLinus Torvalds }
21721da177e4SLinus Torvalds }
21731da177e4SLinus Torvalds else {
21741da177e4SLinus Torvalds /*
21751da177e4SLinus Torvalds * is NaN; signaling or quiet?
21761da177e4SLinus Torvalds */
21771da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd2)) {
21781da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
21791da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21801da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21811da177e4SLinus Torvalds /* make NaN quiet */
21821da177e4SLinus Torvalds Set_invalidflag();
21831da177e4SLinus Torvalds Sgl_set_quiet(opnd2);
21841da177e4SLinus Torvalds }
21851da177e4SLinus Torvalds /*
21861da177e4SLinus Torvalds * is third operand a signaling NaN?
21871da177e4SLinus Torvalds */
21881da177e4SLinus Torvalds else if (Sgl_is_signalingnan(opnd3)) {
21891da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
21901da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
21911da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
21921da177e4SLinus Torvalds /* make NaN quiet */
21931da177e4SLinus Torvalds Set_invalidflag();
21941da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
21951da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
21961da177e4SLinus Torvalds return(NOEXCEPTION);
21971da177e4SLinus Torvalds }
21981da177e4SLinus Torvalds /*
21991da177e4SLinus Torvalds * return quiet NaN
22001da177e4SLinus Torvalds */
22011da177e4SLinus Torvalds Sgl_copytoptr(opnd2,dstptr);
22021da177e4SLinus Torvalds return(NOEXCEPTION);
22031da177e4SLinus Torvalds }
22041da177e4SLinus Torvalds }
22051da177e4SLinus Torvalds
22061da177e4SLinus Torvalds /*
22071da177e4SLinus Torvalds * check third operand for NaN's or infinity
22081da177e4SLinus Torvalds */
22091da177e4SLinus Torvalds if (Sgl_isinfinity_exponent(opnd3)) {
22101da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd3)) {
22111da177e4SLinus Torvalds /* return infinity */
22121da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
22131da177e4SLinus Torvalds return(NOEXCEPTION);
22141da177e4SLinus Torvalds } else {
22151da177e4SLinus Torvalds /*
22161da177e4SLinus Torvalds * is NaN; signaling or quiet?
22171da177e4SLinus Torvalds */
22181da177e4SLinus Torvalds if (Sgl_isone_signaling(opnd3)) {
22191da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
22201da177e4SLinus Torvalds if (Is_invalidtrap_enabled())
22211da177e4SLinus Torvalds return(OPC_2E_INVALIDEXCEPTION);
22221da177e4SLinus Torvalds /* make NaN quiet */
22231da177e4SLinus Torvalds Set_invalidflag();
22241da177e4SLinus Torvalds Sgl_set_quiet(opnd3);
22251da177e4SLinus Torvalds }
22261da177e4SLinus Torvalds /*
22271da177e4SLinus Torvalds * return quiet NaN
22281da177e4SLinus Torvalds */
22291da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
22301da177e4SLinus Torvalds return(NOEXCEPTION);
22311da177e4SLinus Torvalds }
22321da177e4SLinus Torvalds }
22331da177e4SLinus Torvalds
22341da177e4SLinus Torvalds /*
22351da177e4SLinus Torvalds * Generate multiply mantissa
22361da177e4SLinus Torvalds */
22371da177e4SLinus Torvalds if (Sgl_isnotzero_exponent(opnd1)) {
22381da177e4SLinus Torvalds /* set hidden bit */
22391da177e4SLinus Torvalds Sgl_clear_signexponent_set_hidden(opnd1);
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds else {
22421da177e4SLinus Torvalds /* check for zero */
22431da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd1)) {
22441da177e4SLinus Torvalds /*
22451da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
22461da177e4SLinus Torvalds */
22471da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd3)) {
22481da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
22491da177e4SLinus Torvalds Sgl_or_signs(opnd3,resultp1);
22501da177e4SLinus Torvalds } else {
22511da177e4SLinus Torvalds Sgl_and_signs(opnd3,resultp1);
22521da177e4SLinus Torvalds }
22531da177e4SLinus Torvalds }
22541da177e4SLinus Torvalds /*
22551da177e4SLinus Torvalds * Now let's check for trapped underflow case.
22561da177e4SLinus Torvalds */
22571da177e4SLinus Torvalds else if (Sgl_iszero_exponent(opnd3) &&
22581da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
22591da177e4SLinus Torvalds /* need to normalize results mantissa */
22601da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3);
22611da177e4SLinus Torvalds result_exponent = 0;
22621da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
22631da177e4SLinus Torvalds Sgl_normalize(opnd3,result_exponent);
22641da177e4SLinus Torvalds Sgl_set_sign(opnd3,/*using*/sign_save);
22651da177e4SLinus Torvalds Sgl_setwrapped_exponent(opnd3,result_exponent,
22661da177e4SLinus Torvalds unfl);
22671da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
22681da177e4SLinus Torvalds /* inexact = FALSE */
22691da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
22701da177e4SLinus Torvalds }
22711da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
22721da177e4SLinus Torvalds return(NOEXCEPTION);
22731da177e4SLinus Torvalds }
22741da177e4SLinus Torvalds /* is denormalized, adjust exponent */
22751da177e4SLinus Torvalds Sgl_clear_signexponent(opnd1);
22761da177e4SLinus Torvalds Sgl_leftshiftby1(opnd1);
22771da177e4SLinus Torvalds Sgl_normalize(opnd1,mpy_exponent);
22781da177e4SLinus Torvalds }
22791da177e4SLinus Torvalds /* opnd2 needs to have hidden bit set with msb in hidden bit */
22801da177e4SLinus Torvalds if (Sgl_isnotzero_exponent(opnd2)) {
22811da177e4SLinus Torvalds Sgl_clear_signexponent_set_hidden(opnd2);
22821da177e4SLinus Torvalds }
22831da177e4SLinus Torvalds else {
22841da177e4SLinus Torvalds /* check for zero */
22851da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd2)) {
22861da177e4SLinus Torvalds /*
22871da177e4SLinus Torvalds * Perform the add opnd3 with zero here.
22881da177e4SLinus Torvalds */
22891da177e4SLinus Torvalds if (Sgl_iszero_exponentmantissa(opnd3)) {
22901da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS)) {
22911da177e4SLinus Torvalds Sgl_or_signs(opnd3,resultp1);
22921da177e4SLinus Torvalds } else {
22931da177e4SLinus Torvalds Sgl_and_signs(opnd3,resultp1);
22941da177e4SLinus Torvalds }
22951da177e4SLinus Torvalds }
22961da177e4SLinus Torvalds /*
22971da177e4SLinus Torvalds * Now let's check for trapped underflow case.
22981da177e4SLinus Torvalds */
22991da177e4SLinus Torvalds else if (Sgl_iszero_exponent(opnd3) &&
23001da177e4SLinus Torvalds Is_underflowtrap_enabled()) {
23011da177e4SLinus Torvalds /* need to normalize results mantissa */
23021da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3);
23031da177e4SLinus Torvalds result_exponent = 0;
23041da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
23051da177e4SLinus Torvalds Sgl_normalize(opnd3,result_exponent);
23061da177e4SLinus Torvalds Sgl_set_sign(opnd3,/*using*/sign_save);
23071da177e4SLinus Torvalds Sgl_setwrapped_exponent(opnd3,result_exponent,
23081da177e4SLinus Torvalds unfl);
23091da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
23101da177e4SLinus Torvalds /* inexact = FALSE */
23111da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
23121da177e4SLinus Torvalds }
23131da177e4SLinus Torvalds Sgl_copytoptr(opnd3,dstptr);
23141da177e4SLinus Torvalds return(NOEXCEPTION);
23151da177e4SLinus Torvalds }
23161da177e4SLinus Torvalds /* is denormalized; want to normalize */
23171da177e4SLinus Torvalds Sgl_clear_signexponent(opnd2);
23181da177e4SLinus Torvalds Sgl_leftshiftby1(opnd2);
23191da177e4SLinus Torvalds Sgl_normalize(opnd2,mpy_exponent);
23201da177e4SLinus Torvalds }
23211da177e4SLinus Torvalds
23221da177e4SLinus Torvalds /* Multiply the first two source mantissas together */
23231da177e4SLinus Torvalds
23241da177e4SLinus Torvalds /*
23251da177e4SLinus Torvalds * The intermediate result will be kept in tmpres,
23261da177e4SLinus Torvalds * which needs enough room for 106 bits of mantissa,
23271da177e4SLinus Torvalds * so lets call it a Double extended.
23281da177e4SLinus Torvalds */
23291da177e4SLinus Torvalds Sglext_setzero(tmpresp1,tmpresp2);
23301da177e4SLinus Torvalds
23311da177e4SLinus Torvalds /*
23321da177e4SLinus Torvalds * Four bits at a time are inspected in each loop, and a
23331da177e4SLinus Torvalds * simple shift and add multiply algorithm is used.
23341da177e4SLinus Torvalds */
23351da177e4SLinus Torvalds for (count = SGL_P-1; count >= 0; count -= 4) {
23361da177e4SLinus Torvalds Sglext_rightshiftby4(tmpresp1,tmpresp2);
23371da177e4SLinus Torvalds if (Sbit28(opnd1)) {
23381da177e4SLinus Torvalds /* Twoword_add should be an ADD followed by 2 ADDC's */
23391da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
23401da177e4SLinus Torvalds }
23411da177e4SLinus Torvalds if (Sbit29(opnd1)) {
23421da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
23431da177e4SLinus Torvalds }
23441da177e4SLinus Torvalds if (Sbit30(opnd1)) {
23451da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
23461da177e4SLinus Torvalds }
23471da177e4SLinus Torvalds if (Sbit31(opnd1)) {
23481da177e4SLinus Torvalds Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds Sgl_rightshiftby4(opnd1);
23511da177e4SLinus Torvalds }
23521da177e4SLinus Torvalds if (Is_sexthiddenoverflow(tmpresp1)) {
23531da177e4SLinus Torvalds /* result mantissa >= 2 (mantissa overflow) */
23541da177e4SLinus Torvalds mpy_exponent++;
23551da177e4SLinus Torvalds Sglext_rightshiftby4(tmpresp1,tmpresp2);
23561da177e4SLinus Torvalds } else {
23571da177e4SLinus Torvalds Sglext_rightshiftby3(tmpresp1,tmpresp2);
23581da177e4SLinus Torvalds }
23591da177e4SLinus Torvalds
23601da177e4SLinus Torvalds /*
23611da177e4SLinus Torvalds * Restore the sign of the mpy result which was saved in resultp1.
23621da177e4SLinus Torvalds * The exponent will continue to be kept in mpy_exponent.
23631da177e4SLinus Torvalds */
23641da177e4SLinus Torvalds Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
23651da177e4SLinus Torvalds
23661da177e4SLinus Torvalds /*
23671da177e4SLinus Torvalds * No rounding is required, since the result of the multiply
23681da177e4SLinus Torvalds * is exact in the extended format.
23691da177e4SLinus Torvalds */
23701da177e4SLinus Torvalds
23711da177e4SLinus Torvalds /*
23721da177e4SLinus Torvalds * Now we are ready to perform the add portion of the operation.
23731da177e4SLinus Torvalds *
23741da177e4SLinus Torvalds * The exponents need to be kept as integers for now, since the
23751da177e4SLinus Torvalds * multiply result might not fit into the exponent field. We
23761da177e4SLinus Torvalds * can't overflow or underflow because of this yet, since the
23771da177e4SLinus Torvalds * add could bring the final result back into range.
23781da177e4SLinus Torvalds */
23791da177e4SLinus Torvalds add_exponent = Sgl_exponent(opnd3);
23801da177e4SLinus Torvalds
23811da177e4SLinus Torvalds /*
23821da177e4SLinus Torvalds * Check for denormalized or zero add operand.
23831da177e4SLinus Torvalds */
23841da177e4SLinus Torvalds if (add_exponent == 0) {
23851da177e4SLinus Torvalds /* check for zero */
23861da177e4SLinus Torvalds if (Sgl_iszero_mantissa(opnd3)) {
23871da177e4SLinus Torvalds /* right is zero */
23881da177e4SLinus Torvalds /* Left can't be zero and must be result.
23891da177e4SLinus Torvalds *
23901da177e4SLinus Torvalds * The final result is now in tmpres and mpy_exponent,
23911da177e4SLinus Torvalds * and needs to be rounded and squeezed back into
23921da177e4SLinus Torvalds * double precision format from double extended.
23931da177e4SLinus Torvalds */
23941da177e4SLinus Torvalds result_exponent = mpy_exponent;
23951da177e4SLinus Torvalds Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
23961da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
23971da177e4SLinus Torvalds goto round;
23981da177e4SLinus Torvalds }
23991da177e4SLinus Torvalds
24001da177e4SLinus Torvalds /*
24011da177e4SLinus Torvalds * Neither are zeroes.
24021da177e4SLinus Torvalds * Adjust exponent and normalize add operand.
24031da177e4SLinus Torvalds */
24041da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(opnd3); /* save sign */
24051da177e4SLinus Torvalds Sgl_clear_signexponent(opnd3);
24061da177e4SLinus Torvalds Sgl_leftshiftby1(opnd3);
24071da177e4SLinus Torvalds Sgl_normalize(opnd3,add_exponent);
24081da177e4SLinus Torvalds Sgl_set_sign(opnd3,sign_save); /* restore sign */
24091da177e4SLinus Torvalds } else {
24101da177e4SLinus Torvalds Sgl_clear_exponent_set_hidden(opnd3);
24111da177e4SLinus Torvalds }
24121da177e4SLinus Torvalds /*
24131da177e4SLinus Torvalds * Copy opnd3 to the double extended variable called right.
24141da177e4SLinus Torvalds */
24151da177e4SLinus Torvalds Sgl_copyto_sglext(opnd3,rightp1,rightp2);
24161da177e4SLinus Torvalds
24171da177e4SLinus Torvalds /*
24181da177e4SLinus Torvalds * A zero "save" helps discover equal operands (for later),
24191da177e4SLinus Torvalds * and is used in swapping operands (if needed).
24201da177e4SLinus Torvalds */
24211da177e4SLinus Torvalds Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
24221da177e4SLinus Torvalds
24231da177e4SLinus Torvalds /*
24241da177e4SLinus Torvalds * Compare magnitude of operands.
24251da177e4SLinus Torvalds */
24261da177e4SLinus Torvalds Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
24271da177e4SLinus Torvalds Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
24281da177e4SLinus Torvalds if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
24291da177e4SLinus Torvalds Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
24301da177e4SLinus Torvalds /*
24311da177e4SLinus Torvalds * Set the left operand to the larger one by XOR swap.
24321da177e4SLinus Torvalds * First finish the first word "save".
24331da177e4SLinus Torvalds */
24341da177e4SLinus Torvalds Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
24351da177e4SLinus Torvalds Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
24361da177e4SLinus Torvalds Sglext_swap_lower(tmpresp2,rightp2);
24371da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
24381da177e4SLinus Torvalds diff_exponent = add_exponent - mpy_exponent;
24391da177e4SLinus Torvalds result_exponent = add_exponent;
24401da177e4SLinus Torvalds } else {
24411da177e4SLinus Torvalds /* also setup exponents used in rest of routine */
24421da177e4SLinus Torvalds diff_exponent = mpy_exponent - add_exponent;
24431da177e4SLinus Torvalds result_exponent = mpy_exponent;
24441da177e4SLinus Torvalds }
24451da177e4SLinus Torvalds /* Invariant: left is not smaller than right. */
24461da177e4SLinus Torvalds
24471da177e4SLinus Torvalds /*
24481da177e4SLinus Torvalds * Special case alignment of operands that would force alignment
24491da177e4SLinus Torvalds * beyond the extent of the extension. A further optimization
24501da177e4SLinus Torvalds * could special case this but only reduces the path length for
24511da177e4SLinus Torvalds * this infrequent case.
24521da177e4SLinus Torvalds */
24531da177e4SLinus Torvalds if (diff_exponent > SGLEXT_THRESHOLD) {
24541da177e4SLinus Torvalds diff_exponent = SGLEXT_THRESHOLD;
24551da177e4SLinus Torvalds }
24561da177e4SLinus Torvalds
24571da177e4SLinus Torvalds /* Align right operand by shifting it to the right */
24581da177e4SLinus Torvalds Sglext_clear_sign(rightp1);
24591da177e4SLinus Torvalds Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
24601da177e4SLinus Torvalds
24611da177e4SLinus Torvalds /* Treat sum and difference of the operands separately. */
24621da177e4SLinus Torvalds if ((int)save < 0) {
24631da177e4SLinus Torvalds /*
24641da177e4SLinus Torvalds * Difference of the two operands. Overflow can occur if the
24651da177e4SLinus Torvalds * multiply overflowed. A borrow can occur out of the hidden
24661da177e4SLinus Torvalds * bit and force a post normalization phase.
24671da177e4SLinus Torvalds */
24681da177e4SLinus Torvalds Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
24691da177e4SLinus Torvalds resultp1,resultp2);
24701da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);
24711da177e4SLinus Torvalds if (Sgl_iszero_hidden(resultp1)) {
24721da177e4SLinus Torvalds /* Handle normalization */
247325985edcSLucas De Marchi /* A straightforward algorithm would now shift the
24741da177e4SLinus Torvalds * result and extension left until the hidden bit
24751da177e4SLinus Torvalds * becomes one. Not all of the extension bits need
24761da177e4SLinus Torvalds * participate in the shift. Only the two most
24771da177e4SLinus Torvalds * significant bits (round and guard) are needed.
24781da177e4SLinus Torvalds * If only a single shift is needed then the guard
24791da177e4SLinus Torvalds * bit becomes a significant low order bit and the
24801da177e4SLinus Torvalds * extension must participate in the rounding.
24811da177e4SLinus Torvalds * If more than a single shift is needed, then all
24821da177e4SLinus Torvalds * bits to the right of the guard bit are zeros,
24831da177e4SLinus Torvalds * and the guard bit may or may not be zero. */
24841da177e4SLinus Torvalds Sglext_leftshiftby1(resultp1,resultp2);
24851da177e4SLinus Torvalds
24861da177e4SLinus Torvalds /* Need to check for a zero result. The sign and
24871da177e4SLinus Torvalds * exponent fields have already been zeroed. The more
24881da177e4SLinus Torvalds * efficient test of the full object can be used.
24891da177e4SLinus Torvalds */
24901da177e4SLinus Torvalds if (Sglext_iszero(resultp1,resultp2)) {
24911da177e4SLinus Torvalds /* Must have been "x-x" or "x+(-x)". */
24921da177e4SLinus Torvalds if (Is_rounding_mode(ROUNDMINUS))
24931da177e4SLinus Torvalds Sgl_setone_sign(resultp1);
24941da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
24951da177e4SLinus Torvalds return(NOEXCEPTION);
24961da177e4SLinus Torvalds }
24971da177e4SLinus Torvalds result_exponent--;
24981da177e4SLinus Torvalds
24991da177e4SLinus Torvalds /* Look to see if normalization is finished. */
25001da177e4SLinus Torvalds if (Sgl_isone_hidden(resultp1)) {
25011da177e4SLinus Torvalds /* No further normalization is needed */
25021da177e4SLinus Torvalds goto round;
25031da177e4SLinus Torvalds }
25041da177e4SLinus Torvalds
25051da177e4SLinus Torvalds /* Discover first one bit to determine shift amount.
25061da177e4SLinus Torvalds * Use a modified binary search. We have already
25071da177e4SLinus Torvalds * shifted the result one position right and still
25081da177e4SLinus Torvalds * not found a one so the remainder of the extension
25091da177e4SLinus Torvalds * must be zero and simplifies rounding. */
25101da177e4SLinus Torvalds /* Scan bytes */
25111da177e4SLinus Torvalds while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
25121da177e4SLinus Torvalds Sglext_leftshiftby8(resultp1,resultp2);
25131da177e4SLinus Torvalds result_exponent -= 8;
25141da177e4SLinus Torvalds }
25151da177e4SLinus Torvalds /* Now narrow it down to the nibble */
25161da177e4SLinus Torvalds if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
25171da177e4SLinus Torvalds /* The lower nibble contains the
25181da177e4SLinus Torvalds * normalizing one */
25191da177e4SLinus Torvalds Sglext_leftshiftby4(resultp1,resultp2);
25201da177e4SLinus Torvalds result_exponent -= 4;
25211da177e4SLinus Torvalds }
25221da177e4SLinus Torvalds /* Select case where first bit is set (already
25231da177e4SLinus Torvalds * normalized) otherwise select the proper shift. */
25241da177e4SLinus Torvalds jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
25251da177e4SLinus Torvalds if (jumpsize <= 7) switch(jumpsize) {
25261da177e4SLinus Torvalds case 1:
25271da177e4SLinus Torvalds Sglext_leftshiftby3(resultp1,resultp2);
25281da177e4SLinus Torvalds result_exponent -= 3;
25291da177e4SLinus Torvalds break;
25301da177e4SLinus Torvalds case 2:
25311da177e4SLinus Torvalds case 3:
25321da177e4SLinus Torvalds Sglext_leftshiftby2(resultp1,resultp2);
25331da177e4SLinus Torvalds result_exponent -= 2;
25341da177e4SLinus Torvalds break;
25351da177e4SLinus Torvalds case 4:
25361da177e4SLinus Torvalds case 5:
25371da177e4SLinus Torvalds case 6:
25381da177e4SLinus Torvalds case 7:
25391da177e4SLinus Torvalds Sglext_leftshiftby1(resultp1,resultp2);
25401da177e4SLinus Torvalds result_exponent -= 1;
25411da177e4SLinus Torvalds break;
25421da177e4SLinus Torvalds }
25431da177e4SLinus Torvalds } /* end if (hidden...)... */
25441da177e4SLinus Torvalds /* Fall through and round */
25451da177e4SLinus Torvalds } /* end if (save < 0)... */
25461da177e4SLinus Torvalds else {
25471da177e4SLinus Torvalds /* Add magnitudes */
25481da177e4SLinus Torvalds Sglext_addition(tmpresp1,tmpresp2,
25491da177e4SLinus Torvalds rightp1,rightp2, /*to*/resultp1,resultp2);
25501da177e4SLinus Torvalds sign_save = Sgl_signextendedsign(resultp1);
25511da177e4SLinus Torvalds if (Sgl_isone_hiddenoverflow(resultp1)) {
25521da177e4SLinus Torvalds /* Prenormalization required. */
25531da177e4SLinus Torvalds Sglext_arithrightshiftby1(resultp1,resultp2);
25541da177e4SLinus Torvalds result_exponent++;
25551da177e4SLinus Torvalds } /* end if hiddenoverflow... */
25561da177e4SLinus Torvalds } /* end else ...add magnitudes... */
25571da177e4SLinus Torvalds
25581da177e4SLinus Torvalds /* Round the result. If the extension and lower two words are
25591da177e4SLinus Torvalds * all zeros, then the result is exact. Otherwise round in the
25601da177e4SLinus Torvalds * correct direction. Underflow is possible. If a postnormalization
25611da177e4SLinus Torvalds * is necessary, then the mantissa is all zeros so no shift is needed.
25621da177e4SLinus Torvalds */
25631da177e4SLinus Torvalds round:
25641da177e4SLinus Torvalds if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
25651da177e4SLinus Torvalds Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
25661da177e4SLinus Torvalds }
25671da177e4SLinus Torvalds Sgl_set_sign(resultp1,/*using*/sign_save);
25681da177e4SLinus Torvalds if (Sglext_isnotzero_mantissap2(resultp2)) {
25691da177e4SLinus Torvalds inexact = TRUE;
25701da177e4SLinus Torvalds switch(Rounding_mode()) {
25711da177e4SLinus Torvalds case ROUNDNEAREST: /* The default. */
25721da177e4SLinus Torvalds if (Sglext_isone_highp2(resultp2)) {
25731da177e4SLinus Torvalds /* at least 1/2 ulp */
25741da177e4SLinus Torvalds if (Sglext_isnotzero_low31p2(resultp2) ||
25751da177e4SLinus Torvalds Sglext_isone_lowp1(resultp1)) {
25761da177e4SLinus Torvalds /* either exactly half way and odd or
25771da177e4SLinus Torvalds * more than 1/2ulp */
25781da177e4SLinus Torvalds Sgl_increment(resultp1);
25791da177e4SLinus Torvalds }
25801da177e4SLinus Torvalds }
25811da177e4SLinus Torvalds break;
25821da177e4SLinus Torvalds
25831da177e4SLinus Torvalds case ROUNDPLUS:
25841da177e4SLinus Torvalds if (Sgl_iszero_sign(resultp1)) {
25851da177e4SLinus Torvalds /* Round up positive results */
25861da177e4SLinus Torvalds Sgl_increment(resultp1);
25871da177e4SLinus Torvalds }
25881da177e4SLinus Torvalds break;
25891da177e4SLinus Torvalds
25901da177e4SLinus Torvalds case ROUNDMINUS:
25911da177e4SLinus Torvalds if (Sgl_isone_sign(resultp1)) {
25921da177e4SLinus Torvalds /* Round down negative results */
25931da177e4SLinus Torvalds Sgl_increment(resultp1);
25941da177e4SLinus Torvalds }
25951da177e4SLinus Torvalds
25961da177e4SLinus Torvalds case ROUNDZERO:;
25971da177e4SLinus Torvalds /* truncate is simple */
25981da177e4SLinus Torvalds } /* end switch... */
25991da177e4SLinus Torvalds if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
26001da177e4SLinus Torvalds }
26011da177e4SLinus Torvalds if (result_exponent >= SGL_INFINITY_EXPONENT) {
26021da177e4SLinus Torvalds /* Overflow */
26031da177e4SLinus Torvalds if (Is_overflowtrap_enabled()) {
26041da177e4SLinus Torvalds /*
26051da177e4SLinus Torvalds * Adjust bias of result
26061da177e4SLinus Torvalds */
26071da177e4SLinus Torvalds Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
26081da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
26091da177e4SLinus Torvalds if (inexact)
26101da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
26111da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION |
26121da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
26131da177e4SLinus Torvalds else Set_inexactflag();
26141da177e4SLinus Torvalds return (OPC_2E_OVERFLOWEXCEPTION);
26151da177e4SLinus Torvalds }
26161da177e4SLinus Torvalds inexact = TRUE;
26171da177e4SLinus Torvalds Set_overflowflag();
26181da177e4SLinus Torvalds Sgl_setoverflow(resultp1);
26191da177e4SLinus Torvalds } else if (result_exponent <= 0) { /* underflow case */
26201da177e4SLinus Torvalds if (Is_underflowtrap_enabled()) {
26211da177e4SLinus Torvalds /*
26221da177e4SLinus Torvalds * Adjust bias of result
26231da177e4SLinus Torvalds */
26241da177e4SLinus Torvalds Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
26251da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
26261da177e4SLinus Torvalds if (inexact)
26271da177e4SLinus Torvalds if (Is_inexacttrap_enabled())
26281da177e4SLinus Torvalds return (OPC_2E_UNDERFLOWEXCEPTION |
26291da177e4SLinus Torvalds OPC_2E_INEXACTEXCEPTION);
26301da177e4SLinus Torvalds else Set_inexactflag();
26311da177e4SLinus Torvalds return(OPC_2E_UNDERFLOWEXCEPTION);
26321da177e4SLinus Torvalds }
26331da177e4SLinus Torvalds else if (inexact && is_tiny) Set_underflowflag();
26341da177e4SLinus Torvalds }
26351da177e4SLinus Torvalds else Sgl_set_exponent(resultp1,result_exponent);
26361da177e4SLinus Torvalds Sgl_copytoptr(resultp1,dstptr);
26371da177e4SLinus Torvalds if (inexact)
26381da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
26391da177e4SLinus Torvalds else Set_inexactflag();
26401da177e4SLinus Torvalds return(NOEXCEPTION);
26411da177e4SLinus Torvalds }
26421da177e4SLinus Torvalds
2643