1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
#------------------------------------------------------------------------------
#
# Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# DivU64x64Remainder.S
#
# Abstract:
#
# Calculate the quotient of a 64-bit integer by a 64-bit integer and returns
# both the quotient and the remainder
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(InternalMathDivRemU64x32), ASM_PFX(InternalMathDivRemU64x64)
#------------------------------------------------------------------------------
# UINT64
# EFIAPI
# InternalMathDivRemU64x64 (
# IN UINT64 Dividend,
# IN UINT64 Divisor,
# OUT UINT64 *Remainder OPTIONAL
# );
#------------------------------------------------------------------------------
ASM_PFX(InternalMathDivRemU64x64):
movl 16(%esp), %ecx # ecx <- divisor[32..63]
testl %ecx, %ecx
jnz Hard # call _@DivRemU64x64 if Divisor > 2^32
movl 20(%esp), %ecx
jecxz L1
and $0, 4(%ecx) # zero high dword of remainder
movl %ecx, 16(%esp) # set up stack frame to match DivRemU64x32
L1:
jmp ASM_PFX(InternalMathDivRemU64x32)
Hard:
push %ebx
push %esi
push %edi
mov 20(%esp), %edx
mov 16(%esp), %eax # edx:eax <- dividend
movl %edx, %edi
movl %eax, %esi # edi:esi <- dividend
mov 24(%esp), %ebx # ecx:ebx <- divisor
L2:
shrl %edx
rcrl $1, %eax
shrdl $1, %ecx, %ebx
shrl %ecx
jnz L2
divl %ebx
movl %eax, %ebx # ebx <- quotient
movl 28(%esp), %ecx # ecx <- high dword of divisor
mull 24(%esp) # edx:eax <- quotient * divisor[0..31]
imull %ebx, %ecx # ecx <- quotient * divisor[32..63]
addl %ecx, %edx # edx <- (quotient * divisor)[32..63]
mov 32(%esp), %ecx # ecx <- addr for Remainder
jc TooLarge # product > 2^64
cmpl %edx, %edi # compare high 32 bits
ja Correct
jb TooLarge # product > dividend
cmpl %eax, %esi
jae Correct # product <= dividend
TooLarge:
decl %ebx # adjust quotient by -1
jecxz Return # return if Remainder == NULL
sub 24(%esp), %eax
sbb 28(%esp), %edx # edx:eax <- (quotient - 1) * divisor
Correct:
jecxz Return
subl %eax, %esi
sbbl %edx, %edi # edi:esi <- remainder
movl %esi, (%ecx)
movl %edi, 4(%ecx)
Return:
movl %ebx, %eax # eax <- quotient
xorl %edx, %edx # quotient is 32 bits long
pop %edi
pop %esi
pop %ebx
ret
|