divrem.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. #include <sys/regdef.h>
  29. #ifdef __linux__
  30. # include <asm/gentrap.h>
  31. # include <asm/pal.h>
  32. #else
  33. # include <machine/pal.h>
  34. #endif
  35. #define mask v0
  36. #define divisor t0
  37. #define compare AT
  38. #define tmp1 t2
  39. #define tmp2 t3
  40. #define retaddr t9
  41. #define arg1 t10
  42. #define arg2 t11
  43. #define result t12
  44. #if IS_REM
  45. # define DIV_ONLY(x,y...)
  46. # define REM_ONLY(x,y...) x,##y
  47. # define modulus result
  48. # define quotient t1
  49. # define GETSIGN(x) mov arg1, x
  50. # define STACK 32
  51. #else
  52. # define DIV_ONLY(x,y...) x,##y
  53. # define REM_ONLY(x,y...)
  54. # define modulus t1
  55. # define quotient result
  56. # define GETSIGN(x) xor arg1, arg2, x
  57. # define STACK 48
  58. #endif
  59. #if SIZE == 8
  60. # define LONGIFY(x,y) mov x,y
  61. # define SLONGIFY(x,y) mov x,y
  62. # define _SLONGIFY(x)
  63. # define NEG(x,y) negq x,y
  64. #else
  65. # define LONGIFY(x,y) zapnot x,15,y
  66. # define SLONGIFY(x,y) sextl x,y
  67. # define _SLONGIFY(x) sextl x,x
  68. # define NEG(x,y) negl x,y
  69. #endif
  70. .set noreorder
  71. .set noat
  72. .ent UFUNC_NAME
  73. .globl UFUNC_NAME
  74. #ifndef IS_IN_rtld
  75. .hidden UFUNC_NAME
  76. #endif
  77. .align 3
  78. UFUNC_NAME:
  79. lda sp, -STACK(sp)
  80. .frame sp, STACK, retaddr, 0
  81. .prologue 0
  82. $udiv:
  83. stq t0, 0(sp)
  84. LONGIFY (arg2, divisor)
  85. stq t1, 8(sp)
  86. LONGIFY (arg1, modulus)
  87. stq v0, 16(sp)
  88. clr quotient
  89. stq tmp1, 24(sp)
  90. ldiq mask, 1
  91. DIV_ONLY(stq tmp2,32(sp))
  92. beq divisor, $divbyzero
  93. .align 3
  94. #if SIZE == 8
  95. /* Shift divisor left. */
  96. 1: cmpult divisor, modulus, compare
  97. blt divisor, 2f
  98. addq divisor, divisor, divisor
  99. addq mask, mask, mask
  100. bne compare, 1b
  101. unop
  102. 2:
  103. #else
  104. /* Shift divisor left using 3-bit shifts as we can't overflow.
  105. This results in looping three times less here, but up to
  106. two more times later. Thus using a large shift isn't worth it. */
  107. 1: cmpult divisor, modulus, compare
  108. s8addq divisor, zero, divisor
  109. s8addq mask, zero, mask
  110. bne compare, 1b
  111. #endif
  112. /* Now go back to the right. */
  113. 3: DIV_ONLY(addq quotient, mask, tmp2)
  114. srl mask, 1, mask
  115. cmpule divisor, modulus, compare
  116. subq modulus, divisor, tmp1
  117. DIV_ONLY(cmovne compare, tmp2, quotient)
  118. srl divisor, 1, divisor
  119. cmovne compare, tmp1, modulus
  120. bne mask, 3b
  121. $done: ldq t0, 0(sp)
  122. ldq t1, 8(sp)
  123. ldq v0, 16(sp)
  124. ldq tmp1, 24(sp)
  125. DIV_ONLY(ldq tmp2, 32(sp))
  126. lda sp, STACK(sp)
  127. ret zero, (retaddr), 1
  128. $divbyzero:
  129. mov a0, tmp1
  130. ldiq a0, GEN_INTDIV
  131. call_pal PAL_gentrap
  132. mov tmp1, a0
  133. clr result /* If trap returns, return zero. */
  134. br $done
  135. .end UFUNC_NAME
  136. .ent SFUNC_NAME
  137. .globl SFUNC_NAME
  138. .align 3
  139. SFUNC_NAME:
  140. lda sp, -STACK(sp)
  141. .frame sp, STACK, retaddr, 0
  142. .prologue 0
  143. or arg1, arg2, AT
  144. _SLONGIFY(AT)
  145. bge AT, $udiv /* don't need to mess with signs */
  146. /* Save originals and find absolute values. */
  147. stq arg1, 0(sp)
  148. NEG (arg1, AT)
  149. stq arg2, 8(sp)
  150. cmovge AT, AT, arg1
  151. stq retaddr, 16(sp)
  152. NEG (arg2, AT)
  153. stq tmp1, 24(sp)
  154. cmovge AT, AT, arg2
  155. /* Do the unsigned division. */
  156. bsr retaddr, UFUNC_NAME
  157. /* Restore originals and adjust the sign of the result. */
  158. ldq arg1, 0(sp)
  159. ldq arg2, 8(sp)
  160. GETSIGN (AT)
  161. NEG (result, tmp1)
  162. _SLONGIFY(AT)
  163. ldq retaddr, 16(sp)
  164. cmovlt AT, tmp1, result
  165. ldq tmp1, 24(sp)
  166. lda sp, STACK(sp)
  167. ret zero, (retaddr), 1
  168. .end SFUNC_NAME