summaryrefslogtreecommitdiff
path: root/sys/lib/libkern
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2022-12-14 23:50:32 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2022-12-14 23:50:32 +0000
commita5d076476a358e91356d2fc7e2dcc2ae72928a02 (patch)
tree48f8b21fc99c0eb2a16f18ae4328e1d4ce7e9ada /sys/lib/libkern
parentc2d69d98fced9161d5159b65c2b5b7d57e29e6f4 (diff)
add __ctzdi2 to sparc64 kernel
If __builtin_ctzl() is used on sparc64, gcc 4.2 will emit a call to __ctzdi2. For userland this is in libgcc or compiler-rt. In the kernel we put these functions in libkern. 'looks good' deraadt@ miod@
Diffstat (limited to 'sys/lib/libkern')
-rw-r--r--sys/lib/libkern/ctzdi2.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/sys/lib/libkern/ctzdi2.c b/sys/lib/libkern/ctzdi2.c
new file mode 100644
index 00000000000..495657b6011
--- /dev/null
+++ b/sys/lib/libkern/ctzdi2.c
@@ -0,0 +1,61 @@
+/* $OpenBSD: ctzdi2.c,v 1.1 2022/12/14 23:50:31 jsg Exp $ */
+
+/*
+ * Public domain.
+ * Written by Dale Rahn.
+ */
+
+#include <lib/libkern/libkern.h>
+
+/*
+ * ffsl -- vax ffs instruction with long arg
+ */
+
+#ifdef __LP64__
+static int
+ffsl(long mask)
+{
+ int bit;
+ unsigned long r = mask;
+ static const signed char t[16] = {
+ -60, 1, 2, 1,
+ 3, 1, 2, 1,
+ 4, 1, 2, 1,
+ 3, 1, 2, 1
+ };
+
+ bit = 0;
+ if (!(r & 0xffffffff)) {
+ bit += 32;
+ r >>= 32;
+ }
+ if (!(r & 0xffff)) {
+ bit += 16;
+ r >>= 16;
+ }
+ if (!(r & 0xff)) {
+ bit += 8;
+ r >>= 8;
+ }
+ if (!(r & 0xf)) {
+ bit += 4;
+ r >>= 4;
+ }
+
+ return (bit + t[ r & 0xf ]);
+}
+#else
+static int
+ffsl(long mask)
+{
+ return ffs(mask);
+}
+#endif
+
+int
+__ctzdi2(long mask)
+{
+ if (mask == 0)
+ return 0;
+ return ffsl(mask) - 1;
+}