diff mbox series

arc: libgcc: Import __udivdi3 & __udivmoddi4 to allow 64-bit division

Message ID 20190902094244.486-1-abrodkin@synopsys.com
State New
Headers show
Series arc: libgcc: Import __udivdi3 & __udivmoddi4 to allow 64-bit division | expand

Commit Message

Alexey Brodkin Sept. 2, 2019, 9:42 a.m. UTC
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] https://github.com/gcc-mirror/gcc/commit/5d8723600bc0eed41226b5a6785bc02a053b45d5

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Kever Yang <kever.yang@rock-chips.com>
---
 arch/arc/lib/libgcc2.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

Comments

Alexey Brodkin Sept. 2, 2019, 12:19 p.m. UTC | #1
Hi,

> -----Original Message-----
> From: Alexey Brodkin <abrodkin@synopsys.com>
> Sent: Monday, September 2, 2019 12:43 PM
> To: u-boot@lists.denx.de
> Cc: uboot-snps-arc@synopsys.com; linux-snps-arc@lists.infradead.org; Alexey Brodkin
> <abrodkin@synopsys.com>; Kever Yang <kever.yang@rock-chips.com>
> Subject: [PATCH] arc: libgcc: Import __udivdi3 & __udivmoddi4 to allow 64-bit division
> 
> 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] https://github.com/gcc-mirror/gcc/commit/5d8723600bc0eed41226b5a6785bc02a053b45d5
> 
> Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
> Cc: Kever Yang <kever.yang@rock-chips.com>

For the record for EM SDP (emsdp_defconfig) building still
fails this way:
----------------------------->8-------------------------
arc-linux-ld.bfd: arch/arc/lib/lib.a(libgcc2.o): in function `__udivmoddi4':
.../arch/arc/lib/libgcc2.c:195: undefined reference to `__clzdi2'
arc-linux-ld.bfd: .../arch/arc/lib/libgcc2.c:195: undefined reference to `__clzdi2'
arc-linux-ld.bfd: .../arch/arc/lib/libgcc2.c:196: undefined reference to `__clzdi2'
arc-linux-ld.bfd: .../arch/arc/lib/libgcc2.c:196: undefined reference to `__clzdi2'
----------------------------->8-------------------------

That happens because we use a very simple -mcpu=arcem which doesn't use
HW normalizer unit. I'm preparing a patch that will improve EM SDP's compiler
options.

-Alexey
diff mbox series

Patch

diff --git a/arch/arc/lib/libgcc2.c b/arch/arc/lib/libgcc2.c
index b92a841a37..ab1dbe1c13 100644
--- a/arch/arc/lib/libgcc2.c
+++ b/arch/arc/lib/libgcc2.c
@@ -158,3 +158,78 @@  __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);
+}