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