/*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/sfsub.c $Revision: 1.1 $25*26* Purpose:27* Single_subtract: subtract two single precision values.28*29* External Interfaces:30* sgl_fsub(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_subtract: subtract two single precision values.46*/47int48sgl_fsub(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;5657register int result_exponent, right_exponent, diff_exponent;58register int sign_save, jumpsize;59register boolean inexact = FALSE, underflowtrap;6061/* Create local copies of the numbers */62left = *leftptr;63right = *rightptr;6465/* A zero "save" helps discover equal operands (for later), *66* and is used in swapping operands (if needed). */67Sgl_xortointp1(left,right,/*to*/save);6869/*70* check first operand for NaN's or infinity71*/72if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)73{74if (Sgl_iszero_mantissa(left))75{76if (Sgl_isnotnan(right))77{78if (Sgl_isinfinity(right) && save==0)79{80/*81* invalid since operands are same signed infinity's82*/83if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);84Set_invalidflag();85Sgl_makequietnan(result);86*dstptr = result;87return(NOEXCEPTION);88}89/*90* return infinity91*/92*dstptr = left;93return(NOEXCEPTION);94}95}96else97{98/*99* is NaN; signaling or quiet?100*/101if (Sgl_isone_signaling(left))102{103/* trap if INVALIDTRAP enabled */104if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);105/* make NaN quiet */106Set_invalidflag();107Sgl_set_quiet(left);108}109/*110* is second operand a signaling NaN?111*/112else if (Sgl_is_signalingnan(right))113{114/* trap if INVALIDTRAP enabled */115if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);116/* make NaN quiet */117Set_invalidflag();118Sgl_set_quiet(right);119*dstptr = right;120return(NOEXCEPTION);121}122/*123* return quiet NaN124*/125*dstptr = left;126return(NOEXCEPTION);127}128} /* End left NaN or Infinity processing */129/*130* check second operand for NaN's or infinity131*/132if (Sgl_isinfinity_exponent(right))133{134if (Sgl_iszero_mantissa(right))135{136/* return infinity */137Sgl_invert_sign(right);138*dstptr = right;139return(NOEXCEPTION);140}141/*142* is NaN; signaling or quiet?143*/144if (Sgl_isone_signaling(right))145{146/* trap if INVALIDTRAP enabled */147if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);148/* make NaN quiet */149Set_invalidflag();150Sgl_set_quiet(right);151}152/*153* return quiet NaN154*/155*dstptr = right;156return(NOEXCEPTION);157} /* End right NaN or Infinity processing */158159/* Invariant: Must be dealing with finite numbers */160161/* Compare operands by removing the sign */162Sgl_copytoint_exponentmantissa(left,signless_upper_left);163Sgl_copytoint_exponentmantissa(right,signless_upper_right);164165/* sign difference selects sub or add operation. */166if(Sgl_ismagnitudeless(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" */170Sgl_xorfromintp1(save,right,/*to*/right);171Sgl_xorfromintp1(save,left,/*to*/left);172result_exponent = Sgl_exponent(left);173Sgl_invert_sign(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 */186Sgl_invert_sign(right);187if(Is_rounding_mode(ROUNDMINUS))188{189Sgl_or_signs(left,/*with*/right);190}191else192{193Sgl_and_signs(left,/*with*/right);194}195}196else197{198/* Left is not a zero and must be the result. Trapped199* underflows are signaled if left is denormalized. Result200* is always exact. */201if( (result_exponent == 0) && Is_underflowtrap_enabled() )202{203/* need to normalize results mantissa */204sign_save = Sgl_signextendedsign(left);205Sgl_leftshiftby1(left);206Sgl_normalize(left,result_exponent);207Sgl_set_sign(left,/*using*/sign_save);208Sgl_setwrapped_exponent(left,result_exponent,unfl);209*dstptr = left;210/* inexact = FALSE */211return(UNDERFLOWEXCEPTION);212}213}214*dstptr = left;215return(NOEXCEPTION);216}217218/* Neither are zeroes */219Sgl_clear_sign(right); /* Exponent is already cleared */220if(result_exponent == 0 )221{222/* Both operands are denormalized. The result must be exact223* and is simply calculated. A sum could become normalized and a224* difference could cancel to a true zero. */225if( (/*signed*/int) save >= 0 )226{227Sgl_subtract(left,/*minus*/right,/*into*/result);228if(Sgl_iszero_mantissa(result))229{230if(Is_rounding_mode(ROUNDMINUS))231{232Sgl_setone_sign(result);233}234else235{236Sgl_setzero_sign(result);237}238*dstptr = result;239return(NOEXCEPTION);240}241}242else243{244Sgl_addition(left,right,/*into*/result);245if(Sgl_isone_hidden(result))246{247*dstptr = result;248return(NOEXCEPTION);249}250}251if(Is_underflowtrap_enabled())252{253/* need to normalize result */254sign_save = Sgl_signextendedsign(result);255Sgl_leftshiftby1(result);256Sgl_normalize(result,result_exponent);257Sgl_set_sign(result,/*using*/sign_save);258Sgl_setwrapped_exponent(result,result_exponent,unfl);259*dstptr = result;260/* inexact = FALSE */261return(UNDERFLOWEXCEPTION);262}263*dstptr = result;264return(NOEXCEPTION);265}266right_exponent = 1; /* Set exponent to reflect different bias267* with denomalized numbers. */268}269else270{271Sgl_clear_signexponent_set_hidden(right);272}273Sgl_clear_exponent_set_hidden(left);274diff_exponent = result_exponent - right_exponent;275276/*277* Special case alignment of operands that would force alignment278* beyond the extent of the extension. A further optimization279* could special case this but only reduces the path length for this280* infrequent case.281*/282if(diff_exponent > SGL_THRESHOLD)283{284diff_exponent = SGL_THRESHOLD;285}286287/* Align right operand by shifting to right */288Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,289/*and lower to*/extent);290291/* Treat sum and difference of the operands separately. */292if( (/*signed*/int) save >= 0 )293{294/*295* Difference of the two operands. Their can be no overflow. A296* borrow can occur out of the hidden bit and force a post297* normalization phase.298*/299Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);300if(Sgl_iszero_hidden(result))301{302/* Handle normalization */303/* A straightforward algorithm would now shift the result304* and extension left until the hidden bit becomes one. Not305* all of the extension bits need participate in the shift.306* Only the two most significant bits (round and guard) are307* needed. If only a single shift is needed then the guard308* bit becomes a significant low order bit and the extension309* must participate in the rounding. If more than a single310* shift is needed, then all bits to the right of the guard311* bit are zeros, and the guard bit may or may not be zero. */312sign_save = Sgl_signextendedsign(result);313Sgl_leftshiftby1_withextent(result,extent,result);314315/* Need to check for a zero result. The sign and exponent316* fields have already been zeroed. The more efficient test317* of the full object can be used.318*/319if(Sgl_iszero(result))320/* Must have been "x-x" or "x+(-x)". */321{322if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);323*dstptr = result;324return(NOEXCEPTION);325}326result_exponent--;327/* Look to see if normalization is finished. */328if(Sgl_isone_hidden(result))329{330if(result_exponent==0)331{332/* Denormalized, exponent should be zero. Left operand *333* was normalized, so extent (guard, round) was zero */334goto underflow;335}336else337{338/* No further normalization is needed. */339Sgl_set_sign(result,/*using*/sign_save);340Ext_leftshiftby1(extent);341goto round;342}343}344345/* Check for denormalized, exponent should be zero. Left *346* operand was normalized, so extent (guard, round) was zero */347if(!(underflowtrap = Is_underflowtrap_enabled()) &&348result_exponent==0) goto underflow;349350/* Shift extension to complete one bit of normalization and351* update exponent. */352Ext_leftshiftby1(extent);353354/* Discover first one bit to determine shift amount. Use a355* modified binary search. We have already shifted the result356* one position right and still not found a one so the remainder357* of the extension must be zero and simplifies rounding. */358/* Scan bytes */359while(Sgl_iszero_hiddenhigh7mantissa(result))360{361Sgl_leftshiftby8(result);362if((result_exponent -= 8) <= 0 && !underflowtrap)363goto underflow;364}365/* Now narrow it down to the nibble */366if(Sgl_iszero_hiddenhigh3mantissa(result))367{368/* The lower nibble contains the normalizing one */369Sgl_leftshiftby4(result);370if((result_exponent -= 4) <= 0 && !underflowtrap)371goto underflow;372}373/* Select case were first bit is set (already normalized)374* otherwise select the proper shift. */375if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)376{377/* Already normalized */378if(result_exponent <= 0) goto underflow;379Sgl_set_sign(result,/*using*/sign_save);380Sgl_set_exponent(result,/*using*/result_exponent);381*dstptr = result;382return(NOEXCEPTION);383}384Sgl_sethigh4bits(result,/*using*/sign_save);385switch(jumpsize)386{387case 1:388{389Sgl_leftshiftby3(result);390result_exponent -= 3;391break;392}393case 2:394case 3:395{396Sgl_leftshiftby2(result);397result_exponent -= 2;398break;399}400case 4:401case 5:402case 6:403case 7:404{405Sgl_leftshiftby1(result);406result_exponent -= 1;407break;408}409}410if(result_exponent > 0)411{412Sgl_set_exponent(result,/*using*/result_exponent);413*dstptr = result; /* Sign bit is already set */414return(NOEXCEPTION);415}416/* Fixup potential underflows */417underflow:418if(Is_underflowtrap_enabled())419{420Sgl_set_sign(result,sign_save);421Sgl_setwrapped_exponent(result,result_exponent,unfl);422*dstptr = result;423/* inexact = FALSE */424return(UNDERFLOWEXCEPTION);425}426/*427* Since we cannot get an inexact denormalized result,428* we can now return.429*/430Sgl_right_align(result,/*by*/(1-result_exponent),extent);431Sgl_clear_signexponent(result);432Sgl_set_sign(result,sign_save);433*dstptr = result;434return(NOEXCEPTION);435} /* end if(hidden...)... */436/* Fall through and round */437} /* end if(save >= 0)... */438else439{440/* Add magnitudes */441Sgl_addition(left,right,/*to*/result);442if(Sgl_isone_hiddenoverflow(result))443{444/* Prenormalization required. */445Sgl_rightshiftby1_withextent(result,extent,extent);446Sgl_arithrightshiftby1(result);447result_exponent++;448} /* end if hiddenoverflow... */449} /* end else ...sub magnitudes... */450451/* Round the result. If the extension is all zeros,then the result is452* exact. Otherwise round in the correct direction. No underflow is453* possible. If a postnormalization is necessary, then the mantissa is454* all zeros so no shift is needed. */455round:456if(Ext_isnotzero(extent))457{458inexact = TRUE;459switch(Rounding_mode())460{461case ROUNDNEAREST: /* The default. */462if(Ext_isone_sign(extent))463{464/* at least 1/2 ulp */465if(Ext_isnotzero_lower(extent) ||466Sgl_isone_lowmantissa(result))467{468/* either exactly half way and odd or more than 1/2ulp */469Sgl_increment(result);470}471}472break;473474case ROUNDPLUS:475if(Sgl_iszero_sign(result))476{477/* Round up positive results */478Sgl_increment(result);479}480break;481482case ROUNDMINUS:483if(Sgl_isone_sign(result))484{485/* Round down negative results */486Sgl_increment(result);487}488489case ROUNDZERO:;490/* truncate is simple */491} /* end switch... */492if(Sgl_isone_hiddenoverflow(result)) result_exponent++;493}494if(result_exponent == SGL_INFINITY_EXPONENT)495{496/* Overflow */497if(Is_overflowtrap_enabled())498{499Sgl_setwrapped_exponent(result,result_exponent,ovfl);500*dstptr = result;501if (inexact)502if (Is_inexacttrap_enabled())503return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);504else Set_inexactflag();505return(OVERFLOWEXCEPTION);506}507else508{509Set_overflowflag();510inexact = TRUE;511Sgl_setoverflow(result);512}513}514else Sgl_set_exponent(result,result_exponent);515*dstptr = result;516if(inexact)517if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);518else Set_inexactflag();519return(NOEXCEPTION);520}521522523