divrem.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
  2. Contributed by David Mosberger (davidm@cs.arizona.edu).
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307 USA. */
  16. /* The current Alpha chips don't provide hardware for integer
  17. division. The C compiler expects the functions
  18. __divqu: 64-bit unsigned long divide
  19. __remqu: 64-bit unsigned long remainder
  20. __divqs/__remqs: signed 64-bit
  21. __divlu/__remlu: unsigned 32-bit
  22. __divls/__remls: signed 32-bit
  23. These are not normal C functions: instead of the normal calling
  24. sequence, these expect their arguments in registers t10 and t11, and
  25. return the result in t12 (aka pv). Register AT may be clobbered
  26. (assembly temporary), anything else must be saved. */
  27. #include <features.h>
  28. #ifdef __linux__
  29. # include <asm/gentrap.h>
  30. # include <asm/pal.h>
  31. #else
  32. # include <machine/pal.h>
  33. #endif
  34. #define mask v0
  35. #define divisor t0
  36. #define compare AT
  37. #define tmp1 t2
  38. #define tmp2 t3
  39. #define retaddr t9
  40. #define arg1 t10
  41. #define arg2 t11
  42. #define result t12
  43. #define v0 $0 /* function return value */
  44. #define t0 $1 /* temporary registers (caller-saved) */
  45. #define t1 $2
  46. #define t2 $3
  47. #define t3 $4
  48. #define t4 $5
  49. #define t5 $6
  50. #define t6 $7
  51. #define t7 $8
  52. #define s0 $9 /* saved-registers (callee-saved registers) */
  53. #define s1 $10
  54. #define s2 $11
  55. #define s3 $12
  56. #define s4 $13
  57. #define s5 $14
  58. #define s6 $15
  59. #define fp s6 /* frame-pointer (s6 in frame-less procedures) */
  60. #define a0 $16 /* argument registers (caller-saved) */
  61. #define a1 $17
  62. #define a2 $18
  63. #define a3 $19
  64. #define a4 $20
  65. #define a5 $21
  66. #define t8 $22 /* more temps (caller-saved) */
  67. #define t9 $23
  68. #define t10 $24
  69. #define t11 $25
  70. #define ra $26 /* return address register */
  71. #define t12 $27
  72. #define pv t12 /* procedure-variable register */
  73. #define AT $at /* assembler temporary */
  74. #define gp $29 /* global pointer */
  75. #define sp $30 /* stack pointer */
  76. #define zero $31 /* reads as zero, writes are noops */
  77. #if IS_REM
  78. # define DIV_ONLY(x,y...)
  79. # define REM_ONLY(x,y...) x,##y
  80. # define modulus result
  81. # define quotient t1
  82. # define GETSIGN(x) mov arg1, x
  83. # define STACK 32
  84. #else
  85. # define DIV_ONLY(x,y...) x,##y
  86. # define REM_ONLY(x,y...)
  87. # define modulus t1
  88. # define quotient result
  89. # define GETSIGN(x) xor arg1, arg2, x
  90. # define STACK 48
  91. #endif
  92. #if SIZE == 8
  93. # define LONGIFY(x,y) mov x,y
  94. # define SLONGIFY(x,y) mov x,y
  95. # define _SLONGIFY(x)
  96. # define NEG(x,y) negq x,y
  97. #else
  98. # define LONGIFY(x,y) zapnot x,15,y
  99. # define SLONGIFY(x,y) sextl x,y
  100. # define _SLONGIFY(x) sextl x,x
  101. # define NEG(x,y) negl x,y
  102. #endif
  103. .set noreorder
  104. .set noat
  105. .ent UFUNC_NAME
  106. .globl UFUNC_NAME
  107. .align 3
  108. UFUNC_NAME:
  109. lda sp, -STACK(sp)
  110. .frame sp, STACK, retaddr, 0
  111. .prologue 0
  112. $udiv:
  113. stq t0, 0(sp)
  114. LONGIFY (arg2, divisor)
  115. stq t1, 8(sp)
  116. LONGIFY (arg1, modulus)
  117. stq v0, 16(sp)
  118. clr quotient
  119. stq tmp1, 24(sp)
  120. ldiq mask, 1
  121. DIV_ONLY(stq tmp2,32(sp))
  122. beq divisor, $divbyzero
  123. .align 3
  124. #if SIZE == 8
  125. /* Shift divisor left. */
  126. 1: cmpult divisor, modulus, compare
  127. blt divisor, 2f
  128. addq divisor, divisor, divisor
  129. addq mask, mask, mask
  130. bne compare, 1b
  131. unop
  132. 2:
  133. #else
  134. /* Shift divisor left using 3-bit shifts as we can't overflow.
  135. This results in looping three times less here, but up to
  136. two more times later. Thus using a large shift isn't worth it. */
  137. 1: cmpult divisor, modulus, compare
  138. s8addq divisor, zero, divisor
  139. s8addq mask, zero, mask
  140. bne compare, 1b
  141. #endif
  142. /* Now go back to the right. */
  143. 3: DIV_ONLY(addq quotient, mask, tmp2)
  144. srl mask, 1, mask
  145. cmpule divisor, modulus, compare
  146. subq modulus, divisor, tmp1
  147. DIV_ONLY(cmovne compare, tmp2, quotient)
  148. srl divisor, 1, divisor
  149. cmovne compare, tmp1, modulus
  150. bne mask, 3b
  151. $done: ldq t0, 0(sp)
  152. ldq t1, 8(sp)
  153. ldq v0, 16(sp)
  154. ldq tmp1, 24(sp)
  155. DIV_ONLY(ldq tmp2, 32(sp))
  156. lda sp, STACK(sp)
  157. ret zero, (retaddr), 1
  158. $divbyzero:
  159. mov a0, tmp1
  160. ldiq a0, GEN_INTDIV
  161. call_pal PAL_gentrap
  162. mov tmp1, a0
  163. clr result /* If trap returns, return zero. */
  164. br $done
  165. .end UFUNC_NAME
  166. .ent SFUNC_NAME
  167. .globl SFUNC_NAME
  168. .align 3
  169. SFUNC_NAME:
  170. lda sp, -STACK(sp)
  171. .frame sp, STACK, retaddr, 0
  172. .prologue 0
  173. or arg1, arg2, AT
  174. _SLONGIFY(AT)
  175. bge AT, $udiv /* don't need to mess with signs */
  176. /* Save originals and find absolute values. */
  177. stq arg1, 0(sp)
  178. NEG (arg1, AT)
  179. stq arg2, 8(sp)
  180. cmovge AT, AT, arg1
  181. stq retaddr, 16(sp)
  182. NEG (arg2, AT)
  183. stq tmp1, 24(sp)
  184. cmovge AT, AT, arg2
  185. /* Do the unsigned division. */
  186. bsr retaddr, UFUNC_NAME
  187. /* Restore originals and adjust the sign of the result. */
  188. ldq arg1, 0(sp)
  189. ldq arg2, 8(sp)
  190. GETSIGN (AT)
  191. NEG (result, tmp1)
  192. _SLONGIFY(AT)
  193. ldq retaddr, 16(sp)
  194. cmovlt AT, tmp1, result
  195. ldq tmp1, 24(sp)
  196. lda sp, STACK(sp)
  197. ret zero, (retaddr), 1
  198. .end SFUNC_NAME