Full 64-bit multitplication and division added to u64 library
This commit is contained in:
@@ -4,13 +4,16 @@
|
||||
SRCS+= \
|
||||
add64.S \
|
||||
add64u.S \
|
||||
bsr64.S \
|
||||
cmp64.S \
|
||||
cv64u.S \
|
||||
cvu64.S \
|
||||
diff64.S \
|
||||
div64.c \
|
||||
div64u.S \
|
||||
ex64.S \
|
||||
make64.S \
|
||||
mul64.c \
|
||||
mul64u.S \
|
||||
sub64.S \
|
||||
sub64u.S
|
||||
|
||||
17
lib/libc/arch/i386/int64/bsr64.S
Normal file
17
lib/libc/arch/i386/int64/bsr64.S
Normal file
@@ -0,0 +1,17 @@
|
||||
/* bsr64() - 64 bit bit scan reverse Author: Erik van der Kouwe */
|
||||
/* 15 May 2010 */
|
||||
#include <minix/compiler.h>
|
||||
|
||||
.text
|
||||
.globl _bsr64
|
||||
|
||||
_bsr64:
|
||||
/* int bsr64(u64_t i); */
|
||||
bsr 8(%esp), %eax /* check high-order DWORD */
|
||||
jnz 0f /* non-zero: return index+32 */
|
||||
bsr 4(%esp), %eax /* check low-order DWORD */
|
||||
jnz 1f /* non-zero: return index */
|
||||
movl $-1, %eax /* both were zero, return -1 */
|
||||
jmp 1f
|
||||
0: addl $32, %eax /* add 32 to high-order index */
|
||||
1: ret
|
||||
87
lib/libc/arch/i386/int64/div64.c
Normal file
87
lib/libc/arch/i386/int64/div64.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/* div64() - full 64-bit division */
|
||||
/* rem64() - full 64-bit modulo */
|
||||
/* Author: Erik van der Kouwe */
|
||||
/* 14 May 2010 */
|
||||
#include <assert.h>
|
||||
#include <minix/u64.h>
|
||||
|
||||
static u32_t shl64hi(u64_t i, unsigned shift)
|
||||
{
|
||||
/* compute the high-order 32-bit value in (i << shift) */
|
||||
if (shift == 0)
|
||||
return i.hi;
|
||||
else if (shift < 32)
|
||||
return (i.hi << shift) | (i.lo >> (32 - shift));
|
||||
else if (shift == 32)
|
||||
return i.lo;
|
||||
else if (shift < 64)
|
||||
return i.lo << (shift - 32);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64_t divrem64(u64_t *i, u64_t j)
|
||||
{
|
||||
u32_t i32, j32, q;
|
||||
u64_t result = { 0, 0 };
|
||||
unsigned shift;
|
||||
|
||||
assert(i);
|
||||
|
||||
/* this function is not suitable for small divisors */
|
||||
assert(ex64hi(j) != 0);
|
||||
|
||||
/* as long as i >= j we work on reducing i */
|
||||
while (cmp64(*i, j) >= 0) {
|
||||
/* shift to obtain the 32 most significant bits */
|
||||
shift = 63 - bsr64(*i);
|
||||
i32 = shl64hi(*i, shift);
|
||||
j32 = shl64hi(j, shift);
|
||||
|
||||
/* find a lower bound for *i/j */
|
||||
if (j32 + 1 < j32) {
|
||||
/* avoid overflow, since *i >= j we know q >= 1 */
|
||||
q = 1;
|
||||
} else {
|
||||
/* use 32-bit division, round j32 up to ensure that
|
||||
* we obtain a lower bound
|
||||
*/
|
||||
q = i32 / (j32 + 1);
|
||||
|
||||
/* since *i >= j we know q >= 1 */
|
||||
if (q < 1) q = 1;
|
||||
}
|
||||
|
||||
/* perform the division using the lower bound we found */
|
||||
*i = sub64(*i, mul64(j, cvu64(q)));
|
||||
result = add64u(result, q);
|
||||
}
|
||||
|
||||
/* if we get here then *i < j; because we round down we are finished */
|
||||
return result;
|
||||
}
|
||||
|
||||
u64_t div64(u64_t i, u64_t j)
|
||||
{
|
||||
/* divrem64 is unsuitable for small divisors, especially zero which would
|
||||
* trigger a infinite loop; use assembly function in this case
|
||||
*/
|
||||
if (!ex64hi(j)) {
|
||||
return div64u64(i, ex64lo(j));
|
||||
}
|
||||
|
||||
return divrem64(&i, j);
|
||||
}
|
||||
|
||||
u64_t rem64(u64_t i, u64_t j)
|
||||
{
|
||||
/* divrem64 is unsuitable for small divisors, especially zero which would
|
||||
* trigger a infinite loop; use assembly function in this case
|
||||
*/
|
||||
if (!ex64hi(j)) {
|
||||
return cvu64(rem64u(i, ex64lo(j)));
|
||||
}
|
||||
|
||||
divrem64(&i, j);
|
||||
return i;
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
/* div64u() - 64 bit divided by unsigned giving unsigned long */
|
||||
/* Author: Kees J. Bot */
|
||||
/* 7 Dec 1995 */
|
||||
#include <minix/compiler.h>
|
||||
|
||||
.text
|
||||
.globl _div64u, _rem64u
|
||||
.globl _div64u, _div64u64, _rem64u
|
||||
|
||||
_div64u:
|
||||
/* unsigned long div64u(u64_t i, unsigned j); */
|
||||
@@ -13,6 +15,19 @@ _div64u:
|
||||
divl 12(%esp) /* i / j = (q<<32) + ((r<<32) + il) / j */
|
||||
ret
|
||||
|
||||
_div64u64:
|
||||
/* u64_t div64u64(u64_t i, unsigned j); */
|
||||
xorl %edx, %edx
|
||||
movl 12(%esp), %eax /* i = (ih<<32) + il */
|
||||
divl 16(%esp) /* ih = q * j + r */
|
||||
movl 4(%esp), %ecx /* get pointer to result */
|
||||
movl %eax, 4(%ecx) /* store high-order result */
|
||||
movl 8(%esp), %eax
|
||||
divl 16(%esp) /* i / j = (q<<32) + ((r<<32) + il) / j */
|
||||
movl %eax, 0(%ecx) /* store low result */
|
||||
movl %ecx, %eax /* return pointer to result struct */
|
||||
ret BYTES_TO_POP_ON_STRUCT_RETURN
|
||||
|
||||
_rem64u:
|
||||
/* unsigned rem64u(u64_t i, unsigned j); */
|
||||
pop %ecx
|
||||
|
||||
20
lib/libc/arch/i386/int64/mul64.c
Normal file
20
lib/libc/arch/i386/int64/mul64.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <minix/u64.h>
|
||||
|
||||
u64_t mul64(u64_t i, u64_t j)
|
||||
{
|
||||
u64_t result;
|
||||
|
||||
/* Compute as follows:
|
||||
* i * j =
|
||||
* (i.hi << 32 + i.lo) * (j.hi << 32 + j.lo) =
|
||||
* (i.hi << 32) * (j.hi << 32 + j.lo) + i.lo * (j.hi << 32 + j.lo) =
|
||||
* (i.hi * j.hi) << 64 + (i.hi * j.lo) << 32 + (i.lo * j.hi << 32) + i.lo * j.lo
|
||||
*
|
||||
* 64-bit-result multiply only needed for (i.lo * j.lo)
|
||||
* upper 32 bits overflow for (i.lo * j.hi) and (i.hi * j.lo)
|
||||
* all overflows for (i.hi * j.hi)
|
||||
*/
|
||||
result = mul64u(i.lo, j.lo);
|
||||
result.hi += i.hi * j.lo + i.lo * j.hi;
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user