From ddeda01ec5ece849f30e767a1feaba2def1a798f Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 29 Aug 2020 14:30:44 +0200
Subject: [PATCH] WIP __udivti3()

---
 sys/conf/kern.pre.mk                 |   4 +-
 sys/cpu/x86_64/include/stdint.h      |   6 +
 sys/platform/pc64/conf/files         |   1 +
 sys/platform/pc64/x86_64/__udivti3.c | 318 +++++++++++++++++++++++++++
 sys/sys/systm.h                      |   9 +-
 5 files changed, 331 insertions(+), 7 deletions(-)
 create mode 100644 sys/platform/pc64/x86_64/__udivti3.c

diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index 1c432cf652..d9feeb2991 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -105,8 +105,6 @@ NORMAL_FWO= ${LD} -b binary -d -warn-common -r -o ${.TARGET} ${.ALLSRC:M*.fw}
 WERROR=-Werror
 .endif
 
-# NOTE: -lgcc only needed for muldivu64 (__udivti3)
-#
 GEN_CFILES= $S/platform/$P/$M/genassym.c
 SYSTEM_CFILES= ioconf.c config.c
 SYSTEM_SFILES= $S/platform/$P/$M/locore.s
@@ -115,7 +113,7 @@ SYSTEM_OBJS= locore.o ${OBJS} ioconf.o config.o hack.So
 SYSTEM_LD= @${CC} -nostdlib -ffreestanding -Wl,--hash-style=sysv \
 	-Wl,-Bdynamic -Wl,-T,$S/platform/$P/conf/ldscript.$M \
 	-Wl,--export-dynamic -Wl,--dynamic-linker,/red/herring \
-	-o ${.TARGET} -Wl,-X ${SYSTEM_OBJS} vers.o -lgcc
+	-o ${.TARGET} -Wl,-X ${SYSTEM_OBJS} vers.o
 
 # In case of LTO provide all standard CFLAGS!
 .if ${CFLAGS:M-flto}
diff --git a/sys/cpu/x86_64/include/stdint.h b/sys/cpu/x86_64/include/stdint.h
index 51c3d15942..99cb45997a 100644
--- a/sys/cpu/x86_64/include/stdint.h
+++ b/sys/cpu/x86_64/include/stdint.h
@@ -136,4 +136,10 @@ typedef __uint32_t	__socklen_t;
 typedef volatile int	__atomic_intr_t;
 typedef __int64_t	__rlim_t;
 
+/* kernel only for now, for __udivti3() */
+#if defined(_KERNEL) && !defined(_KERNEL_VIRTUAL)
+typedef	int		__int128_t __attribute__((__mode__(TI)));
+typedef	unsigned	__uint128_t __attribute__((__mode__(TI)));
+#endif
+
 #endif /* _CPU_STDINT_H_ */
diff --git a/sys/platform/pc64/conf/files b/sys/platform/pc64/conf/files
index 6867a4d125..6170176557 100644
--- a/sys/platform/pc64/conf/files
+++ b/sys/platform/pc64/conf/files
@@ -169,6 +169,7 @@ platform/pc64/x86_64/identcpu.c		standard
 platform/pc64/x86_64/amd64_mem.c	standard
 platform/pc64/x86_64/cpufreq_machdep.c    standard
 platform/pc64/x86_64/msi.c		standard
+platform/pc64/x86_64/__udivti3.c	standard
 platform/pc64/x86_64/uwrapper.c		standard
 
 platform/pc64/apic/lapic.c		standard
