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