Source code of Windows XP (NT5)
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.

220 lines
5.7 KiB

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