riscv64: fix linking with binutils 2.40
[uclibc-ng.git] / libc / sysdeps / linux / alpha / divrem.h
blob27475f02974b242e2fb3bd50f69e11c9a9351ea8
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.
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.
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.
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/>. */
19 /* The current Alpha chips don't provide hardware for integer
20 division. The C compiler expects the functions
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
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. */
33 #include <features.h>
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
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
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
87 #ifndef IS_IN_rtld
88 .hidden UFUNC_NAME
89 #endif
91 .align 3
92 UFUNC_NAME:
93 lda sp, -STACK(sp)
94 .frame sp, STACK, retaddr, 0
95 .prologue 0
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))
108 beq divisor, $divbyzero
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
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
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
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
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
156 .end UFUNC_NAME
158 .ent SFUNC_NAME
159 .globl SFUNC_NAME
161 .align 3
162 SFUNC_NAME:
163 lda sp, -STACK(sp)
164 .frame sp, STACK, retaddr, 0
165 .prologue 0
167 or arg1, arg2, AT
168 _SLONGIFY(AT)
169 bge AT, $udiv /* don't need to mess with signs */
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
181 /* Do the unsigned division. */
182 bsr retaddr, UFUNC_NAME
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)
194 lda sp, STACK(sp)
195 ret zero, (retaddr), 1
197 .end SFUNC_NAME