mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-26 05:51:29 +01:00 
			
		
		
		
	As reported by Kever here [1] we were unable to compile 64-bit division
code due to missing definition of __udivdi3().
Import its implementation and __udivmoddi4() as its direct dependency
from today's libgcc [2].
[1] https://patchwork.ozlabs.org/patch/1146845/
[2] 5d8723600b
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Kever Yang <kever.yang@rock-chips.com>
		
	
			
		
			
				
	
	
		
			236 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // 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);
 | |
| }
 |