2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / config / alpha / lib1funcs.asm
bloba2abb1f8ae4932d00761730180db8db20e4f75f2
1 /* DEC Alpha division and remainder support.
2 Copyright (C) 1994, 1999 Free Software Foundation, Inc.
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any
7 later version.
9 In addition to the permissions in the GNU General Public License, the
10 Free Software Foundation gives you unlimited permission to link the
11 compiled version of this file into combinations with other programs,
12 and to distribute those combinations without any restriction coming
13 from the use of this file. (The General Public License restrictions
14 do apply in other respects; for example, they cover modification of
15 the file, and distribution when not linked into a combine
16 executable.)
18 This file is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA. */
28 /* This had to be written in assembler because the division functions
29 use a non-standard calling convention.
31 This file provides an implementation of __divqu, __divq, __divlu,
32 __divl, __remqu, __remq, __remlu and __reml. CPP macros control
33 the exact operation.
35 Operation performed: $27 := $24 o $25, clobber $28, return address to
36 caller in $23, where o one of the operations.
38 The following macros need to be defined:
40 SIZE, the number of bits, 32 or 64.
42 TYPE, either UNSIGNED or SIGNED
44 OPERATION, either DIVISION or REMAINDER
46 SPECIAL_CALLING_CONVENTION, 0 or 1. It is useful for debugging to
47 define this to 0. That removes the `__' prefix to make the function
48 name not collide with the existing libc.a names, and uses the
49 standard Alpha procedure calling convention.
52 #ifndef SPECIAL_CALLING_CONVENTION
53 #define SPECIAL_CALLING_CONVENTION 1
54 #endif
56 #ifdef L_divl
57 #if SPECIAL_CALLING_CONVENTION
58 #define FUNCTION_NAME __divl
59 #else
60 #define FUNCTION_NAME divl
61 #endif
62 #define SIZE 32
63 #define TYPE SIGNED
64 #define OPERATION DIVISION
65 #endif
67 #ifdef L_divlu
68 #if SPECIAL_CALLING_CONVENTION
69 #define FUNCTION_NAME __divlu
70 #else
71 #define FUNCTION_NAME divlu
72 #endif
73 #define SIZE 32
74 #define TYPE UNSIGNED
75 #define OPERATION DIVISION
76 #endif
78 #ifdef L_divq
79 #if SPECIAL_CALLING_CONVENTION
80 #define FUNCTION_NAME __divq
81 #else
82 #define FUNCTION_NAME divq
83 #endif
84 #define SIZE 64
85 #define TYPE SIGNED
86 #define OPERATION DIVISION
87 #endif
89 #ifdef L_divqu
90 #if SPECIAL_CALLING_CONVENTION
91 #define FUNCTION_NAME __divqu
92 #else
93 #define FUNCTION_NAME divqu
94 #endif
95 #define SIZE 64
96 #define TYPE UNSIGNED
97 #define OPERATION DIVISION
98 #endif
100 #ifdef L_reml
101 #if SPECIAL_CALLING_CONVENTION
102 #define FUNCTION_NAME __reml
103 #else
104 #define FUNCTION_NAME reml
105 #endif
106 #define SIZE 32
107 #define TYPE SIGNED
108 #define OPERATION REMAINDER
109 #endif
111 #ifdef L_remlu
112 #if SPECIAL_CALLING_CONVENTION
113 #define FUNCTION_NAME __remlu
114 #else
115 #define FUNCTION_NAME remlu
116 #endif
117 #define SIZE 32
118 #define TYPE UNSIGNED
119 #define OPERATION REMAINDER
120 #endif
122 #ifdef L_remq
123 #if SPECIAL_CALLING_CONVENTION
124 #define FUNCTION_NAME __remq
125 #else
126 #define FUNCTION_NAME remq
127 #endif
128 #define SIZE 64
129 #define TYPE SIGNED
130 #define OPERATION REMAINDER
131 #endif
133 #ifdef L_remqu
134 #if SPECIAL_CALLING_CONVENTION
135 #define FUNCTION_NAME __remqu
136 #else
137 #define FUNCTION_NAME remqu
138 #endif
139 #define SIZE 64
140 #define TYPE UNSIGNED
141 #define OPERATION REMAINDER
142 #endif
144 #define tmp0 $3
145 #define tmp1 $28
146 #define cnt $1
147 #define result_sign $2
149 #if SPECIAL_CALLING_CONVENTION
150 #define N $24
151 #define D $25
152 #define Q RETREG
153 #define RETREG $27
154 #else
155 #define N $16
156 #define D $17
157 #define Q RETREG
158 #define RETREG $0
159 #endif
161 /* Misc symbols to make alpha assembler easier to read. */
162 #define zero $31
163 #define sp $30
165 /* Symbols to make interface nicer. */
166 #define UNSIGNED 0
167 #define SIGNED 1
168 #define DIVISION 0
169 #define REMAINDER 1
171 .set noreorder
172 .set noat
173 .text
174 .align 3
175 .globl FUNCTION_NAME
176 .ent FUNCTION_NAME
177 FUNCTION_NAME:
179 .frame $30,0,$26,0
180 .prologue 0
182 /* Under the special calling convention, we have to preserve all register
183 values but $23 and $28. */
184 #if SPECIAL_CALLING_CONVENTION
185 lda sp,-64(sp)
186 #if OPERATION == DIVISION
187 stq N,0(sp)
188 #endif
189 stq D,8(sp)
190 stq cnt,16(sp)
191 stq result_sign,24(sp)
192 stq tmp0,32(sp)
193 #endif
195 /* If we are computing the remainder, move N to the register that is used
196 for the return value, and redefine what register is used for N. */
197 #if OPERATION == REMAINDER
198 bis N,N,RETREG
199 #undef N
200 #define N RETREG
201 #endif
203 /* Perform conversion from 32 bit types to 64 bit types. */
204 #if SIZE == 32
205 #if TYPE == SIGNED
206 /* If there are problems with the signed case, add these instructions.
207 The caller should already have done this.
208 addl N,0,N # sign extend N
209 addl D,0,D # sign extend D
211 #else /* UNSIGNED */
212 zap N,0xf0,N # zero extend N (caller required to sign extend)
213 zap D,0xf0,D # zero extend D
214 #endif
215 #endif
217 /* Check for divide by zero. */
218 bne D,$34
219 lda $16,-2(zero)
220 call_pal 0xaa
221 $34:
223 #if TYPE == SIGNED
224 #if OPERATION == DIVISION
225 xor N,D,result_sign
226 #else
227 bis N,N,result_sign
228 #endif
229 /* Get the absolute values of N and D. */
230 subq zero,N,tmp0
231 cmovlt N,tmp0,N
232 subq zero,D,tmp0
233 cmovlt D,tmp0,D
234 #endif
236 /* Compute CNT = ceil(log2(N)) - ceil(log2(D)). This is the number of
237 divide iterations we will have to perform. Should you wish to optimize
238 this, check a few bits at a time, preferably using zap/zapnot. Be
239 careful though, this code runs fast fro the most common cases, when the
240 quotient is small. */
241 bge N,$35
242 bis zero,1,cnt
243 blt D,$40
244 .align 3
245 $39: addq D,D,D
246 addl cnt,1,cnt
247 bge D,$39
248 br zero,$40
249 $35: cmpult N,D,tmp0
250 bis zero,zero,cnt
251 bne tmp0,$42
252 .align 3
253 $44: addq D,D,D
254 cmpult N,D,tmp0
255 addl cnt,1,cnt
256 beq tmp0,$44
257 $42: srl D,1,D
258 $40:
259 subl cnt,1,cnt
262 /* Actual divide. Could be optimized with unrolling. */
263 #if OPERATION == DIVISION
264 bis zero,zero,Q
265 #endif
266 blt cnt,$46
267 .align 3
268 $49: cmpule D,N,tmp1
269 subq N,D,tmp0
270 srl D,1,D
271 subl cnt,1,cnt
272 cmovne tmp1,tmp0,N
273 #if OPERATION == DIVISION
274 addq Q,Q,Q
275 bis Q,tmp1,Q
276 #endif
277 bge cnt,$49
278 $46:
281 /* The result is now in RETREG. NOTE! It was written to RETREG using
282 either N or Q as a synonym! */
285 /* Change the sign of the result as needed. */
286 #if TYPE == SIGNED
287 subq zero,RETREG,tmp0
288 cmovlt result_sign,tmp0,RETREG
289 #endif
292 /* Restore clobbered registers. */
293 #if SPECIAL_CALLING_CONVENTION
294 #if OPERATION == DIVISION
295 ldq N,0(sp)
296 #endif
297 ldq D,8(sp)
298 ldq cnt,16(sp)
299 ldq result_sign,24(sp)
300 ldq tmp0,32(sp)
302 lda sp,64(sp)
303 #endif
306 /* Sign extend an *unsigned* 32 bit result, as required by the Alpha
307 conventions. */
308 #if TYPE == UNSIGNED && SIZE == 32
309 /* This could be avoided by adding some CPP hair to the divide loop.
310 It is probably not worth the added complexity. */
311 addl RETREG,0,RETREG
312 #endif
315 #if SPECIAL_CALLING_CONVENTION
316 ret zero,($23),1
317 #else
318 ret zero,($26),1
319 #endif
320 .end FUNCTION_NAME