re PR libffi/28313 (libffi has not been ported to mips64-linux-gnu)
[official-gcc.git] / libffi / src / mips / n32.S
blobff268c6a173ad43147e1baa223532cbd71dd4866
1 /* -----------------------------------------------------------------------
2    n32.S - Copyright (c) 1996, 1998, 2005  Red Hat, Inc.
3    
4    MIPS Foreign Function Interface 
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23    OTHER DEALINGS IN THE SOFTWARE.
24    ----------------------------------------------------------------------- */
26 #define LIBFFI_ASM      
27 #include <fficonfig.h>
28 #include <ffi.h>
30 /* Only build this code if we are compiling for n32 */  
32 #if defined(FFI_MIPS_N32)
34 #define callback a0
35 #define bytes    a2
36 #define flags    a3
37 #define raddr    a4
38 #define fn       a5
40 #define SIZEOF_FRAME    ( 8 * FFI_SIZEOF_ARG )
42         .abicalls
43         .text
44         .align  2
45         .globl  ffi_call_N32
46         .ent    ffi_call_N32
47 ffi_call_N32:   
48 .LFB3:
49         .frame  $fp, SIZEOF_FRAME, ra
50         .mask   0xc0000000,-FFI_SIZEOF_ARG
51         .fmask  0x00000000,0
53         # Prologue
54         SUBU    $sp, SIZEOF_FRAME                       # Frame size
55 .LCFI0:
56         REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
57         REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return address
58 .LCFI1:
59         move    $fp, $sp
60 .LCFI3:
61         move    t9, callback    # callback function pointer
62         REG_S   bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
63         REG_S   flags, 3*FFI_SIZEOF_ARG($fp) # flags
64         REG_S   raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
65         REG_S   fn,    5*FFI_SIZEOF_ARG($fp) # fn
67         # Allocate at least 4 words in the argstack
68         move    v0, bytes
69         bge     bytes, 4 * FFI_SIZEOF_ARG, bigger       
70         LI      v0, 4 * FFI_SIZEOF_ARG
71         b       sixteen
73         bigger: 
74         ADDU    t4, v0, 2 * FFI_SIZEOF_ARG -1   # make sure it is aligned 
75         and     v0, t4, -2 * FFI_SIZEOF_ARG             # to a proper boundry.
77 sixteen:
78         SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
79                                 # arg space
81         ADDU    a0, $sp, 0      # 4 * FFI_SIZEOF_ARG
82         ADDU    a3, $fp, 3 * FFI_SIZEOF_ARG
84         # Call ffi_prep_args
85         jal     t9
86         
87         #       ADDU    $sp, $sp, 4 * FFI_SIZEOF_ARG    # adjust $sp to new args
89         # Copy the stack pointer to t9
90         move    t9, $sp
91         
92         # Fix the stack if there are more than 8 64bit slots worth
93         # of arguments.
95         # Load the number of bytes
96         REG_L   t6, 2*FFI_SIZEOF_ARG($fp)
98         # Is it bigger than 8 * FFI_SIZEOF_ARG?
99         dadd    t7, $0, 8 * FFI_SIZEOF_ARG
100         dsub    t8, t6, t7
101         bltz    t8, loadregs
103         add     t9, t9, t8
104         
105 loadregs:       
107         REG_L   t4, 3*FFI_SIZEOF_ARG($fp)  # load the flags word
108         add     t6, t4, 0                             # and copy it into t6
110         and     t4, ((1<<FFI_FLAG_BITS)-1)
111         bnez    t4, arg1_floatp
112         REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
113         b       arg1_next
114 arg1_floatp:    
115         bne     t4, FFI_TYPE_FLOAT, arg1_doublep
116         l.s     $f12, 0*FFI_SIZEOF_ARG(t9)
117         b       arg1_next
118 arg1_doublep:   
119         l.d     $f12, 0*FFI_SIZEOF_ARG(t9)
120 arg1_next:      
121         
122         add     t4, t6, 0
123         SRL     t4, 1*FFI_FLAG_BITS
124         and     t4, ((1<<FFI_FLAG_BITS)-1)
125         bnez    t4, arg2_floatp
126         REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
127         b       arg2_next
128 arg2_floatp:
129         bne     t4, FFI_TYPE_FLOAT, arg2_doublep
130         l.s     $f13, 1*FFI_SIZEOF_ARG(t9)      
131         b       arg2_next
132 arg2_doublep:   
133         l.d     $f13, 1*FFI_SIZEOF_ARG(t9)      
134 arg2_next:      
135         
136         add     t4, t6, 0
137         SRL     t4, 2*FFI_FLAG_BITS
138         and     t4, ((1<<FFI_FLAG_BITS)-1)
139         bnez    t4, arg3_floatp
140         REG_L   a2, 2*FFI_SIZEOF_ARG(t9)
141         b       arg3_next
142 arg3_floatp:
143         bne     t4, FFI_TYPE_FLOAT, arg3_doublep
144         l.s     $f14, 2*FFI_SIZEOF_ARG(t9)      
145         b       arg3_next
146 arg3_doublep:   
147         l.d     $f14, 2*FFI_SIZEOF_ARG(t9)      
148 arg3_next:      
149         
150         add     t4, t6, 0
151         SRL     t4, 3*FFI_FLAG_BITS
152         and     t4, ((1<<FFI_FLAG_BITS)-1)
153         bnez    t4, arg4_floatp
154         REG_L   a3, 3*FFI_SIZEOF_ARG(t9)
155         b       arg4_next
156 arg4_floatp:
157         bne     t4, FFI_TYPE_FLOAT, arg4_doublep
158         l.s     $f15, 3*FFI_SIZEOF_ARG(t9)      
159         b       arg4_next
160 arg4_doublep:   
161         l.d     $f15, 3*FFI_SIZEOF_ARG(t9)      
162 arg4_next:      
163         
164         add     t4, t6, 0
165         SRL     t4, 4*FFI_FLAG_BITS
166         and     t4, ((1<<FFI_FLAG_BITS)-1)
167         bnez    t4, arg5_floatp
168         REG_L   a4, 4*FFI_SIZEOF_ARG(t9)
169         b       arg5_next
170 arg5_floatp:
171         bne     t4, FFI_TYPE_FLOAT, arg5_doublep
172         l.s     $f16, 4*FFI_SIZEOF_ARG(t9)      
173         b       arg5_next
174 arg5_doublep:   
175         l.d     $f16, 4*FFI_SIZEOF_ARG(t9)      
176 arg5_next:      
177         
178         add     t4, t6, 0
179         SRL     t4, 5*FFI_FLAG_BITS
180         and     t4, ((1<<FFI_FLAG_BITS)-1)
181         bnez    t4, arg6_floatp
182         REG_L   a5, 5*FFI_SIZEOF_ARG(t9)
183         b       arg6_next
184 arg6_floatp:
185         bne     t4, FFI_TYPE_FLOAT, arg6_doublep
186         l.s     $f17, 5*FFI_SIZEOF_ARG(t9)      
187         b       arg6_next
188 arg6_doublep:   
189         l.d     $f17, 5*FFI_SIZEOF_ARG(t9)      
190 arg6_next:      
191         
192         add     t4, t6, 0
193         SRL     t4, 6*FFI_FLAG_BITS
194         and     t4, ((1<<FFI_FLAG_BITS)-1)
195         bnez    t4, arg7_floatp
196         REG_L   a6, 6*FFI_SIZEOF_ARG(t9)
197         b       arg7_next
198 arg7_floatp:
199         bne     t4, FFI_TYPE_FLOAT, arg7_doublep
200         l.s     $f18, 6*FFI_SIZEOF_ARG(t9)      
201         b       arg7_next
202 arg7_doublep:   
203         l.d     $f18, 6*FFI_SIZEOF_ARG(t9)      
204 arg7_next:      
205         
206         add     t4, t6, 0
207         SRL     t4, 7*FFI_FLAG_BITS
208         and     t4, ((1<<FFI_FLAG_BITS)-1)
209         bnez    t4, arg8_floatp
210         REG_L   a7, 7*FFI_SIZEOF_ARG(t9)
211         b       arg8_next
212 arg8_floatp:
213         bne     t4, FFI_TYPE_FLOAT, arg8_doublep
214         l.s     $f19, 7*FFI_SIZEOF_ARG(t9)      
215         b       arg8_next
216 arg8_doublep:   
217         l.d     $f19, 7*FFI_SIZEOF_ARG(t9)      
218 arg8_next:      
220 callit:         
221         # Load the function pointer
222         REG_L   t9, 5*FFI_SIZEOF_ARG($fp)
224         # If the return value pointer is NULL, assume no return value.
225         REG_L   t5, 4*FFI_SIZEOF_ARG($fp)
226         beqz    t5, noretval
228         # Shift the return type flag over
229         SRL     t6, 8*FFI_FLAG_BITS
230         
231         bne     t6, FFI_TYPE_INT, retfloat
232         jal     t9
233         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
234         REG_S   v0, 0(t4)
235         b       epilogue
237 retfloat:
238         bne     t6, FFI_TYPE_FLOAT, retdouble
239         jal     t9
240         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
241         s.s     $f0, 0(t4)
242         b       epilogue
244 retdouble:      
245         bne     t6, FFI_TYPE_DOUBLE, retstruct_d
246         jal     t9
247         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
248         s.d     $f0, 0(t4)
249         b       epilogue
251 retstruct_d:    
252         bne     t6, FFI_TYPE_STRUCT_D, retstruct_f
253         jal     t9
254         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
255         s.d     $f0, 0(t4)
256         b       epilogue
257         
258 retstruct_f:    
259         bne     t6, FFI_TYPE_STRUCT_F, retstruct_d_d
260         jal     t9
261         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
262         s.s     $f0, 0(t4)
263         b       epilogue
264         
265 retstruct_d_d:  
266         bne     t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
267         jal     t9
268         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
269         s.d     $f0, 0(t4)
270         s.d     $f2, 8(t4)
271         b       epilogue
272         
273 retstruct_f_f:  
274         bne     t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
275         jal     t9
276         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
277         s.s     $f0, 0(t4)
278         s.s     $f2, 4(t4)
279         b       epilogue
280         
281 retstruct_d_f:  
282         bne     t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
283         jal     t9
284         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
285         s.d     $f0, 0(t4)
286         s.s     $f2, 8(t4)
287         b       epilogue
288         
289 retstruct_f_d:  
290         bne     t6, FFI_TYPE_STRUCT_FD, retstruct_small
291         jal     t9
292         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
293         s.s     $f0, 0(t4)
294         s.d     $f2, 8(t4)
295         b       epilogue
296         
297 retstruct_small:        
298         bne     t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
299         jal     t9
300         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
301         REG_S   v0, 0(t4)
302         b       epilogue
303         
304 retstruct_small2:       
305         bne     t6, FFI_TYPE_STRUCT_SMALL2, retstruct
306         jal     t9
307         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
308         REG_S   v0, 0(t4)
309         REG_S   v1, 8(t4)
310         b       epilogue
311         
312 retstruct:      
313 noretval:       
314         jal     t9
315         
316         # Epilogue
317 epilogue:       
318         move    $sp, $fp        
319         REG_L   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
320         REG_L   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)  # Restore return address
321         ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
322         j       ra
324 .LFE3:
325         .end    ffi_call_N32
327 /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
328    ($12). Stores any arguments passed in registers onto the stack,
329    then calls ffi_closure_mips_inner_N32, which then decodes
330    them.
331         
332         Stack layout:
334         20 - Start of parameters, original sp
335         19 - Called function a7 save
336         18 - Called function a6 save
337         17 - Called function a5 save
338         16 - Called function a4 save
339         15 - Called function a3 save
340         14 - Called function a2 save
341         13 - Called function a1 save
342         12 - Called function a0 save
343         11 - Called function f19
344         10 - Called function f18
345          9 - Called function f17
346          8 - Called function f16
347          7 - Called function f15
348          6 - Called function f14
349          5 - Called function f13
350          4 - Called function f12
351          3 - return value high (v1 or $f2)
352          2 - return value low (v0 or $f0)
353          1 - ra save
354          0 - gp save our sp  points here
355          */
357 #define SIZEOF_FRAME2   (20 * FFI_SIZEOF_ARG)
358         
359 #define A7_OFF2         (19 * FFI_SIZEOF_ARG)
360 #define A6_OFF2         (18 * FFI_SIZEOF_ARG)
361 #define A5_OFF2         (17 * FFI_SIZEOF_ARG)
362 #define A4_OFF2         (16 * FFI_SIZEOF_ARG)
363 #define A3_OFF2         (15 * FFI_SIZEOF_ARG)
364 #define A2_OFF2         (14 * FFI_SIZEOF_ARG)
365 #define A1_OFF2         (13 * FFI_SIZEOF_ARG)
366 #define A0_OFF2         (12 * FFI_SIZEOF_ARG)   
368 #define F19_OFF2        (11 * FFI_SIZEOF_ARG)
369 #define F18_OFF2        (10 * FFI_SIZEOF_ARG)
370 #define F17_OFF2        (9  * FFI_SIZEOF_ARG)
371 #define F16_OFF2        (8  * FFI_SIZEOF_ARG)
372 #define F15_OFF2        (7  * FFI_SIZEOF_ARG)
373 #define F14_OFF2        (6  * FFI_SIZEOF_ARG)
374 #define F13_OFF2        (5  * FFI_SIZEOF_ARG)
375 #define F12_OFF2        (4  * FFI_SIZEOF_ARG)
377 #define V1_OFF2         (3  * FFI_SIZEOF_ARG)
378 #define V0_OFF2         (2  * FFI_SIZEOF_ARG)
380 #define RA_OFF2         (1  * FFI_SIZEOF_ARG)
381 #define GP_OFF2         (0  * FFI_SIZEOF_ARG)
383         .align  2
384         .globl  ffi_closure_N32
385         .ent    ffi_closure_N32
386 ffi_closure_N32:
387 .LFB2:
388         .frame  $sp, SIZEOF_FRAME2, ra
389         .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
390         .fmask  0x00000000,0
391         SUBU    $sp, SIZEOF_FRAME2
392 .LCFI5:
393         .cpsetup t9, GP_OFF2, ffi_closure_N32
394         REG_S   ra, RA_OFF2($sp)        # Save return address
395 .LCFI6:
396         # Store all possible argument registers. If there are more than
397         # fit in registers, then they were stored on the stack.
398         REG_S   a0, A0_OFF2($sp)
399         REG_S   a1, A1_OFF2($sp)
400         REG_S   a2, A2_OFF2($sp)
401         REG_S   a3, A3_OFF2($sp)
402         REG_S   a4, A4_OFF2($sp)
403         REG_S   a5, A5_OFF2($sp)
404         REG_S   a6, A6_OFF2($sp)
405         REG_S   a7, A7_OFF2($sp)
407         # Store all possible float/double registers.
408         s.d     $f12, F12_OFF2($sp)
409         s.d     $f13, F13_OFF2($sp)
410         s.d     $f14, F14_OFF2($sp)
411         s.d     $f15, F15_OFF2($sp)
412         s.d     $f16, F16_OFF2($sp)
413         s.d     $f17, F17_OFF2($sp)
414         s.d     $f18, F18_OFF2($sp)
415         s.d     $f19, F19_OFF2($sp)
417         # Call ffi_closure_mips_inner_N32 to do the real work.
418         LA      t9, ffi_closure_mips_inner_N32
419         move    a0, $12  # Pointer to the ffi_closure
420         addu    a1, $sp, V0_OFF2
421         addu    a2, $sp, A0_OFF2
422         addu    a3, $sp, F12_OFF2
423         jalr    t9
425         # Return flags are in v0
426         bne     v0, FFI_TYPE_INT, cls_retfloat
427         REG_L   v0, V0_OFF2($sp)
428         b       cls_epilogue
430 cls_retfloat:
431         bne     v0, FFI_TYPE_FLOAT, cls_retdouble
432         l.s     $f0, V0_OFF2($sp)
433         b       cls_epilogue
435 cls_retdouble:  
436         bne     v0, FFI_TYPE_DOUBLE, cls_retstruct_d
437         l.d     $f0, V0_OFF2($sp)
438         b       cls_epilogue
440 cls_retstruct_d:        
441         bne     v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
442         l.d     $f0, V0_OFF2($sp)
443         b       cls_epilogue
444         
445 cls_retstruct_f:        
446         bne     v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
447         l.s     $f0, V0_OFF2($sp)
448         b       cls_epilogue
449         
450 cls_retstruct_d_d:      
451         bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
452         l.d     $f0, V0_OFF2($sp)
453         l.d     $f2, V1_OFF2($sp)
454         b       cls_epilogue
455         
456 cls_retstruct_f_f:      
457         bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
458         l.s     $f0, V0_OFF2($sp)
459         l.s     $f2, V1_OFF2($sp)
460         b       cls_epilogue
461         
462 cls_retstruct_d_f:      
463         bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
464         l.d     $f0, V0_OFF2($sp)
465         l.s     $f2, V1_OFF2($sp)
466         b       cls_epilogue
467         
468 cls_retstruct_f_d:      
469         bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
470         l.s     $f0, V0_OFF2($sp)
471         l.d     $f2, V1_OFF2($sp)
472         b       cls_epilogue
473         
474 cls_retstruct_small2:   
475         REG_L   v0, V0_OFF2($sp)
476         REG_L   v1, V1_OFF2($sp)
477         
478         # Epilogue
479 cls_epilogue:   
480         REG_L   ra,  RA_OFF2($sp)        # Restore return address
481         .cpreturn
482         ADDU    $sp, SIZEOF_FRAME2
483         j       ra
484 .LFE2:  
485         .end    ffi_closure_N32
487         .section        .eh_frame,"aw",@progbits
488 .Lframe1:
489         .4byte  .LECIE1-.LSCIE1         # length
490 .LSCIE1:
491         .4byte  0x0                     # CIE
492         .byte   0x1                     # Version 1
493         .ascii  "\000"                  # Augmentation
494         .uleb128 0x1                    # Code alignment 1
495         .sleb128 -4                     # Data alignment -4
496         .byte   0x1f                    # Return Address $31
497         .byte   0xc                     # DW_CFA_def_cfa
498         .uleb128 0x1d                   # in $sp
499         .uleb128 0x0                    # offset 0
500         .align  EH_FRAME_ALIGN
501 .LECIE1:
503 .LSFDE1:
504         .4byte  .LEFDE1-.LASFDE1        # length.
505 .LASFDE1:
506         .4byte  .LASFDE1-.Lframe1       # CIE_pointer.
507         FDE_ADDR_BYTES  .LFB3           # initial_location.
508         FDE_ADDR_BYTES  .LFE3-.LFB3     # address_range.
509         .byte   0x4                     # DW_CFA_advance_loc4
510         .4byte  .LCFI0-.LFB3            # to .LCFI0
511         .byte   0xe                     # DW_CFA_def_cfa_offset
512         .uleb128 SIZEOF_FRAME           # adjust stack.by SIZEOF_FRAME
513         .byte   0x4                     # DW_CFA_advance_loc4
514         .4byte  .LCFI1-.LCFI0           # to .LCFI1
515         .byte   0x9e                    # DW_CFA_offset of $fp
516         .uleb128 2*FFI_SIZEOF_ARG/4     # 
517         .byte   0x9f                    # DW_CFA_offset of ra
518         .uleb128 1*FFI_SIZEOF_ARG/4     # 
519         .byte   0x4                     # DW_CFA_advance_loc4
520         .4byte  .LCFI3-.LCFI1           # to .LCFI3
521         .byte   0xd                     # DW_CFA_def_cfa_register
522         .uleb128 0x1e                   # in $fp
523         .align  EH_FRAME_ALIGN
524 .LEFDE1:
525 .LSFDE3:
526         .4byte  .LEFDE3-.LASFDE3        # length
527 .LASFDE3:
528         .4byte  .LASFDE3-.Lframe1       # CIE_pointer.
529         FDE_ADDR_BYTES  .LFB2           # initial_location.
530         FDE_ADDR_BYTES  .LFE2-.LFB2     # address_range.
531         .byte   0x4                     # DW_CFA_advance_loc4
532         .4byte  .LCFI5-.LFB2            # to .LCFI5
533         .byte   0xe                     # DW_CFA_def_cfa_offset
534         .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
535         .byte   0x4                     # DW_CFA_advance_loc4
536         .4byte  .LCFI6-.LCFI5           # to .LCFI6
537         .byte   0x9c                    # DW_CFA_offset of $gp ($28)
538         .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
539         .byte   0x9f                    # DW_CFA_offset of ra ($31)
540         .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
541         .align  EH_FRAME_ALIGN
542 .LEFDE3:
543         
544 #endif