📄 fmpyfadd.c
字号:
/* * Linux/PA-RISC Project (http://www.parisc-linux.org/) * * Floating-point emulation code * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * BEGIN_DESC * * File: * @(#) pa/spmath/fmpyfadd.c $Revision: 1.1 $ * * Purpose: * Double Floating-point Multiply Fused Add * Double Floating-point Multiply Negate Fused Add * Single Floating-point Multiply Fused Add * Single Floating-point Multiply Negate Fused Add * * External Interfaces: * dbl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr) * dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr) * sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr) * sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr) * * Internal Interfaces: * * Theory: * <<please update with a overview of the operation of this file>> * * END_DESC*/#include "float.h"#include "sgl_float.h"#include "dbl_float.h"/* * Double Floating-point Multiply Fused Add */intdbl_fmpyfadd( dbl_floating_point *src1ptr, dbl_floating_point *src2ptr, dbl_floating_point *src3ptr, unsigned int *status, dbl_floating_point *dstptr){ unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2; register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4; unsigned int rightp1, rightp2, rightp3, rightp4; unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0; register int mpy_exponent, add_exponent, count; boolean inexact = FALSE, is_tiny = FALSE; unsigned int signlessleft1, signlessright1, save; register int result_exponent, diff_exponent; int sign_save, jumpsize; Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2); Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2); Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2); /* * set sign bit of result of multiply */ if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) Dbl_setnegativezerop1(resultp1); else Dbl_setzerop1(resultp1); /* * Generate multiply exponent */ mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS; /* * check first operand for NaN's or infinity */ if (Dbl_isinfinity_exponent(opnd1p1)) { if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { if (Dbl_isnotnan(opnd2p1,opnd2p2) && Dbl_isnotnan(opnd3p1,opnd3p2)) { if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) { /* * invalid since operands are infinity * and zero */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); Set_invalidflag(); Dbl_makequietnan(resultp1,resultp2); Dbl_copytoptr(resultp1,resultp2,dstptr); return(NOEXCEPTION); } /* * Check third operand for infinity with a * sign opposite of the multiply result */ if (Dbl_isinfinity(opnd3p1,opnd3p2) && (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) { /* * invalid since attempting a magnitude * subtraction of infinities */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); Set_invalidflag(); Dbl_makequietnan(resultp1,resultp2); Dbl_copytoptr(resultp1,resultp2,dstptr); return(NOEXCEPTION); } /* * return infinity */ Dbl_setinfinity_exponentmantissa(resultp1,resultp2); Dbl_copytoptr(resultp1,resultp2,dstptr); return(NOEXCEPTION); } } else { /* * is NaN; signaling or quiet? */ if (Dbl_isone_signaling(opnd1p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd1p1); } /* * is second operand a signaling NaN? */ else if (Dbl_is_signalingnan(opnd2p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd2p1); Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); return(NOEXCEPTION); } /* * is third operand a signaling NaN? */ else if (Dbl_is_signalingnan(opnd3p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd3p1); Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } /* * return quiet NaN */ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); return(NOEXCEPTION); } } /* * check second operand for NaN's or infinity */ if (Dbl_isinfinity_exponent(opnd2p1)) { if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) { if (Dbl_isnotnan(opnd3p1,opnd3p2)) { if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) { /* * invalid since multiply operands are * zero & infinity */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); Set_invalidflag(); Dbl_makequietnan(opnd2p1,opnd2p2); Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); return(NOEXCEPTION); } /* * Check third operand for infinity with a * sign opposite of the multiply result */ if (Dbl_isinfinity(opnd3p1,opnd3p2) && (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) { /* * invalid since attempting a magnitude * subtraction of infinities */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); Set_invalidflag(); Dbl_makequietnan(resultp1,resultp2); Dbl_copytoptr(resultp1,resultp2,dstptr); return(NOEXCEPTION); } /* * return infinity */ Dbl_setinfinity_exponentmantissa(resultp1,resultp2); Dbl_copytoptr(resultp1,resultp2,dstptr); return(NOEXCEPTION); } } else { /* * is NaN; signaling or quiet? */ if (Dbl_isone_signaling(opnd2p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd2p1); } /* * is third operand a signaling NaN? */ else if (Dbl_is_signalingnan(opnd3p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd3p1); Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } /* * return quiet NaN */ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); return(NOEXCEPTION); } } /* * check third operand for NaN's or infinity */ if (Dbl_isinfinity_exponent(opnd3p1)) { if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) { /* return infinity */ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } else { /* * is NaN; signaling or quiet? */ if (Dbl_isone_signaling(opnd3p1)) { /* trap if INVALIDTRAP enabled */ if (Is_invalidtrap_enabled()) return(OPC_2E_INVALIDEXCEPTION); /* make NaN quiet */ Set_invalidflag(); Dbl_set_quiet(opnd3p1); } /* * return quiet NaN */ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } } /* * Generate multiply mantissa */ if (Dbl_isnotzero_exponent(opnd1p1)) { /* set hidden bit */ Dbl_clear_signexponent_set_hidden(opnd1p1); } else { /* check for zero */ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { /* * Perform the add opnd3 with zero here. */ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) { if (Is_rounding_mode(ROUNDMINUS)) { Dbl_or_signs(opnd3p1,resultp1); } else { Dbl_and_signs(opnd3p1,resultp1); } } /* * Now let's check for trapped underflow case. */ else if (Dbl_iszero_exponent(opnd3p1) && Is_underflowtrap_enabled()) { /* need to normalize results mantissa */ sign_save = Dbl_signextendedsign(opnd3p1); result_exponent = 0; Dbl_leftshiftby1(opnd3p1,opnd3p2); Dbl_normalize(opnd3p1,opnd3p2,result_exponent); Dbl_set_sign(opnd3p1,/*using*/sign_save); Dbl_setwrapped_exponent(opnd3p1,result_exponent, unfl); Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); /* inexact = FALSE */ return(OPC_2E_UNDERFLOWEXCEPTION); } Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } /* is denormalized, adjust exponent */ Dbl_clear_signexponent(opnd1p1); Dbl_leftshiftby1(opnd1p1,opnd1p2); Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent); } /* opnd2 needs to have hidden bit set with msb in hidden bit */ if (Dbl_isnotzero_exponent(opnd2p1)) { Dbl_clear_signexponent_set_hidden(opnd2p1); } else { /* check for zero */ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) { /* * Perform the add opnd3 with zero here. */ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) { if (Is_rounding_mode(ROUNDMINUS)) { Dbl_or_signs(opnd3p1,resultp1); } else { Dbl_and_signs(opnd3p1,resultp1); } } /* * Now let's check for trapped underflow case. */ else if (Dbl_iszero_exponent(opnd3p1) && Is_underflowtrap_enabled()) { /* need to normalize results mantissa */ sign_save = Dbl_signextendedsign(opnd3p1); result_exponent = 0; Dbl_leftshiftby1(opnd3p1,opnd3p2); Dbl_normalize(opnd3p1,opnd3p2,result_exponent); Dbl_set_sign(opnd3p1,/*using*/sign_save); Dbl_setwrapped_exponent(opnd3p1,result_exponent, unfl); Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); /* inexact = FALSE */ return(OPC_2E_UNDERFLOWEXCEPTION); } Dbl_copytoptr(opnd3p1,opnd3p2,dstptr); return(NOEXCEPTION); } /* is denormalized; want to normalize */ Dbl_clear_signexponent(opnd2p1); Dbl_leftshiftby1(opnd2p1,opnd2p2); Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent); } /* Multiply the first two source mantissas together */ /* * The intermediate result will be kept in tmpres, * which needs enough room for 106 bits of mantissa, * so lets call it a Double extended. */ Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4); /* * Four bits at a time are inspected in each loop, and a * simple shift and add multiply algorithm is used. */ for (count = DBL_P-1; count >= 0; count -= 4) { Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4); if (Dbit28p2(opnd1p2)) { /* Fourword_add should be an ADD followed by 3 ADDC's */ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0); } if (Dbit29p2(opnd1p2)) { Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0); } if (Dbit30p2(opnd1p2)) { Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0); } if (Dbit31p2(opnd1p2)) { Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, opnd2p1, opnd2p2, 0, 0); } Dbl_rightshiftby4(opnd1p1,opnd1p2); } if (Is_dexthiddenoverflow(tmpresp1)) { /* result mantissa >= 2 (mantissa overflow) */ mpy_exponent++; Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4); } /* * Restore the sign of the mpy result which was saved in resultp1. * The exponent will continue to be kept in mpy_exponent. */ Dblext_set_sign(tmpresp1,Dbl_sign(resultp1)); /* * No rounding is required, since the result of the multiply * is exact in the extended format. */ /* * Now we are ready to perform the add portion of the operation. * * The exponents need to be kept as integers for now, since the * multiply result might not fit into the exponent field. We * can't overflow or underflow because of this yet, since the * add could bring the final result back into range. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -