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/fcnvff.c $Revision: 1.1 $ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Purpose: 158c2ecf20Sopenharmony_ci * Single Floating-point to Double Floating-point 168c2ecf20Sopenharmony_ci * Double Floating-point to Single Floating-point 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * External Interfaces: 198c2ecf20Sopenharmony_ci * dbl_to_sgl_fcnvff(srcptr,nullptr,dstptr,status) 208c2ecf20Sopenharmony_ci * sgl_to_dbl_fcnvff(srcptr,nullptr,dstptr,status) 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Internal Interfaces: 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Theory: 258c2ecf20Sopenharmony_ci * <<please update with a overview of the operation of this file>> 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * END_DESC 288c2ecf20Sopenharmony_ci*/ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "float.h" 328c2ecf20Sopenharmony_ci#include "sgl_float.h" 338c2ecf20Sopenharmony_ci#include "dbl_float.h" 348c2ecf20Sopenharmony_ci#include "cnv_float.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Single Floating-point to Double Floating-point 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci/*ARGSUSED*/ 408c2ecf20Sopenharmony_ciint 418c2ecf20Sopenharmony_cisgl_to_dbl_fcnvff( 428c2ecf20Sopenharmony_ci sgl_floating_point *srcptr, 438c2ecf20Sopenharmony_ci unsigned int *nullptr, 448c2ecf20Sopenharmony_ci dbl_floating_point *dstptr, 458c2ecf20Sopenharmony_ci unsigned int *status) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci register unsigned int src, resultp1, resultp2; 488c2ecf20Sopenharmony_ci register int src_exponent; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci src = *srcptr; 518c2ecf20Sopenharmony_ci src_exponent = Sgl_exponent(src); 528c2ecf20Sopenharmony_ci Dbl_allp1(resultp1) = Sgl_all(src); /* set sign of result */ 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * Test for NaN or infinity 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci if (src_exponent == SGL_INFINITY_EXPONENT) { 578c2ecf20Sopenharmony_ci /* 588c2ecf20Sopenharmony_ci * determine if NaN or infinity 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(src)) { 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * is infinity; want to return double infinity 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci Dbl_setinfinity_exponentmantissa(resultp1,resultp2); 658c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 668c2ecf20Sopenharmony_ci return(NOEXCEPTION); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci else { 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci if (Sgl_isone_signaling(src)) { 738c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 748c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) 758c2ecf20Sopenharmony_ci return(INVALIDEXCEPTION); 768c2ecf20Sopenharmony_ci /* make NaN quiet */ 778c2ecf20Sopenharmony_ci else { 788c2ecf20Sopenharmony_ci Set_invalidflag(); 798c2ecf20Sopenharmony_ci Sgl_set_quiet(src); 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * NaN is quiet, return as double NaN 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci Dbl_setinfinity_exponent(resultp1); 868c2ecf20Sopenharmony_ci Sgl_to_dbl_mantissa(src,resultp1,resultp2); 878c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 888c2ecf20Sopenharmony_ci return(NOEXCEPTION); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * Test for zero or denormalized 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci if (src_exponent == 0) { 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * determine if zero or denormalized 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (Sgl_isnotzero_mantissa(src)) { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * is denormalized; want to normalize 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci Sgl_clear_signexponent(src); 1038c2ecf20Sopenharmony_ci Sgl_leftshiftby1(src); 1048c2ecf20Sopenharmony_ci Sgl_normalize(src,src_exponent); 1058c2ecf20Sopenharmony_ci Sgl_to_dbl_exponent(src_exponent,resultp1); 1068c2ecf20Sopenharmony_ci Sgl_to_dbl_mantissa(src,resultp1,resultp2); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci else { 1098c2ecf20Sopenharmony_ci Dbl_setzero_exponentmantissa(resultp1,resultp2); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 1128c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * No special cases, just complete the conversion 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci Sgl_to_dbl_exponent(src_exponent, resultp1); 1188c2ecf20Sopenharmony_ci Sgl_to_dbl_mantissa(Sgl_mantissa(src), resultp1,resultp2); 1198c2ecf20Sopenharmony_ci Dbl_copytoptr(resultp1,resultp2,dstptr); 1208c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Double Floating-point to Single Floating-point 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci/*ARGSUSED*/ 1278c2ecf20Sopenharmony_ciint 1288c2ecf20Sopenharmony_cidbl_to_sgl_fcnvff( 1298c2ecf20Sopenharmony_ci dbl_floating_point *srcptr, 1308c2ecf20Sopenharmony_ci unsigned int *nullptr, 1318c2ecf20Sopenharmony_ci sgl_floating_point *dstptr, 1328c2ecf20Sopenharmony_ci unsigned int *status) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci register unsigned int srcp1, srcp2, result; 1358c2ecf20Sopenharmony_ci register int src_exponent, dest_exponent, dest_mantissa; 1368c2ecf20Sopenharmony_ci register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE; 1378c2ecf20Sopenharmony_ci register boolean lsb_odd = FALSE; 1388c2ecf20Sopenharmony_ci boolean is_tiny = FALSE; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci Dbl_copyfromptr(srcptr,srcp1,srcp2); 1418c2ecf20Sopenharmony_ci src_exponent = Dbl_exponent(srcp1); 1428c2ecf20Sopenharmony_ci Sgl_all(result) = Dbl_allp1(srcp1); /* set sign of result */ 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Test for NaN or infinity 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci if (src_exponent == DBL_INFINITY_EXPONENT) { 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * determine if NaN or infinity 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci if (Dbl_iszero_mantissa(srcp1,srcp2)) { 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * is infinity; want to return single infinity 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci Sgl_setinfinity_exponentmantissa(result); 1558c2ecf20Sopenharmony_ci *dstptr = result; 1568c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * is NaN; signaling or quiet? 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci if (Dbl_isone_signaling(srcp1)) { 1628c2ecf20Sopenharmony_ci /* trap if INVALIDTRAP enabled */ 1638c2ecf20Sopenharmony_ci if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 1648c2ecf20Sopenharmony_ci else { 1658c2ecf20Sopenharmony_ci Set_invalidflag(); 1668c2ecf20Sopenharmony_ci /* make NaN quiet */ 1678c2ecf20Sopenharmony_ci Dbl_set_quiet(srcp1); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci /* 1718c2ecf20Sopenharmony_ci * NaN is quiet, return as single NaN 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci Sgl_setinfinity_exponent(result); 1748c2ecf20Sopenharmony_ci Sgl_set_mantissa(result,Dallp1(srcp1)<<3 | Dallp2(srcp2)>>29); 1758c2ecf20Sopenharmony_ci if (Sgl_iszero_mantissa(result)) Sgl_set_quiet(result); 1768c2ecf20Sopenharmony_ci *dstptr = result; 1778c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Generate result 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci Dbl_to_sgl_exponent(src_exponent,dest_exponent); 1838c2ecf20Sopenharmony_ci if (dest_exponent > 0) { 1848c2ecf20Sopenharmony_ci Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,guardbit, 1858c2ecf20Sopenharmony_ci stickybit,lsb_odd); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci else { 1888c2ecf20Sopenharmony_ci if (Dbl_iszero_exponentmantissa(srcp1,srcp2)){ 1898c2ecf20Sopenharmony_ci Sgl_setzero_exponentmantissa(result); 1908c2ecf20Sopenharmony_ci *dstptr = result; 1918c2ecf20Sopenharmony_ci return(NOEXCEPTION); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci if (Is_underflowtrap_enabled()) { 1948c2ecf20Sopenharmony_ci Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact, 1958c2ecf20Sopenharmony_ci guardbit,stickybit,lsb_odd); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci else { 1988c2ecf20Sopenharmony_ci /* compute result, determine inexact info, 1998c2ecf20Sopenharmony_ci * and set Underflowflag if appropriate 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci Dbl_to_sgl_denormalized(srcp1,srcp2,dest_exponent, 2028c2ecf20Sopenharmony_ci dest_mantissa,inexact,guardbit,stickybit,lsb_odd, 2038c2ecf20Sopenharmony_ci is_tiny); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Now round result if not exact 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci if (inexact) { 2108c2ecf20Sopenharmony_ci switch (Rounding_mode()) { 2118c2ecf20Sopenharmony_ci case ROUNDPLUS: 2128c2ecf20Sopenharmony_ci if (Sgl_iszero_sign(result)) dest_mantissa++; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci case ROUNDMINUS: 2158c2ecf20Sopenharmony_ci if (Sgl_isone_sign(result)) dest_mantissa++; 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci case ROUNDNEAREST: 2188c2ecf20Sopenharmony_ci if (guardbit) { 2198c2ecf20Sopenharmony_ci if (stickybit || lsb_odd) dest_mantissa++; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci Sgl_set_exponentmantissa(result,dest_mantissa); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * check for mantissa overflow after rounding 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci if ((dest_exponent>0 || Is_underflowtrap_enabled()) && 2298c2ecf20Sopenharmony_ci Sgl_isone_hidden(result)) dest_exponent++; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Test for overflow 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (dest_exponent >= SGL_INFINITY_EXPONENT) { 2358c2ecf20Sopenharmony_ci /* trap if OVERFLOWTRAP enabled */ 2368c2ecf20Sopenharmony_ci if (Is_overflowtrap_enabled()) { 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * Check for gross overflow 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (dest_exponent >= SGL_INFINITY_EXPONENT+SGL_WRAP) 2418c2ecf20Sopenharmony_ci return(UNIMPLEMENTEDEXCEPTION); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * Adjust bias of result 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,dest_exponent,ovfl); 2478c2ecf20Sopenharmony_ci *dstptr = result; 2488c2ecf20Sopenharmony_ci if (inexact) 2498c2ecf20Sopenharmony_ci if (Is_inexacttrap_enabled()) 2508c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION|INEXACTEXCEPTION); 2518c2ecf20Sopenharmony_ci else Set_inexactflag(); 2528c2ecf20Sopenharmony_ci return(OVERFLOWEXCEPTION); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci Set_overflowflag(); 2558c2ecf20Sopenharmony_ci inexact = TRUE; 2568c2ecf20Sopenharmony_ci /* set result to infinity or largest number */ 2578c2ecf20Sopenharmony_ci Sgl_setoverflow(result); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci /* 2608c2ecf20Sopenharmony_ci * Test for underflow 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci else if (dest_exponent <= 0) { 2638c2ecf20Sopenharmony_ci /* trap if UNDERFLOWTRAP enabled */ 2648c2ecf20Sopenharmony_ci if (Is_underflowtrap_enabled()) { 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * Check for gross underflow 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if (dest_exponent <= -(SGL_WRAP)) 2698c2ecf20Sopenharmony_ci return(UNIMPLEMENTEDEXCEPTION); 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * Adjust bias of result 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci Sgl_setwrapped_exponent(result,dest_exponent,unfl); 2748c2ecf20Sopenharmony_ci *dstptr = result; 2758c2ecf20Sopenharmony_ci if (inexact) 2768c2ecf20Sopenharmony_ci if (Is_inexacttrap_enabled()) 2778c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION|INEXACTEXCEPTION); 2788c2ecf20Sopenharmony_ci else Set_inexactflag(); 2798c2ecf20Sopenharmony_ci return(UNDERFLOWEXCEPTION); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci /* 2828c2ecf20Sopenharmony_ci * result is denormalized or signed zero 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci if (inexact && is_tiny) Set_underflowflag(); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci else Sgl_set_exponent(result,dest_exponent); 2888c2ecf20Sopenharmony_ci *dstptr = result; 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * Trap if inexact trap is enabled 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if (inexact) 2938c2ecf20Sopenharmony_ci if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 2948c2ecf20Sopenharmony_ci else Set_inexactflag(); 2958c2ecf20Sopenharmony_ci return(NOEXCEPTION); 2968c2ecf20Sopenharmony_ci} 297