Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
5.5 KiB

  1. title lldiv - signed long divide routine
  2. ;***
  3. ;lldiv.asm - signed long divide routine
  4. ;
  5. ; Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  6. ;
  7. ;Purpose:
  8. ; defines the signed long divide routine
  9. ; __alldiv
  10. ;
  11. ;Revision History:
  12. ; 11-29-83 DFW initial version
  13. ; 06-01-84 RN modified to use cmacros
  14. ; 10-24-87 SKS fixed off-by-1 error for dividend close to 2**32.
  15. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog
  16. ; 11-28-89 GJF Fixed copyright
  17. ; 11-19-93 SMK Modified to work on 64 bit integers
  18. ; 01-17-94 GJF Minor changes to build with NT's masm386.
  19. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened
  20. ; conditional jumps. Also, don't use xchg to do a
  21. ; simple move between regs.
  22. ;
  23. ;*******************************************************************************
  24. .xlist
  25. include cruntime.inc
  26. include mm.inc
  27. .list
  28. ;***
  29. ;lldiv - signed long divide
  30. ;
  31. ;Purpose:
  32. ; Does a signed long divide of the arguments. Arguments are
  33. ; not changed.
  34. ;
  35. ;Entry:
  36. ; Arguments are passed on the stack:
  37. ; 1st pushed: divisor (QWORD)
  38. ; 2nd pushed: dividend (QWORD)
  39. ;
  40. ;Exit:
  41. ; EDX:EAX contains the quotient (dividend/divisor)
  42. ; NOTE: this routine removes the parameters from the stack.
  43. ;
  44. ;Uses:
  45. ; ECX
  46. ;
  47. ;Exceptions:
  48. ;
  49. ;*******************************************************************************
  50. CODESEG
  51. _alldiv PROC NEAR
  52. push edi
  53. push esi
  54. push ebx
  55. ; Set up the local stack and save the index registers. When this is done
  56. ; the stack frame will look as follows (assuming that the expression a/b will
  57. ; generate a call to lldiv(a, b)):
  58. ;
  59. ; -----------------
  60. ; | |
  61. ; |---------------|
  62. ; | |
  63. ; |--divisor (b)--|
  64. ; | |
  65. ; |---------------|
  66. ; | |
  67. ; |--dividend (a)-|
  68. ; | |
  69. ; |---------------|
  70. ; | return addr** |
  71. ; |---------------|
  72. ; | EDI |
  73. ; |---------------|
  74. ; | ESI |
  75. ; |---------------|
  76. ; ESP---->| EBX |
  77. ; -----------------
  78. ;
  79. DVND equ [esp + 16] ; stack address of dividend (a)
  80. DVSR equ [esp + 24] ; stack address of divisor (b)
  81. ; Determine sign of the result (edi = 0 if result is positive, non-zero
  82. ; otherwise) and make operands positive.
  83. xor edi,edi ; result sign assumed positive
  84. mov eax,HIWORD(DVND) ; hi word of a
  85. or eax,eax ; test to see if signed
  86. jge short L1 ; skip rest if a is already positive
  87. inc edi ; complement result sign flag
  88. mov edx,LOWORD(DVND) ; lo word of a
  89. neg eax ; make a positive
  90. neg edx
  91. sbb eax,0
  92. mov HIWORD(DVND),eax ; save positive value
  93. mov LOWORD(DVND),edx
  94. L1:
  95. mov eax,HIWORD(DVSR) ; hi word of b
  96. or eax,eax ; test to see if signed
  97. jge short L2 ; skip rest if b is already positive
  98. inc edi ; complement the result sign flag
  99. mov edx,LOWORD(DVSR) ; lo word of a
  100. neg eax ; make b positive
  101. neg edx
  102. sbb eax,0
  103. mov HIWORD(DVSR),eax ; save positive value
  104. mov LOWORD(DVSR),edx
  105. L2:
  106. ;
  107. ; Now do the divide. First look to see if the divisor is less than 4194304K.
  108. ; If so, then we can use a simple algorithm with word divides, otherwise
  109. ; things get a little more complex.
  110. ;
  111. ; NOTE - eax currently contains the high order word of DVSR
  112. ;
  113. or eax,eax ; check to see if divisor < 4194304K
  114. jnz short L3 ; nope, gotta do this the hard way
  115. mov ecx,LOWORD(DVSR) ; load divisor
  116. mov eax,HIWORD(DVND) ; load high word of dividend
  117. xor edx,edx
  118. div ecx ; eax <- high order bits of quotient
  119. mov ebx,eax ; save high bits of quotient
  120. mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
  121. div ecx ; eax <- low order bits of quotient
  122. mov edx,ebx ; edx:eax <- quotient
  123. jmp short L4 ; set sign, restore stack and return
  124. ;
  125. ; Here we do it the hard way. Remember, eax contains the high word of DVSR
  126. ;
  127. L3:
  128. mov ebx,eax ; ebx:ecx <- divisor
  129. mov ecx,LOWORD(DVSR)
  130. mov edx,HIWORD(DVND) ; edx:eax <- dividend
  131. mov eax,LOWORD(DVND)
  132. L5:
  133. shr ebx,1 ; shift divisor right one bit
  134. rcr ecx,1
  135. shr edx,1 ; shift dividend right one bit
  136. rcr eax,1
  137. or ebx,ebx
  138. jnz short L5 ; loop until divisor < 4194304K
  139. div ecx ; now divide, ignore remainder
  140. mov esi,eax ; save quotient
  141. ;
  142. ; We may be off by one, so to check, we will multiply the quotient
  143. ; by the divisor and check the result against the orignal dividend
  144. ; Note that we must also check for overflow, which can occur if the
  145. ; dividend is close to 2**64 and the quotient is off by 1.
  146. ;
  147. mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
  148. mov ecx,eax
  149. mov eax,LOWORD(DVSR)
  150. mul esi ; QUOT * LOWORD(DVSR)
  151. add edx,ecx ; EDX:EAX = QUOT * DVSR
  152. jc short L6 ; carry means Quotient is off by 1
  153. ;
  154. ; do long compare here between original dividend and the result of the
  155. ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
  156. ; subtract one (1) from the quotient.
  157. ;
  158. cmp edx,HIWORD(DVND) ; compare hi words of result and original
  159. ja short L6 ; if result > original, do subtract
  160. jb short L7 ; if result < original, we are ok
  161. cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
  162. jbe short L7 ; if less or equal we are ok, else subtract
  163. L6:
  164. dec esi ; subtract 1 from quotient
  165. L7:
  166. xor edx,edx ; edx:eax <- quotient
  167. mov eax,esi
  168. ;
  169. ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
  170. ; according to the save value, cleanup the stack, and return.
  171. ;
  172. L4:
  173. dec edi ; check to see if result is negative
  174. jnz short L8 ; if EDI == 0, result should be negative
  175. neg edx ; otherwise, negate the result
  176. neg eax
  177. sbb edx,0
  178. ;
  179. ; Restore the saved registers and return.
  180. ;
  181. L8:
  182. pop ebx
  183. pop esi
  184. pop edi
  185. ret 16
  186. _alldiv ENDP
  187. end