[PATCH 7/9] arm: replace arbitrary divisions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



arm can't do arbitrary divisions without software support. Usually
libgcc would jump in here, but depending on the toolchain used that may
or may not work. Luckily, we only care about two types of divisions.
Divide by 10 and divide by 16. Divide by 16 is already covered by gcc
since it's a power of two. Divide by 10 can be hacked up using a
multiplication and shift.

Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx>
---
 lib/divmod.h | 20 ++++++++++++++++++++
 lib/printf.c | 27 ++++++++++++++-------------
 2 files changed, 34 insertions(+), 13 deletions(-)
 create mode 100644 lib/divmod.h

diff --git a/lib/divmod.h b/lib/divmod.h
new file mode 100644
index 0000000000000..c0f04d7d8386d
--- /dev/null
+++ b/lib/divmod.h
@@ -0,0 +1,20 @@
+#ifndef _DIVMOD_H_
+#define _DIVMOD_H_
+#ifdef __arm__
+static inline long long div10(long long n)
+{
+    /*
+     * multiply n by 2^32/10 and the result of n/10
+     * will be in the upper word
+     */
+    return (n * 0x1999999aU) >> 32;
+}
+static inline int mod10(long long n)
+{
+    return n - div10(n) * 10;
+}
+#else
+#define div10(n) ((n) / 10)
+#define mod10(n) ((n) % 10)
+#endif
+#endif
diff --git a/lib/printf.c b/lib/printf.c
index 867eb1926f742..9fb8133868c7a 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -1,4 +1,5 @@
 #include "libcflat.h"
+#include "divmod.h"
 
 typedef struct pstream {
     char *buffer;
@@ -23,7 +24,7 @@ void print_str(pstream_t *p, const char *s)
 
 static char digits[16] = "0123456789abcdef";
 
-void print_int(pstream_t *ps, long long n, int base)
+void print_int(pstream_t *ps, long long n)
 {
     char buf[sizeof(long) * 3 + 2], *p = buf;
     int s = 0, i;
@@ -34,8 +35,8 @@ void print_int(pstream_t *ps, long long n, int base)
     }
 
     while (n) {
-	*p++ = digits[n % base];
-	n /= base;
+	*p++ = digits[mod10(n)];
+	n = div10(n);
     }
 
     if (s)
@@ -57,14 +58,14 @@ void print_int(pstream_t *ps, long long n, int base)
     print_str(ps, buf);
 }
 
-void print_unsigned(pstream_t *ps, unsigned long long n, int base)
+void print_unsigned(pstream_t *ps, unsigned long long n)
 {
     char buf[sizeof(long) * 3 + 1], *p = buf;
     int i;
 
     while (n) {
-	*p++ = digits[n % base];
-	n /= base;
+	*p++ = digits[n % 16];
+	n /= 16;
     }
 
     if (p == buf)
@@ -116,32 +117,32 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 	case 'd':
 	    switch (nlong) {
 	    case 0:
-		print_int(&s, va_arg(va, int), 10);
+		print_int(&s, va_arg(va, int));
 		break;
 	    case 1:
-		print_int(&s, va_arg(va, long), 10);
+		print_int(&s, va_arg(va, long));
 		break;
 	    default:
-		print_int(&s, va_arg(va, long long), 10);
+		print_int(&s, va_arg(va, long long));
 		break;
 	    }
 	    break;
 	case 'x':
 	    switch (nlong) {
 	    case 0:
-		print_unsigned(&s, va_arg(va, unsigned), 16);
+		print_unsigned(&s, va_arg(va, unsigned));
 		break;
 	    case 1:
-		print_unsigned(&s, va_arg(va, unsigned long), 16);
+		print_unsigned(&s, va_arg(va, unsigned long));
 		break;
 	    default:
-		print_unsigned(&s, va_arg(va, unsigned long long), 16);
+		print_unsigned(&s, va_arg(va, unsigned long long));
 		break;
 	    }
 	    break;
 	case 'p':
 	    print_str(&s, "0x");
-	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+	    print_unsigned(&s, (unsigned long)va_arg(va, void *));
 	    break;
 	case 's':
 	    print_str(&s, va_arg(va, const char *));
-- 
1.8.1.4

_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm




[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux