// 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/sfsub.c $Revision: 1.1 $12*13* Purpose:14* Single_subtract: subtract two single precision values.15*16* External Interfaces:17* sgl_fsub(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_subtract: subtract two single precision values.33*/34int35sgl_fsub(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;4344register int result_exponent, right_exponent, diff_exponent;45register int sign_save, jumpsize;46register boolean inexact = FALSE, underflowtrap;4748/* Create local copies of the numbers */49left = *leftptr;50right = *rightptr;5152/* A zero "save" helps discover equal operands (for later), *53* and is used in swapping operands (if needed). */54Sgl_xortointp1(left,right,/*to*/save);5556/*57* check first operand for NaN's or infinity58*/59if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)60{61if (Sgl_iszero_mantissa(left))62{63if (Sgl_isnotnan(right))64{65if (Sgl_isinfinity(right) && save==0)66{67/*68* invalid since operands are same signed infinity's69*/70if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);71Set_invalidflag();72Sgl_makequietnan(result);73*dstptr = result;74return(NOEXCEPTION);75}76/*77* return infinity78*/79*dstptr = left;80return(NOEXCEPTION);81}82}83else84{85/*86* is NaN; signaling or quiet?87*/88if (Sgl_isone_signaling(left))89{90/* trap if INVALIDTRAP enabled */91if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);92/* make NaN quiet */93Set_invalidflag();94Sgl_set_quiet(left);95}96/*97* is second operand a signaling NaN?98*/99else if (Sgl_is_signalingnan(right))100{101/* trap if INVALIDTRAP enabled */102if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);103/* make NaN quiet */104Set_invalidflag();105Sgl_set_quiet(right);106*dstptr = right;107return(NOEXCEPTION);108}109/*110* return quiet NaN111*/112*dstptr = left;113return(NOEXCEPTION);114}115} /* End left NaN or Infinity processing */116/*117* check second operand for NaN's or infinity118*/119if (Sgl_isinfinity_exponent(right))120{121if (Sgl_iszero_mantissa(right))122{123/* return infinity */124Sgl_invert_sign(right);125*dstptr = right;126return(NOEXCEPTION);127}128/*129* is NaN; signaling or quiet?130*/131if (Sgl_isone_signaling(right))132{133/* trap if INVALIDTRAP enabled */134if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);135/* make NaN quiet */136Set_invalidflag();137Sgl_set_quiet(right);138}139/*140* return quiet NaN141*/142*dstptr = right;143return(NOEXCEPTION);144} /* End right NaN or Infinity processing */145146/* Invariant: Must be dealing with finite numbers */147148/* Compare operands by removing the sign */149Sgl_copytoint_exponentmantissa(left,signless_upper_left);150Sgl_copytoint_exponentmantissa(right,signless_upper_right);151152/* sign difference selects sub or add operation. */153if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))154{155/* Set the left operand to the larger one by XOR swap *156* First finish the first word using "save" */157Sgl_xorfromintp1(save,right,/*to*/right);158Sgl_xorfromintp1(save,left,/*to*/left);159result_exponent = Sgl_exponent(left);160Sgl_invert_sign(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 */173Sgl_invert_sign(right);174if(Is_rounding_mode(ROUNDMINUS))175{176Sgl_or_signs(left,/*with*/right);177}178else179{180Sgl_and_signs(left,/*with*/right);181}182}183else184{185/* Left is not a zero and must be the result. Trapped186* underflows are signaled if left is denormalized. Result187* is always exact. */188if( (result_exponent == 0) && Is_underflowtrap_enabled() )189{190/* need to normalize results mantissa */191sign_save = Sgl_signextendedsign(left);192Sgl_leftshiftby1(left);193Sgl_normalize(left,result_exponent);194Sgl_set_sign(left,/*using*/sign_save);195Sgl_setwrapped_exponent(left,result_exponent,unfl);196*dstptr = left;197/* inexact = FALSE */198return(UNDERFLOWEXCEPTION);199}200}201*dstptr = left;202return(NOEXCEPTION);203}204205/* Neither are zeroes */206Sgl_clear_sign(right); /* Exponent is already cleared */207if(result_exponent == 0 )208{209/* Both operands are denormalized. The result must be exact210* and is simply calculated. A sum could become normalized and a211* difference could cancel to a true zero. */212if( (/*signed*/int) save >= 0 )213{214Sgl_subtract(left,/*minus*/right,/*into*/result);215if(Sgl_iszero_mantissa(result))216{217if(Is_rounding_mode(ROUNDMINUS))218{219Sgl_setone_sign(result);220}221else222{223Sgl_setzero_sign(result);224}225*dstptr = result;226return(NOEXCEPTION);227}228}229else230{231Sgl_addition(left,right,/*into*/result);232if(Sgl_isone_hidden(result))233{234*dstptr = result;235return(NOEXCEPTION);236}237}238if(Is_underflowtrap_enabled())239{240/* need to normalize result */241sign_save = Sgl_signextendedsign(result);242Sgl_leftshiftby1(result);243Sgl_normalize(result,result_exponent);244Sgl_set_sign(result,/*using*/sign_save);245Sgl_setwrapped_exponent(result,result_exponent,unfl);246*dstptr = result;247/* inexact = FALSE */248return(UNDERFLOWEXCEPTION);249}250*dstptr = result;251return(NOEXCEPTION);252}253right_exponent = 1; /* Set exponent to reflect different bias254* with denormalized numbers. */255}256else257{258Sgl_clear_signexponent_set_hidden(right);259}260Sgl_clear_exponent_set_hidden(left);261diff_exponent = result_exponent - right_exponent;262263/*264* Special case alignment of operands that would force alignment265* beyond the extent of the extension. A further optimization266* could special case this but only reduces the path length for this267* infrequent case.268*/269if(diff_exponent > SGL_THRESHOLD)270{271diff_exponent = SGL_THRESHOLD;272}273274/* Align right operand by shifting to right */275Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,276/*and lower to*/extent);277278/* Treat sum and difference of the operands separately. */279if( (/*signed*/int) save >= 0 )280{281/*282* Difference of the two operands. Their can be no overflow. A283* borrow can occur out of the hidden bit and force a post284* normalization phase.285*/286Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);287if(Sgl_iszero_hidden(result))288{289/* Handle normalization */290/* A straightforward algorithm would now shift the result291* and extension left until the hidden bit becomes one. Not292* all of the extension bits need participate in the shift.293* Only the two most significant bits (round and guard) are294* needed. If only a single shift is needed then the guard295* bit becomes a significant low order bit and the extension296* must participate in the rounding. If more than a single297* shift is needed, then all bits to the right of the guard298* bit are zeros, and the guard bit may or may not be zero. */299sign_save = Sgl_signextendedsign(result);300Sgl_leftshiftby1_withextent(result,extent,result);301302/* Need to check for a zero result. The sign and exponent303* fields have already been zeroed. The more efficient test304* of the full object can be used.305*/306if(Sgl_iszero(result))307/* Must have been "x-x" or "x+(-x)". */308{309if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);310*dstptr = result;311return(NOEXCEPTION);312}313result_exponent--;314/* Look to see if normalization is finished. */315if(Sgl_isone_hidden(result))316{317if(result_exponent==0)318{319/* Denormalized, exponent should be zero. Left operand *320* was normalized, so extent (guard, round) was zero */321goto underflow;322}323else324{325/* No further normalization is needed. */326Sgl_set_sign(result,/*using*/sign_save);327Ext_leftshiftby1(extent);328goto round;329}330}331332/* Check for denormalized, exponent should be zero. Left *333* operand was normalized, so extent (guard, round) was zero */334if(!(underflowtrap = Is_underflowtrap_enabled()) &&335result_exponent==0) goto underflow;336337/* Shift extension to complete one bit of normalization and338* update exponent. */339Ext_leftshiftby1(extent);340341/* Discover first one bit to determine shift amount. Use a342* modified binary search. We have already shifted the result343* one position right and still not found a one so the remainder344* of the extension must be zero and simplifies rounding. */345/* Scan bytes */346while(Sgl_iszero_hiddenhigh7mantissa(result))347{348Sgl_leftshiftby8(result);349if((result_exponent -= 8) <= 0 && !underflowtrap)350goto underflow;351}352/* Now narrow it down to the nibble */353if(Sgl_iszero_hiddenhigh3mantissa(result))354{355/* The lower nibble contains the normalizing one */356Sgl_leftshiftby4(result);357if((result_exponent -= 4) <= 0 && !underflowtrap)358goto underflow;359}360/* Select case were first bit is set (already normalized)361* otherwise select the proper shift. */362if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)363{364/* Already normalized */365if(result_exponent <= 0) goto underflow;366Sgl_set_sign(result,/*using*/sign_save);367Sgl_set_exponent(result,/*using*/result_exponent);368*dstptr = result;369return(NOEXCEPTION);370}371Sgl_sethigh4bits(result,/*using*/sign_save);372switch(jumpsize)373{374case 1:375{376Sgl_leftshiftby3(result);377result_exponent -= 3;378break;379}380case 2:381case 3:382{383Sgl_leftshiftby2(result);384result_exponent -= 2;385break;386}387case 4:388case 5:389case 6:390case 7:391{392Sgl_leftshiftby1(result);393result_exponent -= 1;394break;395}396}397if(result_exponent > 0)398{399Sgl_set_exponent(result,/*using*/result_exponent);400*dstptr = result; /* Sign bit is already set */401return(NOEXCEPTION);402}403/* Fixup potential underflows */404underflow:405if(Is_underflowtrap_enabled())406{407Sgl_set_sign(result,sign_save);408Sgl_setwrapped_exponent(result,result_exponent,unfl);409*dstptr = result;410/* inexact = FALSE */411return(UNDERFLOWEXCEPTION);412}413/*414* Since we cannot get an inexact denormalized result,415* we can now return.416*/417Sgl_right_align(result,/*by*/(1-result_exponent),extent);418Sgl_clear_signexponent(result);419Sgl_set_sign(result,sign_save);420*dstptr = result;421return(NOEXCEPTION);422} /* end if(hidden...)... */423/* Fall through and round */424} /* end if(save >= 0)... */425else426{427/* Add magnitudes */428Sgl_addition(left,right,/*to*/result);429if(Sgl_isone_hiddenoverflow(result))430{431/* Prenormalization required. */432Sgl_rightshiftby1_withextent(result,extent,extent);433Sgl_arithrightshiftby1(result);434result_exponent++;435} /* end if hiddenoverflow... */436} /* end else ...sub magnitudes... */437438/* Round the result. If the extension is all zeros,then the result is439* exact. Otherwise round in the correct direction. No underflow is440* possible. If a postnormalization is necessary, then the mantissa is441* all zeros so no shift is needed. */442round:443if(Ext_isnotzero(extent))444{445inexact = TRUE;446switch(Rounding_mode())447{448case ROUNDNEAREST: /* The default. */449if(Ext_isone_sign(extent))450{451/* at least 1/2 ulp */452if(Ext_isnotzero_lower(extent) ||453Sgl_isone_lowmantissa(result))454{455/* either exactly half way and odd or more than 1/2ulp */456Sgl_increment(result);457}458}459break;460461case ROUNDPLUS:462if(Sgl_iszero_sign(result))463{464/* Round up positive results */465Sgl_increment(result);466}467break;468469case ROUNDMINUS:470if(Sgl_isone_sign(result))471{472/* Round down negative results */473Sgl_increment(result);474}475476case ROUNDZERO:;477/* truncate is simple */478} /* end switch... */479if(Sgl_isone_hiddenoverflow(result)) result_exponent++;480}481if(result_exponent == SGL_INFINITY_EXPONENT)482{483/* Overflow */484if(Is_overflowtrap_enabled())485{486Sgl_setwrapped_exponent(result,result_exponent,ovfl);487*dstptr = result;488if (inexact)489if (Is_inexacttrap_enabled())490return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);491else Set_inexactflag();492return(OVERFLOWEXCEPTION);493}494else495{496Set_overflowflag();497inexact = TRUE;498Sgl_setoverflow(result);499}500}501else Sgl_set_exponent(result,result_exponent);502*dstptr = result;503if(inexact)504if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);505else Set_inexactflag();506return(NOEXCEPTION);507}508509510