18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <math-emu/soft-fp.h> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#undef count_leading_zeros 78c2ecf20Sopenharmony_ci#define count_leading_zeros __FP_CLZ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_civoid 108c2ecf20Sopenharmony_ci_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], 118c2ecf20Sopenharmony_ci _FP_W_TYPE n1, _FP_W_TYPE n0, 128c2ecf20Sopenharmony_ci _FP_W_TYPE d1, _FP_W_TYPE d0) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci _FP_W_TYPE q0, q1, r0, r1; 158c2ecf20Sopenharmony_ci _FP_I_TYPE b, bm; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci if (d1 == 0) 188c2ecf20Sopenharmony_ci { 198c2ecf20Sopenharmony_ci#if !UDIV_NEEDS_NORMALIZATION 208c2ecf20Sopenharmony_ci if (d0 > n1) 218c2ecf20Sopenharmony_ci { 228c2ecf20Sopenharmony_ci /* 0q = nn / 0D */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 258c2ecf20Sopenharmony_ci q1 = 0; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* Remainder in n0. */ 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci else 308c2ecf20Sopenharmony_ci { 318c2ecf20Sopenharmony_ci /* qq = NN / 0d */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (d0 == 0) 348c2ecf20Sopenharmony_ci d0 = 1 / d0; /* Divide intentionally by zero. */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci udiv_qrnnd (q1, n1, 0, n1, d0); 378c2ecf20Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Remainder in n0. */ 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci r0 = n0; 438c2ecf20Sopenharmony_ci r1 = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#else /* UDIV_NEEDS_NORMALIZATION */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (d0 > n1) 488c2ecf20Sopenharmony_ci { 498c2ecf20Sopenharmony_ci /* 0q = nn / 0D */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci count_leading_zeros (bm, d0); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (bm != 0) 548c2ecf20Sopenharmony_ci { 558c2ecf20Sopenharmony_ci /* Normalize, i.e. make the most significant bit of the 568c2ecf20Sopenharmony_ci denominator set. */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci d0 = d0 << bm; 598c2ecf20Sopenharmony_ci n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm)); 608c2ecf20Sopenharmony_ci n0 = n0 << bm; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 648c2ecf20Sopenharmony_ci q1 = 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Remainder in n0 >> bm. */ 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci { 708c2ecf20Sopenharmony_ci /* qq = NN / 0d */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (d0 == 0) 738c2ecf20Sopenharmony_ci d0 = 1 / d0; /* Divide intentionally by zero. */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci count_leading_zeros (bm, d0); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (bm == 0) 788c2ecf20Sopenharmony_ci { 798c2ecf20Sopenharmony_ci /* From (n1 >= d0) /\ (the most significant bit of d0 is set), 808c2ecf20Sopenharmony_ci conclude (the most significant bit of n1 is set) /\ (the 818c2ecf20Sopenharmony_ci leading quotient digit q1 = 1). 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci This special case is necessary, not an optimization. 848c2ecf20Sopenharmony_ci (Shifts counts of SI_TYPE_SIZE are undefined.) */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci n1 -= d0; 878c2ecf20Sopenharmony_ci q1 = 1; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci { 918c2ecf20Sopenharmony_ci _FP_W_TYPE n2; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Normalize. */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci b = _FP_W_TYPE_SIZE - bm; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci d0 = d0 << bm; 988c2ecf20Sopenharmony_ci n2 = n1 >> b; 998c2ecf20Sopenharmony_ci n1 = (n1 << bm) | (n0 >> b); 1008c2ecf20Sopenharmony_ci n0 = n0 << bm; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci udiv_qrnnd (q1, n1, n2, n1, d0); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* n1 != d0... */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Remainder in n0 >> bm. */ 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci r0 = n0 >> bm; 1138c2ecf20Sopenharmony_ci r1 = 0; 1148c2ecf20Sopenharmony_ci#endif /* UDIV_NEEDS_NORMALIZATION */ 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci { 1188c2ecf20Sopenharmony_ci if (d1 > n1) 1198c2ecf20Sopenharmony_ci { 1208c2ecf20Sopenharmony_ci /* 00 = nn / DD */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci q0 = 0; 1238c2ecf20Sopenharmony_ci q1 = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Remainder in n1n0. */ 1268c2ecf20Sopenharmony_ci r0 = n0; 1278c2ecf20Sopenharmony_ci r1 = n1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci else 1308c2ecf20Sopenharmony_ci { 1318c2ecf20Sopenharmony_ci /* 0q = NN / dd */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci count_leading_zeros (bm, d1); 1348c2ecf20Sopenharmony_ci if (bm == 0) 1358c2ecf20Sopenharmony_ci { 1368c2ecf20Sopenharmony_ci /* From (n1 >= d1) /\ (the most significant bit of d1 is set), 1378c2ecf20Sopenharmony_ci conclude (the most significant bit of n1 is set) /\ (the 1388c2ecf20Sopenharmony_ci quotient digit q0 = 0 or 1). 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci This special case is necessary, not an optimization. */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* The condition on the next line takes advantage of that 1438c2ecf20Sopenharmony_ci n1 >= d1 (true due to program flow). */ 1448c2ecf20Sopenharmony_ci if (n1 > d1 || n0 >= d0) 1458c2ecf20Sopenharmony_ci { 1468c2ecf20Sopenharmony_ci q0 = 1; 1478c2ecf20Sopenharmony_ci sub_ddmmss (n1, n0, n1, n0, d1, d0); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci q0 = 0; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci q1 = 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci r0 = n0; 1558c2ecf20Sopenharmony_ci r1 = n1; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci { 1598c2ecf20Sopenharmony_ci _FP_W_TYPE m1, m0, n2; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Normalize. */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci b = _FP_W_TYPE_SIZE - bm; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci d1 = (d1 << bm) | (d0 >> b); 1668c2ecf20Sopenharmony_ci d0 = d0 << bm; 1678c2ecf20Sopenharmony_ci n2 = n1 >> b; 1688c2ecf20Sopenharmony_ci n1 = (n1 << bm) | (n0 >> b); 1698c2ecf20Sopenharmony_ci n0 = n0 << bm; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci udiv_qrnnd (q0, n1, n2, n1, d1); 1728c2ecf20Sopenharmony_ci umul_ppmm (m1, m0, q0, d0); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (m1 > n1 || (m1 == n1 && m0 > n0)) 1758c2ecf20Sopenharmony_ci { 1768c2ecf20Sopenharmony_ci q0--; 1778c2ecf20Sopenharmony_ci sub_ddmmss (m1, m0, m1, m0, d1, d0); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci q1 = 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Remainder in (n1n0 - m1m0) >> bm. */ 1838c2ecf20Sopenharmony_ci sub_ddmmss (n1, n0, n1, n0, m1, m0); 1848c2ecf20Sopenharmony_ci r0 = (n1 << b) | (n0 >> bm); 1858c2ecf20Sopenharmony_ci r1 = n1 >> bm; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci q[0] = q0; q[1] = q1; 1918c2ecf20Sopenharmony_ci r[0] = r0, r[1] = r1; 1928c2ecf20Sopenharmony_ci} 193