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