]>
Commit | Line | Data |
---|---|---|
83ffe9cd | 1 | /* Copyright (C) 2018-2023 Free Software Foundation, Inc. |
d929e137 SH |
2 | |
3 | This file is free software; you can redistribute it and/or modify it | |
4 | under the terms of the GNU General Public License as published by the | |
5 | Free Software Foundation; either version 3, or (at your option) any | |
6 | later version. | |
7 | ||
8 | This file is distributed in the hope that it will be useful, but | |
9 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | General Public License for more details. | |
12 | ||
13 | Under Section 7 of GPL version 3, you are granted additional | |
14 | permissions described in the GCC Runtime Library Exception, version | |
15 | 3.1, as published by the Free Software Foundation. | |
16 | ||
17 | You should have received a copy of the GNU General Public License and | |
18 | a copy of the GCC Runtime Library Exception along with this program; | |
19 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
20 | <http://www.gnu.org/licenses/>. */ | |
21 | ||
22 | ||
23 | #ifdef L__mulsi3 | |
24 | .balign 4 | |
25 | .globl __mulsi3 | |
26 | .type __mulsi3, @function | |
27 | __mulsi3: | |
28 | l.movhi r11, 0 /* initial r */ | |
29 | ||
30 | /* Given R = X * Y ... */ | |
31 | 1: l.sfeq r4, r0 /* while (y != 0) */ | |
32 | l.bf 2f | |
33 | l.andi r5, r4, 1 /* if (y & 1) ... */ | |
34 | l.add r12, r11, r3 | |
35 | l.sfne r5, r0 | |
36 | #if defined(__or1k_cmov__) | |
37 | l.cmov r11, r12, r11 /* ... r += x. */ | |
38 | l.srli r4, r4, 1 /* y >>= 1 */ | |
39 | #else | |
40 | l.bnf 3f | |
41 | l.srli r4, r4, 1 /* y >>= 1 */ | |
42 | l.ori r11, r12, 0 | |
43 | 3: | |
44 | #endif | |
45 | l.j 1b | |
46 | l.add r3, r3, r3 /* x <<= 1 */ | |
47 | ||
48 | 2: l.jr r9 | |
49 | l.nop | |
50 | ||
51 | .size __mulsi3, . - __mulsi3 | |
52 | #endif | |
53 | ||
54 | #if defined(L__udivsi3) || defined(L__umodsi3) \ | |
55 | || defined(L__divsi3) || defined(L__modsi3) | |
56 | .global __udivmodsi3_internal | |
57 | .hidden __udivmodsi3_internal | |
58 | .type __udivmodsi3_internal, @function | |
59 | #endif | |
60 | ||
61 | #ifdef L__udivsi3 | |
62 | .balign 4 | |
63 | .global __udivsi3 | |
64 | .type __udivsi3, @function | |
65 | __udivsi3: | |
66 | __udivmodsi3_internal: | |
67 | /* Note that the other division routines assume that r13 | |
68 | is not clobbered by this routine, and use that as to | |
69 | save a return address without creating a stack frame. */ | |
70 | ||
9c0dba7c | 71 | l.sfeq r4, r0 /* division by zero; return 0. */ |
d929e137 SH |
72 | l.ori r11, r0, 0 /* initial quotient */ |
73 | l.bf 9f | |
74 | l.ori r12, r3, 0 /* initial remainder */ | |
75 | ||
76 | /* Given X/Y, shift Y left until Y >= X. */ | |
77 | l.ori r6, r0, 1 /* mask = 1 */ | |
9c0dba7c | 78 | 1: l.sflts r4, r0 /* y has msb set */ |
d929e137 SH |
79 | l.bf 2f |
80 | l.sfltu r4, r12 /* y < x */ | |
81 | l.add r4, r4, r4 /* y <<= 1 */ | |
9c0dba7c | 82 | l.bf 1b |
d929e137 SH |
83 | l.add r6, r6, r6 /* mask <<= 1 */ |
84 | ||
85 | /* Shift Y back to the right again, subtracting from X. */ | |
86 | 2: l.add r7, r11, r6 /* tmp1 = quot + mask */ | |
87 | 3: l.srli r6, r6, 1 /* mask >>= 1 */ | |
88 | l.sub r8, r12, r4 /* tmp2 = x - y */ | |
89 | l.sfleu r4, r12 /* y <= x */ | |
90 | l.srli r4, r4, 1 /* y >>= 1 */ | |
91 | #if defined(__or1k_cmov__) | |
92 | l.cmov r11, r7, r11 /* if (y <= x) quot = tmp1 */ | |
93 | l.cmov r12, r8, r12 /* if (y <= x) x = tmp2 */ | |
94 | #else | |
95 | l.bnf 4f | |
96 | l.nop | |
97 | l.ori r11, r7, 0 | |
98 | l.ori r12, r8, 0 | |
99 | 4: | |
100 | #endif | |
101 | l.sfne r6, r0 /* loop until mask == 0 */ | |
102 | l.bf 3b | |
103 | l.add r7, r11, r6 /* delay fill from loop start */ | |
104 | ||
105 | 9: l.jr r9 | |
106 | l.nop | |
107 | ||
108 | .size __udivsi3, . - __udivsi3 | |
109 | .size __udivmodsi3_internal, . - __udivmodsi3_internal | |
110 | #endif | |
111 | ||
112 | #ifdef L__umodsi3 | |
113 | .balign 4 | |
114 | .global __umodsi3 | |
115 | .type __umodsi3, @function | |
116 | .cfi_startproc | |
117 | __umodsi3: | |
118 | /* Know that __udivmodsi3_internal does not clobber r13. */ | |
119 | l.ori r13, r9, 0 | |
120 | .cfi_register 9, 13 | |
121 | l.jal __udivmodsi3_internal | |
122 | l.nop | |
123 | l.jr r13 /* return to saved lr */ | |
124 | l.ori r11, r12, 0 /* move remainder to rv */ | |
125 | ||
126 | .cfi_endproc | |
127 | .size __umodsi3, . - __umodsi3 | |
128 | #endif | |
129 | ||
130 | /* For signed division we do: | |
131 | ||
132 | -x / y = x / -y = -(x / y) | |
133 | -x % y = -(x % y) | |
134 | x % -y = x % y | |
135 | ||
136 | which has the property that (x/y)*y + (x%y) = x. */ | |
137 | ||
138 | #ifdef L__divsi3 | |
139 | .balign 4 | |
140 | .global __divsi3 | |
141 | .type __divsi3, @function | |
142 | .cfi_startproc | |
143 | __divsi3: | |
144 | l.xor r6, r3, r4 /* need result negate? */ | |
145 | ||
146 | l.sflts r3, r0 /* abs(x) */ | |
147 | #if defined(__or1k_cmov__) | |
148 | l.sub r5, r0, r3 | |
149 | l.cmov r3, r5, r3 | |
150 | #else | |
151 | l.bnf 1f | |
152 | l.sub r5, r0, r3 | |
153 | l.ori r3, r5, 0 | |
154 | 1: | |
155 | #endif | |
156 | l.sflts r4, r0 /* abs(y) */ | |
157 | #if defined(__or1k_cmov__) | |
158 | l.sub r5, r0, r4 | |
159 | l.cmov r4, r5, r4 | |
160 | #else | |
161 | l.bnf 2f | |
162 | l.sub r5, r0, r4 | |
163 | l.ori r4, r5, 0 | |
164 | 2: | |
165 | #endif | |
166 | ||
167 | /* If the result will not require sign flip, tail call. */ | |
168 | l.sflts r6, r0 | |
169 | l.bnf __udivmodsi3_internal | |
170 | l.ori r13, r9, 0 /* save lr */ | |
171 | ||
172 | /* Otherwise, know that __udivmodsi3_internal does not clobber r13. | |
173 | Perform a normal call, then negate and return via saved lr. */ | |
174 | .cfi_register 9, 13 | |
175 | l.jal __udivmodsi3_internal | |
176 | l.nop | |
177 | l.jr r13 | |
178 | l.sub r11, r0, r11 | |
179 | ||
180 | .cfi_endproc | |
181 | .size __divsi3, . - __divsi3 | |
182 | #endif | |
183 | ||
184 | #ifdef L__modsi3 | |
185 | .balign 4 | |
186 | .global __modsi3 | |
187 | .type __modsi3, @function | |
188 | .cfi_startproc | |
189 | __modsi3: | |
190 | l.sflts r4, r0 /* abs(y) */ | |
191 | #if defined(__or1k_cmov__) | |
192 | l.sub r5, r0, r4 | |
193 | l.cmov r4, r5, r4 | |
194 | #else | |
195 | l.bnf 2f | |
196 | l.sub r5, r0, r4 | |
197 | l.ori r4, r5, 0 | |
198 | 2: | |
199 | #endif | |
200 | ||
201 | l.sflts r3, r0 /* x negative? */ | |
202 | l.bf 1f | |
203 | l.ori r13, r9, 0 /* save lr */ | |
204 | ||
205 | /* Know that __udivmodsi3_internal does not clobber r13. */ | |
206 | .cfi_register 9, 13 | |
207 | ||
208 | /* X positive; no negate of the result required. */ | |
209 | l.jal __udivmodsi3_internal | |
210 | l.nop | |
211 | l.jr r13 /* return to saved lr */ | |
212 | l.ori r11, r12, 0 /* move remainder to rv */ | |
213 | ||
214 | /* X negative; negate both X and the result. */ | |
215 | 1: l.jal __udivmodsi3_internal | |
216 | l.sub r3, r0, r3 | |
217 | l.jr r13 /* return to saved lr */ | |
218 | l.sub r11, r0, r12 /* negate remainder to rv */ | |
219 | ||
220 | .cfi_endproc | |
221 | .size __modsi3, .- __modsi3 | |
222 | #endif |