divrem.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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, see
  14. <http://www.gnu.org/licenses/>. */
  15. /* The current Alpha chips don't provide hardware for integer
  16. division. The C compiler expects the functions
  17. __divqu: 64-bit unsigned long divide
  18. __remqu: 64-bit unsigned long remainder
  19. __divqs/__remqs: signed 64-bit
  20. __divlu/__remlu: unsigned 32-bit
  21. __divls/__remls: signed 32-bit
  22. These are not normal C functions: instead of the normal calling
  23. sequence, these expect their arguments in registers t10 and t11, and
  24. return the result in t12 (aka pv). Register AT may be clobbered
  25. (assembly temporary), anything else must be saved. */
  26. #include <features.h>
  27. #include <sys/regdef.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. #if IS_REM
  44. # define DIV_ONLY(x,y...)
  45. # define REM_ONLY(x,y...) x,##y
  46. # define modulus result
  47. # define quotient t1
  48. # define GETSIGN(x) mov arg1, x
  49. # define STACK 32
  50. #else
  51. # define DIV_ONLY(x,y...) x,##y
  52. # define REM_ONLY(x,y...)
  53. # define modulus t1
  54. # define quotient result
  55. # define GETSIGN(x) xor arg1, arg2, x
  56. # define STACK 48
  57. #endif
  58. #if SIZE == 8
  59. # define LONGIFY(x,y) mov x,y
  60. # define SLONGIFY(x,y) mov x,y
  61. # define _SLONGIFY(x)
  62. # define NEG(x,y) negq x,y
  63. #else
  64. # define LONGIFY(x,y) zapnot x,15,y
  65. # define SLONGIFY(x,y) sextl x,y
  66. # define _SLONGIFY(x) sextl x,x
  67. # define NEG(x,y) negl x,y
  68. #endif
  69. .set noreorder
  70. .set noat
  71. .ent UFUNC_NAME
  72. .globl UFUNC_NAME
  73. #ifndef IS_IN_rtld
  74. .hidden UFUNC_NAME
  75. #endif
  76. .align 3
  77. UFUNC_NAME:
  78. lda sp, -STACK(sp)
  79. .frame sp, STACK, retaddr, 0
  80. .prologue 0
  81. $udiv:
  82. stq t0, 0(sp)
  83. LONGIFY (arg2, divisor)
  84. stq t1, 8(sp)
  85. LONGIFY (arg1, modulus)
  86. stq v0, 16(sp)
  87. clr quotient
  88. stq tmp1, 24(sp)
  89. ldiq mask, 1
  90. DIV_ONLY(stq tmp2,32(sp))
  91. beq divisor, $divbyzero
  92. .align 3
  93. #if SIZE == 8
  94. /* Shift divisor left. */
  95. 1: cmpult divisor, modulus, compare
  96. blt divisor, 2f
  97. addq divisor, divisor, divisor
  98. addq mask, mask, mask
  99. bne compare, 1b
  100. unop
  101. 2:
  102. #else
  103. /* Shift divisor left using 3-bit shifts as we can't overflow.
  104. This results in looping three times less here, but up to
  105. two more times later. Thus using a large shift isn't worth it. */
  106. 1: cmpult divisor, modulus, compare
  107. s8addq divisor, zero, divisor
  108. s8addq mask, zero, mask
  109. bne compare, 1b
  110. #endif
  111. /* Now go back to the right. */
  112. 3: DIV_ONLY(addq quotient, mask, tmp2)
  113. srl mask, 1, mask
  114. cmpule divisor, modulus, compare
  115. subq modulus, divisor, tmp1
  116. DIV_ONLY(cmovne compare, tmp2, quotient)
  117. srl divisor, 1, divisor
  118. cmovne compare, tmp1, modulus
  119. bne mask, 3b
  120. $done: ldq t0, 0(sp)
  121. ldq t1, 8(sp)
  122. ldq v0, 16(sp)
  123. ldq tmp1, 24(sp)
  124. DIV_ONLY(ldq tmp2, 32(sp))
  125. lda sp, STACK(sp)
  126. ret zero, (retaddr), 1
  127. $divbyzero:
  128. mov a0, tmp1
  129. ldiq a0, GEN_INTDIV
  130. call_pal PAL_gentrap
  131. mov tmp1, a0
  132. clr result /* If trap returns, return zero. */
  133. br $done
  134. .end UFUNC_NAME
  135. .ent SFUNC_NAME
  136. .globl SFUNC_NAME
  137. .align 3
  138. SFUNC_NAME:
  139. lda sp, -STACK(sp)
  140. .frame sp, STACK, retaddr, 0
  141. .prologue 0
  142. or arg1, arg2, AT
  143. _SLONGIFY(AT)
  144. bge AT, $udiv /* don't need to mess with signs */
  145. /* Save originals and find absolute values. */
  146. stq arg1, 0(sp)
  147. NEG (arg1, AT)
  148. stq arg2, 8(sp)
  149. cmovge AT, AT, arg1
  150. stq retaddr, 16(sp)
  151. NEG (arg2, AT)
  152. stq tmp1, 24(sp)
  153. cmovge AT, AT, arg2
  154. /* Do the unsigned division. */
  155. bsr retaddr, UFUNC_NAME
  156. /* Restore originals and adjust the sign of the result. */
  157. ldq arg1, 0(sp)
  158. ldq arg2, 8(sp)
  159. GETSIGN (AT)
  160. NEG (result, tmp1)
  161. _SLONGIFY(AT)
  162. ldq retaddr, 16(sp)
  163. cmovlt AT, tmp1, result
  164. ldq tmp1, 24(sp)
  165. lda sp, STACK(sp)
  166. ret zero, (retaddr), 1
  167. .end SFUNC_NAME