Add _dl_function_address.
[kopensolaris-gnu/glibc.git] / sysdeps / alpha / divrem.h
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2    Contributed by David Mosberger (davidm@cs.arizona.edu).
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 /* The current Alpha chips don't provide hardware for integer
21    division.  The C compiler expects the functions
22
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
28
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.  */
33
34 #include <sysdep.h>
35
36 #ifdef __linux__
37 # include <asm/gentrap.h>
38 # include <asm/pal.h>
39 #else
40 # include <machine/pal.h>
41 #endif
42
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
52
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
68
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
80
81         .set noreorder
82         .set noat
83
84         .ent UFUNC_NAME
85         .globl UFUNC_NAME
86
87         .align 3
88 UFUNC_NAME:
89         lda     sp, -STACK(sp)
90         .frame  sp, STACK, retaddr, 0
91 #ifdef PROF
92         stq     ra, 0(sp)
93         stq     pv, 8(sp)
94         stq     gp, 16(sp)
95
96         br      AT, 1f
97 1:      ldgp    gp, 0(AT)
98
99         mov     retaddr, ra
100         lda     AT, _mcount
101         jsr     AT, (AT), _mcount
102
103         ldq     ra, 0(sp)
104         ldq     pv, 8(sp)
105         ldq     gp, 16(sp)
106 #endif
107         .prologue 0
108
109 $udiv:
110         stq     t0, 0(sp)
111         LONGIFY (arg2, divisor)
112         stq     t1, 8(sp)
113         LONGIFY (arg1, modulus)
114         stq     v0, 16(sp)
115         clr     quotient
116         stq     tmp1, 24(sp)
117         ldiq    mask, 1
118         DIV_ONLY(stq tmp2,32(sp))
119
120         beq     divisor, $divbyzero
121
122         .align 3
123 #if SIZE == 8
124         /* Shift divisor left.  */
125 1:      cmpult  divisor, modulus, compare
126         blt     divisor, 2f
127         addq    divisor, divisor, divisor
128         addq    mask, mask, mask
129         bne     compare, 1b
130         unop
131 2:
132 #else
133         /* Shift divisor left using 3-bit shifts as we can't overflow.
134            This results in looping three times less here, but up to
135            two more times later.  Thus using a large shift isn't worth it.  */
136 1:      cmpult  divisor, modulus, compare
137         s8addq  divisor, zero, divisor
138         s8addq  mask, zero, mask
139         bne     compare, 1b
140 #endif
141
142         /* Now go back to the right.  */
143 3:      DIV_ONLY(addq quotient, mask, tmp2)
144         srl     mask, 1, mask
145         cmpule  divisor, modulus, compare
146         subq    modulus, divisor, tmp1
147         DIV_ONLY(cmovne compare, tmp2, quotient)
148         srl     divisor, 1, divisor
149         cmovne  compare, tmp1, modulus
150         bne     mask, 3b
151
152 $done:  ldq     t0, 0(sp)
153         ldq     t1, 8(sp)
154         ldq     v0, 16(sp)
155         ldq     tmp1, 24(sp)
156         DIV_ONLY(ldq tmp2, 32(sp))
157         lda     sp, STACK(sp)
158         ret     zero, (retaddr), 1
159
160 $divbyzero:
161         mov     a0, tmp1
162         ldiq    a0, GEN_INTDIV
163         call_pal PAL_gentrap
164         mov     tmp1, a0
165         clr     result                  /* If trap returns, return zero.  */
166         br      $done
167
168         .end UFUNC_NAME
169
170         .ent SFUNC_NAME
171         .globl SFUNC_NAME
172
173         .align 3
174 SFUNC_NAME:
175         lda     sp, -STACK(sp)
176         .frame  sp, STACK, retaddr, 0
177 #ifdef PROF
178         stq     ra, 0(sp)
179         stq     pv, 8(sp)
180         stq     gp, 16(sp)
181
182         br      AT, 1f
183 1:      ldgp    gp, 0(AT)
184
185         mov     retaddr, ra
186         jsr     AT, _mcount
187
188         ldq     ra, 0(sp)
189         ldq     pv, 8(sp)
190         ldq     gp, 16(sp)
191 #endif
192         .prologue 0
193
194         or      arg1, arg2, AT
195         _SLONGIFY(AT)
196         bge     AT, $udiv               /* don't need to mess with signs */
197
198         /* Save originals and find absolute values.  */
199         stq     arg1, 0(sp)
200         NEG     (arg1, AT)
201         stq     arg2, 8(sp)
202         cmovge  AT, AT, arg1
203         stq     retaddr, 16(sp)
204         NEG     (arg2, AT)
205         stq     tmp1, 24(sp)
206         cmovge  AT, AT, arg2
207
208         /* Do the unsigned division.  */
209         bsr     retaddr, UFUNC_NAME
210
211         /* Restore originals and adjust the sign of the result.  */
212         ldq     arg1, 0(sp)
213         ldq     arg2, 8(sp)
214         GETSIGN (AT)
215         NEG     (result, tmp1)
216         _SLONGIFY(AT)
217         ldq     retaddr, 16(sp)
218         cmovlt  AT, tmp1, result
219         ldq     tmp1, 24(sp)
220
221         lda     sp, STACK(sp)
222         ret     zero, (retaddr), 1
223
224         .end    SFUNC_NAME