From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoffer Dall Subject: Re: [PATCH 7/9] arm: replace arbitrary divisions Date: Wed, 16 Oct 2013 18:06:29 -0700 Message-ID: <20131017010629.GJ24837@cbox> References: <1381767815-12510-1-git-send-email-drjones@redhat.com> <1381767815-12510-8-git-send-email-drjones@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, gleb@redhat.com To: Andrew Jones Return-path: Received: from mail-pd0-f172.google.com ([209.85.192.172]:37951 "EHLO mail-pd0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1761322Ab3JQBFq (ORCPT ); Wed, 16 Oct 2013 21:05:46 -0400 Received: by mail-pd0-f172.google.com with SMTP id z10so1824325pdj.3 for ; Wed, 16 Oct 2013 18:05:45 -0700 (PDT) Content-Disposition: inline In-Reply-To: <1381767815-12510-8-git-send-email-drjones@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: On Mon, Oct 14, 2013 at 06:23:33PM +0200, Andrew Jones wrote: > 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. Isn't this just a matter of supplying a few libc implementations to handle div_by_0 and that sort? I'm pretty sure we had that working in the kvm-selftest for ARM thingy that allowed you to use the standard '/' operator in C code.... I suspect there will be more users of this eventually. Or wait, do you mean 'long long' operations by arbitrary? In that case, I'm less sure... A library implementation to support the operator would still be preferred IMHO. > > Signed-off-by: Andrew Jones > --- > 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 >