1 /* Copyright (C) 1996 Free Software Foundation, Inc.
2 Contributed by David Mosberger (davidm@cs.arizona.edu).
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 Cambridge, MA 02139, USA. */
21 /* The current Alpha chips don't provide hardware for integer
22 division. The C compiler expects the functions
24 __divqu: 64-bit unsigned long divide
25 __remqu: 64-bit unsigned long remainder
26 __divqs/__remqs: signed 64-bit
27 __divlu/__remlu: unsigned 32-bit
28 __divls/__remls: signed 32-bit
30 These are not normal C functions: instead of the normal calling
31 sequence, these expect their arguments in registers t10 and t11, and
32 return the result in t12 (aka pv). Register AT may be clobbered
33 (assembly temporary), anything else must be saved. */
38 # include <asm/gentrap.h>
41 # 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
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
, UFUNC_NAME
212 /* Restore originals and adjust the sign of the result. */
219 cmovlt AT
, tmp1
, result
223 ret zero
, (retaddr
), 1