162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <math-emu/soft-fp.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#undef count_leading_zeros 762306a36Sopenharmony_ci#define count_leading_zeros __FP_CLZ 862306a36Sopenharmony_ci 962306a36Sopenharmony_civoid 1062306a36Sopenharmony_ci_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], 1162306a36Sopenharmony_ci _FP_W_TYPE n1, _FP_W_TYPE n0, 1262306a36Sopenharmony_ci _FP_W_TYPE d1, _FP_W_TYPE d0) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci _FP_W_TYPE q0, q1, r0, r1; 1562306a36Sopenharmony_ci _FP_I_TYPE b, bm; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci if (d1 == 0) 1862306a36Sopenharmony_ci { 1962306a36Sopenharmony_ci#if !UDIV_NEEDS_NORMALIZATION 2062306a36Sopenharmony_ci if (d0 > n1) 2162306a36Sopenharmony_ci { 2262306a36Sopenharmony_ci /* 0q = nn / 0D */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 2562306a36Sopenharmony_ci q1 = 0; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* Remainder in n0. */ 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci else 3062306a36Sopenharmony_ci { 3162306a36Sopenharmony_ci /* qq = NN / 0d */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (d0 == 0) 3462306a36Sopenharmony_ci d0 = 1 / d0; /* Divide intentionally by zero. */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci udiv_qrnnd (q1, n1, 0, n1, d0); 3762306a36Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* Remainder in n0. */ 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci r0 = n0; 4362306a36Sopenharmony_ci r1 = 0; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#else /* UDIV_NEEDS_NORMALIZATION */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (d0 > n1) 4862306a36Sopenharmony_ci { 4962306a36Sopenharmony_ci /* 0q = nn / 0D */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci count_leading_zeros (bm, d0); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (bm != 0) 5462306a36Sopenharmony_ci { 5562306a36Sopenharmony_ci /* Normalize, i.e. make the most significant bit of the 5662306a36Sopenharmony_ci denominator set. */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci d0 = d0 << bm; 5962306a36Sopenharmony_ci n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm)); 6062306a36Sopenharmony_ci n0 = n0 << bm; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 6462306a36Sopenharmony_ci q1 = 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Remainder in n0 >> bm. */ 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci { 7062306a36Sopenharmony_ci /* qq = NN / 0d */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (d0 == 0) 7362306a36Sopenharmony_ci d0 = 1 / d0; /* Divide intentionally by zero. */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci count_leading_zeros (bm, d0); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (bm == 0) 7862306a36Sopenharmony_ci { 7962306a36Sopenharmony_ci /* From (n1 >= d0) /\ (the most significant bit of d0 is set), 8062306a36Sopenharmony_ci conclude (the most significant bit of n1 is set) /\ (the 8162306a36Sopenharmony_ci leading quotient digit q1 = 1). 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci This special case is necessary, not an optimization. 8462306a36Sopenharmony_ci (Shifts counts of SI_TYPE_SIZE are undefined.) */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci n1 -= d0; 8762306a36Sopenharmony_ci q1 = 1; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci else 9062306a36Sopenharmony_ci { 9162306a36Sopenharmony_ci _FP_W_TYPE n2; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Normalize. */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci b = _FP_W_TYPE_SIZE - bm; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci d0 = d0 << bm; 9862306a36Sopenharmony_ci n2 = n1 >> b; 9962306a36Sopenharmony_ci n1 = (n1 << bm) | (n0 >> b); 10062306a36Sopenharmony_ci n0 = n0 << bm; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci udiv_qrnnd (q1, n1, n2, n1, d0); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* n1 != d0... */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci udiv_qrnnd (q0, n0, n1, n0, d0); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Remainder in n0 >> bm. */ 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci r0 = n0 >> bm; 11362306a36Sopenharmony_ci r1 = 0; 11462306a36Sopenharmony_ci#endif /* UDIV_NEEDS_NORMALIZATION */ 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci else 11762306a36Sopenharmony_ci { 11862306a36Sopenharmony_ci if (d1 > n1) 11962306a36Sopenharmony_ci { 12062306a36Sopenharmony_ci /* 00 = nn / DD */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci q0 = 0; 12362306a36Sopenharmony_ci q1 = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Remainder in n1n0. */ 12662306a36Sopenharmony_ci r0 = n0; 12762306a36Sopenharmony_ci r1 = n1; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci else 13062306a36Sopenharmony_ci { 13162306a36Sopenharmony_ci /* 0q = NN / dd */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci count_leading_zeros (bm, d1); 13462306a36Sopenharmony_ci if (bm == 0) 13562306a36Sopenharmony_ci { 13662306a36Sopenharmony_ci /* From (n1 >= d1) /\ (the most significant bit of d1 is set), 13762306a36Sopenharmony_ci conclude (the most significant bit of n1 is set) /\ (the 13862306a36Sopenharmony_ci quotient digit q0 = 0 or 1). 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci This special case is necessary, not an optimization. */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* The condition on the next line takes advantage of that 14362306a36Sopenharmony_ci n1 >= d1 (true due to program flow). */ 14462306a36Sopenharmony_ci if (n1 > d1 || n0 >= d0) 14562306a36Sopenharmony_ci { 14662306a36Sopenharmony_ci q0 = 1; 14762306a36Sopenharmony_ci sub_ddmmss (n1, n0, n1, n0, d1, d0); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci else 15062306a36Sopenharmony_ci q0 = 0; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci q1 = 0; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci r0 = n0; 15562306a36Sopenharmony_ci r1 = n1; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci else 15862306a36Sopenharmony_ci { 15962306a36Sopenharmony_ci _FP_W_TYPE m1, m0, n2; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Normalize. */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci b = _FP_W_TYPE_SIZE - bm; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci d1 = (d1 << bm) | (d0 >> b); 16662306a36Sopenharmony_ci d0 = d0 << bm; 16762306a36Sopenharmony_ci n2 = n1 >> b; 16862306a36Sopenharmony_ci n1 = (n1 << bm) | (n0 >> b); 16962306a36Sopenharmony_ci n0 = n0 << bm; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci udiv_qrnnd (q0, n1, n2, n1, d1); 17262306a36Sopenharmony_ci umul_ppmm (m1, m0, q0, d0); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (m1 > n1 || (m1 == n1 && m0 > n0)) 17562306a36Sopenharmony_ci { 17662306a36Sopenharmony_ci q0--; 17762306a36Sopenharmony_ci sub_ddmmss (m1, m0, m1, m0, d1, d0); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci q1 = 0; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Remainder in (n1n0 - m1m0) >> bm. */ 18362306a36Sopenharmony_ci sub_ddmmss (n1, n0, n1, n0, m1, m0); 18462306a36Sopenharmony_ci r0 = (n1 << b) | (n0 >> bm); 18562306a36Sopenharmony_ci r1 = n1 >> bm; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci q[0] = q0; q[1] = q1; 19162306a36Sopenharmony_ci r[0] = r0, r[1] = r1; 19262306a36Sopenharmony_ci} 193