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