linux/arch/parisc/math-emu/sfadd.c
<<
>>
Prefs
   1/*
   2 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
   3 *
   4 * Floating-point emulation code
   5 *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
   6 *
   7 *    This program is free software; you can redistribute it and/or modify
   8 *    it under the terms of the GNU General Public License as published by
   9 *    the Free Software Foundation; either version 2, or (at your option)
  10 *    any later version.
  11 *
  12 *    This program is distributed in the hope that it will be useful,
  13 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *    GNU General Public License for more details.
  16 *
  17 *    You should have received a copy of the GNU General Public License
  18 *    along with this program; if not, write to the Free Software
  19 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 */
  21/*
  22 * BEGIN_DESC
  23 *
  24 *  File:
  25 *      @(#)    pa/spmath/sfadd.c               $Revision: 1.1 $
  26 *
  27 *  Purpose:
  28 *      Single_add: add two single precision values.
  29 *
  30 *  External Interfaces:
  31 *      sgl_fadd(leftptr, rightptr, dstptr, status)
  32 *
  33 *  Internal Interfaces:
  34 *
  35 *  Theory:
  36 *      <<please update with a overview of the operation of this file>>
  37 *
  38 * END_DESC
  39*/
  40
  41
  42#include "float.h"
  43#include "sgl_float.h"
  44
  45/*
  46 * Single_add: add two single precision values.
  47 */
  48int
  49sgl_fadd(
  50    sgl_floating_point *leftptr,
  51    sgl_floating_point *rightptr,
  52    sgl_floating_point *dstptr,
  53    unsigned int *status)
  54    {
  55    register unsigned int left, right, result, extent;
  56    register unsigned int signless_upper_left, signless_upper_right, save;
  57    
  58    
  59    register int result_exponent, right_exponent, diff_exponent;
  60    register int sign_save, jumpsize;
  61    register boolean inexact = FALSE;
  62    register boolean underflowtrap;
  63        
  64    /* Create local copies of the numbers */
  65    left = *leftptr;
  66    right = *rightptr;
  67
  68    /* A zero "save" helps discover equal operands (for later),  *
  69     * and is used in swapping operands (if needed).             */
  70    Sgl_xortointp1(left,right,/*to*/save);
  71
  72    /*
  73     * check first operand for NaN's or infinity
  74     */
  75    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
  76        {
  77        if (Sgl_iszero_mantissa(left)) 
  78            {
  79            if (Sgl_isnotnan(right)) 
  80                {
  81                if (Sgl_isinfinity(right) && save!=0) 
  82                    {
  83                    /* 
  84                     * invalid since operands are opposite signed infinity's
  85                     */
  86                    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
  87                    Set_invalidflag();
  88                    Sgl_makequietnan(result);
  89                    *dstptr = result;
  90                    return(NOEXCEPTION);
  91                    }
  92                /*
  93                 * return infinity
  94                 */
  95                *dstptr = left;
  96                return(NOEXCEPTION);
  97                }
  98            }
  99        else 
 100            {
 101            /*
 102             * is NaN; signaling or quiet?
 103             */
 104            if (Sgl_isone_signaling(left)) 
 105                {
 106                /* trap if INVALIDTRAP enabled */
 107                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 108                /* make NaN quiet */
 109                Set_invalidflag();
 110                Sgl_set_quiet(left);
 111                }
 112            /* 
 113             * is second operand a signaling NaN? 
 114             */
 115            else if (Sgl_is_signalingnan(right)) 
 116                {
 117                /* trap if INVALIDTRAP enabled */
 118                if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 119                /* make NaN quiet */
 120                Set_invalidflag();
 121                Sgl_set_quiet(right);
 122                *dstptr = right;
 123                return(NOEXCEPTION);
 124                }
 125            /*
 126             * return quiet NaN
 127             */
 128            *dstptr = left;
 129            return(NOEXCEPTION);
 130            }
 131        } /* End left NaN or Infinity processing */
 132    /*
 133     * check second operand for NaN's or infinity
 134     */
 135    if (Sgl_isinfinity_exponent(right)) 
 136        {
 137        if (Sgl_iszero_mantissa(right)) 
 138            {
 139            /* return infinity */
 140            *dstptr = right;
 141            return(NOEXCEPTION);
 142            }
 143        /*
 144         * is NaN; signaling or quiet?
 145         */
 146        if (Sgl_isone_signaling(right)) 
 147            {
 148            /* trap if INVALIDTRAP enabled */
 149            if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
 150            /* make NaN quiet */
 151            Set_invalidflag();
 152            Sgl_set_quiet(right);
 153            }
 154        /*
 155         * return quiet NaN
 156         */
 157        *dstptr = right;
 158        return(NOEXCEPTION);
 159        } /* End right NaN or Infinity processing */
 160
 161    /* Invariant: Must be dealing with finite numbers */
 162
 163    /* Compare operands by removing the sign */
 164    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
 165    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
 166
 167    /* sign difference selects add or sub operation. */
 168    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
 169        {
 170        /* Set the left operand to the larger one by XOR swap *
 171         *  First finish the first word using "save"          */
 172        Sgl_xorfromintp1(save,right,/*to*/right);
 173        Sgl_xorfromintp1(save,left,/*to*/left);
 174        result_exponent = Sgl_exponent(left);
 175        }
 176    /* Invariant:  left is not smaller than right. */ 
 177
 178    if((right_exponent = Sgl_exponent(right)) == 0)
 179        {
 180        /* Denormalized operands.  First look for zeroes */
 181        if(Sgl_iszero_mantissa(right)) 
 182            {
 183            /* right is zero */
 184            if(Sgl_iszero_exponentmantissa(left))
 185                {
 186                /* Both operands are zeros */
 187                if(Is_rounding_mode(ROUNDMINUS))
 188                    {
 189                    Sgl_or_signs(left,/*with*/right);
 190                    }
 191                else
 192                    {
 193                    Sgl_and_signs(left,/*with*/right);
 194                    }
 195                }
 196            else 
 197                {
 198                /* Left is not a zero and must be the result.  Trapped
 199                 * underflows are signaled if left is denormalized.  Result
 200                 * is always exact. */
 201                if( (result_exponent == 0) && Is_underflowtrap_enabled() )
 202                    {
 203                    /* need to normalize results mantissa */
 204                    sign_save = Sgl_signextendedsign(left);
 205                    Sgl_leftshiftby1(left);
 206                    Sgl_normalize(left,result_exponent);
 207                    Sgl_set_sign(left,/*using*/sign_save);
 208                    Sgl_setwrapped_exponent(left,result_exponent,unfl);
 209                    *dstptr = left;
 210                    return(UNDERFLOWEXCEPTION);
 211                    }
 212                }
 213            *dstptr = left;
 214            return(NOEXCEPTION);
 215            }
 216
 217        /* Neither are zeroes */
 218        Sgl_clear_sign(right);  /* Exponent is already cleared */
 219        if(result_exponent == 0 )
 220            {
 221            /* Both operands are denormalized.  The result must be exact
 222             * and is simply calculated.  A sum could become normalized and a
 223             * difference could cancel to a true zero. */
 224            if( (/*signed*/int) save < 0 )
 225                {
 226                Sgl_subtract(left,/*minus*/right,/*into*/result);
 227                if(Sgl_iszero_mantissa(result))
 228                    {
 229                    if(Is_rounding_mode(ROUNDMINUS))
 230                        {
 231                        Sgl_setone_sign(result);
 232                        }
 233                    else
 234                        {
 235                        Sgl_setzero_sign(result);
 236                        }
 237                    *dstptr = result;
 238                    return(NOEXCEPTION);
 239                    }
 240                }
 241            else
 242                {
 243                Sgl_addition(left,right,/*into*/result);
 244                if(Sgl_isone_hidden(result))
 245                    {
 246                    *dstptr = result;
 247                    return(NOEXCEPTION);
 248                    }
 249                }
 250            if(Is_underflowtrap_enabled())
 251                {
 252                /* need to normalize result */
 253                sign_save = Sgl_signextendedsign(result);
 254                Sgl_leftshiftby1(result);
 255                Sgl_normalize(result,result_exponent);
 256                Sgl_set_sign(result,/*using*/sign_save);
 257                Sgl_setwrapped_exponent(result,result_exponent,unfl);
 258                *dstptr = result;
 259                return(UNDERFLOWEXCEPTION);
 260                }
 261            *dstptr = result;
 262            return(NOEXCEPTION);
 263            }
 264        right_exponent = 1;     /* Set exponent to reflect different bias
 265                                 * with denomalized numbers. */
 266        }
 267    else
 268        {
 269        Sgl_clear_signexponent_set_hidden(right);
 270        }
 271    Sgl_clear_exponent_set_hidden(left);
 272    diff_exponent = result_exponent - right_exponent;
 273
 274    /* 
 275     * Special case alignment of operands that would force alignment 
 276     * beyond the extent of the extension.  A further optimization
 277     * could special case this but only reduces the path length for this
 278     * infrequent case.
 279     */
 280    if(diff_exponent > SGL_THRESHOLD)
 281        {
 282        diff_exponent = SGL_THRESHOLD;
 283        }
 284    
 285    /* Align right operand by shifting to right */
 286    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
 287     /*and lower to*/extent);
 288
 289    /* Treat sum and difference of the operands separately. */
 290    if( (/*signed*/int) save < 0 )
 291        {
 292        /*
 293         * Difference of the two operands.  Their can be no overflow.  A
 294         * borrow can occur out of the hidden bit and force a post
 295         * normalization phase.
 296         */
 297        Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
 298        if(Sgl_iszero_hidden(result))
 299            {
 300            /* Handle normalization */
 301            /* A straight foward algorithm would now shift the result
 302             * and extension left until the hidden bit becomes one.  Not
 303             * all of the extension bits need participate in the shift.
 304             * Only the two most significant bits (round and guard) are
 305             * needed.  If only a single shift is needed then the guard
 306             * bit becomes a significant low order bit and the extension
 307             * must participate in the rounding.  If more than a single 
 308             * shift is needed, then all bits to the right of the guard 
 309             * bit are zeros, and the guard bit may or may not be zero. */
 310            sign_save = Sgl_signextendedsign(result);
 311            Sgl_leftshiftby1_withextent(result,extent,result);
 312
 313            /* Need to check for a zero result.  The sign and exponent
 314             * fields have already been zeroed.  The more efficient test
 315             * of the full object can be used.
 316             */
 317            if(Sgl_iszero(result))
 318                /* Must have been "x-x" or "x+(-x)". */
 319                {
 320                if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
 321                *dstptr = result;
 322                return(NOEXCEPTION);
 323                }
 324            result_exponent--;
 325            /* Look to see if normalization is finished. */
 326            if(Sgl_isone_hidden(result))
 327                {
 328                if(result_exponent==0)
 329                    {
 330                    /* Denormalized, exponent should be zero.  Left operand *
 331                     * was normalized, so extent (guard, round) was zero    */
 332                    goto underflow;
 333                    }
 334                else
 335                    {
 336                    /* No further normalization is needed. */
 337                    Sgl_set_sign(result,/*using*/sign_save);
 338                    Ext_leftshiftby1(extent);
 339                    goto round;
 340                    }
 341                }
 342
 343            /* Check for denormalized, exponent should be zero.  Left    * 
 344             * operand was normalized, so extent (guard, round) was zero */
 345            if(!(underflowtrap = Is_underflowtrap_enabled()) &&
 346               result_exponent==0) goto underflow;
 347
 348            /* Shift extension to complete one bit of normalization and
 349             * update exponent. */
 350            Ext_leftshiftby1(extent);
 351
 352            /* Discover first one bit to determine shift amount.  Use a
 353             * modified binary search.  We have already shifted the result
 354             * one position right and still not found a one so the remainder
 355             * of the extension must be zero and simplifies rounding. */
 356            /* Scan bytes */
 357            while(Sgl_iszero_hiddenhigh7mantissa(result))
 358                {
 359                Sgl_leftshiftby8(result);
 360                if((result_exponent -= 8) <= 0  && !underflowtrap)
 361                    goto underflow;
 362                }
 363            /* Now narrow it down to the nibble */
 364            if(Sgl_iszero_hiddenhigh3mantissa(result))
 365                {
 366                /* The lower nibble contains the normalizing one */
 367                Sgl_leftshiftby4(result);
 368                if((result_exponent -= 4) <= 0 && !underflowtrap)
 369                    goto underflow;
 370                }
 371            /* Select case were first bit is set (already normalized)
 372             * otherwise select the proper shift. */
 373            if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
 374                {
 375                /* Already normalized */
 376                if(result_exponent <= 0) goto underflow;
 377                Sgl_set_sign(result,/*using*/sign_save);
 378                Sgl_set_exponent(result,/*using*/result_exponent);
 379                *dstptr = result;
 380                return(NOEXCEPTION);
 381                }
 382            Sgl_sethigh4bits(result,/*using*/sign_save);
 383            switch(jumpsize) 
 384                {
 385                case 1:
 386                    {
 387                    Sgl_leftshiftby3(result);
 388                    result_exponent -= 3;
 389                    break;
 390                    }
 391                case 2:
 392                case 3:
 393                    {
 394                    Sgl_leftshiftby2(result);
 395                    result_exponent -= 2;
 396                    break;
 397                    }
 398                case 4:
 399                case 5:
 400                case 6:
 401                case 7:
 402                    {
 403                    Sgl_leftshiftby1(result);
 404                    result_exponent -= 1;
 405                    break;
 406                    }
 407                }
 408            if(result_exponent > 0) 
 409                {
 410                Sgl_set_exponent(result,/*using*/result_exponent);
 411                *dstptr = result;
 412                return(NOEXCEPTION); /* Sign bit is already set */
 413                }
 414            /* Fixup potential underflows */
 415          underflow:
 416            if(Is_underflowtrap_enabled())
 417                {
 418                Sgl_set_sign(result,sign_save);
 419                Sgl_setwrapped_exponent(result,result_exponent,unfl);
 420                *dstptr = result;
 421                /* inexact = FALSE; */
 422                return(UNDERFLOWEXCEPTION);
 423                }
 424            /* 
 425             * Since we cannot get an inexact denormalized result,
 426             * we can now return.
 427             */
 428            Sgl_right_align(result,/*by*/(1-result_exponent),extent);
 429            Sgl_clear_signexponent(result);
 430            Sgl_set_sign(result,sign_save);
 431            *dstptr = result;
 432            return(NOEXCEPTION);
 433            } /* end if(hidden...)... */
 434        /* Fall through and round */
 435        } /* end if(save < 0)... */
 436    else 
 437        {
 438        /* Add magnitudes */
 439        Sgl_addition(left,right,/*to*/result);
 440        if(Sgl_isone_hiddenoverflow(result))
 441            {
 442            /* Prenormalization required. */
 443            Sgl_rightshiftby1_withextent(result,extent,extent);
 444            Sgl_arithrightshiftby1(result);
 445            result_exponent++;
 446            } /* end if hiddenoverflow... */
 447        } /* end else ...add magnitudes... */
 448    
 449    /* Round the result.  If the extension is all zeros,then the result is
 450     * exact.  Otherwise round in the correct direction.  No underflow is
 451     * possible. If a postnormalization is necessary, then the mantissa is
 452     * all zeros so no shift is needed. */
 453  round:
 454    if(Ext_isnotzero(extent))
 455        {
 456        inexact = TRUE;
 457        switch(Rounding_mode())
 458            {
 459            case ROUNDNEAREST: /* The default. */
 460            if(Ext_isone_sign(extent))
 461                {
 462                /* at least 1/2 ulp */
 463                if(Ext_isnotzero_lower(extent)  ||
 464                  Sgl_isone_lowmantissa(result))
 465                    {
 466                    /* either exactly half way and odd or more than 1/2ulp */
 467                    Sgl_increment(result);
 468                    }
 469                }
 470            break;
 471
 472            case ROUNDPLUS:
 473            if(Sgl_iszero_sign(result))
 474                {
 475                /* Round up positive results */
 476                Sgl_increment(result);
 477                }
 478            break;
 479            
 480            case ROUNDMINUS:
 481            if(Sgl_isone_sign(result))
 482                {
 483                /* Round down negative results */
 484                Sgl_increment(result);
 485                }
 486            
 487            case ROUNDZERO:;
 488            /* truncate is simple */
 489            } /* end switch... */
 490        if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
 491        }
 492    if(result_exponent == SGL_INFINITY_EXPONENT)
 493        {
 494        /* Overflow */
 495        if(Is_overflowtrap_enabled())
 496            {
 497            Sgl_setwrapped_exponent(result,result_exponent,ovfl);
 498            *dstptr = result;
 499            if (inexact)
 500                if (Is_inexacttrap_enabled())
 501                    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
 502                else Set_inexactflag();
 503            return(OVERFLOWEXCEPTION);
 504            }
 505        else
 506            {
 507            Set_overflowflag();
 508            inexact = TRUE;
 509            Sgl_setoverflow(result);
 510            }
 511        }
 512    else Sgl_set_exponent(result,result_exponent);
 513    *dstptr = result;
 514    if(inexact) 
 515        if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
 516        else Set_inexactflag();
 517    return(NOEXCEPTION);
 518    }
 519