]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/mips/mips16.S
coverage.c (coverage_counter_ref): Set MEM_NOTRAP_P.
[thirdparty/gcc.git] / gcc / config / mips / mips16.S
CommitLineData
afba61d1 1/* mips16 floating point support code
eb774d8d 2 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
afba61d1
ILT
3 Contributed by Cygnus Support
4
5This file is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10In addition to the permissions in the GNU General Public License, the
11Free Software Foundation gives you unlimited permission to link the
12compiled version of this file with other programs, and to distribute
13those programs without any restriction coming from the use of this
14file. (The General Public License restrictions do apply in other
15respects; for example, they cover modification of the file, and
16distribution when not linked into another program.)
17
18This file is distributed in the hope that it will be useful, but
19WITHOUT ANY WARRANTY; without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program; see the file COPYING. If not, write to
25the Free Software Foundation, 59 Temple Place - Suite 330,
26Boston, MA 02111-1307, USA. */
27
28/* As a special exception, if you link this library with other files,
29 some of which are compiled with GCC, to produce an executable,
30 this library does not by itself cause the resulting executable
31 to be covered by the GNU General Public License.
32 This exception does not however invalidate any other reasons why
33 the executable file might be covered by the GNU General Public License. */
34
35/* This file contains mips16 floating point support functions. These
36 functions are called by mips16 code to handle floating point when
37 -msoft-float is not used. They accept the arguments and return
38 values using the soft-float calling convention, but do the actual
39 operation using the hard floating point instructions. */
40
41/* This file contains 32 bit assembly code. */
42 .set nomips16
43
987ba558 44/* Start a function. */
afba61d1
ILT
45
46#define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
47
48/* Finish a function. */
49
50#define ENDFN(NAME) .end NAME
51
52/* Single precision math. */
53
54/* This macro defines a function which loads two single precision
55 values, performs an operation, and returns the single precision
56 result. */
57
58#define SFOP(NAME, OPCODE) \
59STARTFN (NAME); \
60 .set noreorder; \
61 mtc1 $4,$f0; \
62 mtc1 $5,$f2; \
63 nop; \
64 OPCODE $f0,$f0,$f2; \
65 mfc1 $2,$f0; \
66 j $31; \
67 nop; \
68 .set reorder; \
69 ENDFN (NAME)
70
71#ifdef L_m16addsf3
72SFOP(__mips16_addsf3, add.s)
73#endif
74#ifdef L_m16subsf3
75SFOP(__mips16_subsf3, sub.s)
76#endif
77#ifdef L_m16mulsf3
78SFOP(__mips16_mulsf3, mul.s)
79#endif
80#ifdef L_m16divsf3
81SFOP(__mips16_divsf3, div.s)
82#endif
83
eb774d8d
NS
84#define SFOP2(NAME, OPCODE) \
85STARTFN (NAME); \
86 .set noreorder; \
87 mtc1 $4,$f0; \
88 nop; \
89 OPCODE $f0,$f0; \
90 mfc1 $2,$f0; \
91 j $31; \
92 nop; \
93 .set reorder; \
94 ENDFN (NAME)
95
96#ifdef L_m16negsf2
97SFOP2(__mips16_negsf2, neg.s)
98#endif
99#ifdef L_m16abssf2
100SFOP2(__mips16_abssf2, abs.s)
101#endif
102
afba61d1
ILT
103/* Single precision comparisons. */
104
105/* This macro defines a function which loads two single precision
106 values, performs a floating point comparison, and returns the
107 specified values according to whether the comparison is true or
108 false. */
109
110#define SFCMP(NAME, OPCODE, TRUE, FALSE) \
111STARTFN (NAME); \
112 mtc1 $4,$f0; \
113 mtc1 $5,$f2; \
114 OPCODE $f0,$f2; \
115 li $2,TRUE; \
116 bc1t 1f; \
117 li $2,FALSE; \
1181:; \
119 j $31; \
120 ENDFN (NAME)
121
122/* This macro is like SFCMP, but it reverses the comparison. */
123
124#define SFREVCMP(NAME, OPCODE, TRUE, FALSE) \
125STARTFN (NAME); \
126 mtc1 $4,$f0; \
127 mtc1 $5,$f2; \
128 OPCODE $f2,$f0; \
129 li $2,TRUE; \
130 bc1t 1f; \
131 li $2,FALSE; \
1321:; \
133 j $31; \
134 ENDFN (NAME)
135
136#ifdef L_m16eqsf2
137SFCMP(__mips16_eqsf2, c.eq.s, 0, 1)
138#endif
139#ifdef L_m16nesf2
140SFCMP(__mips16_nesf2, c.eq.s, 0, 1)
141#endif
142#ifdef L_m16gtsf2
143SFREVCMP(__mips16_gtsf2, c.lt.s, 1, 0)
144#endif
145#ifdef L_m16gesf2
146SFREVCMP(__mips16_gesf2, c.le.s, 0, -1)
147#endif
148#ifdef L_m16lesf2
149SFCMP(__mips16_lesf2, c.le.s, 0, 1)
150#endif
151#ifdef L_m16ltsf2
152SFCMP(__mips16_ltsf2, c.lt.s, -1, 0)
153#endif
154
155/* Single precision conversions. */
156
157#ifdef L_m16fltsisf
158STARTFN (__mips16_floatsisf)
159 .set noreorder
160 mtc1 $4,$f0
161 nop
162 cvt.s.w $f0,$f0
163 mfc1 $2,$f0
164 j $31
165 nop
166 .set reorder
167 ENDFN (__mips16_floatsisf)
168#endif
169
170#ifdef L_m16fixsfsi
171STARTFN (__mips16_fixsfsi)
172 .set noreorder
173 mtc1 $4,$f0
174 nop
175 trunc.w.s $f0,$f0,$4
176 mfc1 $2,$f0
177 j $31
178 nop
179 .set reorder
180 ENDFN (__mips16_fixsfsi)
181#endif
182
eb774d8d
NS
183#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
184
afba61d1
ILT
185/* The double precision operations. We need to use different code
186 based on the preprocessor symbol __mips64, because the way in which
187 double precision values will change. Without __mips64, the value
188 is passed in two 32 bit registers. With __mips64, the value is
189 passed in a single 64 bit register. */
190
191/* Load the first double precision operand. */
192
eb774d8d
NS
193#if defined(__mips64)
194#define LDDBL1 dmtc1 $4,$f12
195#elif defined(__mipsfp64)
196#define LDDBL1 sw $4,0($29); sw $5,4($29); l.d $f12,0($29)
197#elif defined(__MIPSEB__)
198#define LDDBL1 mtc1 $4,$f13; mtc1 $5,$f12
199#else
200#define LDDBL1 mtc1 $4,$f12; mtc1 $5,$f13
afba61d1
ILT
201#endif
202
203/* Load the second double precision operand. */
204
eb774d8d
NS
205#if defined(__mips64)
206/* XXX this should be $6 for Algo arg passing model */
207#define LDDBL2 dmtc1 $5,$f14
208#elif defined(__mipsfp64)
209#define LDDBL2 sw $6,8($29); sw $7,12($29); l.d $f14,8($29)
210#elif defined(__MIPSEB__)
211#define LDDBL2 mtc1 $6,$f15; mtc1 $7,$f14
212#else
213#define LDDBL2 mtc1 $6,$f14; mtc1 $7,$f15
214#endif
215
afba61d1
ILT
216/* Move the double precision return value to the right place. */
217
eb774d8d 218#if defined(__mips64)
afba61d1 219#define RETDBL dmfc1 $2,$f0
eb774d8d
NS
220#elif defined(__mipsfp64)
221#define RETDBL s.d $f0,0($29); lw $2,0($29); lw $3,4($29)
222#elif defined(__MIPSEB__)
afba61d1 223#define RETDBL mfc1 $2,$f1; mfc1 $3,$f0
eb774d8d
NS
224#else
225#define RETDBL mfc1 $2,$f0; mfc1 $3,$f1
afba61d1 226#endif
eb774d8d 227
afba61d1
ILT
228/* Double precision math. */
229
230/* This macro defines a function which loads two double precision
231 values, performs an operation, and returns the double precision
232 result. */
233
234#define DFOP(NAME, OPCODE) \
235STARTFN (NAME); \
236 .set noreorder; \
237 LDDBL1; \
238 LDDBL2; \
239 nop; \
eb774d8d 240 OPCODE $f0,$f12,$f14; \
afba61d1
ILT
241 RETDBL; \
242 j $31; \
243 nop; \
244 .set reorder; \
245 ENDFN (NAME)
246
247#ifdef L_m16adddf3
248DFOP(__mips16_adddf3, add.d)
249#endif
250#ifdef L_m16subdf3
251DFOP(__mips16_subdf3, sub.d)
252#endif
253#ifdef L_m16muldf3
254DFOP(__mips16_muldf3, mul.d)
255#endif
256#ifdef L_m16divdf3
257DFOP(__mips16_divdf3, div.d)
258#endif
259
eb774d8d
NS
260#define DFOP2(NAME, OPCODE) \
261STARTFN (NAME); \
262 .set noreorder; \
263 LDDBL1; \
264 nop; \
265 OPCODE $f0,$f12; \
266 RETDBL; \
267 j $31; \
268 nop; \
269 .set reorder; \
270 ENDFN (NAME)
271
272#ifdef L_m16negdf2
273DFOP2(__mips16_negdf2, neg.d)
274#endif
275#ifdef L_m16absdf2
276DFOP2(__mips16_absdf2, abs.d)
277#endif
278
279
afba61d1
ILT
280/* Conversions between single and double precision. */
281
282#ifdef L_m16extsfdf2
283STARTFN (__mips16_extendsfdf2)
284 .set noreorder
eb774d8d 285 mtc1 $4,$f12
afba61d1 286 nop
eb774d8d 287 cvt.d.s $f0,$f12
afba61d1
ILT
288 RETDBL
289 j $31
290 nop
291 .set reorder
292 ENDFN (__mips16_extendsfdf2)
293#endif
294
295#ifdef L_m16trdfsf2
296STARTFN (__mips16_truncdfsf2)
297 .set noreorder
298 LDDBL1
299 nop
eb774d8d 300 cvt.s.d $f0,$f12
afba61d1
ILT
301 mfc1 $2,$f0
302 j $31
303 nop
304 .set reorder
305 ENDFN (__mips16_truncdfsf2)
306#endif
307
308/* Double precision comparisons. */
309
310/* This macro defines a function which loads two double precision
311 values, performs a floating point comparison, and returns the
312 specified values according to whether the comparison is true or
313 false. */
314
315#define DFCMP(NAME, OPCODE, TRUE, FALSE) \
316STARTFN (NAME); \
317 LDDBL1; \
318 LDDBL2; \
eb774d8d 319 OPCODE $f12,$f14; \
afba61d1
ILT
320 li $2,TRUE; \
321 bc1t 1f; \
322 li $2,FALSE; \
3231:; \
324 j $31; \
325 ENDFN (NAME)
326
327/* This macro is like DFCMP, but it reverses the comparison. */
328
329#define DFREVCMP(NAME, OPCODE, TRUE, FALSE) \
330STARTFN (NAME); \
331 LDDBL1; \
332 LDDBL2; \
a3bc83cc 333 OPCODE $f14,$f12; \
afba61d1
ILT
334 li $2,TRUE; \
335 bc1t 1f; \
336 li $2,FALSE; \
3371:; \
338 j $31; \
339 ENDFN (NAME)
340
341#ifdef L_m16eqdf2
342DFCMP(__mips16_eqdf2, c.eq.d, 0, 1)
343#endif
344#ifdef L_m16nedf2
345DFCMP(__mips16_nedf2, c.eq.d, 0, 1)
346#endif
347#ifdef L_m16gtdf2
348DFREVCMP(__mips16_gtdf2, c.lt.d, 1, 0)
349#endif
350#ifdef L_m16gedf2
351DFREVCMP(__mips16_gedf2, c.le.d, 0, -1)
352#endif
353#ifdef L_m16ledf2
354DFCMP(__mips16_ledf2, c.le.d, 0, 1)
355#endif
356#ifdef L_m16ltdf2
357DFCMP(__mips16_ltdf2, c.lt.d, -1, 0)
358#endif
359
360/* Double precision conversions. */
361
362#ifdef L_m16fltsidf
363STARTFN (__mips16_floatsidf)
364 .set noreorder
eb774d8d 365 mtc1 $4,$f12
afba61d1 366 nop
eb774d8d 367 cvt.d.w $f0,$f12
afba61d1
ILT
368 RETDBL
369 j $31
370 nop
371 .set reorder
372 ENDFN (__mips16_floatsidf)
373#endif
374
375#ifdef L_m16fixdfsi
376STARTFN (__mips16_fixdfsi)
377 .set noreorder
378 LDDBL1
379 nop
eb774d8d 380 trunc.w.d $f0,$f12,$4
afba61d1
ILT
381 mfc1 $2,$f0
382 j $31
383 nop
384 .set reorder
385 ENDFN (__mips16_fixdfsi)
386#endif
eb774d8d 387#endif /* !__mips_single_float */
afba61d1
ILT
388
389/* These functions are used to return floating point values from
46b9a73c
RS
390 mips16 functions. In this case we can put mtc1 in a jump delay slot,
391 because we know that the next instruction will not refer to a floating
392 point register. */
afba61d1
ILT
393
394#ifdef L_m16retsf
395STARTFN (__mips16_ret_sf)
396 .set noreorder
397 j $31
398 mtc1 $2,$f0
399 .set reorder
400 ENDFN (__mips16_ret_sf)
401#endif
402
eb774d8d 403#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
afba61d1
ILT
404#ifdef L_m16retdf
405STARTFN (__mips16_ret_df)
406 .set noreorder
eb774d8d
NS
407#if defined(__mips64)
408 j $31
409 dmtc1 $2,$f0
410#elif defined(__mipsfp64)
411 sw $2,0($29)
412 sw $3,4($29)
413 l.d $f0,0($29)
414#elif defined(__MIPSEB__)
afba61d1
ILT
415 mtc1 $2,$f1
416 j $31
417 mtc1 $3,$f0
eb774d8d
NS
418#else
419 mtc1 $2,$f0
420 j $31
421 mtc1 $3,$f1
422#endif
423 .set reorder
afba61d1
ILT
424 ENDFN (__mips16_ret_df)
425#endif
eb774d8d 426#endif /* !__mips_single_float */
afba61d1
ILT
427
428/* These functions are used by 16 bit code when calling via a function
429 pointer. They must copy the floating point arguments from the gp
430 regs into the fp regs. The function to call will be in $2. The
431 exact set of floating point arguments to copy is encoded in the
432 function name; the final number is an fp_code, as described in
433 mips.h in the comment about CUMULATIVE_ARGS. */
434
435#ifdef L_m16stub1
436/* (float) */
437STARTFN (__mips16_call_stub_1)
438 .set noreorder
439 mtc1 $4,$f12
440 j $2
441 nop
442 .set reorder
443 ENDFN (__mips16_call_stub_1)
444#endif
445
afba61d1
ILT
446#ifdef L_m16stub5
447/* (float, float) */
448STARTFN (__mips16_call_stub_5)
449 .set noreorder
450 mtc1 $4,$f12
451 mtc1 $5,$f14
452 j $2
453 nop
454 .set reorder
455 ENDFN (__mips16_call_stub_5)
456#endif
457
eb774d8d
NS
458#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
459
460#ifdef L_m16stub2
461/* (double) */
462STARTFN (__mips16_call_stub_2)
463 .set noreorder
464 LDDBL1
465 j $2
466 nop
467 .set reorder
468 ENDFN (__mips16_call_stub_2)
469#endif
470
afba61d1
ILT
471#ifdef L_m16stub6
472/* (double, float) */
473STARTFN (__mips16_call_stub_6)
474 .set noreorder
eb774d8d 475 LDDBL1
afba61d1
ILT
476 mtc1 $6,$f14
477 j $2
478 nop
479 .set reorder
480 ENDFN (__mips16_call_stub_6)
481#endif
482
483#ifdef L_m16stub9
484/* (float, double) */
485STARTFN (__mips16_call_stub_9)
486 .set noreorder
487 mtc1 $4,$f12
eb774d8d 488 LDDBL2
afba61d1
ILT
489 j $2
490 nop
491 .set reorder
492 ENDFN (__mips16_call_stub_9)
493#endif
494
495#ifdef L_m16stub10
496/* (double, double) */
497STARTFN (__mips16_call_stub_10)
498 .set noreorder
eb774d8d
NS
499 LDDBL1
500 LDDBL2
afba61d1
ILT
501 j $2
502 nop
503 .set reorder
504 ENDFN (__mips16_call_stub_10)
505#endif
eb774d8d 506#endif /* !__mips_single_float */
afba61d1
ILT
507
508/* Now we have the same set of functions, except that this time the
509 function being called returns an SFmode value. The calling
510 function will arrange to preserve $18, so these functions are free
511 to use it to hold the return address.
512
513 Note that we do not know whether the function we are calling is 16
514 bit or 32 bit. However, it does not matter, because 16 bit
515 functions always return floating point values in both the gp and
516 the fp regs. It would be possible to check whether the function
517 being called is 16 bits, in which case the copy is unnecessary;
518 however, it's faster to always do the copy. */
519
520#ifdef L_m16stubsf0
521/* () */
522STARTFN (__mips16_call_stub_sf_0)
523 .set noreorder
524 move $18,$31
525 jal $2
526 nop
eb774d8d 527 mfc1 $2,$f0
afba61d1
ILT
528 j $18
529 nop
530 .set reorder
531 ENDFN (__mips16_call_stub_sf_0)
532#endif
533
534#ifdef L_m16stubsf1
535/* (float) */
536STARTFN (__mips16_call_stub_sf_1)
537 .set noreorder
538 mtc1 $4,$f12
539 move $18,$31
540 jal $2
541 nop
eb774d8d 542 mfc1 $2,$f0
afba61d1
ILT
543 j $18
544 nop
545 .set reorder
546 ENDFN (__mips16_call_stub_sf_1)
547#endif
548
eb774d8d
NS
549#ifdef L_m16stubsf5
550/* (float, float) */
551STARTFN (__mips16_call_stub_sf_5)
afba61d1 552 .set noreorder
eb774d8d
NS
553 mtc1 $4,$f12
554 mtc1 $5,$f14
afba61d1
ILT
555 move $18,$31
556 jal $2
557 nop
eb774d8d 558 mfc1 $2,$f0
afba61d1
ILT
559 j $18
560 nop
561 .set reorder
eb774d8d 562 ENDFN (__mips16_call_stub_sf_5)
afba61d1
ILT
563#endif
564
eb774d8d
NS
565#if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
566#ifdef L_m16stubsf2
567/* (double) */
568STARTFN (__mips16_call_stub_sf_2)
afba61d1 569 .set noreorder
eb774d8d 570 LDDBL1
afba61d1
ILT
571 move $18,$31
572 jal $2
573 nop
eb774d8d 574 mfc1 $2,$f0
afba61d1
ILT
575 j $18
576 nop
577 .set reorder
eb774d8d 578 ENDFN (__mips16_call_stub_sf_2)
afba61d1
ILT
579#endif
580
581#ifdef L_m16stubsf6
582/* (double, float) */
583STARTFN (__mips16_call_stub_sf_6)
584 .set noreorder
eb774d8d 585 LDDBL1
afba61d1
ILT
586 mtc1 $6,$f14
587 move $18,$31
588 jal $2
589 nop
eb774d8d 590 mfc1 $2,$f0
afba61d1
ILT
591 j $18
592 nop
593 .set reorder
594 ENDFN (__mips16_call_stub_sf_6)
595#endif
596
597#ifdef L_m16stubsf9
598/* (float, double) */
599STARTFN (__mips16_call_stub_sf_9)
600 .set noreorder
601 mtc1 $4,$f12
eb774d8d 602 LDDBL2
afba61d1
ILT
603 move $18,$31
604 jal $2
605 nop
eb774d8d 606 mfc1 $2,$f0
afba61d1
ILT
607 j $18
608 nop
609 .set reorder
610 ENDFN (__mips16_call_stub_sf_9)
611#endif
612
613#ifdef L_m16stubsf10
614/* (double, double) */
615STARTFN (__mips16_call_stub_sf_10)
616 .set noreorder
eb774d8d
NS
617 LDDBL1
618 LDDBL2
afba61d1
ILT
619 move $18,$31
620 jal $2
621 nop
eb774d8d 622 mfc1 $2,$f0
afba61d1
ILT
623 j $18
624 nop
625 .set reorder
626 ENDFN (__mips16_call_stub_sf_10)
627#endif
628
629/* Now we have the same set of functions again, except that this time
630 the function being called returns an DFmode value. */
631
632#ifdef L_m16stubdf0
633/* () */
634STARTFN (__mips16_call_stub_df_0)
635 .set noreorder
636 move $18,$31
637 jal $2
638 nop
eb774d8d 639 RETDBL
afba61d1
ILT
640 j $18
641 nop
642 .set reorder
643 ENDFN (__mips16_call_stub_df_0)
644#endif
645
646#ifdef L_m16stubdf1
647/* (float) */
648STARTFN (__mips16_call_stub_df_1)
649 .set noreorder
650 mtc1 $4,$f12
651 move $18,$31
652 jal $2
653 nop
eb774d8d 654 RETDBL
afba61d1
ILT
655 j $18
656 nop
657 .set reorder
658 ENDFN (__mips16_call_stub_df_1)
659#endif
660
661#ifdef L_m16stubdf2
662/* (double) */
663STARTFN (__mips16_call_stub_df_2)
664 .set noreorder
eb774d8d 665 LDDBL1
afba61d1
ILT
666 move $18,$31
667 jal $2
668 nop
eb774d8d 669 RETDBL
afba61d1
ILT
670 j $18
671 nop
672 .set reorder
673 ENDFN (__mips16_call_stub_df_2)
674#endif
675
676#ifdef L_m16stubdf5
677/* (float, float) */
678STARTFN (__mips16_call_stub_df_5)
679 .set noreorder
680 mtc1 $4,$f12
681 mtc1 $5,$f14
682 move $18,$31
683 jal $2
684 nop
eb774d8d 685 RETDBL
afba61d1
ILT
686 j $18
687 nop
688 .set reorder
689 ENDFN (__mips16_call_stub_df_5)
690#endif
691
692#ifdef L_m16stubdf6
693/* (double, float) */
694STARTFN (__mips16_call_stub_df_6)
695 .set noreorder
eb774d8d 696 LDDBL1
afba61d1
ILT
697 mtc1 $6,$f14
698 move $18,$31
699 jal $2
700 nop
eb774d8d 701 RETDBL
afba61d1
ILT
702 j $18
703 nop
704 .set reorder
705 ENDFN (__mips16_call_stub_df_6)
706#endif
707
708#ifdef L_m16stubdf9
709/* (float, double) */
710STARTFN (__mips16_call_stub_df_9)
711 .set noreorder
712 mtc1 $4,$f12
eb774d8d 713 LDDBL2
afba61d1
ILT
714 move $18,$31
715 jal $2
716 nop
eb774d8d 717 RETDBL
afba61d1
ILT
718 j $18
719 nop
720 .set reorder
721 ENDFN (__mips16_call_stub_df_9)
722#endif
723
724#ifdef L_m16stubdf10
725/* (double, double) */
726STARTFN (__mips16_call_stub_df_10)
727 .set noreorder
eb774d8d
NS
728 LDDBL1
729 LDDBL2
afba61d1
ILT
730 move $18,$31
731 jal $2
732 nop
eb774d8d 733 RETDBL
afba61d1
ILT
734 j $18
735 nop
736 .set reorder
737 ENDFN (__mips16_call_stub_df_10)
738#endif
eb774d8d
NS
739#endif /* !__mips_single_float */
740