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.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 /* The current Alpha chips don't provide hardware for integer
20 division. The C compiler expects the functions
22 __divqu: 64-bit unsigned long divide
23 __remqu: 64-bit unsigned long remainder
24 __divqs/__remqs: signed 64-bit
25 __divlu/__remlu: unsigned 32-bit
26 __divls/__remls: signed 32-bit
28 These are not normal C functions: instead of the normal calling
29 sequence, these expect their arguments in registers t10 and t11, and
30 return the result in t12 (aka pv). Register AT may be clobbered
31 (assembly temporary), anything else must be saved. */
35 #include <sys/regdef.h>
37 # include <asm/gentrap.h>
40 # include <machine/pal.h>
55 # define DIV_ONLY(x,y...)
56 # define REM_ONLY(x,y...) x,##y
57 # define modulus result
59 # define GETSIGN(x) mov arg1, x
62 # define DIV_ONLY(x,y...) x,##y
63 # define REM_ONLY(x,y...)
65 # define quotient result
66 # define GETSIGN(x) xor arg1, arg2, x
71 # define LONGIFY(x,y) mov x,y
72 # define SLONGIFY(x,y) mov x,y
74 # define NEG(x,y) negq x,y
76 # define LONGIFY(x,y) zapnot x,15,y
77 # define SLONGIFY(x,y) sextl x,y
78 # define _SLONGIFY(x) sextl x,x
79 # define NEG(x,y) negl x,y
94 .frame sp
, STACK
, retaddr
, 0
99 LONGIFY (arg2
, divisor
)
101 LONGIFY (arg1
, modulus
)
106 DIV_ONLY(stq tmp2
,32(sp
))
108 beq divisor
, $divbyzero
112 /* Shift divisor left. */
113 1: cmpult divisor
, modulus
, compare
115 addq divisor
, divisor
, divisor
116 addq mask
, mask
, mask
121 /* Shift divisor left using 3-bit shifts as we can't overflow.
122 This results in looping three times less here, but up to
123 two more times later. Thus using a large shift isn't worth it. */
124 1: cmpult divisor
, modulus
, compare
125 s8addq divisor
, zero
, divisor
126 s8addq mask
, zero
, mask
130 /* Now go back to the right. */
131 3: DIV_ONLY(addq quotient
, mask
, tmp2
)
133 cmpule divisor
, modulus
, compare
134 subq modulus
, divisor
, tmp1
135 DIV_ONLY(cmovne compare
, tmp2
, quotient
)
136 srl divisor
, 1, divisor
137 cmovne compare
, tmp1
, modulus
144 DIV_ONLY(ldq tmp2
, 32(sp
))
146 ret zero
, (retaddr
), 1
153 clr result
/* If trap returns, return zero. */
164 .frame sp
, STACK
, retaddr
, 0
169 bge AT
, $udiv
/* don't need to mess with signs */
171 /* Save originals and find absolute values. */
181 /* Do the unsigned division. */
182 bsr retaddr
, UFUNC_NAME
184 /* Restore originals and adjust the sign of the result. */
191 cmovlt AT
, tmp1
, result
195 ret zero
, (retaddr
), 1