OSDN Git Service

* alpha.h, arc.h, arm/aout.h, avr.h, cris.h, d30v.h, dsp16xx.h,
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / lib1funcs.asm
1 /* DEC Alpha division and remainder support.
2    Copyright (C) 1994, 1999 Free Software Foundation, Inc.
3
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.
8
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.)
17
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.
22
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.  */
27
28 /* This had to be written in assembler because the division functions 
29    use a non-standard calling convention. 
30
31    This file provides an implementation of __divqu, __divq, __divlu, 
32    __divl, __remqu, __remq, __remlu and __reml.  CPP macros control
33    the exact operation.
34
35    Operation performed: $27 := $24 o $25, clobber $28, return address to
36    caller in $23, where o one of the operations.
37
38    The following macros need to be defined: 
39
40         SIZE, the number of bits, 32 or 64.
41
42         TYPE, either UNSIGNED or SIGNED
43
44         OPERATION, either DIVISION or REMAINDER
45    
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.
50 */
51
52 #ifndef SPECIAL_CALLING_CONVENTION
53 #define SPECIAL_CALLING_CONVENTION 1
54 #endif
55
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
66
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
77
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
88
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
99
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
110
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
121
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
132
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
143
144 #define tmp0 $3
145 #define tmp1 $28
146 #define cnt $1
147 #define result_sign $2
148
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
160
161 /* Misc symbols to make alpha assembler easier to read.  */
162 #define zero $31
163 #define sp $30
164
165 /* Symbols to make interface nicer.  */
166 #define UNSIGNED 0
167 #define SIGNED 1
168 #define DIVISION 0
169 #define REMAINDER 1
170
171         .set noreorder
172         .set noat
173 .text
174         .align 3
175         .globl FUNCTION_NAME
176         .ent FUNCTION_NAME
177 FUNCTION_NAME:
178
179         .frame  $30,0,$26,0
180         .prologue 0
181
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
194
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
202
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
210         */
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
216
217 /* Check for divide by zero.  */
218         bne     D,$34
219         lda     $16,-2(zero)
220         call_pal 0xaa
221 $34:
222
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
235
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
260
261
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:
279
280
281 /* The result is now in RETREG.  NOTE!  It was written to RETREG using
282    either N or Q as a synonym!  */
283
284
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
290
291
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)
301
302         lda     sp,64(sp)
303 #endif
304
305
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
313
314
315 #if SPECIAL_CALLING_CONVENTION
316         ret     zero,($23),1
317 #else
318         ret     zero,($26),1
319 #endif
320         .end    FUNCTION_NAME