diff --git a/sys/platform/pc64/x86_64/__udivti3.c b/sys/platform/pc64/x86_64/__udivti3.c
new file mode 100644
index 0000000000..68ca313fdd
--- /dev/null
+++ b/sys/platform/pc64/x86_64/__udivti3.c
@@ -0,0 +1,318 @@
+/*-
+ * This file is dual licensed under the MIT and the University of Illinois
+ * Open Source Licenses.
+ *
+ *-
+ * University of Illinois/NCSA
+ * Open Source License
+ *
+ * Copyright (c) 2009-2014 by the contributors listed below
+ *
+ * All rights reserved.
+ *
+ * Developed by:
+ *
+ * LLVM Team
+ *
+ * University of Illinois at Urbana-Champaign
+ *
+ * http://llvm.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal with the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimers.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimers in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the names of the LLVM Team, University of Illinois at
+ *   Urbana-Champaign, nor the names of its contributors may be used to
+ *   endorse or promote products derived from this Software without specific
+ *   prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * WITH THE SOFTWARE.
+ *
+ *-
+ * Copyright (c) 2009-2014 by the contributors listed below
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * -
+ * List of contributors:
+ *
+ * Craig van Vliet <cvanvliet@auroraux.org>
+ * Edward O'Callaghan <eocallaghan@auroraux.org>
+ * Howard Hinnant <hhinnant@apple.com>
+ * Matt Thomas <matt@NetBSD.org>
+ * Joerg Sonnenberger <joerg@NetBSD.org>
+ */
+
+#include <machine/limits.h>
+#include <machine/stdint.h>
+
+typedef union
+{
+	__uint128_t all;
+	struct {
+		unsigned long low;
+		unsigned long high;
+	} s;
+} utwords;
+
+/* Effects: if rem != 0, *rem = a % b
+ * Returns: a / b
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+static __uint128_t
+__udivmodti4(__uint128_t a, __uint128_t b, __uint128_t *rem)
+{
+	const unsigned n_udword_bits = sizeof(unsigned long) * CHAR_BIT;
+	const unsigned n_utword_bits = sizeof(__uint128_t) * CHAR_BIT;
+	utwords n, d, q, r;
+	unsigned sr;
+
+	n.all = a;
+	d.all = b;
+
+	/* special cases, X is unknown, K != 0 */
+	if (n.s.high == 0) {
+		if (d.s.high == 0) {
+			/* 0 X
+			 * ---
+			 * 0 X
+			 */
+			if (rem)
+				*rem = n.s.low % d.s.low;
+			return n.s.low / d.s.low;
+		}
+		/* 0 X
+		 * ---
+		 * K X
+		 */
+		if (rem)
+			*rem = n.s.low;
+		return 0;
+	}
+	/* n.s.high != 0 */
+	if (d.s.low == 0) {
+		if (d.s.high == 0) {
+			/* K X
+			 * ---
+			 * 0 0
+			 */
+			if (rem)
+				*rem = n.s.high % d.s.low;
+			return n.s.high / d.s.low;
+		}
+		/* d.s.high != 0 */
+		if (n.s.low == 0) {
+			/* K 0
+			 * ---
+			 * K 0
+			 */
+			if (rem) {
+				r.s.high = n.s.high % d.s.high;
+				r.s.low = 0;
+				*rem = r.all;
+			}
+			return n.s.high / d.s.high;
+		}
+		/* K K
+		 * ---
+		 * K 0
+		 */
+		if ((d.s.high & (d.s.high - 1)) == 0) { /* if d is a power of 2 */
+			if (rem) {
+				r.s.low = n.s.low;
+				r.s.high = n.s.high & (d.s.high - 1);
+				*rem = r.all;
+			}
+			return n.s.high >> __builtin_ctzl(d.s.high);
+		}
+		/* K K
+		 * ---
+		 * K 0
+		 */
+		sr = __builtin_clzl(d.s.high) - __builtin_clzl(n.s.high);
+		/* 0 <= sr <= n_udword_bits - 2 or sr large */
+		if (sr > n_udword_bits - 2) {
+			if (rem)
+				*rem = n.all;
+			return 0;
+		}
+		++sr;
+		/* 1 <= sr <= n_udword_bits - 1 */
+		/* q.all = n.all << (n_utword_bits - sr); */
+		q.s.low = 0;
+		q.s.high = n.s.low << (n_udword_bits - sr);
+		/* r.all = n.all >> sr; */
+		r.s.high = n.s.high >> sr;
+		r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+	} else {  /* d.s.low != 0 */
+		if (d.s.high == 0) {
+			/* K X
+			 * ---
+			 * 0 K
+			 */
+			if ((d.s.low & (d.s.low - 1)) == 0) { /* if d is a power of 2 */
+				if (rem)
+					*rem = n.s.low & (d.s.low - 1);
+				if (d.s.low == 1)
+					return n.all;
+				sr = __builtin_ctzl(d.s.low);
+				q.s.high = n.s.high >> sr;
+				q.s.low = (n.s.high << (n_udword_bits - sr)) |
+				    (n.s.low >> sr);
+				return q.all;
+			}
+			/* K X
+			 * ---
+			 * 0 K
+			 */
+			sr = 1 + n_udword_bits + __builtin_clzl(d.s.low) -
+			    __builtin_clzl(n.s.high);
+			/* 2 <= sr <= n_utword_bits - 1
+			 * q.all = n.all << (n_utword_bits - sr);
+			 * r.all = n.all >> sr;
+			 * if (sr == n_udword_bits)
+			 * {
+			 *     q.s.low = 0;
+			 *     q.s.high = n.s.low;
+			 *     r.s.high = 0;
+			 *     r.s.low = n.s.high;
+			 * }
+			 * else if (sr < n_udword_bits)  // 2 <= sr <= n_udword_bits - 1
+			 * {
+			 *     q.s.low = 0;
+			 *     q.s.high = n.s.low << (n_udword_bits - sr);
+			 *     r.s.high = n.s.high >> sr;
+			 *     r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+			 * }
+			 * else              // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+			 * {
+			 *     q.s.low = n.s.low << (n_utword_bits - sr);
+			 *     q.s.high = (n.s.high << (n_utword_bits - sr)) |
+			 *              (n.s.low >> (sr - n_udword_bits));
+			 *     r.s.high = 0;
+			 *     r.s.low = n.s.high >> (sr - n_udword_bits);
+			 * }
+			 */
+			q.s.low =  (n.s.low << (n_utword_bits - sr)) &
+			    ((long)(int)(n_udword_bits - sr) >> (n_udword_bits-1));
+			q.s.high = ((n.s.low << ( n_udword_bits - sr)) &
+			    ((long)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) |
+			    (((n.s.high << (n_utword_bits - sr)) |
+				(n.s.low >> (sr - n_udword_bits))) &
+				((long)(int)(n_udword_bits - sr) >> (n_udword_bits-1)));
+			r.s.high = (n.s.high >> sr) &
+			    ((long)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
+			r.s.low =  ((n.s.high >> (sr - n_udword_bits)) &
+			    ((long)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) |
+			    (((n.s.high << (n_udword_bits - sr)) |
+				(n.s.low >> sr)) &
+				((long)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
+		} else {
+			/* K X
+			 * ---
+			 * K K
+			 */
+			sr = __builtin_clzl(d.s.high) - __builtin_clzl(n.s.high);
+			/*0 <= sr <= n_udword_bits - 1 or sr large */
+			if (sr > n_udword_bits - 1) {
+				if (rem)
+					*rem = n.all;
+				return 0;
+			}
+			++sr;
+			/* 1 <= sr <= n_udword_bits */
+			/* q.all = n.all << (n_utword_bits - sr); */
+			q.s.low = 0;
+			q.s.high = n.s.low << (n_udword_bits - sr);
+			/* r.all = n.all >> sr;
+			 * if (sr < n_udword_bits)
+			 * {
+			 *     r.s.high = n.s.high >> sr;
+			 *     r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+			 * }
+			 * else
+			 * {
+			 *     r.s.high = 0;
+			 *     r.s.low = n.s.high;
+			 * }
+			 */
+			r.s.high = (n.s.high >> sr) &
+			    ((long)(int)(sr - n_udword_bits) >> (n_udword_bits-1));
+			r.s.low = (n.s.high << (n_udword_bits - sr)) |
+			    ((n.s.low >> sr) &
+				((long)(int)(sr - n_udword_bits) >> (n_udword_bits-1)));
+		}
+	}
+	/* Not a special case
+	 * q and r are initialized with:
+	 * q.all = n.all << (n_utword_bits - sr);
+	 * r.all = n.all >> sr;
+	 * 1 <= sr <= n_utword_bits - 1
+	 */
+	unsigned carry = 0;
+	for (; sr > 0; --sr) {
+		/* r:q = ((r:q)  << 1) | carry */
+		r.s.high = (r.s.high << 1) | (r.s.low  >> (n_udword_bits - 1));
+		r.s.low  = (r.s.low  << 1) | (q.s.high >> (n_udword_bits - 1));
+		q.s.high = (q.s.high << 1) | (q.s.low  >> (n_udword_bits - 1));
+		q.s.low  = (q.s.low  << 1) | carry;
+		/* carry = 0;
+		 * if (r.all >= d.all)
+		 * {
+		 *     r.all -= d.all;
+		 *      carry = 1;
+		 * }
+		 */
+		const __int128_t s =
+		    (__int128_t)(d.all - r.all - 1) >> (n_utword_bits - 1);
+		carry = s & 1;
+		r.all -= d.all & s;
+	}
+	q.all = (q.all << 1) | carry;
+	if (rem)
+		*rem = r.all;
+	return q.all;
+}
+
+__uint128_t __udivti3(__uint128_t a, __uint128_t b);
+
+__uint128_t
+__udivti3(__uint128_t a, __uint128_t b)
+{
+	return __udivmodti4(a, b, 0);
+}
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index d4ebacf2cc..76486595b9 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -48,6 +48,7 @@
 #include <machine/stdarg.h>
 #include <machine/atomic.h>
 #include <machine/cpufunc.h>
+#include <machine/int_limits.h>
 
 extern int securelevel;		/* system security level (see init(8)) */
 extern int kernel_mem_readonly;	/* disable writes to kernel memory */
@@ -505,11 +506,11 @@ bitcount64(uint64_t x)
 static __inline uint64_t
 muldivu64(uint64_t a, uint64_t b, uint64_t d)
 {
-	unsigned __int128 t;
+	__uint128_t t;
 
-	t = (unsigned __int128)a * b;
-	if (t / d > 0xFFFFFFFFFFFFFFFFLU) {
-		kprintf("muldivu64: overflow %ld,%ld,%ld\n", a, b, d);
+	t = (__uint128_t)a * b;
+	if (t / d > UINT64_MAX) {
+		kprintf("muldivu64: overflow %lu,%lu,%lu\n", a, b, d);
 		print_backtrace(-1);
 	}
 	return (t / d);
-- 
2.27.0

