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