/*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/sfadd.c $Revision: 1.1 $25*26* Purpose:27* Single_add: add two single precision values.28*29* External Interfaces:30* sgl_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 "sgl_float.h"4344/*45* Single_add: add two single precision values.46*/47int48sgl_fadd(49sgl_floating_point *leftptr,50sgl_floating_point *rightptr,51sgl_floating_point *dstptr,52unsigned int *status)53{54register unsigned int left, right, result, extent;55register unsigned int signless_upper_left, signless_upper_right, save;565758register int result_exponent, right_exponent, diff_exponent;59register int sign_save, jumpsize;60register boolean inexact = FALSE;61register boolean underflowtrap;6263/* Create local copies of the numbers */64left = *leftptr;65right = *rightptr;6667/* A zero "save" helps discover equal operands (for later), *68* and is used in swapping operands (if needed). */69Sgl_xortointp1(left,right,/*to*/save);7071/*72* check first operand for NaN's or infinity73*/74if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)75{76if (Sgl_iszero_mantissa(left))77{78if (Sgl_isnotnan(right))79{80if (Sgl_isinfinity(right) && save!=0)81{82/*83* invalid since operands are opposite signed infinity's84*/85if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);86Set_invalidflag();87Sgl_makequietnan(result);88*dstptr = result;89return(NOEXCEPTION);90}91/*92* return infinity93*/94*dstptr = left;95return(NOEXCEPTION);96}97}98else99{100/*101* is NaN; signaling or quiet?102*/103if (Sgl_isone_signaling(left))104{105/* trap if INVALIDTRAP enabled */106if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);107/* make NaN quiet */108Set_invalidflag();109Sgl_set_quiet(left);110}111/*112* is second operand a signaling NaN?113*/114else if (Sgl_is_signalingnan(right))115{116/* trap if INVALIDTRAP enabled */117if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);118/* make NaN quiet */119Set_invalidflag();120Sgl_set_quiet(right);121*dstptr = right;122return(NOEXCEPTION);123}124/*125* return quiet NaN126*/127*dstptr = left;128return(NOEXCEPTION);129}130} /* End left NaN or Infinity processing */131/*132* check second operand for NaN's or infinity133*/134if (Sgl_isinfinity_exponent(right))135{136if (Sgl_iszero_mantissa(right))137{138/* return infinity */139*dstptr = right;140return(NOEXCEPTION);141}142/*143* is NaN; signaling or quiet?144*/145if (Sgl_isone_signaling(right))146{147/* trap if INVALIDTRAP enabled */148if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);149/* make NaN quiet */150Set_invalidflag();151Sgl_set_quiet(right);152}153/*154* return quiet NaN155*/156*dstptr = right;157return(NOEXCEPTION);158} /* End right NaN or Infinity processing */159160/* Invariant: Must be dealing with finite numbers */161162/* Compare operands by removing the sign */163Sgl_copytoint_exponentmantissa(left,signless_upper_left);164Sgl_copytoint_exponentmantissa(right,signless_upper_right);165166/* sign difference selects add or sub operation. */167if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))168{169/* Set the left operand to the larger one by XOR swap *170* First finish the first word using "save" */171Sgl_xorfromintp1(save,right,/*to*/right);172Sgl_xorfromintp1(save,left,/*to*/left);173result_exponent = Sgl_exponent(left);174}175/* Invariant: left is not smaller than right. */176177if((right_exponent = Sgl_exponent(right)) == 0)178{179/* Denormalized operands. First look for zeroes */180if(Sgl_iszero_mantissa(right))181{182/* right is zero */183if(Sgl_iszero_exponentmantissa(left))184{185/* Both operands are zeros */186if(Is_rounding_mode(ROUNDMINUS))187{188Sgl_or_signs(left,/*with*/right);189}190else191{192Sgl_and_signs(left,/*with*/right);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 = Sgl_signextendedsign(left);204Sgl_leftshiftby1(left);205Sgl_normalize(left,result_exponent);206Sgl_set_sign(left,/*using*/sign_save);207Sgl_setwrapped_exponent(left,result_exponent,unfl);208*dstptr = left;209return(UNDERFLOWEXCEPTION);210}211}212*dstptr = left;213return(NOEXCEPTION);214}215216/* Neither are zeroes */217Sgl_clear_sign(right); /* Exponent is already cleared */218if(result_exponent == 0 )219{220/* Both operands are denormalized. The result must be exact221* and is simply calculated. A sum could become normalized and a222* difference could cancel to a true zero. */223if( (/*signed*/int) save < 0 )224{225Sgl_subtract(left,/*minus*/right,/*into*/result);226if(Sgl_iszero_mantissa(result))227{228if(Is_rounding_mode(ROUNDMINUS))229{230Sgl_setone_sign(result);231}232else233{234Sgl_setzero_sign(result);235}236*dstptr = result;237return(NOEXCEPTION);238}239}240else241{242Sgl_addition(left,right,/*into*/result);243if(Sgl_isone_hidden(result))244{245*dstptr = result;246return(NOEXCEPTION);247}248}249if(Is_underflowtrap_enabled())250{251/* need to normalize result */252sign_save = Sgl_signextendedsign(result);253Sgl_leftshiftby1(result);254Sgl_normalize(result,result_exponent);255Sgl_set_sign(result,/*using*/sign_save);256Sgl_setwrapped_exponent(result,result_exponent,unfl);257*dstptr = result;258return(UNDERFLOWEXCEPTION);259}260*dstptr = result;261return(NOEXCEPTION);262}263right_exponent = 1; /* Set exponent to reflect different bias264* with denomalized numbers. */265}266else267{268Sgl_clear_signexponent_set_hidden(right);269}270Sgl_clear_exponent_set_hidden(left);271diff_exponent = result_exponent - right_exponent;272273/*274* Special case alignment of operands that would force alignment275* beyond the extent of the extension. A further optimization276* could special case this but only reduces the path length for this277* infrequent case.278*/279if(diff_exponent > SGL_THRESHOLD)280{281diff_exponent = SGL_THRESHOLD;282}283284/* Align right operand by shifting to right */285Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,286/*and lower to*/extent);287288/* Treat sum and difference of the operands separately. */289if( (/*signed*/int) save < 0 )290{291/*292* Difference of the two operands. Their can be no overflow. A293* borrow can occur out of the hidden bit and force a post294* normalization phase.295*/296Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);297if(Sgl_iszero_hidden(result))298{299/* Handle normalization */300/* A straightforward algorithm would now shift the result301* and extension left until the hidden bit becomes one. Not302* all of the extension bits need participate in the shift.303* Only the two most significant bits (round and guard) are304* needed. If only a single shift is needed then the guard305* bit becomes a significant low order bit and the extension306* must participate in the rounding. If more than a single307* shift is needed, then all bits to the right of the guard308* bit are zeros, and the guard bit may or may not be zero. */309sign_save = Sgl_signextendedsign(result);310Sgl_leftshiftby1_withextent(result,extent,result);311312/* Need to check for a zero result. The sign and exponent313* fields have already been zeroed. The more efficient test314* of the full object can be used.315*/316if(Sgl_iszero(result))317/* Must have been "x-x" or "x+(-x)". */318{319if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);320*dstptr = result;321return(NOEXCEPTION);322}323result_exponent--;324/* Look to see if normalization is finished. */325if(Sgl_isone_hidden(result))326{327if(result_exponent==0)328{329/* Denormalized, exponent should be zero. Left operand *330* was normalized, so extent (guard, round) was zero */331goto underflow;332}333else334{335/* No further normalization is needed. */336Sgl_set_sign(result,/*using*/sign_save);337Ext_leftshiftby1(extent);338goto round;339}340}341342/* Check for denormalized, exponent should be zero. Left *343* operand was normalized, so extent (guard, round) was zero */344if(!(underflowtrap = Is_underflowtrap_enabled()) &&345result_exponent==0) goto underflow;346347/* Shift extension to complete one bit of normalization and348* update exponent. */349Ext_leftshiftby1(extent);350351/* Discover first one bit to determine shift amount. Use a352* modified binary search. We have already shifted the result353* one position right and still not found a one so the remainder354* of the extension must be zero and simplifies rounding. */355/* Scan bytes */356while(Sgl_iszero_hiddenhigh7mantissa(result))357{358Sgl_leftshiftby8(result);359if((result_exponent -= 8) <= 0 && !underflowtrap)360goto underflow;361}362/* Now narrow it down to the nibble */363if(Sgl_iszero_hiddenhigh3mantissa(result))364{365/* The lower nibble contains the normalizing one */366Sgl_leftshiftby4(result);367if((result_exponent -= 4) <= 0 && !underflowtrap)368goto underflow;369}370/* Select case were first bit is set (already normalized)371* otherwise select the proper shift. */372if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)373{374/* Already normalized */375if(result_exponent <= 0) goto underflow;376Sgl_set_sign(result,/*using*/sign_save);377Sgl_set_exponent(result,/*using*/result_exponent);378*dstptr = result;379return(NOEXCEPTION);380}381Sgl_sethigh4bits(result,/*using*/sign_save);382switch(jumpsize)383{384case 1:385{386Sgl_leftshiftby3(result);387result_exponent -= 3;388break;389}390case 2:391case 3:392{393Sgl_leftshiftby2(result);394result_exponent -= 2;395break;396}397case 4:398case 5:399case 6:400case 7:401{402Sgl_leftshiftby1(result);403result_exponent -= 1;404break;405}406}407if(result_exponent > 0)408{409Sgl_set_exponent(result,/*using*/result_exponent);410*dstptr = result;411return(NOEXCEPTION); /* Sign bit is already set */412}413/* Fixup potential underflows */414underflow:415if(Is_underflowtrap_enabled())416{417Sgl_set_sign(result,sign_save);418Sgl_setwrapped_exponent(result,result_exponent,unfl);419*dstptr = result;420/* inexact = FALSE; */421return(UNDERFLOWEXCEPTION);422}423/*424* Since we cannot get an inexact denormalized result,425* we can now return.426*/427Sgl_right_align(result,/*by*/(1-result_exponent),extent);428Sgl_clear_signexponent(result);429Sgl_set_sign(result,sign_save);430*dstptr = result;431return(NOEXCEPTION);432} /* end if(hidden...)... */433/* Fall through and round */434} /* end if(save < 0)... */435else436{437/* Add magnitudes */438Sgl_addition(left,right,/*to*/result);439if(Sgl_isone_hiddenoverflow(result))440{441/* Prenormalization required. */442Sgl_rightshiftby1_withextent(result,extent,extent);443Sgl_arithrightshiftby1(result);444result_exponent++;445} /* end if hiddenoverflow... */446} /* end else ...add magnitudes... */447448/* Round the result. If the extension is all zeros,then the result is449* exact. Otherwise round in the correct direction. No underflow is450* possible. If a postnormalization is necessary, then the mantissa is451* all zeros so no shift is needed. */452round:453if(Ext_isnotzero(extent))454{455inexact = TRUE;456switch(Rounding_mode())457{458case ROUNDNEAREST: /* The default. */459if(Ext_isone_sign(extent))460{461/* at least 1/2 ulp */462if(Ext_isnotzero_lower(extent) ||463Sgl_isone_lowmantissa(result))464{465/* either exactly half way and odd or more than 1/2ulp */466Sgl_increment(result);467}468}469break;470471case ROUNDPLUS:472if(Sgl_iszero_sign(result))473{474/* Round up positive results */475Sgl_increment(result);476}477break;478479case ROUNDMINUS:480if(Sgl_isone_sign(result))481{482/* Round down negative results */483Sgl_increment(result);484}485486case ROUNDZERO:;487/* truncate is simple */488} /* end switch... */489if(Sgl_isone_hiddenoverflow(result)) result_exponent++;490}491if(result_exponent == SGL_INFINITY_EXPONENT)492{493/* Overflow */494if(Is_overflowtrap_enabled())495{496Sgl_setwrapped_exponent(result,result_exponent,ovfl);497*dstptr = result;498if (inexact)499if (Is_inexacttrap_enabled())500return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);501else Set_inexactflag();502return(OVERFLOWEXCEPTION);503}504else505{506Set_overflowflag();507inexact = TRUE;508Sgl_setoverflow(result);509}510}511else Sgl_set_exponent(result,result_exponent);512*dstptr = result;513if(inexact)514if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);515else Set_inexactflag();516return(NOEXCEPTION);517}518519520