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/sfrem.c $Revision: 1.1 $ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Purpose: 158c2ecf20Sopenharmony_ci * Single Precision Floating-point Remainder 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * External Interfaces: 188c2ecf20Sopenharmony_ci * sgl_frem(srcptr1,srcptr2,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 308c2ecf20Sopenharmony_ci#include "float.h" 318c2ecf20Sopenharmony_ci#include "sgl_float.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Single Precision Floating-point Remainder 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciint 388c2ecf20Sopenharmony_cisgl_frem (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2, 398c2ecf20Sopenharmony_ci sgl_floating_point * dstptr, unsigned int *status) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci register unsigned int opnd1, opnd2, result; 428c2ecf20Sopenharmony_ci register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount; 438c2ecf20Sopenharmony_ci register boolean roundup = FALSE; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci opnd1 = *srcptr1; 468c2ecf20Sopenharmony_ci opnd2 = *srcptr2; 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * check first operand for NaN's or infinity 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci if ((opnd1_exponent = Sgl_exponent(opnd1)) == SGL_INFINITY_EXPONENT) { 518c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(opnd1)) { 528c2ecf20Sopenharmony_ci if (Sgl_isnotnan(opnd2)) { 538c2ecf20Sopenharmony_ci /* invalid since first operand is infinity */ 548c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 558c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 568c2ecf20Sopenharmony_ci Set_invalidflag(); 578c2ecf20Sopenharmony_ci Sgl_makequietnan(result); 588c2ecf20Sopenharmony_ci *dstptr = result; 598c2ecf20Sopenharmony_ci return(NOEXCEPTION); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci else { 638c2ecf20Sopenharmony_ci /* 648c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci if (Sgl_isone_signaling(opnd1)) { 678c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 688c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 698c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 708c2ecf20Sopenharmony_ci /* make NaN quiet */ 718c2ecf20Sopenharmony_ci Set_invalidflag(); 728c2ecf20Sopenharmony_ci Sgl_set_quiet(opnd1); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * is second operand a signaling NaN? 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci else if (Sgl_is_signalingnan(opnd2)) { 788c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 798c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 808c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 818c2ecf20Sopenharmony_ci /* make NaN quiet */ 828c2ecf20Sopenharmony_ci Set_invalidflag(); 838c2ecf20Sopenharmony_ci Sgl_set_quiet(opnd2); 848c2ecf20Sopenharmony_ci *dstptr = opnd2; 858c2ecf20Sopenharmony_ci return(NOEXCEPTION); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * return quiet NaN 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci *dstptr = opnd1; 918c2ecf20Sopenharmony_ci return(NOEXCEPTION); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * check second operand for NaN's or infinity 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci if ((opnd2_exponent = Sgl_exponent(opnd2)) == SGL_INFINITY_EXPONENT) { 988c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(opnd2)) { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * return first operand 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci *dstptr = opnd1; 1038c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci if (Sgl_isone_signaling(opnd2)) { 1098c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1108c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1118c2ecf20Sopenharmony_ci /* make NaN quiet */ 1128c2ecf20Sopenharmony_ci Set_invalidflag(); 1138c2ecf20Sopenharmony_ci Sgl_set_quiet(opnd2); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * return quiet NaN 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci *dstptr = opnd2; 1198c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * check second operand for zero 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci if (Sgl_iszero_exponentmantissa(opnd2)) { 1258c2ecf20Sopenharmony_ci /* invalid since second operand is zero */ 1268c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1278c2ecf20Sopenharmony_ci Set_invalidflag(); 1288c2ecf20Sopenharmony_ci Sgl_makequietnan(result); 1298c2ecf20Sopenharmony_ci *dstptr = result; 1308c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * get sign of result 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci result = opnd1; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * check for denormalized operands 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (opnd1_exponent == 0) { 1428c2ecf20Sopenharmony_ci /* check for zero */ 1438c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(opnd1)) { 1448c2ecf20Sopenharmony_ci *dstptr = opnd1; 1458c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci /* normalize, then continue */ 1488c2ecf20Sopenharmony_ci opnd1_exponent = 1; 1498c2ecf20Sopenharmony_ci Sgl_normalize(opnd1,opnd1_exponent); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci else { 1528c2ecf20Sopenharmony_ci Sgl_clear_signexponent_set_hidden(opnd1); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci if (opnd2_exponent == 0) { 1558c2ecf20Sopenharmony_ci /* normalize, then continue */ 1568c2ecf20Sopenharmony_ci opnd2_exponent = 1; 1578c2ecf20Sopenharmony_ci Sgl_normalize(opnd2,opnd2_exponent); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci else { 1608c2ecf20Sopenharmony_ci Sgl_clear_signexponent_set_hidden(opnd2); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* find result exponent and divide step loop count */ 1648c2ecf20Sopenharmony_ci dest_exponent = opnd2_exponent - 1; 1658c2ecf20Sopenharmony_ci stepcount = opnd1_exponent - opnd2_exponent; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* 1688c2ecf20Sopenharmony_ci * check for opnd1/opnd2 < 1 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci if (stepcount < 0) { 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * check for opnd1/opnd2 > 1/2 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * In this case n will round to 1, so 1758c2ecf20Sopenharmony_ci * r = opnd1 - opnd2 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci if (stepcount == -1 && Sgl_isgreaterthan(opnd1,opnd2)) { 1788c2ecf20Sopenharmony_ci Sgl_all(result) = ~Sgl_all(result); /* set sign */ 1798c2ecf20Sopenharmony_ci /* align opnd2 with opnd1 */ 1808c2ecf20Sopenharmony_ci Sgl_leftshiftby1(opnd2); 1818c2ecf20Sopenharmony_ci Sgl_subtract(opnd2,opnd1,opnd2); 1828c2ecf20Sopenharmony_ci /* now normalize */ 1838c2ecf20Sopenharmony_ci while (Sgl_iszero_hidden(opnd2)) { 1848c2ecf20Sopenharmony_ci Sgl_leftshiftby1(opnd2); 1858c2ecf20Sopenharmony_ci dest_exponent--; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci Sgl_set_exponentmantissa(result,opnd2); 1888c2ecf20Sopenharmony_ci goto testforunderflow; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * opnd1/opnd2 <= 1/2 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * In this case n will round to zero, so 1948c2ecf20Sopenharmony_ci * r = opnd1 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci Sgl_set_exponentmantissa(result,opnd1); 1978c2ecf20Sopenharmony_ci dest_exponent = opnd1_exponent; 1988c2ecf20Sopenharmony_ci goto testforunderflow; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Generate result 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Do iterative subtract until remainder is less than operand 2. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci while (stepcount-- > 0 && Sgl_all(opnd1)) { 2078c2ecf20Sopenharmony_ci if (Sgl_isnotlessthan(opnd1,opnd2)) 2088c2ecf20Sopenharmony_ci Sgl_subtract(opnd1,opnd2,opnd1); 2098c2ecf20Sopenharmony_ci Sgl_leftshiftby1(opnd1); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * Do last subtract, then determine which way to round if remainder 2138c2ecf20Sopenharmony_ci * is exactly 1/2 of opnd2 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci if (Sgl_isnotlessthan(opnd1,opnd2)) { 2168c2ecf20Sopenharmony_ci Sgl_subtract(opnd1,opnd2,opnd1); 2178c2ecf20Sopenharmony_ci roundup = TRUE; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci if (stepcount > 0 || Sgl_iszero(opnd1)) { 2208c2ecf20Sopenharmony_ci /* division is exact, remainder is zero */ 2218c2ecf20Sopenharmony_ci Sgl_setzero_exponentmantissa(result); 2228c2ecf20Sopenharmony_ci *dstptr = result; 2238c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * Check for cases where opnd1/opnd2 < n 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * In this case the result's sign will be opposite that of 2308c2ecf20Sopenharmony_ci * opnd1. The mantissa also needs some correction. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci Sgl_leftshiftby1(opnd1); 2338c2ecf20Sopenharmony_ci if (Sgl_isgreaterthan(opnd1,opnd2)) { 2348c2ecf20Sopenharmony_ci Sgl_invert_sign(result); 2358c2ecf20Sopenharmony_ci Sgl_subtract((opnd2<<1),opnd1,opnd1); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci /* check for remainder being exactly 1/2 of opnd2 */ 2388c2ecf20Sopenharmony_ci else if (Sgl_isequal(opnd1,opnd2) && roundup) { 2398c2ecf20Sopenharmony_ci Sgl_invert_sign(result); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* normalize result's mantissa */ 2438c2ecf20Sopenharmony_ci while (Sgl_iszero_hidden(opnd1)) { 2448c2ecf20Sopenharmony_ci dest_exponent--; 2458c2ecf20Sopenharmony_ci Sgl_leftshiftby1(opnd1); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci Sgl_set_exponentmantissa(result,opnd1); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* 2508c2ecf20Sopenharmony_ci * Test for underflow 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci testforunderflow: 2538c2ecf20Sopenharmony_ci if (dest_exponent <= 0) { 2548c2ecf20Sopenharmony_ci /* trap if UNDERFLOWTRAP enabled */ 2558c2ecf20Sopenharmony_ci if (Is_underflowtrap_enabled()) { 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * Adjust bias of result 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,dest_exponent,unfl); 2608c2ecf20Sopenharmony_ci *dstptr = result; 2618c2ecf20Sopenharmony_ci /* frem is always exact */ 2628c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * denormalize result or set to signed zero 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (dest_exponent >= (1 - SGL_P)) { 2688c2ecf20Sopenharmony_ci Sgl_rightshift_exponentmantissa(result,1-dest_exponent); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci else { 2718c2ecf20Sopenharmony_ci Sgl_setzero_exponentmantissa(result); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci else Sgl_set_exponent(result,dest_exponent); 2758c2ecf20Sopenharmony_ci *dstptr = result; 2768c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2778c2ecf20Sopenharmony_ci} 278