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