ldiv.S 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* Copyright (C) 1996-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library. If not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #include "div_libc.h"
  15. #undef FRAME
  16. #ifdef __alpha_fix__
  17. #define FRAME 0
  18. #else
  19. #define FRAME 16
  20. #endif
  21. #undef X
  22. #undef Y
  23. #define X $17
  24. #define Y $18
  25. .set noat
  26. .align 4
  27. .globl ldiv
  28. .ent ldiv
  29. ldiv:
  30. .frame sp, FRAME, ra
  31. #if FRAME > 0
  32. lda sp, -FRAME(sp)
  33. #endif
  34. #ifdef PROF
  35. .set macro
  36. ldgp gp, 0(pv)
  37. lda AT, _mcount
  38. jsr AT, (AT), _mcount
  39. .set nomacro
  40. .prologue 1
  41. #else
  42. .prologue 0
  43. #endif
  44. beq Y, $divbyzero
  45. excb
  46. mf_fpcr $f10
  47. _ITOFT2 X, $f0, 0, Y, $f1, 8
  48. .align 4
  49. cvtqt $f0, $f0
  50. cvtqt $f1, $f1
  51. divt/c $f0, $f1, $f0
  52. unop
  53. /* Check to see if X fit in the double as an exact value. */
  54. sll X, (64-53), AT
  55. sra AT, (64-53), AT
  56. cmpeq X, AT, AT
  57. beq AT, $x_big
  58. /* If we get here, we're expecting exact results from the division.
  59. Do nothing else besides convert and clean up. */
  60. cvttq/c $f0, $f0
  61. excb
  62. mt_fpcr $f10
  63. _FTOIT $f0, $0, 0
  64. $egress:
  65. mulq $0, Y, $1
  66. subq X, $1, $1
  67. stq $0, 0($16)
  68. stq $1, 8($16)
  69. mov $16, $0
  70. #if FRAME > 0
  71. lda sp, FRAME(sp)
  72. #endif
  73. ret
  74. .align 4
  75. $x_big:
  76. /* If we get here, X is large enough that we don't expect exact
  77. results, and neither X nor Y got mis-translated for the fp
  78. division. Our task is to take the fp result, figure out how
  79. far it's off from the correct result and compute a fixup. */
  80. #define Q v0 /* quotient */
  81. #define R t0 /* remainder */
  82. #define SY t1 /* scaled Y */
  83. #define S t2 /* scalar */
  84. #define QY t3 /* Q*Y */
  85. /* The fixup code below can only handle unsigned values. */
  86. or X, Y, AT
  87. mov $31, t5
  88. blt AT, $fix_sign_in
  89. $fix_sign_in_ret1:
  90. cvttq/c $f0, $f0
  91. _FTOIT $f0, Q, 8
  92. $fix_sign_in_ret2:
  93. mulq Q, Y, QY
  94. excb
  95. mt_fpcr $f10
  96. .align 4
  97. subq QY, X, R
  98. mov Y, SY
  99. mov 1, S
  100. bgt R, $q_high
  101. $q_high_ret:
  102. subq X, QY, R
  103. mov Y, SY
  104. mov 1, S
  105. bgt R, $q_low
  106. $q_low_ret:
  107. negq Q, t4
  108. cmovlbs t5, t4, Q
  109. br $egress
  110. .align 4
  111. /* The quotient that we computed was too large. We need to reduce
  112. it by S such that Y*S >= R. Obviously the closer we get to the
  113. correct value the better, but overshooting high is ok, as we'll
  114. fix that up later. */
  115. 0:
  116. addq SY, SY, SY
  117. addq S, S, S
  118. $q_high:
  119. cmpult SY, R, AT
  120. bne AT, 0b
  121. subq Q, S, Q
  122. unop
  123. subq QY, SY, QY
  124. br $q_high_ret
  125. .align 4
  126. /* The quotient that we computed was too small. Divide Y by the
  127. current remainder (R) and add that to the existing quotient (Q).
  128. The expectation, of course, is that R is much smaller than X. */
  129. /* Begin with a shift-up loop. Compute S such that Y*S >= R. We
  130. already have a copy of Y in SY and the value 1 in S. */
  131. 0:
  132. addq SY, SY, SY
  133. addq S, S, S
  134. $q_low:
  135. cmpult SY, R, AT
  136. bne AT, 0b
  137. /* Shift-down and subtract loop. Each iteration compares our scaled
  138. Y (SY) with the remainder (R); if SY <= R then X is divisible by
  139. Y's scalar (S) so add it to the quotient (Q). */
  140. 2: addq Q, S, t3
  141. srl S, 1, S
  142. cmpule SY, R, AT
  143. subq R, SY, t4
  144. cmovne AT, t3, Q
  145. cmovne AT, t4, R
  146. srl SY, 1, SY
  147. bne S, 2b
  148. br $q_low_ret
  149. .align 4
  150. $fix_sign_in:
  151. /* If we got here, then X|Y is negative. Need to adjust everything
  152. such that we're doing unsigned division in the fixup loop. */
  153. /* T5 is true if result should be negative. */
  154. xor X, Y, AT
  155. cmplt AT, 0, t5
  156. cmplt X, 0, AT
  157. negq X, t0
  158. cmovne AT, t0, X
  159. cmplt Y, 0, AT
  160. negq Y, t0
  161. cmovne AT, t0, Y
  162. blbc t5, $fix_sign_in_ret1
  163. cvttq/c $f0, $f0
  164. _FTOIT $f0, Q, 8
  165. .align 3
  166. negq Q, Q
  167. br $fix_sign_in_ret2
  168. $divbyzero:
  169. mov a0, v0
  170. lda a0, GEN_INTDIV
  171. call_pal PAL_gentrap
  172. stq zero, 0(v0)
  173. stq zero, 8(v0)
  174. #if FRAME > 0
  175. lda sp, FRAME(sp)
  176. #endif
  177. ret
  178. .end ldiv
  179. weak_alias (ldiv, lldiv)
  180. weak_alias (ldiv, imaxdiv)