]>
Commit | Line | Data |
---|---|---|
afba61d1 | 1 | /* mips16 floating point support code |
ac1dca3c | 2 | Copyright (C) 1996-2014 Free Software Foundation, Inc. |
afba61d1 ILT |
3 | Contributed by Cygnus Support |
4 | ||
5 | This file is free software; you can redistribute it and/or modify it | |
6 | under the terms of the GNU General Public License as published by the | |
748086b7 | 7 | Free Software Foundation; either version 3, or (at your option) any |
afba61d1 ILT |
8 | later version. |
9 | ||
afba61d1 ILT |
10 | This file is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | General Public License for more details. | |
14 | ||
748086b7 JJ |
15 | Under Section 7 of GPL version 3, you are granted additional |
16 | permissions described in the GCC Runtime Library Exception, version | |
17 | 3.1, as published by the Free Software Foundation. | |
afba61d1 | 18 | |
748086b7 JJ |
19 | You should have received a copy of the GNU General Public License and |
20 | a copy of the GCC Runtime Library Exception along with this program; | |
21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
22 | <http://www.gnu.org/licenses/>. */ | |
afba61d1 | 23 | |
050af144 MF |
24 | #include "auto-host.h" |
25 | ||
5b1ea7c5 SE |
26 | #if defined(__mips_micromips) || defined(__mips_soft_float) |
27 | /* Do nothing because this code is only needed when linking | |
28 | against mips16 hard-float objects. Neither micromips code | |
29 | nor soft-float code can be linked against mips16 hard-float | |
30 | objects so we do not need these routines when building libgcc | |
31 | for those cases. */ | |
22c4c869 CM |
32 | #else |
33 | ||
050af144 MF |
34 | #if defined(HAVE_AS_MODULE) |
35 | #if __mips_fpr == 32 | |
36 | .module fp=32 | |
37 | #elif __mips_fpr == 0 | |
38 | .module fp=xx | |
39 | #elif __mips_fpr == 64 | |
40 | .module fp=64 | |
41 | #endif | |
42 | #endif | |
43 | ||
afba61d1 ILT |
44 | /* This file contains mips16 floating point support functions. These |
45 | functions are called by mips16 code to handle floating point when | |
46 | -msoft-float is not used. They accept the arguments and return | |
47 | values using the soft-float calling convention, but do the actual | |
48 | operation using the hard floating point instructions. */ | |
49 | ||
08d0963a RS |
50 | #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64) |
51 | ||
85f65093 | 52 | /* This file contains 32-bit assembly code. */ |
afba61d1 ILT |
53 | .set nomips16 |
54 | ||
987ba558 | 55 | /* Start a function. */ |
afba61d1 ILT |
56 | |
57 | #define STARTFN(NAME) .globl NAME; .ent NAME; NAME: | |
58 | ||
59 | /* Finish a function. */ | |
60 | ||
61 | #define ENDFN(NAME) .end NAME | |
62 | ||
a38e0142 SL |
63 | /* ARG1 |
64 | The FPR that holds the first floating-point argument. | |
afba61d1 | 65 | |
a38e0142 SL |
66 | ARG2 |
67 | The FPR that holds the second floating-point argument. | |
afba61d1 | 68 | |
a38e0142 SL |
69 | RET |
70 | The FPR that holds a floating-point return value. */ | |
71 | ||
72 | #define RET $f0 | |
73 | #define ARG1 $f12 | |
74 | #ifdef __mips64 | |
75 | #define ARG2 $f13 | |
76 | #else | |
77 | #define ARG2 $f14 | |
78 | #endif | |
79 | ||
80 | /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR | |
81 | and so that its low 32 bits contain LOW_FPR. */ | |
82 | #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \ | |
83 | .set noat; \ | |
a38e0142 | 84 | mfc1 $1, LOW_FPR; \ |
93f63c68 RS |
85 | mfc1 GPR, HIGH_FPR; \ |
86 | dsll $1, $1, 32; \ | |
a38e0142 | 87 | dsll GPR, GPR, 32; \ |
93f63c68 | 88 | dsrl $1, $1, 32; \ |
a38e0142 SL |
89 | or GPR, GPR, $1; \ |
90 | .set at | |
91 | ||
92 | /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of | |
93 | GPR to LOW_FPR. */ | |
94 | #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \ | |
95 | .set noat; \ | |
96 | dsrl $1, GPR, 32; \ | |
97 | mtc1 GPR, LOW_FPR; \ | |
98 | mtc1 $1, HIGH_FPR; \ | |
99 | .set at | |
100 | ||
101 | /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */ | |
102 | #define DELAYt(T, OPCODE, OP2) \ | |
103 | .set noreorder; \ | |
104 | jr T; \ | |
105 | OPCODE, OP2; \ | |
106 | .set reorder | |
107 | ||
72be589b MR |
108 | #if __mips >= 4 |
109 | /* Coprocessor moves are interlocked from the MIPS IV ISA up. */ | |
110 | #define DELAYf(T, OPCODE, OP2) DELAYt (T, OPCODE, OP2) | |
111 | #else | |
a38e0142 SL |
112 | /* Use "OPCODE. OP2" and jump to T. */ |
113 | #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T | |
72be589b | 114 | #endif |
a38e0142 SL |
115 | |
116 | /* MOVE_SF_BYTE0(D) | |
117 | Move the first single-precision floating-point argument between | |
118 | GPRs and FPRs. | |
119 | ||
120 | MOVE_SI_BYTE0(D) | |
121 | Likewise the first single-precision integer argument. | |
122 | ||
123 | MOVE_SF_BYTE4(D) | |
124 | Move the second single-precision floating-point argument between | |
125 | GPRs and FPRs, given that the first argument occupies 4 bytes. | |
126 | ||
127 | MOVE_SF_BYTE8(D) | |
128 | Move the second single-precision floating-point argument between | |
129 | GPRs and FPRs, given that the first argument occupies 8 bytes. | |
130 | ||
131 | MOVE_DF_BYTE0(D) | |
132 | Move the first double-precision floating-point argument between | |
133 | GPRs and FPRs. | |
134 | ||
135 | MOVE_DF_BYTE8(D) | |
136 | Likewise the second double-precision floating-point argument. | |
137 | ||
138 | MOVE_SF_RET(D, T) | |
139 | Likewise a single-precision floating-point return value, | |
140 | then jump to T. | |
141 | ||
142 | MOVE_SC_RET(D, T) | |
143 | Likewise a complex single-precision floating-point return value. | |
144 | ||
145 | MOVE_DF_RET(D, T) | |
146 | Likewise a double-precision floating-point return value. | |
147 | ||
148 | MOVE_DC_RET(D, T) | |
149 | Likewise a complex double-precision floating-point return value. | |
150 | ||
151 | MOVE_SI_RET(D, T) | |
152 | Likewise a single-precision integer return value. | |
153 | ||
154 | The D argument is "t" to move to FPRs and "f" to move from FPRs. | |
155 | The return macros may assume that the target of the jump does not | |
156 | use a floating-point register. */ | |
157 | ||
158 | #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0) | |
159 | #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0) | |
160 | ||
161 | #if defined(__mips64) && defined(__MIPSEB__) | |
162 | #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T | |
163 | #elif defined(__mips64) | |
164 | /* The high 32 bits of $2 correspond to the second word in memory; | |
165 | i.e. the imaginary part. */ | |
166 | #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T | |
a38e0142 SL |
167 | #else |
168 | #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2) | |
169 | #endif | |
170 | ||
171 | #if defined(__mips64) | |
172 | #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12 | |
173 | #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13 | |
174 | #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13 | |
175 | #else | |
176 | #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12 | |
177 | #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14 | |
178 | #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14 | |
179 | #endif | |
180 | #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D) | |
181 | ||
182 | #if defined(__mips64) | |
183 | #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12 | |
184 | #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13 | |
185 | #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0) | |
186 | #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T) | |
050af144 | 187 | #elif __mips_fpr != 32 && __mips_isa_rev >= 2 && defined(__MIPSEB__) |
a38e0142 SL |
188 | #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12 |
189 | #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14 | |
190 | #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0) | |
050af144 MF |
191 | #define MOVE_DC_RET(D, T) m##D##c1 $5,$f2; m##D##hc1 $4,$f2; MOVE_DF_RET (D, T) |
192 | #elif __mips_fpr != 32 && __mips_isa_rev >= 2 | |
a38e0142 SL |
193 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12 |
194 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14 | |
195 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0) | |
050af144 MF |
196 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##hc1 $5,$f2; MOVE_DF_RET (D, T) |
197 | #elif __mips_fpr == 0 | |
198 | #define MOVE_DF_BYTE0t sw $4, 0($29); sw $5, 4($29); ldc1 $f12, 0($29) | |
199 | #define MOVE_DF_BYTE0f sdc1 $f12, 0($29); lw $4, 0($29); lw $5, 4($29) | |
200 | #define MOVE_DF_BYTE0(D) MOVE_DF_BYTE0##D | |
201 | #define MOVE_DF_BYTE8t sw $6, 8($29); sw $7, 12($29); ldc1 $f14, 8($29) | |
202 | #define MOVE_DF_BYTE8f sdc1 $f14, 8($29); lw $6, 8($29); lw $7, 12($29) | |
203 | #define MOVE_DF_BYTE8(D) MOVE_DF_BYTE8##D | |
204 | #define MOVE_DF_RETt(T) sw $2, 0($29); sw $3, 4($29); DELAYt (T, ldc1 $f0, 0($29)) | |
205 | #define MOVE_DF_RETf(T) sdc1 $f0, 0($29); lw $2, 0($29); DELAYf (T, lw $3, 4($29)) | |
206 | #define MOVE_DF_RET(D, T) MOVE_DF_RET##D(T) | |
207 | #define MOVE_DC_RETt(T) sw $4, 8($29); sw $5, 12($29); ldc1 $f2, 8($29); MOVE_DF_RETt(T) | |
208 | #define MOVE_DC_RETf(T) sdc1 $f2, 8($29); lw $4, 8($29); lw $5, 12($29); MOVE_DF_RETf(T) | |
209 | #define MOVE_DC_RET(D, T) MOVE_DF_RET##D(T) | |
a38e0142 SL |
210 | #elif defined(__MIPSEB__) |
211 | /* FPRs are little-endian. */ | |
212 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12 | |
213 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14 | |
214 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0) | |
215 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T) | |
216 | #else | |
217 | #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13 | |
218 | #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15 | |
219 | #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1) | |
220 | #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T) | |
221 | #endif | |
222 | ||
223 | /* Single-precision math. */ | |
224 | ||
225 | /* Define a function NAME that loads two single-precision values, | |
226 | performs FPU operation OPCODE on them, and returns the single- | |
227 | precision result. */ | |
228 | ||
229 | #define OPSF3(NAME, OPCODE) \ | |
afba61d1 | 230 | STARTFN (NAME); \ |
a38e0142 SL |
231 | MOVE_SF_BYTE0 (t); \ |
232 | MOVE_SF_BYTE4 (t); \ | |
233 | OPCODE RET,ARG1,ARG2; \ | |
234 | MOVE_SF_RET (f, $31); \ | |
afba61d1 ILT |
235 | ENDFN (NAME) |
236 | ||
237 | #ifdef L_m16addsf3 | |
a38e0142 | 238 | OPSF3 (__mips16_addsf3, add.s) |
afba61d1 ILT |
239 | #endif |
240 | #ifdef L_m16subsf3 | |
a38e0142 | 241 | OPSF3 (__mips16_subsf3, sub.s) |
afba61d1 ILT |
242 | #endif |
243 | #ifdef L_m16mulsf3 | |
a38e0142 | 244 | OPSF3 (__mips16_mulsf3, mul.s) |
afba61d1 ILT |
245 | #endif |
246 | #ifdef L_m16divsf3 | |
a38e0142 | 247 | OPSF3 (__mips16_divsf3, div.s) |
afba61d1 ILT |
248 | #endif |
249 | ||
a38e0142 SL |
250 | /* Define a function NAME that loads a single-precision value, |
251 | performs FPU operation OPCODE on it, and returns the single- | |
252 | precision result. */ | |
253 | ||
254 | #define OPSF2(NAME, OPCODE) \ | |
eb774d8d | 255 | STARTFN (NAME); \ |
a38e0142 SL |
256 | MOVE_SF_BYTE0 (t); \ |
257 | OPCODE RET,ARG1; \ | |
258 | MOVE_SF_RET (f, $31); \ | |
eb774d8d | 259 | ENDFN (NAME) |
91e01231 | 260 | |
eb774d8d | 261 | #ifdef L_m16negsf2 |
a38e0142 | 262 | OPSF2 (__mips16_negsf2, neg.s) |
eb774d8d NS |
263 | #endif |
264 | #ifdef L_m16abssf2 | |
a38e0142 | 265 | OPSF2 (__mips16_abssf2, abs.s) |
eb774d8d | 266 | #endif |
91e01231 | 267 | |
a38e0142 | 268 | /* Single-precision comparisons. */ |
afba61d1 | 269 | |
a38e0142 SL |
270 | /* Define a function NAME that loads two single-precision values, |
271 | performs floating point comparison OPCODE, and returns TRUE or | |
272 | FALSE depending on the result. */ | |
afba61d1 | 273 | |
a38e0142 | 274 | #define CMPSF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 275 | STARTFN (NAME); \ |
a38e0142 SL |
276 | MOVE_SF_BYTE0 (t); \ |
277 | MOVE_SF_BYTE4 (t); \ | |
278 | OPCODE ARG1,ARG2; \ | |
afba61d1 ILT |
279 | li $2,TRUE; \ |
280 | bc1t 1f; \ | |
281 | li $2,FALSE; \ | |
282 | 1:; \ | |
283 | j $31; \ | |
284 | ENDFN (NAME) | |
285 | ||
a38e0142 | 286 | /* Like CMPSF, but reverse the comparison operands. */ |
afba61d1 | 287 | |
a38e0142 | 288 | #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 289 | STARTFN (NAME); \ |
a38e0142 SL |
290 | MOVE_SF_BYTE0 (t); \ |
291 | MOVE_SF_BYTE4 (t); \ | |
292 | OPCODE ARG2,ARG1; \ | |
afba61d1 ILT |
293 | li $2,TRUE; \ |
294 | bc1t 1f; \ | |
295 | li $2,FALSE; \ | |
296 | 1:; \ | |
297 | j $31; \ | |
298 | ENDFN (NAME) | |
299 | ||
300 | #ifdef L_m16eqsf2 | |
a38e0142 | 301 | CMPSF (__mips16_eqsf2, c.eq.s, 0, 1) |
afba61d1 ILT |
302 | #endif |
303 | #ifdef L_m16nesf2 | |
a38e0142 | 304 | CMPSF (__mips16_nesf2, c.eq.s, 0, 1) |
afba61d1 ILT |
305 | #endif |
306 | #ifdef L_m16gtsf2 | |
a38e0142 | 307 | REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0) |
afba61d1 ILT |
308 | #endif |
309 | #ifdef L_m16gesf2 | |
a38e0142 | 310 | REVCMPSF (__mips16_gesf2, c.le.s, 0, -1) |
afba61d1 ILT |
311 | #endif |
312 | #ifdef L_m16lesf2 | |
a38e0142 | 313 | CMPSF (__mips16_lesf2, c.le.s, 0, 1) |
afba61d1 ILT |
314 | #endif |
315 | #ifdef L_m16ltsf2 | |
a38e0142 | 316 | CMPSF (__mips16_ltsf2, c.lt.s, -1, 0) |
afba61d1 | 317 | #endif |
45059ab1 SL |
318 | #ifdef L_m16unordsf2 |
319 | CMPSF(__mips16_unordsf2, c.un.s, 1, 0) | |
320 | #endif | |
321 | ||
afba61d1 | 322 | |
a38e0142 | 323 | /* Single-precision conversions. */ |
afba61d1 ILT |
324 | |
325 | #ifdef L_m16fltsisf | |
326 | STARTFN (__mips16_floatsisf) | |
a38e0142 SL |
327 | MOVE_SF_BYTE0 (t) |
328 | cvt.s.w RET,ARG1 | |
329 | MOVE_SF_RET (f, $31) | |
afba61d1 ILT |
330 | ENDFN (__mips16_floatsisf) |
331 | #endif | |
332 | ||
45059ab1 SL |
333 | #ifdef L_m16fltunsisf |
334 | STARTFN (__mips16_floatunsisf) | |
08d0963a | 335 | .set noreorder |
45059ab1 | 336 | bltz $4,1f |
08d0963a RS |
337 | MOVE_SF_BYTE0 (t) |
338 | .set reorder | |
339 | cvt.s.w RET,ARG1 | |
340 | MOVE_SF_RET (f, $31) | |
45059ab1 SL |
341 | 1: |
342 | and $2,$4,1 | |
343 | srl $3,$4,1 | |
344 | or $2,$2,$3 | |
345 | mtc1 $2,RET | |
346 | cvt.s.w RET,RET | |
347 | add.s RET,RET,RET | |
348 | MOVE_SF_RET (f, $31) | |
349 | ENDFN (__mips16_floatunsisf) | |
350 | #endif | |
351 | ||
91e01231 EC |
352 | #ifdef L_m16fix_truncsfsi |
353 | STARTFN (__mips16_fix_truncsfsi) | |
a38e0142 SL |
354 | MOVE_SF_BYTE0 (t) |
355 | trunc.w.s RET,ARG1,$4 | |
356 | MOVE_SI_RET (f, $31) | |
91e01231 | 357 | ENDFN (__mips16_fix_truncsfsi) |
afba61d1 ILT |
358 | #endif |
359 | ||
eb774d8d | 360 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
91e01231 | 361 | |
a38e0142 | 362 | /* Double-precision math. */ |
afba61d1 | 363 | |
a38e0142 SL |
364 | /* Define a function NAME that loads two double-precision values, |
365 | performs FPU operation OPCODE on them, and returns the double- | |
366 | precision result. */ | |
afba61d1 | 367 | |
a38e0142 | 368 | #define OPDF3(NAME, OPCODE) \ |
afba61d1 | 369 | STARTFN (NAME); \ |
a38e0142 SL |
370 | MOVE_DF_BYTE0 (t); \ |
371 | MOVE_DF_BYTE8 (t); \ | |
372 | OPCODE RET,ARG1,ARG2; \ | |
373 | MOVE_DF_RET (f, $31); \ | |
afba61d1 ILT |
374 | ENDFN (NAME) |
375 | ||
376 | #ifdef L_m16adddf3 | |
a38e0142 | 377 | OPDF3 (__mips16_adddf3, add.d) |
afba61d1 ILT |
378 | #endif |
379 | #ifdef L_m16subdf3 | |
a38e0142 | 380 | OPDF3 (__mips16_subdf3, sub.d) |
afba61d1 ILT |
381 | #endif |
382 | #ifdef L_m16muldf3 | |
a38e0142 | 383 | OPDF3 (__mips16_muldf3, mul.d) |
afba61d1 ILT |
384 | #endif |
385 | #ifdef L_m16divdf3 | |
a38e0142 | 386 | OPDF3 (__mips16_divdf3, div.d) |
afba61d1 ILT |
387 | #endif |
388 | ||
a38e0142 SL |
389 | /* Define a function NAME that loads a double-precision value, |
390 | performs FPU operation OPCODE on it, and returns the double- | |
391 | precision result. */ | |
392 | ||
393 | #define OPDF2(NAME, OPCODE) \ | |
eb774d8d | 394 | STARTFN (NAME); \ |
a38e0142 SL |
395 | MOVE_DF_BYTE0 (t); \ |
396 | OPCODE RET,ARG1; \ | |
397 | MOVE_DF_RET (f, $31); \ | |
eb774d8d | 398 | ENDFN (NAME) |
91e01231 | 399 | |
eb774d8d | 400 | #ifdef L_m16negdf2 |
a38e0142 | 401 | OPDF2 (__mips16_negdf2, neg.d) |
eb774d8d NS |
402 | #endif |
403 | #ifdef L_m16absdf2 | |
a38e0142 | 404 | OPDF2 (__mips16_absdf2, abs.d) |
eb774d8d NS |
405 | #endif |
406 | ||
afba61d1 ILT |
407 | /* Conversions between single and double precision. */ |
408 | ||
409 | #ifdef L_m16extsfdf2 | |
410 | STARTFN (__mips16_extendsfdf2) | |
a38e0142 SL |
411 | MOVE_SF_BYTE0 (t) |
412 | cvt.d.s RET,ARG1 | |
413 | MOVE_DF_RET (f, $31) | |
afba61d1 ILT |
414 | ENDFN (__mips16_extendsfdf2) |
415 | #endif | |
416 | ||
417 | #ifdef L_m16trdfsf2 | |
418 | STARTFN (__mips16_truncdfsf2) | |
a38e0142 SL |
419 | MOVE_DF_BYTE0 (t) |
420 | cvt.s.d RET,ARG1 | |
421 | MOVE_SF_RET (f, $31) | |
afba61d1 ILT |
422 | ENDFN (__mips16_truncdfsf2) |
423 | #endif | |
424 | ||
a38e0142 | 425 | /* Double-precision comparisons. */ |
afba61d1 | 426 | |
a38e0142 SL |
427 | /* Define a function NAME that loads two double-precision values, |
428 | performs floating point comparison OPCODE, and returns TRUE or | |
429 | FALSE depending on the result. */ | |
afba61d1 | 430 | |
a38e0142 | 431 | #define CMPDF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 432 | STARTFN (NAME); \ |
a38e0142 SL |
433 | MOVE_DF_BYTE0 (t); \ |
434 | MOVE_DF_BYTE8 (t); \ | |
435 | OPCODE ARG1,ARG2; \ | |
afba61d1 ILT |
436 | li $2,TRUE; \ |
437 | bc1t 1f; \ | |
438 | li $2,FALSE; \ | |
439 | 1:; \ | |
440 | j $31; \ | |
441 | ENDFN (NAME) | |
442 | ||
a38e0142 | 443 | /* Like CMPDF, but reverse the comparison operands. */ |
afba61d1 | 444 | |
a38e0142 | 445 | #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \ |
afba61d1 | 446 | STARTFN (NAME); \ |
a38e0142 SL |
447 | MOVE_DF_BYTE0 (t); \ |
448 | MOVE_DF_BYTE8 (t); \ | |
449 | OPCODE ARG2,ARG1; \ | |
afba61d1 ILT |
450 | li $2,TRUE; \ |
451 | bc1t 1f; \ | |
452 | li $2,FALSE; \ | |
453 | 1:; \ | |
454 | j $31; \ | |
455 | ENDFN (NAME) | |
456 | ||
457 | #ifdef L_m16eqdf2 | |
a38e0142 | 458 | CMPDF (__mips16_eqdf2, c.eq.d, 0, 1) |
afba61d1 ILT |
459 | #endif |
460 | #ifdef L_m16nedf2 | |
a38e0142 | 461 | CMPDF (__mips16_nedf2, c.eq.d, 0, 1) |
afba61d1 ILT |
462 | #endif |
463 | #ifdef L_m16gtdf2 | |
a38e0142 | 464 | REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0) |
afba61d1 ILT |
465 | #endif |
466 | #ifdef L_m16gedf2 | |
a38e0142 | 467 | REVCMPDF (__mips16_gedf2, c.le.d, 0, -1) |
afba61d1 ILT |
468 | #endif |
469 | #ifdef L_m16ledf2 | |
a38e0142 | 470 | CMPDF (__mips16_ledf2, c.le.d, 0, 1) |
afba61d1 ILT |
471 | #endif |
472 | #ifdef L_m16ltdf2 | |
a38e0142 | 473 | CMPDF (__mips16_ltdf2, c.lt.d, -1, 0) |
afba61d1 | 474 | #endif |
45059ab1 SL |
475 | #ifdef L_m16unorddf2 |
476 | CMPDF(__mips16_unorddf2, c.un.d, 1, 0) | |
477 | #endif | |
afba61d1 | 478 | |
a38e0142 | 479 | /* Double-precision conversions. */ |
afba61d1 ILT |
480 | |
481 | #ifdef L_m16fltsidf | |
482 | STARTFN (__mips16_floatsidf) | |
a38e0142 SL |
483 | MOVE_SI_BYTE0 (t) |
484 | cvt.d.w RET,ARG1 | |
485 | MOVE_DF_RET (f, $31) | |
afba61d1 ILT |
486 | ENDFN (__mips16_floatsidf) |
487 | #endif | |
45059ab1 SL |
488 | |
489 | #ifdef L_m16fltunsidf | |
490 | STARTFN (__mips16_floatunsidf) | |
491 | MOVE_SI_BYTE0 (t) | |
492 | cvt.d.w RET,ARG1 | |
493 | bgez $4,1f | |
494 | li.d ARG1, 4.294967296e+9 | |
495 | add.d RET, RET, ARG1 | |
496 | 1: MOVE_DF_RET (f, $31) | |
497 | ENDFN (__mips16_floatunsidf) | |
498 | #endif | |
499 | ||
91e01231 EC |
500 | #ifdef L_m16fix_truncdfsi |
501 | STARTFN (__mips16_fix_truncdfsi) | |
a38e0142 SL |
502 | MOVE_DF_BYTE0 (t) |
503 | trunc.w.d RET,ARG1,$4 | |
504 | MOVE_SI_RET (f, $31) | |
91e01231 | 505 | ENDFN (__mips16_fix_truncdfsi) |
afba61d1 | 506 | #endif |
eb774d8d | 507 | #endif /* !__mips_single_float */ |
afba61d1 | 508 | |
0f9bde1f MR |
509 | /* We don't export stubs from libgcc_s.so and always require static |
510 | versions to be pulled from libgcc.a as needed because they use $2 | |
511 | and possibly $3 as arguments, diverging from the standard SysV ABI, | |
512 | and as such would require severe pessimisation of MIPS16 PLT entries | |
513 | just for this single special case. | |
514 | ||
515 | For compatibility with old binaries that used safe standard MIPS PLT | |
516 | entries and referred to these functions we still export them at | |
517 | version GCC_4.4.0 for run-time loading only. */ | |
518 | ||
519 | #ifdef SHARED | |
520 | #define CE_STARTFN(NAME) \ | |
521 | STARTFN (NAME##_compat); \ | |
522 | .symver NAME##_compat, NAME@GCC_4.4.0 | |
523 | #define CE_ENDFN(NAME) ENDFN (NAME##_compat) | |
524 | #else | |
525 | #define CE_STARTFN(NAME) \ | |
526 | STARTFN (NAME); \ | |
527 | .hidden NAME | |
528 | #define CE_ENDFN(NAME) ENDFN (NAME) | |
529 | #endif | |
530 | ||
a38e0142 SL |
531 | /* Define a function NAME that moves a return value of mode MODE from |
532 | FPRs to GPRs. */ | |
533 | ||
534 | #define RET_FUNCTION(NAME, MODE) \ | |
0f9bde1f | 535 | CE_STARTFN (NAME); \ |
a38e0142 | 536 | MOVE_##MODE##_RET (t, $31); \ |
0f9bde1f | 537 | CE_ENDFN (NAME) |
afba61d1 ILT |
538 | |
539 | #ifdef L_m16retsf | |
a38e0142 SL |
540 | RET_FUNCTION (__mips16_ret_sf, SF) |
541 | #endif | |
542 | ||
543 | #ifdef L_m16retsc | |
544 | RET_FUNCTION (__mips16_ret_sc, SC) | |
afba61d1 ILT |
545 | #endif |
546 | ||
eb774d8d | 547 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
afba61d1 | 548 | #ifdef L_m16retdf |
a38e0142 | 549 | RET_FUNCTION (__mips16_ret_df, DF) |
eb774d8d | 550 | #endif |
a38e0142 SL |
551 | |
552 | #ifdef L_m16retdc | |
553 | RET_FUNCTION (__mips16_ret_dc, DC) | |
afba61d1 | 554 | #endif |
eb774d8d | 555 | #endif /* !__mips_single_float */ |
afba61d1 | 556 | |
a38e0142 SL |
557 | /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument |
558 | code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2 | |
559 | classify the first and second arguments as follows: | |
560 | ||
561 | 1: a single-precision argument | |
562 | 2: a double-precision argument | |
563 | 0: no argument, or not one of the above. */ | |
564 | ||
565 | #define STUB_ARGS_0 /* () */ | |
566 | #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */ | |
567 | #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */ | |
568 | #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */ | |
569 | #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */ | |
570 | #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */ | |
571 | #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */ | |
572 | ||
85f65093 | 573 | /* These functions are used by 16-bit code when calling via a function |
a38e0142 SL |
574 | pointer. They must copy the floating point arguments from the GPRs |
575 | to FPRs and then call function $2. */ | |
576 | ||
577 | #define CALL_STUB_NO_RET(NAME, CODE) \ | |
0f9bde1f | 578 | CE_STARTFN (NAME); \ |
a38e0142 | 579 | STUB_ARGS_##CODE; \ |
08d0963a | 580 | .set noreorder; \ |
a38e0142 | 581 | jr $2; \ |
08d0963a RS |
582 | move $25,$2; \ |
583 | .set reorder; \ | |
0f9bde1f | 584 | CE_ENDFN (NAME) |
afba61d1 ILT |
585 | |
586 | #ifdef L_m16stub1 | |
a38e0142 | 587 | CALL_STUB_NO_RET (__mips16_call_stub_1, 1) |
afba61d1 ILT |
588 | #endif |
589 | ||
afba61d1 | 590 | #ifdef L_m16stub5 |
a38e0142 | 591 | CALL_STUB_NO_RET (__mips16_call_stub_5, 5) |
afba61d1 ILT |
592 | #endif |
593 | ||
eb774d8d NS |
594 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
595 | ||
596 | #ifdef L_m16stub2 | |
a38e0142 | 597 | CALL_STUB_NO_RET (__mips16_call_stub_2, 2) |
eb774d8d NS |
598 | #endif |
599 | ||
afba61d1 | 600 | #ifdef L_m16stub6 |
a38e0142 | 601 | CALL_STUB_NO_RET (__mips16_call_stub_6, 6) |
afba61d1 ILT |
602 | #endif |
603 | ||
604 | #ifdef L_m16stub9 | |
a38e0142 | 605 | CALL_STUB_NO_RET (__mips16_call_stub_9, 9) |
afba61d1 ILT |
606 | #endif |
607 | ||
608 | #ifdef L_m16stub10 | |
a38e0142 | 609 | CALL_STUB_NO_RET (__mips16_call_stub_10, 10) |
afba61d1 | 610 | #endif |
eb774d8d | 611 | #endif /* !__mips_single_float */ |
afba61d1 ILT |
612 | |
613 | /* Now we have the same set of functions, except that this time the | |
a38e0142 SL |
614 | function being called returns an SFmode, SCmode, DFmode or DCmode |
615 | value; we need to instantiate a set for each case. The calling | |
afba61d1 ILT |
616 | function will arrange to preserve $18, so these functions are free |
617 | to use it to hold the return address. | |
618 | ||
619 | Note that we do not know whether the function we are calling is 16 | |
85f65093 | 620 | bit or 32 bit. However, it does not matter, because 16-bit |
afba61d1 ILT |
621 | functions always return floating point values in both the gp and |
622 | the fp regs. It would be possible to check whether the function | |
623 | being called is 16 bits, in which case the copy is unnecessary; | |
624 | however, it's faster to always do the copy. */ | |
625 | ||
5adeb246 | 626 | #define CALL_STUB_RET(NAME, CODE, MODE) \ |
0f9bde1f | 627 | CE_STARTFN (NAME); \ |
5adeb246 RS |
628 | .cfi_startproc; \ |
629 | /* Create a fake CFA 4 bytes below the stack pointer. */ \ | |
630 | .cfi_def_cfa 29,-4; \ | |
631 | /* "Save" $sp in itself so we don't use the fake CFA. \ | |
632 | This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \ | |
633 | .cfi_escape 0x16,29,1,0x6d; \ | |
634 | move $18,$31; \ | |
635 | .cfi_register 31,18; \ | |
636 | STUB_ARGS_##CODE; \ | |
637 | .set noreorder; \ | |
638 | jalr $2; \ | |
639 | move $25,$2; \ | |
640 | .set reorder; \ | |
641 | MOVE_##MODE##_RET (f, $18); \ | |
642 | .cfi_endproc; \ | |
0f9bde1f | 643 | CE_ENDFN (NAME) |
a38e0142 SL |
644 | |
645 | /* First, instantiate the single-float set. */ | |
646 | ||
afba61d1 | 647 | #ifdef L_m16stubsf0 |
a38e0142 | 648 | CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF) |
afba61d1 ILT |
649 | #endif |
650 | ||
651 | #ifdef L_m16stubsf1 | |
a38e0142 | 652 | CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF) |
afba61d1 ILT |
653 | #endif |
654 | ||
eb774d8d | 655 | #ifdef L_m16stubsf5 |
a38e0142 | 656 | CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF) |
afba61d1 ILT |
657 | #endif |
658 | ||
eb774d8d NS |
659 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
660 | #ifdef L_m16stubsf2 | |
a38e0142 | 661 | CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF) |
afba61d1 ILT |
662 | #endif |
663 | ||
664 | #ifdef L_m16stubsf6 | |
a38e0142 | 665 | CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF) |
afba61d1 ILT |
666 | #endif |
667 | ||
668 | #ifdef L_m16stubsf9 | |
a38e0142 | 669 | CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF) |
afba61d1 ILT |
670 | #endif |
671 | ||
672 | #ifdef L_m16stubsf10 | |
a38e0142 | 673 | CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF) |
afba61d1 | 674 | #endif |
a38e0142 SL |
675 | #endif /* !__mips_single_float */ |
676 | ||
afba61d1 ILT |
677 | |
678 | /* Now we have the same set of functions again, except that this time | |
679 | the function being called returns an DFmode value. */ | |
680 | ||
a38e0142 | 681 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) |
afba61d1 | 682 | #ifdef L_m16stubdf0 |
a38e0142 | 683 | CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF) |
afba61d1 ILT |
684 | #endif |
685 | ||
686 | #ifdef L_m16stubdf1 | |
a38e0142 | 687 | CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF) |
afba61d1 ILT |
688 | #endif |
689 | ||
a38e0142 SL |
690 | #ifdef L_m16stubdf5 |
691 | CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF) | |
afba61d1 ILT |
692 | #endif |
693 | ||
a38e0142 SL |
694 | #ifdef L_m16stubdf2 |
695 | CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF) | |
afba61d1 ILT |
696 | #endif |
697 | ||
698 | #ifdef L_m16stubdf6 | |
a38e0142 | 699 | CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF) |
afba61d1 ILT |
700 | #endif |
701 | ||
702 | #ifdef L_m16stubdf9 | |
a38e0142 | 703 | CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF) |
afba61d1 ILT |
704 | #endif |
705 | ||
706 | #ifdef L_m16stubdf10 | |
a38e0142 SL |
707 | CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF) |
708 | #endif | |
709 | #endif /* !__mips_single_float */ | |
710 | ||
711 | ||
712 | /* Ho hum. Here we have the same set of functions again, this time | |
713 | for when the function being called returns an SCmode value. */ | |
714 | ||
715 | #ifdef L_m16stubsc0 | |
716 | CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC) | |
717 | #endif | |
718 | ||
719 | #ifdef L_m16stubsc1 | |
720 | CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC) | |
721 | #endif | |
722 | ||
723 | #ifdef L_m16stubsc5 | |
724 | CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC) | |
725 | #endif | |
726 | ||
727 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) | |
728 | #ifdef L_m16stubsc2 | |
729 | CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC) | |
730 | #endif | |
731 | ||
732 | #ifdef L_m16stubsc6 | |
733 | CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC) | |
734 | #endif | |
735 | ||
736 | #ifdef L_m16stubsc9 | |
737 | CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC) | |
738 | #endif | |
739 | ||
740 | #ifdef L_m16stubsc10 | |
741 | CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC) | |
742 | #endif | |
743 | #endif /* !__mips_single_float */ | |
744 | ||
745 | ||
746 | /* Finally, another set of functions for DCmode. */ | |
747 | ||
748 | #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT) | |
749 | #ifdef L_m16stubdc0 | |
750 | CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC) | |
751 | #endif | |
752 | ||
753 | #ifdef L_m16stubdc1 | |
754 | CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC) | |
755 | #endif | |
756 | ||
757 | #ifdef L_m16stubdc5 | |
758 | CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC) | |
759 | #endif | |
760 | ||
761 | #ifdef L_m16stubdc2 | |
762 | CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC) | |
763 | #endif | |
764 | ||
765 | #ifdef L_m16stubdc6 | |
766 | CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC) | |
767 | #endif | |
768 | ||
769 | #ifdef L_m16stubdc9 | |
770 | CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC) | |
771 | #endif | |
772 | ||
773 | #ifdef L_m16stubdc10 | |
774 | CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC) | |
afba61d1 | 775 | #endif |
eb774d8d | 776 | #endif /* !__mips_single_float */ |
ddaf8125 | 777 | |
08d0963a | 778 | #endif |
5b1ea7c5 | 779 | #endif /* defined(__mips_micromips) || defined(__mips_soft_float) */ |