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 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html