18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Floating-point emulation code 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * BEGIN_DESC 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * File: 128c2ecf20Sopenharmony_ci * @(#) pa/spmath/sfsub.c $Revision: 1.1 $ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Purpose: 158c2ecf20Sopenharmony_ci * Single_subtract: subtract two single precision values. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * External Interfaces: 188c2ecf20Sopenharmony_ci * sgl_fsub(leftptr, rightptr, dstptr, status) 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Internal Interfaces: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Theory: 238c2ecf20Sopenharmony_ci * <<please update with a overview of the operation of this file>> 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * END_DESC 268c2ecf20Sopenharmony_ci*/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "float.h" 308c2ecf20Sopenharmony_ci#include "sgl_float.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Single_subtract: subtract two single precision values. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ciint 368c2ecf20Sopenharmony_cisgl_fsub( 378c2ecf20Sopenharmony_ci sgl_floating_point *leftptr, 388c2ecf20Sopenharmony_ci sgl_floating_point *rightptr, 398c2ecf20Sopenharmony_ci sgl_floating_point *dstptr, 408c2ecf20Sopenharmony_ci unsigned int *status) 418c2ecf20Sopenharmony_ci { 428c2ecf20Sopenharmony_ci register unsigned int left, right, result, extent; 438c2ecf20Sopenharmony_ci register unsigned int signless_upper_left, signless_upper_right, save; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci register int result_exponent, right_exponent, diff_exponent; 468c2ecf20Sopenharmony_ci register int sign_save, jumpsize; 478c2ecf20Sopenharmony_ci register boolean inexact = FALSE, underflowtrap; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Create local copies of the numbers */ 508c2ecf20Sopenharmony_ci left = *leftptr; 518c2ecf20Sopenharmony_ci right = *rightptr; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* A zero "save" helps discover equal operands (for later), * 548c2ecf20Sopenharmony_ci * and is used in swapping operands (if needed). */ 558c2ecf20Sopenharmony_ci Sgl_xortointp1(left,right,/*to*/save); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* 588c2ecf20Sopenharmony_ci * check first operand for NaN's or infinity 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT) 618c2ecf20Sopenharmony_ci { 628c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(left)) 638c2ecf20Sopenharmony_ci { 648c2ecf20Sopenharmony_ci if (Sgl_isnotnan(right)) 658c2ecf20Sopenharmony_ci { 668c2ecf20Sopenharmony_ci if (Sgl_isinfinity(right) && save==0) 678c2ecf20Sopenharmony_ci { 688c2ecf20Sopenharmony_ci /* 698c2ecf20Sopenharmony_ci * invalid since operands are same signed infinity's 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 728c2ecf20Sopenharmony_ci Set_invalidflag(); 738c2ecf20Sopenharmony_ci Sgl_makequietnan(result); 748c2ecf20Sopenharmony_ci *dstptr = result; 758c2ecf20Sopenharmony_ci return(NOEXCEPTION); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * return infinity 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci *dstptr = left; 818c2ecf20Sopenharmony_ci return(NOEXCEPTION); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci if (Sgl_isone_signaling(left)) 908c2ecf20Sopenharmony_ci { 918c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 928c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 938c2ecf20Sopenharmony_ci /* make NaN quiet */ 948c2ecf20Sopenharmony_ci Set_invalidflag(); 958c2ecf20Sopenharmony_ci Sgl_set_quiet(left); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * is second operand a signaling NaN? 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci else if (Sgl_is_signalingnan(right)) 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1038c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1048c2ecf20Sopenharmony_ci /* make NaN quiet */ 1058c2ecf20Sopenharmony_ci Set_invalidflag(); 1068c2ecf20Sopenharmony_ci Sgl_set_quiet(right); 1078c2ecf20Sopenharmony_ci *dstptr = right; 1088c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * return quiet NaN 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci *dstptr = left; 1148c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci } /* End left NaN or Infinity processing */ 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * check second operand for NaN's or infinity 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (Sgl_isinfinity_exponent(right)) 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(right)) 1238c2ecf20Sopenharmony_ci { 1248c2ecf20Sopenharmony_ci /* return infinity */ 1258c2ecf20Sopenharmony_ci Sgl_invert_sign(right); 1268c2ecf20Sopenharmony_ci *dstptr = right; 1278c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci if (Sgl_isone_signaling(right)) 1338c2ecf20Sopenharmony_ci { 1348c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1358c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1368c2ecf20Sopenharmony_ci /* make NaN quiet */ 1378c2ecf20Sopenharmony_ci Set_invalidflag(); 1388c2ecf20Sopenharmony_ci Sgl_set_quiet(right); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * return quiet NaN 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci *dstptr = right; 1448c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1458c2ecf20Sopenharmony_ci } /* End right NaN or Infinity processing */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Invariant: Must be dealing with finite numbers */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Compare operands by removing the sign */ 1508c2ecf20Sopenharmony_ci Sgl_copytoint_exponentmantissa(left,signless_upper_left); 1518c2ecf20Sopenharmony_ci Sgl_copytoint_exponentmantissa(right,signless_upper_right); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* sign difference selects sub or add operation. */ 1548c2ecf20Sopenharmony_ci if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right)) 1558c2ecf20Sopenharmony_ci { 1568c2ecf20Sopenharmony_ci /* Set the left operand to the larger one by XOR swap * 1578c2ecf20Sopenharmony_ci * First finish the first word using "save" */ 1588c2ecf20Sopenharmony_ci Sgl_xorfromintp1(save,right,/*to*/right); 1598c2ecf20Sopenharmony_ci Sgl_xorfromintp1(save,left,/*to*/left); 1608c2ecf20Sopenharmony_ci result_exponent = Sgl_exponent(left); 1618c2ecf20Sopenharmony_ci Sgl_invert_sign(left); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci /* Invariant: left is not smaller than right. */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if((right_exponent = Sgl_exponent(right)) == 0) 1668c2ecf20Sopenharmony_ci { 1678c2ecf20Sopenharmony_ci /* Denormalized operands. First look for zeroes */ 1688c2ecf20Sopenharmony_ci if(Sgl_iszero_mantissa(right)) 1698c2ecf20Sopenharmony_ci { 1708c2ecf20Sopenharmony_ci /* right is zero */ 1718c2ecf20Sopenharmony_ci if(Sgl_iszero_exponentmantissa(left)) 1728c2ecf20Sopenharmony_ci { 1738c2ecf20Sopenharmony_ci /* Both operands are zeros */ 1748c2ecf20Sopenharmony_ci Sgl_invert_sign(right); 1758c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) 1768c2ecf20Sopenharmony_ci { 1778c2ecf20Sopenharmony_ci Sgl_or_signs(left,/*with*/right); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci else 1808c2ecf20Sopenharmony_ci { 1818c2ecf20Sopenharmony_ci Sgl_and_signs(left,/*with*/right); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci else 1858c2ecf20Sopenharmony_ci { 1868c2ecf20Sopenharmony_ci /* Left is not a zero and must be the result. Trapped 1878c2ecf20Sopenharmony_ci * underflows are signaled if left is denormalized. Result 1888c2ecf20Sopenharmony_ci * is always exact. */ 1898c2ecf20Sopenharmony_ci if( (result_exponent == 0) && Is_underflowtrap_enabled() ) 1908c2ecf20Sopenharmony_ci { 1918c2ecf20Sopenharmony_ci /* need to normalize results mantissa */ 1928c2ecf20Sopenharmony_ci sign_save = Sgl_signextendedsign(left); 1938c2ecf20Sopenharmony_ci Sgl_leftshiftby1(left); 1948c2ecf20Sopenharmony_ci Sgl_normalize(left,result_exponent); 1958c2ecf20Sopenharmony_ci Sgl_set_sign(left,/*using*/sign_save); 1968c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(left,result_exponent,unfl); 1978c2ecf20Sopenharmony_ci *dstptr = left; 1988c2ecf20Sopenharmony_ci /* inexact = FALSE */ 1998c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci *dstptr = left; 2038c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Neither are zeroes */ 2078c2ecf20Sopenharmony_ci Sgl_clear_sign(right); /* Exponent is already cleared */ 2088c2ecf20Sopenharmony_ci if(result_exponent == 0 ) 2098c2ecf20Sopenharmony_ci { 2108c2ecf20Sopenharmony_ci /* Both operands are denormalized. The result must be exact 2118c2ecf20Sopenharmony_ci * and is simply calculated. A sum could become normalized and a 2128c2ecf20Sopenharmony_ci * difference could cancel to a true zero. */ 2138c2ecf20Sopenharmony_ci if( (/*signed*/int) save >= 0 ) 2148c2ecf20Sopenharmony_ci { 2158c2ecf20Sopenharmony_ci Sgl_subtract(left,/*minus*/right,/*into*/result); 2168c2ecf20Sopenharmony_ci if(Sgl_iszero_mantissa(result)) 2178c2ecf20Sopenharmony_ci { 2188c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) 2198c2ecf20Sopenharmony_ci { 2208c2ecf20Sopenharmony_ci Sgl_setone_sign(result); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci { 2248c2ecf20Sopenharmony_ci Sgl_setzero_sign(result); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci *dstptr = result; 2278c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci { 2328c2ecf20Sopenharmony_ci Sgl_addition(left,right,/*into*/result); 2338c2ecf20Sopenharmony_ci if(Sgl_isone_hidden(result)) 2348c2ecf20Sopenharmony_ci { 2358c2ecf20Sopenharmony_ci *dstptr = result; 2368c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci if(Is_underflowtrap_enabled()) 2408c2ecf20Sopenharmony_ci { 2418c2ecf20Sopenharmony_ci /* need to normalize result */ 2428c2ecf20Sopenharmony_ci sign_save = Sgl_signextendedsign(result); 2438c2ecf20Sopenharmony_ci Sgl_leftshiftby1(result); 2448c2ecf20Sopenharmony_ci Sgl_normalize(result,result_exponent); 2458c2ecf20Sopenharmony_ci Sgl_set_sign(result,/*using*/sign_save); 2468c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,result_exponent,unfl); 2478c2ecf20Sopenharmony_ci *dstptr = result; 2488c2ecf20Sopenharmony_ci /* inexact = FALSE */ 2498c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci *dstptr = result; 2528c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci right_exponent = 1; /* Set exponent to reflect different bias 2558c2ecf20Sopenharmony_ci * with denomalized numbers. */ 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci else 2588c2ecf20Sopenharmony_ci { 2598c2ecf20Sopenharmony_ci Sgl_clear_signexponent_set_hidden(right); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci Sgl_clear_exponent_set_hidden(left); 2628c2ecf20Sopenharmony_ci diff_exponent = result_exponent - right_exponent; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Special case alignment of operands that would force alignment 2668c2ecf20Sopenharmony_ci * beyond the extent of the extension. A further optimization 2678c2ecf20Sopenharmony_ci * could special case this but only reduces the path length for this 2688c2ecf20Sopenharmony_ci * infrequent case. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci if(diff_exponent > SGL_THRESHOLD) 2718c2ecf20Sopenharmony_ci { 2728c2ecf20Sopenharmony_ci diff_exponent = SGL_THRESHOLD; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Align right operand by shifting to right */ 2768c2ecf20Sopenharmony_ci Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent, 2778c2ecf20Sopenharmony_ci /*and lower to*/extent); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Treat sum and difference of the operands separately. */ 2808c2ecf20Sopenharmony_ci if( (/*signed*/int) save >= 0 ) 2818c2ecf20Sopenharmony_ci { 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * Difference of the two operands. Their can be no overflow. A 2848c2ecf20Sopenharmony_ci * borrow can occur out of the hidden bit and force a post 2858c2ecf20Sopenharmony_ci * normalization phase. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result); 2888c2ecf20Sopenharmony_ci if(Sgl_iszero_hidden(result)) 2898c2ecf20Sopenharmony_ci { 2908c2ecf20Sopenharmony_ci /* Handle normalization */ 2918c2ecf20Sopenharmony_ci /* A straightforward algorithm would now shift the result 2928c2ecf20Sopenharmony_ci * and extension left until the hidden bit becomes one. Not 2938c2ecf20Sopenharmony_ci * all of the extension bits need participate in the shift. 2948c2ecf20Sopenharmony_ci * Only the two most significant bits (round and guard) are 2958c2ecf20Sopenharmony_ci * needed. If only a single shift is needed then the guard 2968c2ecf20Sopenharmony_ci * bit becomes a significant low order bit and the extension 2978c2ecf20Sopenharmony_ci * must participate in the rounding. If more than a single 2988c2ecf20Sopenharmony_ci * shift is needed, then all bits to the right of the guard 2998c2ecf20Sopenharmony_ci * bit are zeros, and the guard bit may or may not be zero. */ 3008c2ecf20Sopenharmony_ci sign_save = Sgl_signextendedsign(result); 3018c2ecf20Sopenharmony_ci Sgl_leftshiftby1_withextent(result,extent,result); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Need to check for a zero result. The sign and exponent 3048c2ecf20Sopenharmony_ci * fields have already been zeroed. The more efficient test 3058c2ecf20Sopenharmony_ci * of the full object can be used. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci if(Sgl_iszero(result)) 3088c2ecf20Sopenharmony_ci /* Must have been "x-x" or "x+(-x)". */ 3098c2ecf20Sopenharmony_ci { 3108c2ecf20Sopenharmony_ci if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result); 3118c2ecf20Sopenharmony_ci *dstptr = result; 3128c2ecf20Sopenharmony_ci return(NOEXCEPTION); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci result_exponent--; 3158c2ecf20Sopenharmony_ci /* Look to see if normalization is finished. */ 3168c2ecf20Sopenharmony_ci if(Sgl_isone_hidden(result)) 3178c2ecf20Sopenharmony_ci { 3188c2ecf20Sopenharmony_ci if(result_exponent==0) 3198c2ecf20Sopenharmony_ci { 3208c2ecf20Sopenharmony_ci /* Denormalized, exponent should be zero. Left operand * 3218c2ecf20Sopenharmony_ci * was normalized, so extent (guard, round) was zero */ 3228c2ecf20Sopenharmony_ci goto underflow; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci { 3268c2ecf20Sopenharmony_ci /* No further normalization is needed. */ 3278c2ecf20Sopenharmony_ci Sgl_set_sign(result,/*using*/sign_save); 3288c2ecf20Sopenharmony_ci Ext_leftshiftby1(extent); 3298c2ecf20Sopenharmony_ci goto round; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Check for denormalized, exponent should be zero. Left * 3348c2ecf20Sopenharmony_ci * operand was normalized, so extent (guard, round) was zero */ 3358c2ecf20Sopenharmony_ci if(!(underflowtrap = Is_underflowtrap_enabled()) && 3368c2ecf20Sopenharmony_ci result_exponent==0) goto underflow; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Shift extension to complete one bit of normalization and 3398c2ecf20Sopenharmony_ci * update exponent. */ 3408c2ecf20Sopenharmony_ci Ext_leftshiftby1(extent); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Discover first one bit to determine shift amount. Use a 3438c2ecf20Sopenharmony_ci * modified binary search. We have already shifted the result 3448c2ecf20Sopenharmony_ci * one position right and still not found a one so the remainder 3458c2ecf20Sopenharmony_ci * of the extension must be zero and simplifies rounding. */ 3468c2ecf20Sopenharmony_ci /* Scan bytes */ 3478c2ecf20Sopenharmony_ci while(Sgl_iszero_hiddenhigh7mantissa(result)) 3488c2ecf20Sopenharmony_ci { 3498c2ecf20Sopenharmony_ci Sgl_leftshiftby8(result); 3508c2ecf20Sopenharmony_ci if((result_exponent -= 8) <= 0 && !underflowtrap) 3518c2ecf20Sopenharmony_ci goto underflow; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci /* Now narrow it down to the nibble */ 3548c2ecf20Sopenharmony_ci if(Sgl_iszero_hiddenhigh3mantissa(result)) 3558c2ecf20Sopenharmony_ci { 3568c2ecf20Sopenharmony_ci /* The lower nibble contains the normalizing one */ 3578c2ecf20Sopenharmony_ci Sgl_leftshiftby4(result); 3588c2ecf20Sopenharmony_ci if((result_exponent -= 4) <= 0 && !underflowtrap) 3598c2ecf20Sopenharmony_ci goto underflow; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci /* Select case were first bit is set (already normalized) 3628c2ecf20Sopenharmony_ci * otherwise select the proper shift. */ 3638c2ecf20Sopenharmony_ci if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7) 3648c2ecf20Sopenharmony_ci { 3658c2ecf20Sopenharmony_ci /* Already normalized */ 3668c2ecf20Sopenharmony_ci if(result_exponent <= 0) goto underflow; 3678c2ecf20Sopenharmony_ci Sgl_set_sign(result,/*using*/sign_save); 3688c2ecf20Sopenharmony_ci Sgl_set_exponent(result,/*using*/result_exponent); 3698c2ecf20Sopenharmony_ci *dstptr = result; 3708c2ecf20Sopenharmony_ci return(NOEXCEPTION); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci Sgl_sethigh4bits(result,/*using*/sign_save); 3738c2ecf20Sopenharmony_ci switch(jumpsize) 3748c2ecf20Sopenharmony_ci { 3758c2ecf20Sopenharmony_ci case 1: 3768c2ecf20Sopenharmony_ci { 3778c2ecf20Sopenharmony_ci Sgl_leftshiftby3(result); 3788c2ecf20Sopenharmony_ci result_exponent -= 3; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci case 2: 3828c2ecf20Sopenharmony_ci case 3: 3838c2ecf20Sopenharmony_ci { 3848c2ecf20Sopenharmony_ci Sgl_leftshiftby2(result); 3858c2ecf20Sopenharmony_ci result_exponent -= 2; 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci case 4: 3898c2ecf20Sopenharmony_ci case 5: 3908c2ecf20Sopenharmony_ci case 6: 3918c2ecf20Sopenharmony_ci case 7: 3928c2ecf20Sopenharmony_ci { 3938c2ecf20Sopenharmony_ci Sgl_leftshiftby1(result); 3948c2ecf20Sopenharmony_ci result_exponent -= 1; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci if(result_exponent > 0) 3998c2ecf20Sopenharmony_ci { 4008c2ecf20Sopenharmony_ci Sgl_set_exponent(result,/*using*/result_exponent); 4018c2ecf20Sopenharmony_ci *dstptr = result; /* Sign bit is already set */ 4028c2ecf20Sopenharmony_ci return(NOEXCEPTION); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci /* Fixup potential underflows */ 4058c2ecf20Sopenharmony_ci underflow: 4068c2ecf20Sopenharmony_ci if(Is_underflowtrap_enabled()) 4078c2ecf20Sopenharmony_ci { 4088c2ecf20Sopenharmony_ci Sgl_set_sign(result,sign_save); 4098c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,result_exponent,unfl); 4108c2ecf20Sopenharmony_ci *dstptr = result; 4118c2ecf20Sopenharmony_ci /* inexact = FALSE */ 4128c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci /* 4158c2ecf20Sopenharmony_ci * Since we cannot get an inexact denormalized result, 4168c2ecf20Sopenharmony_ci * we can now return. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci Sgl_right_align(result,/*by*/(1-result_exponent),extent); 4198c2ecf20Sopenharmony_ci Sgl_clear_signexponent(result); 4208c2ecf20Sopenharmony_ci Sgl_set_sign(result,sign_save); 4218c2ecf20Sopenharmony_ci *dstptr = result; 4228c2ecf20Sopenharmony_ci return(NOEXCEPTION); 4238c2ecf20Sopenharmony_ci } /* end if(hidden...)... */ 4248c2ecf20Sopenharmony_ci /* Fall through and round */ 4258c2ecf20Sopenharmony_ci } /* end if(save >= 0)... */ 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci { 4288c2ecf20Sopenharmony_ci /* Add magnitudes */ 4298c2ecf20Sopenharmony_ci Sgl_addition(left,right,/*to*/result); 4308c2ecf20Sopenharmony_ci if(Sgl_isone_hiddenoverflow(result)) 4318c2ecf20Sopenharmony_ci { 4328c2ecf20Sopenharmony_ci /* Prenormalization required. */ 4338c2ecf20Sopenharmony_ci Sgl_rightshiftby1_withextent(result,extent,extent); 4348c2ecf20Sopenharmony_ci Sgl_arithrightshiftby1(result); 4358c2ecf20Sopenharmony_ci result_exponent++; 4368c2ecf20Sopenharmony_ci } /* end if hiddenoverflow... */ 4378c2ecf20Sopenharmony_ci } /* end else ...sub magnitudes... */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* Round the result. If the extension is all zeros,then the result is 4408c2ecf20Sopenharmony_ci * exact. Otherwise round in the correct direction. No underflow is 4418c2ecf20Sopenharmony_ci * possible. If a postnormalization is necessary, then the mantissa is 4428c2ecf20Sopenharmony_ci * all zeros so no shift is needed. */ 4438c2ecf20Sopenharmony_ci round: 4448c2ecf20Sopenharmony_ci if(Ext_isnotzero(extent)) 4458c2ecf20Sopenharmony_ci { 4468c2ecf20Sopenharmony_ci inexact = TRUE; 4478c2ecf20Sopenharmony_ci switch(Rounding_mode()) 4488c2ecf20Sopenharmony_ci { 4498c2ecf20Sopenharmony_ci case ROUNDNEAREST: /* The default. */ 4508c2ecf20Sopenharmony_ci if(Ext_isone_sign(extent)) 4518c2ecf20Sopenharmony_ci { 4528c2ecf20Sopenharmony_ci /* at least 1/2 ulp */ 4538c2ecf20Sopenharmony_ci if(Ext_isnotzero_lower(extent) || 4548c2ecf20Sopenharmony_ci Sgl_isone_lowmantissa(result)) 4558c2ecf20Sopenharmony_ci { 4568c2ecf20Sopenharmony_ci /* either exactly half way and odd or more than 1/2ulp */ 4578c2ecf20Sopenharmony_ci Sgl_increment(result); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci case ROUNDPLUS: 4638c2ecf20Sopenharmony_ci if(Sgl_iszero_sign(result)) 4648c2ecf20Sopenharmony_ci { 4658c2ecf20Sopenharmony_ci /* Round up positive results */ 4668c2ecf20Sopenharmony_ci Sgl_increment(result); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci case ROUNDMINUS: 4718c2ecf20Sopenharmony_ci if(Sgl_isone_sign(result)) 4728c2ecf20Sopenharmony_ci { 4738c2ecf20Sopenharmony_ci /* Round down negative results */ 4748c2ecf20Sopenharmony_ci Sgl_increment(result); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci case ROUNDZERO:; 4788c2ecf20Sopenharmony_ci /* truncate is simple */ 4798c2ecf20Sopenharmony_ci } /* end switch... */ 4808c2ecf20Sopenharmony_ci if(Sgl_isone_hiddenoverflow(result)) result_exponent++; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci if(result_exponent == SGL_INFINITY_EXPONENT) 4838c2ecf20Sopenharmony_ci { 4848c2ecf20Sopenharmony_ci /* Overflow */ 4858c2ecf20Sopenharmony_ci if(Is_overflowtrap_enabled()) 4868c2ecf20Sopenharmony_ci { 4878c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,result_exponent,ovfl); 4888c2ecf20Sopenharmony_ci *dstptr = result; 4898c2ecf20Sopenharmony_ci if (inexact) 4908c2ecf20Sopenharmony_ci if (Is_inexacttrap_enabled()) 4918c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); 4928c2ecf20Sopenharmony_ci else Set_inexactflag(); 4938c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci { 4978c2ecf20Sopenharmony_ci Set_overflowflag(); 4988c2ecf20Sopenharmony_ci inexact = TRUE; 4998c2ecf20Sopenharmony_ci Sgl_setoverflow(result); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci else Sgl_set_exponent(result,result_exponent); 5038c2ecf20Sopenharmony_ci *dstptr = result; 5048c2ecf20Sopenharmony_ci if(inexact) 5058c2ecf20Sopenharmony_ci if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 5068c2ecf20Sopenharmony_ci else Set_inexactflag(); 5078c2ecf20Sopenharmony_ci return(NOEXCEPTION); 5088c2ecf20Sopenharmony_ci } 509