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