1 /* Copyright (C) 1996,97,2002 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* The current Alpha chips don't provide hardware for integer
21 division. The C compiler expects the functions
23 __divqu: 64-bit unsigned long divide
24 __remqu: 64-bit unsigned long remainder
25 __divqs/__remqs: signed 64-bit
26 __divlu/__remlu: unsigned 32-bit
27 __divls/__remls: signed 32-bit
29 These are not normal C functions: instead of the normal calling
30 sequence, these expect their arguments in registers t10 and t11, and
31 return the result in t12 (aka pv). Register AT may be clobbered
32 (assembly temporary), anything else must be saved. */
37 # include <asm/gentrap.h>
40 # include <machine/pal.h>
54 # define DIV_ONLY(x,y...)
55 # define REM_ONLY(x,y...) x,##y
56 # define modulus result
58 # define GETSIGN(x) mov arg1, x
61 # define DIV_ONLY(x,y...) x,##y
62 # define REM_ONLY(x,y...)
64 # define quotient result
65 # define GETSIGN(x) xor arg1, arg2, x
70 # define LONGIFY(x,y) mov x,y
71 # define SLONGIFY(x,y) mov x,y
73 # define NEG(x,y) negq x,y
75 # define LONGIFY(x,y) zapnot x,15,y
76 # define SLONGIFY(x,y) sextl x,y
77 # define _SLONGIFY(x) sextl x,x
78 # define NEG(x,y) negl x,y
91 .frame sp
, STACK
, retaddr
, 0
102 jsr AT
, (AT
), _mcount
112 LONGIFY (arg2
, divisor
)
114 LONGIFY (arg1
, modulus
)
119 DIV_ONLY(stq tmp2
,32(sp
))
121 beq divisor
, $divbyzero
125 /* Shift divisor left. */
126 1: cmpult divisor
, modulus
, compare
128 addq divisor
, divisor
, divisor
129 addq mask
, mask
, mask
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
143 /* Now go back to the right. */
144 3: DIV_ONLY(addq quotient
, mask
, tmp2
)
146 cmpule divisor
, modulus
, compare
147 subq modulus
, divisor
, tmp1
148 DIV_ONLY(cmovne compare
, tmp2
, quotient
)
149 srl divisor
, 1, divisor
150 cmovne compare
, tmp1
, modulus
157 DIV_ONLY(ldq tmp2
, 32(sp
))
159 ret zero
, (retaddr
), 1
166 clr result
/* If trap returns, return zero. */
177 .frame sp
, STACK
, retaddr
, 0
197 bge AT
, $udiv
/* don't need to mess with signs */
199 /* Save originals and find absolute values. */
209 /* Do the unsigned division. */
210 bsr retaddr
, $udiv_entry
212 /* Restore originals and adjust the sign of the result. */
219 cmovlt AT
, tmp1
, result
223 ret zero
, (retaddr
), 1