162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Floating-point emulation code
662306a36Sopenharmony_ci *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * BEGIN_DESC
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  File:
1262306a36Sopenharmony_ci *	@(#)	pa/spmath/sfadd.c		$Revision: 1.1 $
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Purpose:
1562306a36Sopenharmony_ci *	Single_add: add two single precision values.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  External Interfaces:
1862306a36Sopenharmony_ci *	sgl_fadd(leftptr, rightptr, dstptr, status)
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  Internal Interfaces:
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *  Theory:
2362306a36Sopenharmony_ci *	<<please update with a overview of the operation of this file>>
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * END_DESC
2662306a36Sopenharmony_ci*/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "float.h"
3062306a36Sopenharmony_ci#include "sgl_float.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Single_add: add two single precision values.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ciint
3662306a36Sopenharmony_cisgl_fadd(
3762306a36Sopenharmony_ci    sgl_floating_point *leftptr,
3862306a36Sopenharmony_ci    sgl_floating_point *rightptr,
3962306a36Sopenharmony_ci    sgl_floating_point *dstptr,
4062306a36Sopenharmony_ci    unsigned int *status)
4162306a36Sopenharmony_ci    {
4262306a36Sopenharmony_ci    register unsigned int left, right, result, extent;
4362306a36Sopenharmony_ci    register unsigned int signless_upper_left, signless_upper_right, save;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci    register int result_exponent, right_exponent, diff_exponent;
4762306a36Sopenharmony_ci    register int sign_save, jumpsize;
4862306a36Sopenharmony_ci    register boolean inexact = FALSE;
4962306a36Sopenharmony_ci    register boolean underflowtrap;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci    /* Create local copies of the numbers */
5262306a36Sopenharmony_ci    left = *leftptr;
5362306a36Sopenharmony_ci    right = *rightptr;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci    /* A zero "save" helps discover equal operands (for later),  *
5662306a36Sopenharmony_ci     * and is used in swapping operands (if needed).             */
5762306a36Sopenharmony_ci    Sgl_xortointp1(left,right,/*to*/save);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci    /*
6062306a36Sopenharmony_ci     * check first operand for NaN's or infinity
6162306a36Sopenharmony_ci     */
6262306a36Sopenharmony_ci    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
6362306a36Sopenharmony_ci	{
6462306a36Sopenharmony_ci	if (Sgl_iszero_mantissa(left))
6562306a36Sopenharmony_ci	    {
6662306a36Sopenharmony_ci	    if (Sgl_isnotnan(right))
6762306a36Sopenharmony_ci		{
6862306a36Sopenharmony_ci		if (Sgl_isinfinity(right) && save!=0)
6962306a36Sopenharmony_ci		    {
7062306a36Sopenharmony_ci		    /*
7162306a36Sopenharmony_ci		     * invalid since operands are opposite signed infinity's
7262306a36Sopenharmony_ci		     */
7362306a36Sopenharmony_ci		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
7462306a36Sopenharmony_ci                    Set_invalidflag();
7562306a36Sopenharmony_ci                    Sgl_makequietnan(result);
7662306a36Sopenharmony_ci		    *dstptr = result;
7762306a36Sopenharmony_ci		    return(NOEXCEPTION);
7862306a36Sopenharmony_ci		    }
7962306a36Sopenharmony_ci		/*
8062306a36Sopenharmony_ci	 	 * return infinity
8162306a36Sopenharmony_ci	 	 */
8262306a36Sopenharmony_ci		*dstptr = left;
8362306a36Sopenharmony_ci		return(NOEXCEPTION);
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci	    }
8662306a36Sopenharmony_ci	else
8762306a36Sopenharmony_ci	    {
8862306a36Sopenharmony_ci            /*
8962306a36Sopenharmony_ci             * is NaN; signaling or quiet?
9062306a36Sopenharmony_ci             */
9162306a36Sopenharmony_ci            if (Sgl_isone_signaling(left))
9262306a36Sopenharmony_ci		{
9362306a36Sopenharmony_ci               	/* trap if INVALIDTRAP enabled */
9462306a36Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
9562306a36Sopenharmony_ci        	/* make NaN quiet */
9662306a36Sopenharmony_ci        	Set_invalidflag();
9762306a36Sopenharmony_ci        	Sgl_set_quiet(left);
9862306a36Sopenharmony_ci        	}
9962306a36Sopenharmony_ci	    /*
10062306a36Sopenharmony_ci	     * is second operand a signaling NaN?
10162306a36Sopenharmony_ci	     */
10262306a36Sopenharmony_ci	    else if (Sgl_is_signalingnan(right))
10362306a36Sopenharmony_ci		{
10462306a36Sopenharmony_ci        	/* trap if INVALIDTRAP enabled */
10562306a36Sopenharmony_ci               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
10662306a36Sopenharmony_ci		/* make NaN quiet */
10762306a36Sopenharmony_ci		Set_invalidflag();
10862306a36Sopenharmony_ci		Sgl_set_quiet(right);
10962306a36Sopenharmony_ci		*dstptr = right;
11062306a36Sopenharmony_ci		return(NOEXCEPTION);
11162306a36Sopenharmony_ci		}
11262306a36Sopenharmony_ci	    /*
11362306a36Sopenharmony_ci 	     * return quiet NaN
11462306a36Sopenharmony_ci 	     */
11562306a36Sopenharmony_ci 	    *dstptr = left;
11662306a36Sopenharmony_ci 	    return(NOEXCEPTION);
11762306a36Sopenharmony_ci	    }
11862306a36Sopenharmony_ci	} /* End left NaN or Infinity processing */
11962306a36Sopenharmony_ci    /*
12062306a36Sopenharmony_ci     * check second operand for NaN's or infinity
12162306a36Sopenharmony_ci     */
12262306a36Sopenharmony_ci    if (Sgl_isinfinity_exponent(right))
12362306a36Sopenharmony_ci	{
12462306a36Sopenharmony_ci	if (Sgl_iszero_mantissa(right))
12562306a36Sopenharmony_ci	    {
12662306a36Sopenharmony_ci	    /* return infinity */
12762306a36Sopenharmony_ci	    *dstptr = right;
12862306a36Sopenharmony_ci	    return(NOEXCEPTION);
12962306a36Sopenharmony_ci	    }
13062306a36Sopenharmony_ci        /*
13162306a36Sopenharmony_ci         * is NaN; signaling or quiet?
13262306a36Sopenharmony_ci         */
13362306a36Sopenharmony_ci        if (Sgl_isone_signaling(right))
13462306a36Sopenharmony_ci	    {
13562306a36Sopenharmony_ci            /* trap if INVALIDTRAP enabled */
13662306a36Sopenharmony_ci	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
13762306a36Sopenharmony_ci	    /* make NaN quiet */
13862306a36Sopenharmony_ci	    Set_invalidflag();
13962306a36Sopenharmony_ci	    Sgl_set_quiet(right);
14062306a36Sopenharmony_ci	    }
14162306a36Sopenharmony_ci	/*
14262306a36Sopenharmony_ci	 * return quiet NaN
14362306a36Sopenharmony_ci 	 */
14462306a36Sopenharmony_ci	*dstptr = right;
14562306a36Sopenharmony_ci	return(NOEXCEPTION);
14662306a36Sopenharmony_ci    	} /* End right NaN or Infinity processing */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    /* Invariant: Must be dealing with finite numbers */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci    /* Compare operands by removing the sign */
15162306a36Sopenharmony_ci    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
15262306a36Sopenharmony_ci    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci    /* sign difference selects add or sub operation. */
15562306a36Sopenharmony_ci    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
15662306a36Sopenharmony_ci	{
15762306a36Sopenharmony_ci	/* Set the left operand to the larger one by XOR swap *
15862306a36Sopenharmony_ci	 *  First finish the first word using "save"          */
15962306a36Sopenharmony_ci	Sgl_xorfromintp1(save,right,/*to*/right);
16062306a36Sopenharmony_ci	Sgl_xorfromintp1(save,left,/*to*/left);
16162306a36Sopenharmony_ci	result_exponent = Sgl_exponent(left);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci    /* Invariant:  left is not smaller than right. */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci    if((right_exponent = Sgl_exponent(right)) == 0)
16662306a36Sopenharmony_ci        {
16762306a36Sopenharmony_ci	/* Denormalized operands.  First look for zeroes */
16862306a36Sopenharmony_ci	if(Sgl_iszero_mantissa(right))
16962306a36Sopenharmony_ci	    {
17062306a36Sopenharmony_ci	    /* right is zero */
17162306a36Sopenharmony_ci	    if(Sgl_iszero_exponentmantissa(left))
17262306a36Sopenharmony_ci		{
17362306a36Sopenharmony_ci		/* Both operands are zeros */
17462306a36Sopenharmony_ci		if(Is_rounding_mode(ROUNDMINUS))
17562306a36Sopenharmony_ci		    {
17662306a36Sopenharmony_ci		    Sgl_or_signs(left,/*with*/right);
17762306a36Sopenharmony_ci		    }
17862306a36Sopenharmony_ci		else
17962306a36Sopenharmony_ci		    {
18062306a36Sopenharmony_ci		    Sgl_and_signs(left,/*with*/right);
18162306a36Sopenharmony_ci		    }
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci	    else
18462306a36Sopenharmony_ci		{
18562306a36Sopenharmony_ci		/* Left is not a zero and must be the result.  Trapped
18662306a36Sopenharmony_ci		 * underflows are signaled if left is denormalized.  Result
18762306a36Sopenharmony_ci		 * is always exact. */
18862306a36Sopenharmony_ci		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
18962306a36Sopenharmony_ci		    {
19062306a36Sopenharmony_ci		    /* need to normalize results mantissa */
19162306a36Sopenharmony_ci	    	    sign_save = Sgl_signextendedsign(left);
19262306a36Sopenharmony_ci		    Sgl_leftshiftby1(left);
19362306a36Sopenharmony_ci		    Sgl_normalize(left,result_exponent);
19462306a36Sopenharmony_ci		    Sgl_set_sign(left,/*using*/sign_save);
19562306a36Sopenharmony_ci		    Sgl_setwrapped_exponent(left,result_exponent,unfl);
19662306a36Sopenharmony_ci		    *dstptr = left;
19762306a36Sopenharmony_ci		    return(UNDERFLOWEXCEPTION);
19862306a36Sopenharmony_ci		    }
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	    *dstptr = left;
20162306a36Sopenharmony_ci	    return(NOEXCEPTION);
20262306a36Sopenharmony_ci	    }
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Neither are zeroes */
20562306a36Sopenharmony_ci	Sgl_clear_sign(right);	/* Exponent is already cleared */
20662306a36Sopenharmony_ci	if(result_exponent == 0 )
20762306a36Sopenharmony_ci	    {
20862306a36Sopenharmony_ci	    /* Both operands are denormalized.  The result must be exact
20962306a36Sopenharmony_ci	     * and is simply calculated.  A sum could become normalized and a
21062306a36Sopenharmony_ci	     * difference could cancel to a true zero. */
21162306a36Sopenharmony_ci	    if( (/*signed*/int) save < 0 )
21262306a36Sopenharmony_ci		{
21362306a36Sopenharmony_ci		Sgl_subtract(left,/*minus*/right,/*into*/result);
21462306a36Sopenharmony_ci		if(Sgl_iszero_mantissa(result))
21562306a36Sopenharmony_ci		    {
21662306a36Sopenharmony_ci		    if(Is_rounding_mode(ROUNDMINUS))
21762306a36Sopenharmony_ci			{
21862306a36Sopenharmony_ci			Sgl_setone_sign(result);
21962306a36Sopenharmony_ci			}
22062306a36Sopenharmony_ci		    else
22162306a36Sopenharmony_ci			{
22262306a36Sopenharmony_ci			Sgl_setzero_sign(result);
22362306a36Sopenharmony_ci			}
22462306a36Sopenharmony_ci		    *dstptr = result;
22562306a36Sopenharmony_ci		    return(NOEXCEPTION);
22662306a36Sopenharmony_ci		    }
22762306a36Sopenharmony_ci		}
22862306a36Sopenharmony_ci	    else
22962306a36Sopenharmony_ci		{
23062306a36Sopenharmony_ci		Sgl_addition(left,right,/*into*/result);
23162306a36Sopenharmony_ci		if(Sgl_isone_hidden(result))
23262306a36Sopenharmony_ci		    {
23362306a36Sopenharmony_ci		    *dstptr = result;
23462306a36Sopenharmony_ci		    return(NOEXCEPTION);
23562306a36Sopenharmony_ci		    }
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci	    if(Is_underflowtrap_enabled())
23862306a36Sopenharmony_ci		{
23962306a36Sopenharmony_ci		/* need to normalize result */
24062306a36Sopenharmony_ci	    	sign_save = Sgl_signextendedsign(result);
24162306a36Sopenharmony_ci		Sgl_leftshiftby1(result);
24262306a36Sopenharmony_ci		Sgl_normalize(result,result_exponent);
24362306a36Sopenharmony_ci		Sgl_set_sign(result,/*using*/sign_save);
24462306a36Sopenharmony_ci                Sgl_setwrapped_exponent(result,result_exponent,unfl);
24562306a36Sopenharmony_ci		*dstptr = result;
24662306a36Sopenharmony_ci		return(UNDERFLOWEXCEPTION);
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	    *dstptr = result;
24962306a36Sopenharmony_ci	    return(NOEXCEPTION);
25062306a36Sopenharmony_ci	    }
25162306a36Sopenharmony_ci	right_exponent = 1;	/* Set exponent to reflect different bias
25262306a36Sopenharmony_ci				 * with denormalized numbers. */
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci    else
25562306a36Sopenharmony_ci	{
25662306a36Sopenharmony_ci	Sgl_clear_signexponent_set_hidden(right);
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci    Sgl_clear_exponent_set_hidden(left);
25962306a36Sopenharmony_ci    diff_exponent = result_exponent - right_exponent;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci    /*
26262306a36Sopenharmony_ci     * Special case alignment of operands that would force alignment
26362306a36Sopenharmony_ci     * beyond the extent of the extension.  A further optimization
26462306a36Sopenharmony_ci     * could special case this but only reduces the path length for this
26562306a36Sopenharmony_ci     * infrequent case.
26662306a36Sopenharmony_ci     */
26762306a36Sopenharmony_ci    if(diff_exponent > SGL_THRESHOLD)
26862306a36Sopenharmony_ci	{
26962306a36Sopenharmony_ci	diff_exponent = SGL_THRESHOLD;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci    /* Align right operand by shifting to right */
27362306a36Sopenharmony_ci    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
27462306a36Sopenharmony_ci     /*and lower to*/extent);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci    /* Treat sum and difference of the operands separately. */
27762306a36Sopenharmony_ci    if( (/*signed*/int) save < 0 )
27862306a36Sopenharmony_ci	{
27962306a36Sopenharmony_ci	/*
28062306a36Sopenharmony_ci	 * Difference of the two operands.  Their can be no overflow.  A
28162306a36Sopenharmony_ci	 * borrow can occur out of the hidden bit and force a post
28262306a36Sopenharmony_ci	 * normalization phase.
28362306a36Sopenharmony_ci	 */
28462306a36Sopenharmony_ci	Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
28562306a36Sopenharmony_ci	if(Sgl_iszero_hidden(result))
28662306a36Sopenharmony_ci	    {
28762306a36Sopenharmony_ci	    /* Handle normalization */
28862306a36Sopenharmony_ci	    /* A straightforward algorithm would now shift the result
28962306a36Sopenharmony_ci	     * and extension left until the hidden bit becomes one.  Not
29062306a36Sopenharmony_ci	     * all of the extension bits need participate in the shift.
29162306a36Sopenharmony_ci	     * Only the two most significant bits (round and guard) are
29262306a36Sopenharmony_ci	     * needed.  If only a single shift is needed then the guard
29362306a36Sopenharmony_ci	     * bit becomes a significant low order bit and the extension
29462306a36Sopenharmony_ci	     * must participate in the rounding.  If more than a single
29562306a36Sopenharmony_ci	     * shift is needed, then all bits to the right of the guard
29662306a36Sopenharmony_ci	     * bit are zeros, and the guard bit may or may not be zero. */
29762306a36Sopenharmony_ci	    sign_save = Sgl_signextendedsign(result);
29862306a36Sopenharmony_ci            Sgl_leftshiftby1_withextent(result,extent,result);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci            /* Need to check for a zero result.  The sign and exponent
30162306a36Sopenharmony_ci	     * fields have already been zeroed.  The more efficient test
30262306a36Sopenharmony_ci	     * of the full object can be used.
30362306a36Sopenharmony_ci	     */
30462306a36Sopenharmony_ci    	    if(Sgl_iszero(result))
30562306a36Sopenharmony_ci		/* Must have been "x-x" or "x+(-x)". */
30662306a36Sopenharmony_ci		{
30762306a36Sopenharmony_ci		if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
30862306a36Sopenharmony_ci		*dstptr = result;
30962306a36Sopenharmony_ci		return(NOEXCEPTION);
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	    result_exponent--;
31262306a36Sopenharmony_ci	    /* Look to see if normalization is finished. */
31362306a36Sopenharmony_ci	    if(Sgl_isone_hidden(result))
31462306a36Sopenharmony_ci		{
31562306a36Sopenharmony_ci		if(result_exponent==0)
31662306a36Sopenharmony_ci		    {
31762306a36Sopenharmony_ci		    /* Denormalized, exponent should be zero.  Left operand *
31862306a36Sopenharmony_ci 		     * was normalized, so extent (guard, round) was zero    */
31962306a36Sopenharmony_ci		    goto underflow;
32062306a36Sopenharmony_ci		    }
32162306a36Sopenharmony_ci		else
32262306a36Sopenharmony_ci		    {
32362306a36Sopenharmony_ci		    /* No further normalization is needed. */
32462306a36Sopenharmony_ci		    Sgl_set_sign(result,/*using*/sign_save);
32562306a36Sopenharmony_ci	    	    Ext_leftshiftby1(extent);
32662306a36Sopenharmony_ci		    goto round;
32762306a36Sopenharmony_ci		    }
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	    /* Check for denormalized, exponent should be zero.  Left    *
33162306a36Sopenharmony_ci	     * operand was normalized, so extent (guard, round) was zero */
33262306a36Sopenharmony_ci	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
33362306a36Sopenharmony_ci	       result_exponent==0) goto underflow;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	    /* Shift extension to complete one bit of normalization and
33662306a36Sopenharmony_ci	     * update exponent. */
33762306a36Sopenharmony_ci	    Ext_leftshiftby1(extent);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	    /* Discover first one bit to determine shift amount.  Use a
34062306a36Sopenharmony_ci	     * modified binary search.  We have already shifted the result
34162306a36Sopenharmony_ci	     * one position right and still not found a one so the remainder
34262306a36Sopenharmony_ci	     * of the extension must be zero and simplifies rounding. */
34362306a36Sopenharmony_ci	    /* Scan bytes */
34462306a36Sopenharmony_ci	    while(Sgl_iszero_hiddenhigh7mantissa(result))
34562306a36Sopenharmony_ci		{
34662306a36Sopenharmony_ci		Sgl_leftshiftby8(result);
34762306a36Sopenharmony_ci		if((result_exponent -= 8) <= 0  && !underflowtrap)
34862306a36Sopenharmony_ci		    goto underflow;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci	    /* Now narrow it down to the nibble */
35162306a36Sopenharmony_ci	    if(Sgl_iszero_hiddenhigh3mantissa(result))
35262306a36Sopenharmony_ci		{
35362306a36Sopenharmony_ci		/* The lower nibble contains the normalizing one */
35462306a36Sopenharmony_ci		Sgl_leftshiftby4(result);
35562306a36Sopenharmony_ci		if((result_exponent -= 4) <= 0 && !underflowtrap)
35662306a36Sopenharmony_ci		    goto underflow;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	    /* Select case were first bit is set (already normalized)
35962306a36Sopenharmony_ci	     * otherwise select the proper shift. */
36062306a36Sopenharmony_ci	    if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
36162306a36Sopenharmony_ci		{
36262306a36Sopenharmony_ci		/* Already normalized */
36362306a36Sopenharmony_ci		if(result_exponent <= 0) goto underflow;
36462306a36Sopenharmony_ci		Sgl_set_sign(result,/*using*/sign_save);
36562306a36Sopenharmony_ci		Sgl_set_exponent(result,/*using*/result_exponent);
36662306a36Sopenharmony_ci		*dstptr = result;
36762306a36Sopenharmony_ci		return(NOEXCEPTION);
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci	    Sgl_sethigh4bits(result,/*using*/sign_save);
37062306a36Sopenharmony_ci	    switch(jumpsize)
37162306a36Sopenharmony_ci		{
37262306a36Sopenharmony_ci		case 1:
37362306a36Sopenharmony_ci		    {
37462306a36Sopenharmony_ci		    Sgl_leftshiftby3(result);
37562306a36Sopenharmony_ci		    result_exponent -= 3;
37662306a36Sopenharmony_ci		    break;
37762306a36Sopenharmony_ci		    }
37862306a36Sopenharmony_ci		case 2:
37962306a36Sopenharmony_ci		case 3:
38062306a36Sopenharmony_ci		    {
38162306a36Sopenharmony_ci		    Sgl_leftshiftby2(result);
38262306a36Sopenharmony_ci		    result_exponent -= 2;
38362306a36Sopenharmony_ci		    break;
38462306a36Sopenharmony_ci		    }
38562306a36Sopenharmony_ci		case 4:
38662306a36Sopenharmony_ci		case 5:
38762306a36Sopenharmony_ci		case 6:
38862306a36Sopenharmony_ci		case 7:
38962306a36Sopenharmony_ci		    {
39062306a36Sopenharmony_ci		    Sgl_leftshiftby1(result);
39162306a36Sopenharmony_ci		    result_exponent -= 1;
39262306a36Sopenharmony_ci		    break;
39362306a36Sopenharmony_ci		    }
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci	    if(result_exponent > 0)
39662306a36Sopenharmony_ci		{
39762306a36Sopenharmony_ci		Sgl_set_exponent(result,/*using*/result_exponent);
39862306a36Sopenharmony_ci		*dstptr = result;
39962306a36Sopenharmony_ci		return(NOEXCEPTION); /* Sign bit is already set */
40062306a36Sopenharmony_ci		}
40162306a36Sopenharmony_ci	    /* Fixup potential underflows */
40262306a36Sopenharmony_ci	  underflow:
40362306a36Sopenharmony_ci	    if(Is_underflowtrap_enabled())
40462306a36Sopenharmony_ci		{
40562306a36Sopenharmony_ci		Sgl_set_sign(result,sign_save);
40662306a36Sopenharmony_ci                Sgl_setwrapped_exponent(result,result_exponent,unfl);
40762306a36Sopenharmony_ci		*dstptr = result;
40862306a36Sopenharmony_ci		/* inexact = FALSE; */
40962306a36Sopenharmony_ci		return(UNDERFLOWEXCEPTION);
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci	    /*
41262306a36Sopenharmony_ci	     * Since we cannot get an inexact denormalized result,
41362306a36Sopenharmony_ci	     * we can now return.
41462306a36Sopenharmony_ci	     */
41562306a36Sopenharmony_ci	    Sgl_right_align(result,/*by*/(1-result_exponent),extent);
41662306a36Sopenharmony_ci	    Sgl_clear_signexponent(result);
41762306a36Sopenharmony_ci	    Sgl_set_sign(result,sign_save);
41862306a36Sopenharmony_ci	    *dstptr = result;
41962306a36Sopenharmony_ci	    return(NOEXCEPTION);
42062306a36Sopenharmony_ci	    } /* end if(hidden...)... */
42162306a36Sopenharmony_ci	/* Fall through and round */
42262306a36Sopenharmony_ci	} /* end if(save < 0)... */
42362306a36Sopenharmony_ci    else
42462306a36Sopenharmony_ci	{
42562306a36Sopenharmony_ci	/* Add magnitudes */
42662306a36Sopenharmony_ci	Sgl_addition(left,right,/*to*/result);
42762306a36Sopenharmony_ci	if(Sgl_isone_hiddenoverflow(result))
42862306a36Sopenharmony_ci	    {
42962306a36Sopenharmony_ci	    /* Prenormalization required. */
43062306a36Sopenharmony_ci	    Sgl_rightshiftby1_withextent(result,extent,extent);
43162306a36Sopenharmony_ci	    Sgl_arithrightshiftby1(result);
43262306a36Sopenharmony_ci	    result_exponent++;
43362306a36Sopenharmony_ci	    } /* end if hiddenoverflow... */
43462306a36Sopenharmony_ci	} /* end else ...add magnitudes... */
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci    /* Round the result.  If the extension is all zeros,then the result is
43762306a36Sopenharmony_ci     * exact.  Otherwise round in the correct direction.  No underflow is
43862306a36Sopenharmony_ci     * possible. If a postnormalization is necessary, then the mantissa is
43962306a36Sopenharmony_ci     * all zeros so no shift is needed. */
44062306a36Sopenharmony_ci  round:
44162306a36Sopenharmony_ci    if(Ext_isnotzero(extent))
44262306a36Sopenharmony_ci	{
44362306a36Sopenharmony_ci	inexact = TRUE;
44462306a36Sopenharmony_ci	switch(Rounding_mode())
44562306a36Sopenharmony_ci	    {
44662306a36Sopenharmony_ci	    case ROUNDNEAREST: /* The default. */
44762306a36Sopenharmony_ci	    if(Ext_isone_sign(extent))
44862306a36Sopenharmony_ci		{
44962306a36Sopenharmony_ci		/* at least 1/2 ulp */
45062306a36Sopenharmony_ci		if(Ext_isnotzero_lower(extent)  ||
45162306a36Sopenharmony_ci		  Sgl_isone_lowmantissa(result))
45262306a36Sopenharmony_ci		    {
45362306a36Sopenharmony_ci		    /* either exactly half way and odd or more than 1/2ulp */
45462306a36Sopenharmony_ci		    Sgl_increment(result);
45562306a36Sopenharmony_ci		    }
45662306a36Sopenharmony_ci		}
45762306a36Sopenharmony_ci	    break;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	    case ROUNDPLUS:
46062306a36Sopenharmony_ci	    if(Sgl_iszero_sign(result))
46162306a36Sopenharmony_ci		{
46262306a36Sopenharmony_ci		/* Round up positive results */
46362306a36Sopenharmony_ci		Sgl_increment(result);
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci	    break;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	    case ROUNDMINUS:
46862306a36Sopenharmony_ci	    if(Sgl_isone_sign(result))
46962306a36Sopenharmony_ci		{
47062306a36Sopenharmony_ci		/* Round down negative results */
47162306a36Sopenharmony_ci		Sgl_increment(result);
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	    case ROUNDZERO:;
47562306a36Sopenharmony_ci	    /* truncate is simple */
47662306a36Sopenharmony_ci	    } /* end switch... */
47762306a36Sopenharmony_ci	if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci    if(result_exponent == SGL_INFINITY_EXPONENT)
48062306a36Sopenharmony_ci        {
48162306a36Sopenharmony_ci        /* Overflow */
48262306a36Sopenharmony_ci        if(Is_overflowtrap_enabled())
48362306a36Sopenharmony_ci	    {
48462306a36Sopenharmony_ci	    Sgl_setwrapped_exponent(result,result_exponent,ovfl);
48562306a36Sopenharmony_ci	    *dstptr = result;
48662306a36Sopenharmony_ci	    if (inexact)
48762306a36Sopenharmony_ci		if (Is_inexacttrap_enabled())
48862306a36Sopenharmony_ci		    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
48962306a36Sopenharmony_ci		else Set_inexactflag();
49062306a36Sopenharmony_ci	    return(OVERFLOWEXCEPTION);
49162306a36Sopenharmony_ci	    }
49262306a36Sopenharmony_ci        else
49362306a36Sopenharmony_ci	    {
49462306a36Sopenharmony_ci	    Set_overflowflag();
49562306a36Sopenharmony_ci	    inexact = TRUE;
49662306a36Sopenharmony_ci	    Sgl_setoverflow(result);
49762306a36Sopenharmony_ci	    }
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci    else Sgl_set_exponent(result,result_exponent);
50062306a36Sopenharmony_ci    *dstptr = result;
50162306a36Sopenharmony_ci    if(inexact)
50262306a36Sopenharmony_ci	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
50362306a36Sopenharmony_ci	else Set_inexactflag();
50462306a36Sopenharmony_ci    return(NOEXCEPTION);
50562306a36Sopenharmony_ci    }
506