/*1* Linux/PA-RISC Project (http://www.parisc-linux.org/)2*3* Floating-point emulation code4* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2, or (at your option)9* any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/20/*21* BEGIN_DESC22*23* File:24* @(#) pa/spmath/dfadd.c $Revision: 1.1 $25*26* Purpose:27* Double_add: add two double precision values.28*29* External Interfaces:30* dbl_fadd(leftptr, rightptr, dstptr, status)31*32* Internal Interfaces:33*34* Theory:35* <<please update with a overview of the operation of this file>>36*37* END_DESC38*/394041#include "float.h"42#include "dbl_float.h"4344/*45* Double_add: add two double precision values.46*/47dbl_fadd(48dbl_floating_point *leftptr,49dbl_floating_point *rightptr,50dbl_floating_point *dstptr,51unsigned int *status)52{53register unsigned int signless_upper_left, signless_upper_right, save;54register unsigned int leftp1, leftp2, rightp1, rightp2, extent;55register unsigned int resultp1 = 0, resultp2 = 0;5657register int result_exponent, right_exponent, diff_exponent;58register int sign_save, jumpsize;59register boolean inexact = FALSE;60register boolean underflowtrap;6162/* Create local copies of the numbers */63Dbl_copyfromptr(leftptr,leftp1,leftp2);64Dbl_copyfromptr(rightptr,rightp1,rightp2);6566/* A zero "save" helps discover equal operands (for later), *67* and is used in swapping operands (if needed). */68Dbl_xortointp1(leftp1,rightp1,/*to*/save);6970/*71* check first operand for NaN's or infinity72*/73if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)74{75if (Dbl_iszero_mantissa(leftp1,leftp2))76{77if (Dbl_isnotnan(rightp1,rightp2))78{79if (Dbl_isinfinity(rightp1,rightp2) && save!=0)80{81/*82* invalid since operands are opposite signed infinity's83*/84if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);85Set_invalidflag();86Dbl_makequietnan(resultp1,resultp2);87Dbl_copytoptr(resultp1,resultp2,dstptr);88return(NOEXCEPTION);89}90/*91* return infinity92*/93Dbl_copytoptr(leftp1,leftp2,dstptr);94return(NOEXCEPTION);95}96}97else98{99/*100* is NaN; signaling or quiet?101*/102if (Dbl_isone_signaling(leftp1))103{104/* trap if INVALIDTRAP enabled */105if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);106/* make NaN quiet */107Set_invalidflag();108Dbl_set_quiet(leftp1);109}110/*111* is second operand a signaling NaN?112*/113else if (Dbl_is_signalingnan(rightp1))114{115/* trap if INVALIDTRAP enabled */116if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);117/* make NaN quiet */118Set_invalidflag();119Dbl_set_quiet(rightp1);120Dbl_copytoptr(rightp1,rightp2,dstptr);121return(NOEXCEPTION);122}123/*124* return quiet NaN125*/126Dbl_copytoptr(leftp1,leftp2,dstptr);127return(NOEXCEPTION);128}129} /* End left NaN or Infinity processing */130/*131* check second operand for NaN's or infinity132*/133if (Dbl_isinfinity_exponent(rightp1))134{135if (Dbl_iszero_mantissa(rightp1,rightp2))136{137/* return infinity */138Dbl_copytoptr(rightp1,rightp2,dstptr);139return(NOEXCEPTION);140}141/*142* is NaN; signaling or quiet?143*/144if (Dbl_isone_signaling(rightp1))145{146/* trap if INVALIDTRAP enabled */147if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);148/* make NaN quiet */149Set_invalidflag();150Dbl_set_quiet(rightp1);151}152/*153* return quiet NaN154*/155Dbl_copytoptr(rightp1,rightp2,dstptr);156return(NOEXCEPTION);157} /* End right NaN or Infinity processing */158159/* Invariant: Must be dealing with finite numbers */160161/* Compare operands by removing the sign */162Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);163Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);164165/* sign difference selects add or sub operation. */166if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))167{168/* Set the left operand to the larger one by XOR swap *169* First finish the first word using "save" */170Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);171Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);172Dbl_swap_lower(leftp2,rightp2);173result_exponent = Dbl_exponent(leftp1);174}175/* Invariant: left is not smaller than right. */176177if((right_exponent = Dbl_exponent(rightp1)) == 0)178{179/* Denormalized operands. First look for zeroes */180if(Dbl_iszero_mantissa(rightp1,rightp2))181{182/* right is zero */183if(Dbl_iszero_exponentmantissa(leftp1,leftp2))184{185/* Both operands are zeros */186if(Is_rounding_mode(ROUNDMINUS))187{188Dbl_or_signs(leftp1,/*with*/rightp1);189}190else191{192Dbl_and_signs(leftp1,/*with*/rightp1);193}194}195else196{197/* Left is not a zero and must be the result. Trapped198* underflows are signaled if left is denormalized. Result199* is always exact. */200if( (result_exponent == 0) && Is_underflowtrap_enabled() )201{202/* need to normalize results mantissa */203sign_save = Dbl_signextendedsign(leftp1);204Dbl_leftshiftby1(leftp1,leftp2);205Dbl_normalize(leftp1,leftp2,result_exponent);206Dbl_set_sign(leftp1,/*using*/sign_save);207Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);208Dbl_copytoptr(leftp1,leftp2,dstptr);209/* inexact = FALSE */210return(UNDERFLOWEXCEPTION);211}212}213Dbl_copytoptr(leftp1,leftp2,dstptr);214return(NOEXCEPTION);215}216217/* Neither are zeroes */218Dbl_clear_sign(rightp1); /* Exponent is already cleared */219if(result_exponent == 0 )220{221/* Both operands are denormalized. The result must be exact222* and is simply calculated. A sum could become normalized and a223* difference could cancel to a true zero. */224if( (/*signed*/int) save < 0 )225{226Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,227/*into*/resultp1,resultp2);228if(Dbl_iszero_mantissa(resultp1,resultp2))229{230if(Is_rounding_mode(ROUNDMINUS))231{232Dbl_setone_sign(resultp1);233}234else235{236Dbl_setzero_sign(resultp1);237}238Dbl_copytoptr(resultp1,resultp2,dstptr);239return(NOEXCEPTION);240}241}242else243{244Dbl_addition(leftp1,leftp2,rightp1,rightp2,245/*into*/resultp1,resultp2);246if(Dbl_isone_hidden(resultp1))247{248Dbl_copytoptr(resultp1,resultp2,dstptr);249return(NOEXCEPTION);250}251}252if(Is_underflowtrap_enabled())253{254/* need to normalize result */255sign_save = Dbl_signextendedsign(resultp1);256Dbl_leftshiftby1(resultp1,resultp2);257Dbl_normalize(resultp1,resultp2,result_exponent);258Dbl_set_sign(resultp1,/*using*/sign_save);259Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);260Dbl_copytoptr(resultp1,resultp2,dstptr);261/* inexact = FALSE */262return(UNDERFLOWEXCEPTION);263}264Dbl_copytoptr(resultp1,resultp2,dstptr);265return(NOEXCEPTION);266}267right_exponent = 1; /* Set exponent to reflect different bias268* with denomalized numbers. */269}270else271{272Dbl_clear_signexponent_set_hidden(rightp1);273}274Dbl_clear_exponent_set_hidden(leftp1);275diff_exponent = result_exponent - right_exponent;276277/*278* Special case alignment of operands that would force alignment279* beyond the extent of the extension. A further optimization280* could special case this but only reduces the path length for this281* infrequent case.282*/283if(diff_exponent > DBL_THRESHOLD)284{285diff_exponent = DBL_THRESHOLD;286}287288/* Align right operand by shifting to right */289Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,290/*and lower to*/extent);291292/* Treat sum and difference of the operands separately. */293if( (/*signed*/int) save < 0 )294{295/*296* Difference of the two operands. Their can be no overflow. A297* borrow can occur out of the hidden bit and force a post298* normalization phase.299*/300Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,301/*with*/extent,/*into*/resultp1,resultp2);302if(Dbl_iszero_hidden(resultp1))303{304/* Handle normalization */305/* A straight forward algorithm would now shift the result306* and extension left until the hidden bit becomes one. Not307* all of the extension bits need participate in the shift.308* Only the two most significant bits (round and guard) are309* needed. If only a single shift is needed then the guard310* bit becomes a significant low order bit and the extension311* must participate in the rounding. If more than a single312* shift is needed, then all bits to the right of the guard313* bit are zeros, and the guard bit may or may not be zero. */314sign_save = Dbl_signextendedsign(resultp1);315Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);316317/* Need to check for a zero result. The sign and exponent318* fields have already been zeroed. The more efficient test319* of the full object can be used.320*/321if(Dbl_iszero(resultp1,resultp2))322/* Must have been "x-x" or "x+(-x)". */323{324if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);325Dbl_copytoptr(resultp1,resultp2,dstptr);326return(NOEXCEPTION);327}328result_exponent--;329/* Look to see if normalization is finished. */330if(Dbl_isone_hidden(resultp1))331{332if(result_exponent==0)333{334/* Denormalized, exponent should be zero. Left operand *335* was normalized, so extent (guard, round) was zero */336goto underflow;337}338else339{340/* No further normalization is needed. */341Dbl_set_sign(resultp1,/*using*/sign_save);342Ext_leftshiftby1(extent);343goto round;344}345}346347/* Check for denormalized, exponent should be zero. Left *348* operand was normalized, so extent (guard, round) was zero */349if(!(underflowtrap = Is_underflowtrap_enabled()) &&350result_exponent==0) goto underflow;351352/* Shift extension to complete one bit of normalization and353* update exponent. */354Ext_leftshiftby1(extent);355356/* Discover first one bit to determine shift amount. Use a357* modified binary search. We have already shifted the result358* one position right and still not found a one so the remainder359* of the extension must be zero and simplifies rounding. */360/* Scan bytes */361while(Dbl_iszero_hiddenhigh7mantissa(resultp1))362{363Dbl_leftshiftby8(resultp1,resultp2);364if((result_exponent -= 8) <= 0 && !underflowtrap)365goto underflow;366}367/* Now narrow it down to the nibble */368if(Dbl_iszero_hiddenhigh3mantissa(resultp1))369{370/* The lower nibble contains the normalizing one */371Dbl_leftshiftby4(resultp1,resultp2);372if((result_exponent -= 4) <= 0 && !underflowtrap)373goto underflow;374}375/* Select case were first bit is set (already normalized)376* otherwise select the proper shift. */377if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)378{379/* Already normalized */380if(result_exponent <= 0) goto underflow;381Dbl_set_sign(resultp1,/*using*/sign_save);382Dbl_set_exponent(resultp1,/*using*/result_exponent);383Dbl_copytoptr(resultp1,resultp2,dstptr);384return(NOEXCEPTION);385}386Dbl_sethigh4bits(resultp1,/*using*/sign_save);387switch(jumpsize)388{389case 1:390{391Dbl_leftshiftby3(resultp1,resultp2);392result_exponent -= 3;393break;394}395case 2:396case 3:397{398Dbl_leftshiftby2(resultp1,resultp2);399result_exponent -= 2;400break;401}402case 4:403case 5:404case 6:405case 7:406{407Dbl_leftshiftby1(resultp1,resultp2);408result_exponent -= 1;409break;410}411}412if(result_exponent > 0)413{414Dbl_set_exponent(resultp1,/*using*/result_exponent);415Dbl_copytoptr(resultp1,resultp2,dstptr);416return(NOEXCEPTION); /* Sign bit is already set */417}418/* Fixup potential underflows */419underflow:420if(Is_underflowtrap_enabled())421{422Dbl_set_sign(resultp1,sign_save);423Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);424Dbl_copytoptr(resultp1,resultp2,dstptr);425/* inexact = FALSE */426return(UNDERFLOWEXCEPTION);427}428/*429* Since we cannot get an inexact denormalized result,430* we can now return.431*/432Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);433Dbl_clear_signexponent(resultp1);434Dbl_set_sign(resultp1,sign_save);435Dbl_copytoptr(resultp1,resultp2,dstptr);436return(NOEXCEPTION);437} /* end if(hidden...)... */438/* Fall through and round */439} /* end if(save < 0)... */440else441{442/* Add magnitudes */443Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);444if(Dbl_isone_hiddenoverflow(resultp1))445{446/* Prenormalization required. */447Dbl_rightshiftby1_withextent(resultp2,extent,extent);448Dbl_arithrightshiftby1(resultp1,resultp2);449result_exponent++;450} /* end if hiddenoverflow... */451} /* end else ...add magnitudes... */452453/* Round the result. If the extension is all zeros,then the result is454* exact. Otherwise round in the correct direction. No underflow is455* possible. If a postnormalization is necessary, then the mantissa is456* all zeros so no shift is needed. */457round:458if(Ext_isnotzero(extent))459{460inexact = TRUE;461switch(Rounding_mode())462{463case ROUNDNEAREST: /* The default. */464if(Ext_isone_sign(extent))465{466/* at least 1/2 ulp */467if(Ext_isnotzero_lower(extent) ||468Dbl_isone_lowmantissap2(resultp2))469{470/* either exactly half way and odd or more than 1/2ulp */471Dbl_increment(resultp1,resultp2);472}473}474break;475476case ROUNDPLUS:477if(Dbl_iszero_sign(resultp1))478{479/* Round up positive results */480Dbl_increment(resultp1,resultp2);481}482break;483484case ROUNDMINUS:485if(Dbl_isone_sign(resultp1))486{487/* Round down negative results */488Dbl_increment(resultp1,resultp2);489}490491case ROUNDZERO:;492/* truncate is simple */493} /* end switch... */494if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;495}496if(result_exponent == DBL_INFINITY_EXPONENT)497{498/* Overflow */499if(Is_overflowtrap_enabled())500{501Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);502Dbl_copytoptr(resultp1,resultp2,dstptr);503if (inexact)504if (Is_inexacttrap_enabled())505return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);506else Set_inexactflag();507return(OVERFLOWEXCEPTION);508}509else510{511inexact = TRUE;512Set_overflowflag();513Dbl_setoverflow(resultp1,resultp2);514}515}516else Dbl_set_exponent(resultp1,result_exponent);517Dbl_copytoptr(resultp1,resultp2,dstptr);518if(inexact)519if(Is_inexacttrap_enabled())520return(INEXACTEXCEPTION);521else Set_inexactflag();522return(NOEXCEPTION);523}524525526