// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Linux/PA-RISC Project (http://www.parisc-linux.org/)3*4* Floating-point emulation code5* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>6*/7/*8* BEGIN_DESC9*10* File:11* @(#) pa/spmath/sfadd.c $Revision: 1.1 $12*13* Purpose:14* Single_add: add two single precision values.15*16* External Interfaces:17* sgl_fadd(leftptr, rightptr, dstptr, status)18*19* Internal Interfaces:20*21* Theory:22* <<please update with a overview of the operation of this file>>23*24* END_DESC25*/262728#include "float.h"29#include "sgl_float.h"3031/*32* Single_add: add two single precision values.33*/34int35sgl_fadd(36sgl_floating_point *leftptr,37sgl_floating_point *rightptr,38sgl_floating_point *dstptr,39unsigned int *status)40{41register unsigned int left, right, result, extent;42register unsigned int signless_upper_left, signless_upper_right, save;434445register int result_exponent, right_exponent, diff_exponent;46register int sign_save, jumpsize;47register boolean inexact = FALSE;48register boolean underflowtrap;4950/* Create local copies of the numbers */51left = *leftptr;52right = *rightptr;5354/* A zero "save" helps discover equal operands (for later), *55* and is used in swapping operands (if needed). */56Sgl_xortointp1(left,right,/*to*/save);5758/*59* check first operand for NaN's or infinity60*/61if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)62{63if (Sgl_iszero_mantissa(left))64{65if (Sgl_isnotnan(right))66{67if (Sgl_isinfinity(right) && save!=0)68{69/*70* invalid since operands are opposite signed infinity's71*/72if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);73Set_invalidflag();74Sgl_makequietnan(result);75*dstptr = result;76return(NOEXCEPTION);77}78/*79* return infinity80*/81*dstptr = left;82return(NOEXCEPTION);83}84}85else86{87/*88* is NaN; signaling or quiet?89*/90if (Sgl_isone_signaling(left))91{92/* trap if INVALIDTRAP enabled */93if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);94/* make NaN quiet */95Set_invalidflag();96Sgl_set_quiet(left);97}98/*99* is second operand a signaling NaN?100*/101else if (Sgl_is_signalingnan(right))102{103/* trap if INVALIDTRAP enabled */104if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);105/* make NaN quiet */106Set_invalidflag();107Sgl_set_quiet(right);108*dstptr = right;109return(NOEXCEPTION);110}111/*112* return quiet NaN113*/114*dstptr = left;115return(NOEXCEPTION);116}117} /* End left NaN or Infinity processing */118/*119* check second operand for NaN's or infinity120*/121if (Sgl_isinfinity_exponent(right))122{123if (Sgl_iszero_mantissa(right))124{125/* return infinity */126*dstptr = right;127return(NOEXCEPTION);128}129/*130* is NaN; signaling or quiet?131*/132if (Sgl_isone_signaling(right))133{134/* trap if INVALIDTRAP enabled */135if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);136/* make NaN quiet */137Set_invalidflag();138Sgl_set_quiet(right);139}140/*141* return quiet NaN142*/143*dstptr = right;144return(NOEXCEPTION);145} /* End right NaN or Infinity processing */146147/* Invariant: Must be dealing with finite numbers */148149/* Compare operands by removing the sign */150Sgl_copytoint_exponentmantissa(left,signless_upper_left);151Sgl_copytoint_exponentmantissa(right,signless_upper_right);152153/* sign difference selects add or sub operation. */154if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))155{156/* Set the left operand to the larger one by XOR swap *157* First finish the first word using "save" */158Sgl_xorfromintp1(save,right,/*to*/right);159Sgl_xorfromintp1(save,left,/*to*/left);160result_exponent = Sgl_exponent(left);161}162/* Invariant: left is not smaller than right. */163164if((right_exponent = Sgl_exponent(right)) == 0)165{166/* Denormalized operands. First look for zeroes */167if(Sgl_iszero_mantissa(right))168{169/* right is zero */170if(Sgl_iszero_exponentmantissa(left))171{172/* Both operands are zeros */173if(Is_rounding_mode(ROUNDMINUS))174{175Sgl_or_signs(left,/*with*/right);176}177else178{179Sgl_and_signs(left,/*with*/right);180}181}182else183{184/* Left is not a zero and must be the result. Trapped185* underflows are signaled if left is denormalized. Result186* is always exact. */187if( (result_exponent == 0) && Is_underflowtrap_enabled() )188{189/* need to normalize results mantissa */190sign_save = Sgl_signextendedsign(left);191Sgl_leftshiftby1(left);192Sgl_normalize(left,result_exponent);193Sgl_set_sign(left,/*using*/sign_save);194Sgl_setwrapped_exponent(left,result_exponent,unfl);195*dstptr = left;196return(UNDERFLOWEXCEPTION);197}198}199*dstptr = left;200return(NOEXCEPTION);201}202203/* Neither are zeroes */204Sgl_clear_sign(right); /* Exponent is already cleared */205if(result_exponent == 0 )206{207/* Both operands are denormalized. The result must be exact208* and is simply calculated. A sum could become normalized and a209* difference could cancel to a true zero. */210if( (/*signed*/int) save < 0 )211{212Sgl_subtract(left,/*minus*/right,/*into*/result);213if(Sgl_iszero_mantissa(result))214{215if(Is_rounding_mode(ROUNDMINUS))216{217Sgl_setone_sign(result);218}219else220{221Sgl_setzero_sign(result);222}223*dstptr = result;224return(NOEXCEPTION);225}226}227else228{229Sgl_addition(left,right,/*into*/result);230if(Sgl_isone_hidden(result))231{232*dstptr = result;233return(NOEXCEPTION);234}235}236if(Is_underflowtrap_enabled())237{238/* need to normalize result */239sign_save = Sgl_signextendedsign(result);240Sgl_leftshiftby1(result);241Sgl_normalize(result,result_exponent);242Sgl_set_sign(result,/*using*/sign_save);243Sgl_setwrapped_exponent(result,result_exponent,unfl);244*dstptr = result;245return(UNDERFLOWEXCEPTION);246}247*dstptr = result;248return(NOEXCEPTION);249}250right_exponent = 1; /* Set exponent to reflect different bias251* with denormalized numbers. */252}253else254{255Sgl_clear_signexponent_set_hidden(right);256}257Sgl_clear_exponent_set_hidden(left);258diff_exponent = result_exponent - right_exponent;259260/*261* Special case alignment of operands that would force alignment262* beyond the extent of the extension. A further optimization263* could special case this but only reduces the path length for this264* infrequent case.265*/266if(diff_exponent > SGL_THRESHOLD)267{268diff_exponent = SGL_THRESHOLD;269}270271/* Align right operand by shifting to right */272Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,273/*and lower to*/extent);274275/* Treat sum and difference of the operands separately. */276if( (/*signed*/int) save < 0 )277{278/*279* Difference of the two operands. Their can be no overflow. A280* borrow can occur out of the hidden bit and force a post281* normalization phase.282*/283Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);284if(Sgl_iszero_hidden(result))285{286/* Handle normalization */287/* A straightforward algorithm would now shift the result288* and extension left until the hidden bit becomes one. Not289* all of the extension bits need participate in the shift.290* Only the two most significant bits (round and guard) are291* needed. If only a single shift is needed then the guard292* bit becomes a significant low order bit and the extension293* must participate in the rounding. If more than a single294* shift is needed, then all bits to the right of the guard295* bit are zeros, and the guard bit may or may not be zero. */296sign_save = Sgl_signextendedsign(result);297Sgl_leftshiftby1_withextent(result,extent,result);298299/* Need to check for a zero result. The sign and exponent300* fields have already been zeroed. The more efficient test301* of the full object can be used.302*/303if(Sgl_iszero(result))304/* Must have been "x-x" or "x+(-x)". */305{306if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);307*dstptr = result;308return(NOEXCEPTION);309}310result_exponent--;311/* Look to see if normalization is finished. */312if(Sgl_isone_hidden(result))313{314if(result_exponent==0)315{316/* Denormalized, exponent should be zero. Left operand *317* was normalized, so extent (guard, round) was zero */318goto underflow;319}320else321{322/* No further normalization is needed. */323Sgl_set_sign(result,/*using*/sign_save);324Ext_leftshiftby1(extent);325goto round;326}327}328329/* Check for denormalized, exponent should be zero. Left *330* operand was normalized, so extent (guard, round) was zero */331if(!(underflowtrap = Is_underflowtrap_enabled()) &&332result_exponent==0) goto underflow;333334/* Shift extension to complete one bit of normalization and335* update exponent. */336Ext_leftshiftby1(extent);337338/* Discover first one bit to determine shift amount. Use a339* modified binary search. We have already shifted the result340* one position right and still not found a one so the remainder341* of the extension must be zero and simplifies rounding. */342/* Scan bytes */343while(Sgl_iszero_hiddenhigh7mantissa(result))344{345Sgl_leftshiftby8(result);346if((result_exponent -= 8) <= 0 && !underflowtrap)347goto underflow;348}349/* Now narrow it down to the nibble */350if(Sgl_iszero_hiddenhigh3mantissa(result))351{352/* The lower nibble contains the normalizing one */353Sgl_leftshiftby4(result);354if((result_exponent -= 4) <= 0 && !underflowtrap)355goto underflow;356}357/* Select case were first bit is set (already normalized)358* otherwise select the proper shift. */359if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)360{361/* Already normalized */362if(result_exponent <= 0) goto underflow;363Sgl_set_sign(result,/*using*/sign_save);364Sgl_set_exponent(result,/*using*/result_exponent);365*dstptr = result;366return(NOEXCEPTION);367}368Sgl_sethigh4bits(result,/*using*/sign_save);369switch(jumpsize)370{371case 1:372{373Sgl_leftshiftby3(result);374result_exponent -= 3;375break;376}377case 2:378case 3:379{380Sgl_leftshiftby2(result);381result_exponent -= 2;382break;383}384case 4:385case 5:386case 6:387case 7:388{389Sgl_leftshiftby1(result);390result_exponent -= 1;391break;392}393}394if(result_exponent > 0)395{396Sgl_set_exponent(result,/*using*/result_exponent);397*dstptr = result;398return(NOEXCEPTION); /* Sign bit is already set */399}400/* Fixup potential underflows */401underflow:402if(Is_underflowtrap_enabled())403{404Sgl_set_sign(result,sign_save);405Sgl_setwrapped_exponent(result,result_exponent,unfl);406*dstptr = result;407/* inexact = FALSE; */408return(UNDERFLOWEXCEPTION);409}410/*411* Since we cannot get an inexact denormalized result,412* we can now return.413*/414Sgl_right_align(result,/*by*/(1-result_exponent),extent);415Sgl_clear_signexponent(result);416Sgl_set_sign(result,sign_save);417*dstptr = result;418return(NOEXCEPTION);419} /* end if(hidden...)... */420/* Fall through and round */421} /* end if(save < 0)... */422else423{424/* Add magnitudes */425Sgl_addition(left,right,/*to*/result);426if(Sgl_isone_hiddenoverflow(result))427{428/* Prenormalization required. */429Sgl_rightshiftby1_withextent(result,extent,extent);430Sgl_arithrightshiftby1(result);431result_exponent++;432} /* end if hiddenoverflow... */433} /* end else ...add magnitudes... */434435/* Round the result. If the extension is all zeros,then the result is436* exact. Otherwise round in the correct direction. No underflow is437* possible. If a postnormalization is necessary, then the mantissa is438* all zeros so no shift is needed. */439round:440if(Ext_isnotzero(extent))441{442inexact = TRUE;443switch(Rounding_mode())444{445case ROUNDNEAREST: /* The default. */446if(Ext_isone_sign(extent))447{448/* at least 1/2 ulp */449if(Ext_isnotzero_lower(extent) ||450Sgl_isone_lowmantissa(result))451{452/* either exactly half way and odd or more than 1/2ulp */453Sgl_increment(result);454}455}456break;457458case ROUNDPLUS:459if(Sgl_iszero_sign(result))460{461/* Round up positive results */462Sgl_increment(result);463}464break;465466case ROUNDMINUS:467if(Sgl_isone_sign(result))468{469/* Round down negative results */470Sgl_increment(result);471}472473case ROUNDZERO:;474/* truncate is simple */475} /* end switch... */476if(Sgl_isone_hiddenoverflow(result)) result_exponent++;477}478if(result_exponent == SGL_INFINITY_EXPONENT)479{480/* Overflow */481if(Is_overflowtrap_enabled())482{483Sgl_setwrapped_exponent(result,result_exponent,ovfl);484*dstptr = result;485if (inexact)486if (Is_inexacttrap_enabled())487return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);488else Set_inexactflag();489return(OVERFLOWEXCEPTION);490}491else492{493Set_overflowflag();494inexact = TRUE;495Sgl_setoverflow(result);496}497}498else Sgl_set_exponent(result,result_exponent);499*dstptr = result;500if(inexact)501if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);502else Set_inexactflag();503return(NOEXCEPTION);504}505506507