Update.
[glibc.git] / sysdeps / alpha / divrem.h
blob032308de32fec16c1f7942af4685e8ca2e533191
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
18 02111-1307 USA. */
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. */
34 #include <sysdep.h>
36 #ifdef __linux__
37 # include <asm/gentrap.h>
38 # include <asm/pal.h>
39 #else
40 # include <machine/pal.h>
41 #endif
43 #define mask v0
44 #define divisor t0
45 #define compare AT
46 #define tmp1 t2
47 #define tmp2 t3
48 #define retaddr t9
49 #define arg1 t10
50 #define arg2 t11
51 #define result t12
53 #if IS_REM
54 # define DIV_ONLY(x,y...)
55 # define REM_ONLY(x,y...) x,##y
56 # define modulus result
57 # define quotient t1
58 # define GETSIGN(x) mov arg1, x
59 # define STACK 32
60 #else
61 # define DIV_ONLY(x,y...) x,##y
62 # define REM_ONLY(x,y...)
63 # define modulus t1
64 # define quotient result
65 # define GETSIGN(x) xor arg1, arg2, x
66 # define STACK 48
67 #endif
69 #if SIZE == 8
70 # define LONGIFY(x,y) mov x,y
71 # define SLONGIFY(x,y) mov x,y
72 # define _SLONGIFY(x)
73 # define NEG(x,y) negq x,y
74 #else
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
79 #endif
81 .set noreorder
82 .set noat
84 .ent UFUNC_NAME
85 .globl UFUNC_NAME
87 .align 3
88 UFUNC_NAME:
89 $udiv_entry:
90 lda sp, -STACK(sp)
91 .frame sp, STACK, retaddr, 0
92 #ifdef PROF
93 stq ra, 0(sp)
94 stq pv, 8(sp)
95 stq gp, 16(sp)
97 br AT, 1f
98 1: ldgp gp, 0(AT)
100 mov retaddr, ra
101 lda AT, _mcount
102 jsr AT, (AT), _mcount
104 ldq ra, 0(sp)
105 ldq pv, 8(sp)
106 ldq gp, 16(sp)
107 #endif
108 .prologue 0
110 $udiv:
111 stq t0, 0(sp)
112 LONGIFY (arg2, divisor)
113 stq t1, 8(sp)
114 LONGIFY (arg1, modulus)
115 stq v0, 16(sp)
116 clr quotient
117 stq tmp1, 24(sp)
118 ldiq mask, 1
119 DIV_ONLY(stq tmp2,32(sp))
121 beq divisor, $divbyzero
123 .align 3
124 #if SIZE == 8
125 /* Shift divisor left. */
126 1: cmpult divisor, modulus, compare
127 blt divisor, 2f
128 addq divisor, divisor, divisor
129 addq mask, mask, mask
130 bne compare, 1b
131 unop
133 #else
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
140 bne compare, 1b
141 #endif
143 /* Now go back to the right. */
144 3: DIV_ONLY(addq quotient, mask, tmp2)
145 srl mask, 1, mask
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
151 bne mask, 3b
153 $done: ldq t0, 0(sp)
154 ldq t1, 8(sp)
155 ldq v0, 16(sp)
156 ldq tmp1, 24(sp)
157 DIV_ONLY(ldq tmp2, 32(sp))
158 lda sp, STACK(sp)
159 ret zero, (retaddr), 1
161 $divbyzero:
162 mov a0, tmp1
163 ldiq a0, GEN_INTDIV
164 call_pal PAL_gentrap
165 mov tmp1, a0
166 clr result /* If trap returns, return zero. */
167 br $done
169 .end UFUNC_NAME
171 .ent SFUNC_NAME
172 .globl SFUNC_NAME
174 .align 3
175 SFUNC_NAME:
176 lda sp, -STACK(sp)
177 .frame sp, STACK, retaddr, 0
178 #ifdef PROF
179 stq ra, 0(sp)
180 stq pv, 8(sp)
181 stq gp, 16(sp)
183 br AT, 1f
184 1: ldgp gp, 0(AT)
186 mov retaddr, ra
187 jsr AT, _mcount
189 ldq ra, 0(sp)
190 ldq pv, 8(sp)
191 ldq gp, 16(sp)
192 #endif
193 .prologue 0
195 or arg1, arg2, AT
196 _SLONGIFY(AT)
197 bge AT, $udiv /* don't need to mess with signs */
199 /* Save originals and find absolute values. */
200 stq arg1, 0(sp)
201 NEG (arg1, AT)
202 stq arg2, 8(sp)
203 cmovge AT, AT, arg1
204 stq retaddr, 16(sp)
205 NEG (arg2, AT)
206 stq tmp1, 24(sp)
207 cmovge AT, AT, arg2
209 /* Do the unsigned division. */
210 bsr retaddr, $udiv_entry
212 /* Restore originals and adjust the sign of the result. */
213 ldq arg1, 0(sp)
214 ldq arg2, 8(sp)
215 GETSIGN (AT)
216 NEG (result, tmp1)
217 _SLONGIFY(AT)
218 ldq retaddr, 16(sp)
219 cmovlt AT, tmp1, result
220 ldq tmp1, 24(sp)
222 lda sp, STACK(sp)
223 ret zero, (retaddr), 1
225 .end SFUNC_NAME