Update.
[glibc.git] / sysdeps / alpha / divrem.h
blobb83908dc9f0995d0a009b86dbffc51283bd56b5f
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. */
35 #include <sysdep.h>
37 #ifdef __linux__
38 # include <asm/gentrap.h>
39 # include <asm/pal.h>
40 #else
41 # include <machine/pal.h>
42 #endif
44 #define mask v0
45 #define divisor t0
46 #define compare AT
47 #define tmp1 t2
48 #define tmp2 t3
49 #define retaddr t9
50 #define arg1 t10
51 #define arg2 t11
52 #define result t12
54 #if IS_REM
55 # define DIV_ONLY(x,y...)
56 # define REM_ONLY(x,y...) x,##y
57 # define modulus result
58 # define quotient t1
59 # define GETSIGN(x) mov arg1, x
60 # define STACK 32
61 #else
62 # define DIV_ONLY(x,y...) x,##y
63 # define REM_ONLY(x,y...)
64 # define modulus t1
65 # define quotient result
66 # define GETSIGN(x) xor arg1, arg2, x
67 # define STACK 48
68 #endif
70 #if SIZE == 8
71 # define LONGIFY(x,y) mov x,y
72 # define SLONGIFY(x,y) mov x,y
73 # define _SLONGIFY(x)
74 # define NEG(x,y) negq x,y
75 #else
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
80 #endif
82 .set noreorder
83 .set noat
85 .ent UFUNC_NAME
86 .globl UFUNC_NAME
88 .align 3
89 UFUNC_NAME:
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, UFUNC_NAME
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