OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libc / sysdeps / linux / 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 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.
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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 /* The current Alpha chips don't provide hardware for integer
20    division.  The C compiler expects the functions
21
22         __divqu: 64-bit unsigned long divide
23         __remqu: 64-bit unsigned long remainder
24         __divqs/__remqs: signed 64-bit
25         __divlu/__remlu: unsigned 32-bit
26         __divls/__remls: signed 32-bit
27
28    These are not normal C functions: instead of the normal calling
29    sequence, these expect their arguments in registers t10 and t11, and
30    return the result in t12 (aka pv).  Register AT may be clobbered
31    (assembly temporary), anything else must be saved.  */
32
33 #include <features.h>
34
35 #include <sys/regdef.h>
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
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
69
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
81
82         .set noreorder
83         .set noat
84
85         .ent UFUNC_NAME
86         .globl UFUNC_NAME
87 #ifndef IS_IN_rtld
88         .hidden UFUNC_NAME
89 #endif
90
91         .align 3
92 UFUNC_NAME:
93         lda     sp, -STACK(sp)
94         .frame  sp, STACK, retaddr, 0
95         .prologue 0
96
97 $udiv:
98         stq     t0, 0(sp)
99         LONGIFY (arg2, divisor)
100         stq     t1, 8(sp)
101         LONGIFY (arg1, modulus)
102         stq     v0, 16(sp)
103         clr     quotient
104         stq     tmp1, 24(sp)
105         ldiq    mask, 1
106         DIV_ONLY(stq tmp2,32(sp))
107
108         beq     divisor, $divbyzero
109
110         .align 3
111 #if SIZE == 8
112         /* Shift divisor left.  */
113 1:      cmpult  divisor, modulus, compare
114         blt     divisor, 2f
115         addq    divisor, divisor, divisor
116         addq    mask, mask, mask
117         bne     compare, 1b
118         unop
119 2:
120 #else
121         /* Shift divisor left using 3-bit shifts as we can't overflow.
122            This results in looping three times less here, but up to
123            two more times later.  Thus using a large shift isn't worth it.  */
124 1:      cmpult  divisor, modulus, compare
125         s8addq  divisor, zero, divisor
126         s8addq  mask, zero, mask
127         bne     compare, 1b
128 #endif
129
130         /* Now go back to the right.  */
131 3:      DIV_ONLY(addq quotient, mask, tmp2)
132         srl     mask, 1, mask
133         cmpule  divisor, modulus, compare
134         subq    modulus, divisor, tmp1
135         DIV_ONLY(cmovne compare, tmp2, quotient)
136         srl     divisor, 1, divisor
137         cmovne  compare, tmp1, modulus
138         bne     mask, 3b
139
140 $done:  ldq     t0, 0(sp)
141         ldq     t1, 8(sp)
142         ldq     v0, 16(sp)
143         ldq     tmp1, 24(sp)
144         DIV_ONLY(ldq tmp2, 32(sp))
145         lda     sp, STACK(sp)
146         ret     zero, (retaddr), 1
147
148 $divbyzero:
149         mov     a0, tmp1
150         ldiq    a0, GEN_INTDIV
151         call_pal PAL_gentrap
152         mov     tmp1, a0
153         clr     result                  /* If trap returns, return zero.  */
154         br      $done
155
156         .end UFUNC_NAME
157
158         .ent SFUNC_NAME
159         .globl SFUNC_NAME
160
161         .align 3
162 SFUNC_NAME:
163         lda     sp, -STACK(sp)
164         .frame  sp, STACK, retaddr, 0
165         .prologue 0
166
167         or      arg1, arg2, AT
168         _SLONGIFY(AT)
169         bge     AT, $udiv               /* don't need to mess with signs */
170
171         /* Save originals and find absolute values.  */
172         stq     arg1, 0(sp)
173         NEG     (arg1, AT)
174         stq     arg2, 8(sp)
175         cmovge  AT, AT, arg1
176         stq     retaddr, 16(sp)
177         NEG     (arg2, AT)
178         stq     tmp1, 24(sp)
179         cmovge  AT, AT, arg2
180
181         /* Do the unsigned division.  */
182         bsr     retaddr, UFUNC_NAME
183
184         /* Restore originals and adjust the sign of the result.  */
185         ldq     arg1, 0(sp)
186         ldq     arg2, 8(sp)
187         GETSIGN (AT)
188         NEG     (result, tmp1)
189         _SLONGIFY(AT)
190         ldq     retaddr, 16(sp)
191         cmovlt  AT, tmp1, result
192         ldq     tmp1, 24(sp)
193
194         lda     sp, STACK(sp)
195         ret     zero, (retaddr), 1
196
197         .end    SFUNC_NAME