1*0a6a1f1dSLionel Sambuc /* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== 2*0a6a1f1dSLionel Sambuc * 3*0a6a1f1dSLionel Sambuc * The LLVM Compiler Infrastructure 4*0a6a1f1dSLionel Sambuc * 5*0a6a1f1dSLionel Sambuc * This file is dual licensed under the MIT and the University of Illinois Open 6*0a6a1f1dSLionel Sambuc * Source Licenses. See LICENSE.TXT for details. 7*0a6a1f1dSLionel Sambuc * 8*0a6a1f1dSLionel Sambuc * ===----------------------------------------------------------------------=== 9*0a6a1f1dSLionel Sambuc * 10*0a6a1f1dSLionel Sambuc * This file implements __udivmoddi4 for the compiler_rt library. 11*0a6a1f1dSLionel Sambuc * 12*0a6a1f1dSLionel Sambuc * ===----------------------------------------------------------------------=== 13*0a6a1f1dSLionel Sambuc */ 14*0a6a1f1dSLionel Sambuc 15*0a6a1f1dSLionel Sambuc #include "int_lib.h" 16*0a6a1f1dSLionel Sambuc 17*0a6a1f1dSLionel Sambuc /* Effects: if rem != 0, *rem = a % b 18*0a6a1f1dSLionel Sambuc * Returns: a / b 19*0a6a1f1dSLionel Sambuc */ 20*0a6a1f1dSLionel Sambuc 21*0a6a1f1dSLionel Sambuc /* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ 22*0a6a1f1dSLionel Sambuc 23*0a6a1f1dSLionel Sambuc COMPILER_RT_ABI du_int __udivmoddi4(du_int a,du_int b,du_int * rem)24*0a6a1f1dSLionel Sambuc__udivmoddi4(du_int a, du_int b, du_int* rem) 25*0a6a1f1dSLionel Sambuc { 26*0a6a1f1dSLionel Sambuc const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; 27*0a6a1f1dSLionel Sambuc const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; 28*0a6a1f1dSLionel Sambuc udwords n; 29*0a6a1f1dSLionel Sambuc n.all = a; 30*0a6a1f1dSLionel Sambuc udwords d; 31*0a6a1f1dSLionel Sambuc d.all = b; 32*0a6a1f1dSLionel Sambuc udwords q; 33*0a6a1f1dSLionel Sambuc udwords r; 34*0a6a1f1dSLionel Sambuc unsigned sr; 35*0a6a1f1dSLionel Sambuc /* special cases, X is unknown, K != 0 */ 36*0a6a1f1dSLionel Sambuc if (n.s.high == 0) 37*0a6a1f1dSLionel Sambuc { 38*0a6a1f1dSLionel Sambuc if (d.s.high == 0) 39*0a6a1f1dSLionel Sambuc { 40*0a6a1f1dSLionel Sambuc /* 0 X 41*0a6a1f1dSLionel Sambuc * --- 42*0a6a1f1dSLionel Sambuc * 0 X 43*0a6a1f1dSLionel Sambuc */ 44*0a6a1f1dSLionel Sambuc if (rem) 45*0a6a1f1dSLionel Sambuc *rem = n.s.low % d.s.low; 46*0a6a1f1dSLionel Sambuc return n.s.low / d.s.low; 47*0a6a1f1dSLionel Sambuc } 48*0a6a1f1dSLionel Sambuc /* 0 X 49*0a6a1f1dSLionel Sambuc * --- 50*0a6a1f1dSLionel Sambuc * K X 51*0a6a1f1dSLionel Sambuc */ 52*0a6a1f1dSLionel Sambuc if (rem) 53*0a6a1f1dSLionel Sambuc *rem = n.s.low; 54*0a6a1f1dSLionel Sambuc return 0; 55*0a6a1f1dSLionel Sambuc } 56*0a6a1f1dSLionel Sambuc /* n.s.high != 0 */ 57*0a6a1f1dSLionel Sambuc if (d.s.low == 0) 58*0a6a1f1dSLionel Sambuc { 59*0a6a1f1dSLionel Sambuc if (d.s.high == 0) 60*0a6a1f1dSLionel Sambuc { 61*0a6a1f1dSLionel Sambuc /* K X 62*0a6a1f1dSLionel Sambuc * --- 63*0a6a1f1dSLionel Sambuc * 0 0 64*0a6a1f1dSLionel Sambuc */ 65*0a6a1f1dSLionel Sambuc if (rem) 66*0a6a1f1dSLionel Sambuc *rem = n.s.high % d.s.low; 67*0a6a1f1dSLionel Sambuc return n.s.high / d.s.low; 68*0a6a1f1dSLionel Sambuc } 69*0a6a1f1dSLionel Sambuc /* d.s.high != 0 */ 70*0a6a1f1dSLionel Sambuc if (n.s.low == 0) 71*0a6a1f1dSLionel Sambuc { 72*0a6a1f1dSLionel Sambuc /* K 0 73*0a6a1f1dSLionel Sambuc * --- 74*0a6a1f1dSLionel Sambuc * K 0 75*0a6a1f1dSLionel Sambuc */ 76*0a6a1f1dSLionel Sambuc if (rem) 77*0a6a1f1dSLionel Sambuc { 78*0a6a1f1dSLionel Sambuc r.s.high = n.s.high % d.s.high; 79*0a6a1f1dSLionel Sambuc r.s.low = 0; 80*0a6a1f1dSLionel Sambuc *rem = r.all; 81*0a6a1f1dSLionel Sambuc } 82*0a6a1f1dSLionel Sambuc return n.s.high / d.s.high; 83*0a6a1f1dSLionel Sambuc } 84*0a6a1f1dSLionel Sambuc /* K K 85*0a6a1f1dSLionel Sambuc * --- 86*0a6a1f1dSLionel Sambuc * K 0 87*0a6a1f1dSLionel Sambuc */ 88*0a6a1f1dSLionel Sambuc if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ 89*0a6a1f1dSLionel Sambuc { 90*0a6a1f1dSLionel Sambuc if (rem) 91*0a6a1f1dSLionel Sambuc { 92*0a6a1f1dSLionel Sambuc r.s.low = n.s.low; 93*0a6a1f1dSLionel Sambuc r.s.high = n.s.high & (d.s.high - 1); 94*0a6a1f1dSLionel Sambuc *rem = r.all; 95*0a6a1f1dSLionel Sambuc } 96*0a6a1f1dSLionel Sambuc return n.s.high >> __builtin_ctz(d.s.high); 97*0a6a1f1dSLionel Sambuc } 98*0a6a1f1dSLionel Sambuc /* K K 99*0a6a1f1dSLionel Sambuc * --- 100*0a6a1f1dSLionel Sambuc * K 0 101*0a6a1f1dSLionel Sambuc */ 102*0a6a1f1dSLionel Sambuc sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); 103*0a6a1f1dSLionel Sambuc /* 0 <= sr <= n_uword_bits - 2 or sr large */ 104*0a6a1f1dSLionel Sambuc if (sr > n_uword_bits - 2) 105*0a6a1f1dSLionel Sambuc { 106*0a6a1f1dSLionel Sambuc if (rem) 107*0a6a1f1dSLionel Sambuc *rem = n.all; 108*0a6a1f1dSLionel Sambuc return 0; 109*0a6a1f1dSLionel Sambuc } 110*0a6a1f1dSLionel Sambuc ++sr; 111*0a6a1f1dSLionel Sambuc /* 1 <= sr <= n_uword_bits - 1 */ 112*0a6a1f1dSLionel Sambuc /* q.all = n.all << (n_udword_bits - sr); */ 113*0a6a1f1dSLionel Sambuc q.s.low = 0; 114*0a6a1f1dSLionel Sambuc q.s.high = n.s.low << (n_uword_bits - sr); 115*0a6a1f1dSLionel Sambuc /* r.all = n.all >> sr; */ 116*0a6a1f1dSLionel Sambuc r.s.high = n.s.high >> sr; 117*0a6a1f1dSLionel Sambuc r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); 118*0a6a1f1dSLionel Sambuc } 119*0a6a1f1dSLionel Sambuc else /* d.s.low != 0 */ 120*0a6a1f1dSLionel Sambuc { 121*0a6a1f1dSLionel Sambuc if (d.s.high == 0) 122*0a6a1f1dSLionel Sambuc { 123*0a6a1f1dSLionel Sambuc /* K X 124*0a6a1f1dSLionel Sambuc * --- 125*0a6a1f1dSLionel Sambuc * 0 K 126*0a6a1f1dSLionel Sambuc */ 127*0a6a1f1dSLionel Sambuc if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ 128*0a6a1f1dSLionel Sambuc { 129*0a6a1f1dSLionel Sambuc if (rem) 130*0a6a1f1dSLionel Sambuc *rem = n.s.low & (d.s.low - 1); 131*0a6a1f1dSLionel Sambuc if (d.s.low == 1) 132*0a6a1f1dSLionel Sambuc return n.all; 133*0a6a1f1dSLionel Sambuc sr = __builtin_ctz(d.s.low); 134*0a6a1f1dSLionel Sambuc q.s.high = n.s.high >> sr; 135*0a6a1f1dSLionel Sambuc q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); 136*0a6a1f1dSLionel Sambuc return q.all; 137*0a6a1f1dSLionel Sambuc } 138*0a6a1f1dSLionel Sambuc /* K X 139*0a6a1f1dSLionel Sambuc * --- 140*0a6a1f1dSLionel Sambuc * 0 K 141*0a6a1f1dSLionel Sambuc */ 142*0a6a1f1dSLionel Sambuc sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); 143*0a6a1f1dSLionel Sambuc /* 2 <= sr <= n_udword_bits - 1 144*0a6a1f1dSLionel Sambuc * q.all = n.all << (n_udword_bits - sr); 145*0a6a1f1dSLionel Sambuc * r.all = n.all >> sr; 146*0a6a1f1dSLionel Sambuc */ 147*0a6a1f1dSLionel Sambuc if (sr == n_uword_bits) 148*0a6a1f1dSLionel Sambuc { 149*0a6a1f1dSLionel Sambuc q.s.low = 0; 150*0a6a1f1dSLionel Sambuc q.s.high = n.s.low; 151*0a6a1f1dSLionel Sambuc r.s.high = 0; 152*0a6a1f1dSLionel Sambuc r.s.low = n.s.high; 153*0a6a1f1dSLionel Sambuc } 154*0a6a1f1dSLionel Sambuc else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 155*0a6a1f1dSLionel Sambuc { 156*0a6a1f1dSLionel Sambuc q.s.low = 0; 157*0a6a1f1dSLionel Sambuc q.s.high = n.s.low << (n_uword_bits - sr); 158*0a6a1f1dSLionel Sambuc r.s.high = n.s.high >> sr; 159*0a6a1f1dSLionel Sambuc r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); 160*0a6a1f1dSLionel Sambuc } 161*0a6a1f1dSLionel Sambuc else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 162*0a6a1f1dSLionel Sambuc { 163*0a6a1f1dSLionel Sambuc q.s.low = n.s.low << (n_udword_bits - sr); 164*0a6a1f1dSLionel Sambuc q.s.high = (n.s.high << (n_udword_bits - sr)) | 165*0a6a1f1dSLionel Sambuc (n.s.low >> (sr - n_uword_bits)); 166*0a6a1f1dSLionel Sambuc r.s.high = 0; 167*0a6a1f1dSLionel Sambuc r.s.low = n.s.high >> (sr - n_uword_bits); 168*0a6a1f1dSLionel Sambuc } 169*0a6a1f1dSLionel Sambuc } 170*0a6a1f1dSLionel Sambuc else 171*0a6a1f1dSLionel Sambuc { 172*0a6a1f1dSLionel Sambuc /* K X 173*0a6a1f1dSLionel Sambuc * --- 174*0a6a1f1dSLionel Sambuc * K K 175*0a6a1f1dSLionel Sambuc */ 176*0a6a1f1dSLionel Sambuc sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); 177*0a6a1f1dSLionel Sambuc /* 0 <= sr <= n_uword_bits - 1 or sr large */ 178*0a6a1f1dSLionel Sambuc if (sr > n_uword_bits - 1) 179*0a6a1f1dSLionel Sambuc { 180*0a6a1f1dSLionel Sambuc if (rem) 181*0a6a1f1dSLionel Sambuc *rem = n.all; 182*0a6a1f1dSLionel Sambuc return 0; 183*0a6a1f1dSLionel Sambuc } 184*0a6a1f1dSLionel Sambuc ++sr; 185*0a6a1f1dSLionel Sambuc /* 1 <= sr <= n_uword_bits */ 186*0a6a1f1dSLionel Sambuc /* q.all = n.all << (n_udword_bits - sr); */ 187*0a6a1f1dSLionel Sambuc q.s.low = 0; 188*0a6a1f1dSLionel Sambuc if (sr == n_uword_bits) 189*0a6a1f1dSLionel Sambuc { 190*0a6a1f1dSLionel Sambuc q.s.high = n.s.low; 191*0a6a1f1dSLionel Sambuc r.s.high = 0; 192*0a6a1f1dSLionel Sambuc r.s.low = n.s.high; 193*0a6a1f1dSLionel Sambuc } 194*0a6a1f1dSLionel Sambuc else 195*0a6a1f1dSLionel Sambuc { 196*0a6a1f1dSLionel Sambuc q.s.high = n.s.low << (n_uword_bits - sr); 197*0a6a1f1dSLionel Sambuc r.s.high = n.s.high >> sr; 198*0a6a1f1dSLionel Sambuc r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); 199*0a6a1f1dSLionel Sambuc } 200*0a6a1f1dSLionel Sambuc } 201*0a6a1f1dSLionel Sambuc } 202*0a6a1f1dSLionel Sambuc /* Not a special case 203*0a6a1f1dSLionel Sambuc * q and r are initialized with: 204*0a6a1f1dSLionel Sambuc * q.all = n.all << (n_udword_bits - sr); 205*0a6a1f1dSLionel Sambuc * r.all = n.all >> sr; 206*0a6a1f1dSLionel Sambuc * 1 <= sr <= n_udword_bits - 1 207*0a6a1f1dSLionel Sambuc */ 208*0a6a1f1dSLionel Sambuc su_int carry = 0; 209*0a6a1f1dSLionel Sambuc for (; sr > 0; --sr) 210*0a6a1f1dSLionel Sambuc { 211*0a6a1f1dSLionel Sambuc /* r:q = ((r:q) << 1) | carry */ 212*0a6a1f1dSLionel Sambuc r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); 213*0a6a1f1dSLionel Sambuc r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); 214*0a6a1f1dSLionel Sambuc q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); 215*0a6a1f1dSLionel Sambuc q.s.low = (q.s.low << 1) | carry; 216*0a6a1f1dSLionel Sambuc /* carry = 0; 217*0a6a1f1dSLionel Sambuc * if (r.all >= d.all) 218*0a6a1f1dSLionel Sambuc * { 219*0a6a1f1dSLionel Sambuc * r.all -= d.all; 220*0a6a1f1dSLionel Sambuc * carry = 1; 221*0a6a1f1dSLionel Sambuc * } 222*0a6a1f1dSLionel Sambuc */ 223*0a6a1f1dSLionel Sambuc const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); 224*0a6a1f1dSLionel Sambuc carry = s & 1; 225*0a6a1f1dSLionel Sambuc r.all -= d.all & s; 226*0a6a1f1dSLionel Sambuc } 227*0a6a1f1dSLionel Sambuc q.all = (q.all << 1) | carry; 228*0a6a1f1dSLionel Sambuc if (rem) 229*0a6a1f1dSLionel Sambuc *rem = r.all; 230*0a6a1f1dSLionel Sambuc return q.all; 231*0a6a1f1dSLionel Sambuc } 232