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