Re: [PATCH 1/4] introduce explicit signed/unsigned 64bit divide

Previous thread: [PATCH 5/4] 2.6.25-rc5-mm1 specifc div64_u64 fixes by zippel on Wednesday, March 12, 2008 - 5:22 pm. (1 message)

Next thread: [PATCH 2/4] convert a few do_div user by zippel on Wednesday, March 12, 2008 - 5:22 pm. (2 messages)
From: zippel
Date: Wednesday, March 12, 2008 - 5:22 pm

The current do_div doesn't explicitly say that it's unsigned and the
signed counterpart is missing, which is e.g. needed when dealing with
time values.
This introduces 64bit signed/unsigned divide functions which also
attempts to cleanup the somewhat awkward calling API, which often
requires the use of temporary variables for the dividend. To avoid the
need for temporary variables everywhere for the remainder, each divide
variant also provides a version which doesn't return the remainder.

Each architecture can now provide optimized versions of these function,
otherwise generic fallback implementations will be used.

As an example I provided an alternative for the current x86 divide,
which avoids the asm casts and using an union allows gcc to generate
better code. It also avoids the upper divde in a few more cases, where
the result is known (i.e. upper quotient is zero).

Signed-off-by: Roman Zippel <zippel@linux-m68k.org>

---
 include/asm-x86/div64.h |   20 +++++++++++++
 include/linux/math64.h  |   72 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/div64.c             |   23 ++++++++++++++-
 3 files changed, 113 insertions(+), 2 deletions(-)

Index: linux-2.6/include/asm-x86/div64.h
===================================================================
--- linux-2.6.orig/include/asm-x86/div64.h	2008-03-11 17:15:21.000000000 +0100
+++ linux-2.6/include/asm-x86/div64.h	2008-03-12 21:21:26.000000000 +0100
@@ -50,6 +50,26 @@ div_ll_X_l_rem(long long divs, long div,
 
 }
 
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+	union {
+		u64 v64;
+		u32 v32[2];
+	} d = { dividend };
+	u32 upper;
+
+	upper = d.v32[1];
+	d.v32[1] = 0;
+	if (upper >= divisor) {
+		d.v32[1] = upper / divisor;
+		upper %= divisor;
+	}
+	asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
+		"rm" (divisor), "0" (d.v32[0]), "1" (upper));
+	return d.v64;
+}
+#define div_u64_rem	div_u64_rem
+
 extern uint64_t div64_64(uint64_t dividend, uint64_t ...
From: Geert Uytterhoeven
Date: Thursday, March 13, 2008 - 3:13 am

^       ^       ^             ^            ^

With kind regards,

Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village 
From: Roman Zippel
Date: Thursday, March 13, 2008 - 7:59 am

Hi,


Thanks for noticing.
I'm quite sure I fixed this before, as I compiled this also for 
64bit, so I'm not sure how it got back. Anyway, new patch below.

bye, Roman



[PATCH 1/4] introduce explicit signed/unsigned 64bit divide

The current do_div doesn't explicitly say that it's unsigned and the
signed counterpart is missing, which is e.g. needed when dealing with
time values.
This introduces 64bit signed/unsigned divide functions which also
attempts to cleanup the somewhat awkward calling API, which often
requires the use of temporary variables for the dividend. To avoid the
need for temporary variables everywhere for the remainder, each divide
variant also provides a version which doesn't return the remainder.

Each architecture can now provide optimized versions of these function,
otherwise generic fallback implementations will be used.

As an example I provided an alternative for the current x86 divide,
which avoids the asm casts and using an union allows gcc to generate
better code. It also avoids the upper divde in a few more cases, where
the result is known (i.e. upper quotient is zero).

Signed-off-by: Roman Zippel <zippel@linux-m68k.org>

---
 include/asm-x86/div64.h |   20 +++++++++++++
 include/linux/math64.h  |   72 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/div64.c             |   23 ++++++++++++++-
 3 files changed, 113 insertions(+), 2 deletions(-)

Index: linux-2.6/include/asm-x86/div64.h
===================================================================
--- linux-2.6.orig/include/asm-x86/div64.h	2008-03-11 17:15:21.000000000 +0100
+++ linux-2.6/include/asm-x86/div64.h	2008-03-12 21:21:26.000000000 +0100
@@ -50,6 +50,26 @@ div_ll_X_l_rem(long long divs, long div,
 
 }
 
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+	union {
+		u64 v64;
+		u32 v32[2];
+	} d = { dividend };
+	u32 upper;
+
+	upper = d.v32[1];
+	d.v32[1] = 0;
+	if (upper >= divisor) {
+		d.v32[1] = upper / divisor;
+		upper ...
From: Andrew Morton
Date: Thursday, March 13, 2008 - 1:34 pm

On Thu, 13 Mar 2008 15:59:27 +0100 (CET)

I think what happened was that [patch 3/4] fixed this up.  Of course,
that patch doesn't apply on this updated [1/4].  I _could_ just take the
old [1/4] (I think), but I don't know if that wouild be bisection-friendly.

Anyway, please redo&resend?  Thanks.



Please have a think about that code in arch/x86/kvm/i8254.c too.  It is
painful to see remote subsystems (re)implementing generic infrastructure.
Can KVM use existing code?  Should we hoist what KVM has done there into
generic code?  Did it have to use a(nother bleeding) macro?
--

From: Roman Zippel
Date: Friday, March 14, 2008 - 10:45 am

Hi,



Looker closer at it, div64_u64() seems to be a bit overkill, as the 
divisor is a 32bit value, so the following should do the same job (only 
compile tested):

u64 muldiv64(u64 a, u32 b, u32 c)
{       
	union { 
		u64 ll;
		struct {
			u32 low, high;
		};
	} u, res, rl, rh;

	u.ll = a;
	rl.ll = (u64)b * u.low;
	rh.ll = (u64)b * u.high;
	rh.ll += rl.high;
	res.high = div_u64_rem(rh.ll, c, &rl.high);
	res.low = div_u64(rl.ll, c);
	return res.ll;
}

Moving it to a more generic location shouldn't be a big problem.

bye, Roman
--

Previous thread: [PATCH 5/4] 2.6.25-rc5-mm1 specifc div64_u64 fixes by zippel on Wednesday, March 12, 2008 - 5:22 pm. (1 message)

Next thread: [PATCH 2/4] convert a few do_div user by zippel on Wednesday, March 12, 2008 - 5:22 pm. (2 messages)