ev6-divide.S 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * arch/alpha/lib/ev6-divide.S
  4. *
  5. * 21264 version contributed by Rick Gorton <[email protected]>
  6. *
  7. * Alpha division..
  8. */
  9. /*
  10. * The alpha chip doesn't provide hardware division, so we have to do it
  11. * by hand. The compiler expects the functions
  12. *
  13. * __divqu: 64-bit unsigned long divide
  14. * __remqu: 64-bit unsigned long remainder
  15. * __divqs/__remqs: signed 64-bit
  16. * __divlu/__remlu: unsigned 32-bit
  17. * __divls/__remls: signed 32-bit
  18. *
  19. * These are not normal C functions: instead of the normal
  20. * calling sequence, these expect their arguments in registers
  21. * $24 and $25, and return the result in $27. Register $28 may
  22. * be clobbered (assembly temporary), anything else must be saved.
  23. *
  24. * In short: painful.
  25. *
  26. * This is a rather simple bit-at-a-time algorithm: it's very good
  27. * at dividing random 64-bit numbers, but the more usual case where
  28. * the divisor is small is handled better by the DEC algorithm
  29. * using lookup tables. This uses much less memory, though, and is
  30. * nicer on the cache.. Besides, I don't know the copyright status
  31. * of the DEC code.
  32. */
  33. /*
  34. * My temporaries:
  35. * $0 - current bit
  36. * $1 - shifted divisor
  37. * $2 - modulus/quotient
  38. *
  39. * $23 - return address
  40. * $24 - dividend
  41. * $25 - divisor
  42. *
  43. * $27 - quotient/modulus
  44. * $28 - compare status
  45. *
  46. * Much of the information about 21264 scheduling/coding comes from:
  47. * Compiler Writer's Guide for the Alpha 21264
  48. * abbreviated as 'CWG' in other comments here
  49. * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
  50. * Scheduling notation:
  51. * E - either cluster
  52. * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
  53. * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  54. * Try not to change the actual algorithm if possible for consistency.
  55. */
  56. #include <asm/export.h>
  57. #define halt .long 0
  58. /*
  59. * Select function type and registers
  60. */
  61. #define mask $0
  62. #define divisor $1
  63. #define compare $28
  64. #define tmp1 $3
  65. #define tmp2 $4
  66. #ifdef DIV
  67. #define DIV_ONLY(x,y...) x,##y
  68. #define MOD_ONLY(x,y...)
  69. #define func(x) __div##x
  70. #define modulus $2
  71. #define quotient $27
  72. #define GETSIGN(x) xor $24,$25,x
  73. #define STACK 48
  74. #else
  75. #define DIV_ONLY(x,y...)
  76. #define MOD_ONLY(x,y...) x,##y
  77. #define func(x) __rem##x
  78. #define modulus $27
  79. #define quotient $2
  80. #define GETSIGN(x) bis $24,$24,x
  81. #define STACK 32
  82. #endif
  83. /*
  84. * For 32-bit operations, we need to extend to 64-bit
  85. */
  86. #ifdef INTSIZE
  87. #define ufunction func(lu)
  88. #define sfunction func(l)
  89. #define LONGIFY(x) zapnot x,15,x
  90. #define SLONGIFY(x) addl x,0,x
  91. #else
  92. #define ufunction func(qu)
  93. #define sfunction func(q)
  94. #define LONGIFY(x)
  95. #define SLONGIFY(x)
  96. #endif
  97. .set noat
  98. .align 4
  99. .globl ufunction
  100. .ent ufunction
  101. ufunction:
  102. subq $30,STACK,$30 # E :
  103. .frame $30,STACK,$23
  104. .prologue 0
  105. 7: stq $1, 0($30) # L :
  106. bis $25,$25,divisor # E :
  107. stq $2, 8($30) # L : L U L U
  108. bis $24,$24,modulus # E :
  109. stq $0,16($30) # L :
  110. bis $31,$31,quotient # E :
  111. LONGIFY(divisor) # E : U L L U
  112. stq tmp1,24($30) # L :
  113. LONGIFY(modulus) # E :
  114. bis $31,1,mask # E :
  115. DIV_ONLY(stq tmp2,32($30)) # L : L U U L
  116. beq divisor, 9f /* div by zero */
  117. /*
  118. * In spite of the DIV_ONLY being either a non-instruction
  119. * or an actual stq, the addition of the .align directive
  120. * below ensures that label 1 is going to be nicely aligned
  121. */
  122. .align 4
  123. #ifdef INTSIZE
  124. /*
  125. * shift divisor left, using 3-bit shifts for
  126. * 32-bit divides as we can't overflow. Three-bit
  127. * shifts will result in looping three times less
  128. * here, but can result in two loops more later.
  129. * Thus using a large shift isn't worth it (and
  130. * s8add pairs better than a sll..)
  131. */
  132. 1: cmpult divisor,modulus,compare # E :
  133. s8addq divisor,$31,divisor # E :
  134. s8addq mask,$31,mask # E :
  135. bne compare,1b # U : U L U L
  136. #else
  137. 1: cmpult divisor,modulus,compare # E :
  138. nop # E :
  139. nop # E :
  140. blt divisor, 2f # U : U L U L
  141. addq divisor,divisor,divisor # E :
  142. addq mask,mask,mask # E :
  143. unop # E :
  144. bne compare,1b # U : U L U L
  145. #endif
  146. /* ok, start to go right again.. */
  147. 2:
  148. /*
  149. * Keep things nicely bundled... use a nop instead of not
  150. * having an instruction for DIV_ONLY
  151. */
  152. #ifdef DIV
  153. DIV_ONLY(addq quotient,mask,tmp2) # E :
  154. #else
  155. nop # E :
  156. #endif
  157. srl mask,1,mask # U :
  158. cmpule divisor,modulus,compare # E :
  159. subq modulus,divisor,tmp1 # E :
  160. #ifdef DIV
  161. DIV_ONLY(cmovne compare,tmp2,quotient) # E : Latency 2, extra map slot
  162. nop # E : as part of the cmovne
  163. srl divisor,1,divisor # U :
  164. nop # E : L U L U
  165. nop # E :
  166. cmovne compare,tmp1,modulus # E : Latency 2, extra map slot
  167. nop # E : as part of the cmovne
  168. bne mask,2b # U : U L U L
  169. #else
  170. srl divisor,1,divisor # U :
  171. cmovne compare,tmp1,modulus # E : Latency 2, extra map slot
  172. nop # E : as part of the cmovne
  173. bne mask,2b # U : U L L U
  174. #endif
  175. 9: ldq $1, 0($30) # L :
  176. ldq $2, 8($30) # L :
  177. nop # E :
  178. nop # E : U U L L
  179. ldq $0,16($30) # L :
  180. ldq tmp1,24($30) # L :
  181. nop # E :
  182. nop # E :
  183. #ifdef DIV
  184. DIV_ONLY(ldq tmp2,32($30)) # L :
  185. #else
  186. nop # E :
  187. #endif
  188. addq $30,STACK,$30 # E :
  189. ret $31,($23),1 # L0 : L U U L
  190. .end ufunction
  191. EXPORT_SYMBOL(ufunction)
  192. /*
  193. * Uhh.. Ugly signed division. I'd rather not have it at all, but
  194. * it's needed in some circumstances. There are different ways to
  195. * handle this, really. This does:
  196. * -a / b = a / -b = -(a / b)
  197. * -a % b = -(a % b)
  198. * a % -b = a % b
  199. * which is probably not the best solution, but at least should
  200. * have the property that (x/y)*y + (x%y) = x.
  201. */
  202. .align 4
  203. .globl sfunction
  204. .ent sfunction
  205. sfunction:
  206. subq $30,STACK,$30 # E :
  207. .frame $30,STACK,$23
  208. .prologue 0
  209. bis $24,$25,$28 # E :
  210. SLONGIFY($28) # E :
  211. bge $28,7b # U :
  212. stq $24,0($30) # L :
  213. subq $31,$24,$28 # E :
  214. stq $25,8($30) # L :
  215. nop # E : U L U L
  216. cmovlt $24,$28,$24 /* abs($24) */ # E : Latency 2, extra map slot
  217. nop # E : as part of the cmov
  218. stq $23,16($30) # L :
  219. subq $31,$25,$28 # E : U L U L
  220. stq tmp1,24($30) # L :
  221. cmovlt $25,$28,$25 /* abs($25) */ # E : Latency 2, extra map slot
  222. nop # E :
  223. bsr $23,ufunction # L0: L U L U
  224. ldq $24,0($30) # L :
  225. ldq $25,8($30) # L :
  226. GETSIGN($28) # E :
  227. subq $31,$27,tmp1 # E : U U L L
  228. SLONGIFY($28) # E :
  229. ldq $23,16($30) # L :
  230. cmovlt $28,tmp1,$27 # E : Latency 2, extra map slot
  231. nop # E : U L L U : as part of the cmov
  232. ldq tmp1,24($30) # L :
  233. nop # E : as part of the cmov
  234. addq $30,STACK,$30 # E :
  235. ret $31,($23),1 # L0 : L U U L
  236. .end sfunction
  237. EXPORT_SYMBOL(sfunction)