// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 1989-2013 Free Software Foundation, Inc. */ #include "libgcc2.h" DWtype __ashldi3(DWtype u, shift_count_type b) { if (b == 0) return u; const DWunion uu = {.ll = u}; const shift_count_type bm = W_TYPE_SIZE - b; DWunion w; if (bm <= 0) { w.s.low = 0; w.s.high = (UWtype)uu.s.low << -bm; } else { const UWtype carries = (UWtype) uu.s.low >> bm; w.s.low = (UWtype)uu.s.low << b; w.s.high = ((UWtype)uu.s.high << b) | carries; } return w.ll; } DWtype __ashrdi3(DWtype u, shift_count_type b) { if (b == 0) return u; const DWunion uu = {.ll = u}; const shift_count_type bm = W_TYPE_SIZE - b; DWunion w; if (bm <= 0) { /* w.s.high = 1..1 or 0..0 */ w.s.high = uu.s.high >> (W_TYPE_SIZE - 1); w.s.low = uu.s.high >> -bm; } else { const UWtype carries = (UWtype) uu.s.high << bm; w.s.high = uu.s.high >> b; w.s.low = ((UWtype)uu.s.low >> b) | carries; } return w.ll; } DWtype __lshrdi3(DWtype u, shift_count_type b) { if (b == 0) return u; const DWunion uu = {.ll = u}; const shift_count_type bm = W_TYPE_SIZE - b; DWunion w; if (bm <= 0) { w.s.high = 0; w.s.low = (UWtype)uu.s.high >> -bm; } else { const UWtype carries = (UWtype)uu.s.high << bm; w.s.high = (UWtype)uu.s.high >> b; w.s.low = ((UWtype)uu.s.low >> b) | carries; } return w.ll; } unsigned long udivmodsi4(unsigned long num, unsigned long den, int modwanted) { unsigned long bit = 1; unsigned long res = 0; while (den < num && bit && !(den & (1L<<31))) { den <<= 1; bit <<= 1; } while (bit) { if (num >= den) { num -= den; res |= bit; } bit >>= 1; den >>= 1; } if (modwanted) return num; return res; } long __divsi3(long a, long b) { int neg = 0; long res; if (a < 0) { a = -a; neg = !neg; } if (b < 0) { b = -b; neg = !neg; } res = udivmodsi4(a, b, 0); if (neg) res = -res; return res; } long __modsi3(long a, long b) { int neg = 0; long res; if (a < 0) { a = -a; neg = 1; } if (b < 0) b = -b; res = udivmodsi4(a, b, 1); if (neg) res = -res; return res; } long __udivsi3(long a, long b) { return udivmodsi4(a, b, 0); } long __umodsi3(long a, long b) { return udivmodsi4(a, b, 1); } UDWtype __udivmoddi4(UDWtype n, UDWtype d, UDWtype *rp) { UDWtype q = 0, r = n, y = d; UWtype lz1, lz2, i, k; /* * Implements align divisor shift dividend method. This algorithm * aligns the divisor under the dividend and then perform number of * test-subtract iterations which shift the dividend left. Number of * iterations is k + 1 where k is the number of bit positions the * divisor must be shifted left to align it under the dividend. * quotient bits can be saved in the rightmost positions of the * dividend as it shifts left on each test-subtract iteration. */ if (y <= r) { lz1 = __builtin_clzll(d); lz2 = __builtin_clzll(n); k = lz1 - lz2; y = (y << k); /* * Dividend can exceed 2 ^ (width - 1) - 1 but still be less * than the aligned divisor. Normal iteration can drops the * high order bit of the dividend. Therefore, first * test-subtract iteration is a special case, saving its * quotient bit in a separate location and not shifting * the dividend. */ if (r >= y) { r = r - y; q = (1ULL << k); } if (k > 0) { y = y >> 1; /* * k additional iterations where k regular test * subtract shift dividend iterations are done. */ i = k; do { if (r >= y) r = ((r - y) << 1) + 1; else r = (r << 1); i = i - 1; } while (i != 0); /* * First quotient bit is combined with the quotient * bits resulting from the k regular iterations. */ q = q + r; r = r >> k; q = q - (r << k); } } if (rp) *rp = r; return q; } UDWtype __udivdi3(UDWtype n, UDWtype d) { return __udivmoddi4(n, d, (UDWtype *)0); }