2f9edb48a9b6a3864c99bee7b2c85e933c2a2c60
[libffi.git] / libffi / src / mips / n32.S
1 /* -----------------------------------------------------------------------
2    n32.S - Copyright (c) 1996, 1998, 2005  Red Hat, Inc.
3    
4    MIPS Foreign Function Interface 
5
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:
13
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
16
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    ----------------------------------------------------------------------- */
25
26 #define LIBFFI_ASM      
27 #include <fficonfig.h>
28 #include <ffi.h>
29
30 /* Only build this code if we are compiling for n32 */  
31
32 #if defined(FFI_MIPS_N32)
33
34 #define callback a0
35 #define bytes    a2
36 #define flags    a3
37 #define raddr    a4
38 #define fn       a5
39
40 #define SIZEOF_FRAME    ( 8 * FFI_SIZEOF_ARG )
41
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
52
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
66
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
72
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.
76
77 sixteen:
78         SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
79                                 # arg space
80
81         move    a0, $sp         # 4 * FFI_SIZEOF_ARG
82         ADDU    a3, $fp, 3 * FFI_SIZEOF_ARG
83
84         # Call ffi_prep_args
85         jal     t9
86         
87         # Copy the stack pointer to t9
88         move    t9, $sp
89         
90         # Fix the stack if there are more than 8 64bit slots worth
91         # of arguments.
92
93         # Load the number of bytes
94         REG_L   t6, 2*FFI_SIZEOF_ARG($fp)
95
96         # Is it bigger than 8 * FFI_SIZEOF_ARG?
97         daddiu  t8, t6, -(8 * FFI_SIZEOF_ARG)
98         bltz    t8, loadregs
99
100         ADDU    t9, t9, t8
101         
102 loadregs:       
103
104         REG_L   t6, 3*FFI_SIZEOF_ARG($fp)  # load the flags word into t6.
105
106         and     t4, t6, ((1<<FFI_FLAG_BITS)-1)
107         bnez    t4, arg1_floatp
108         REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
109         b       arg1_next
110 arg1_floatp:    
111         bne     t4, FFI_TYPE_FLOAT, arg1_doublep
112         l.s     $f12, 0*FFI_SIZEOF_ARG(t9)
113         b       arg1_next
114 arg1_doublep:   
115         l.d     $f12, 0*FFI_SIZEOF_ARG(t9)
116 arg1_next:      
117         
118         SRL     t4, t6, 1*FFI_FLAG_BITS
119         and     t4, ((1<<FFI_FLAG_BITS)-1)
120         bnez    t4, arg2_floatp
121         REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
122         b       arg2_next
123 arg2_floatp:
124         bne     t4, FFI_TYPE_FLOAT, arg2_doublep
125         l.s     $f13, 1*FFI_SIZEOF_ARG(t9)      
126         b       arg2_next
127 arg2_doublep:   
128         l.d     $f13, 1*FFI_SIZEOF_ARG(t9)      
129 arg2_next:      
130         
131         SRL     t4, t6, 2*FFI_FLAG_BITS
132         and     t4, ((1<<FFI_FLAG_BITS)-1)
133         bnez    t4, arg3_floatp
134         REG_L   a2, 2*FFI_SIZEOF_ARG(t9)
135         b       arg3_next
136 arg3_floatp:
137         bne     t4, FFI_TYPE_FLOAT, arg3_doublep
138         l.s     $f14, 2*FFI_SIZEOF_ARG(t9)      
139         b       arg3_next
140 arg3_doublep:   
141         l.d     $f14, 2*FFI_SIZEOF_ARG(t9)      
142 arg3_next:      
143         
144         SRL     t4, t6, 3*FFI_FLAG_BITS
145         and     t4, ((1<<FFI_FLAG_BITS)-1)
146         bnez    t4, arg4_floatp
147         REG_L   a3, 3*FFI_SIZEOF_ARG(t9)
148         b       arg4_next
149 arg4_floatp:
150         bne     t4, FFI_TYPE_FLOAT, arg4_doublep
151         l.s     $f15, 3*FFI_SIZEOF_ARG(t9)      
152         b       arg4_next
153 arg4_doublep:   
154         l.d     $f15, 3*FFI_SIZEOF_ARG(t9)      
155 arg4_next:      
156         
157         SRL     t4, t6, 4*FFI_FLAG_BITS
158         and     t4, ((1<<FFI_FLAG_BITS)-1)
159         bnez    t4, arg5_floatp
160         REG_L   a4, 4*FFI_SIZEOF_ARG(t9)
161         b       arg5_next
162 arg5_floatp:
163         bne     t4, FFI_TYPE_FLOAT, arg5_doublep
164         l.s     $f16, 4*FFI_SIZEOF_ARG(t9)      
165         b       arg5_next
166 arg5_doublep:   
167         l.d     $f16, 4*FFI_SIZEOF_ARG(t9)      
168 arg5_next:      
169         
170         SRL     t4, t6, 5*FFI_FLAG_BITS
171         and     t4, ((1<<FFI_FLAG_BITS)-1)
172         bnez    t4, arg6_floatp
173         REG_L   a5, 5*FFI_SIZEOF_ARG(t9)
174         b       arg6_next
175 arg6_floatp:
176         bne     t4, FFI_TYPE_FLOAT, arg6_doublep
177         l.s     $f17, 5*FFI_SIZEOF_ARG(t9)      
178         b       arg6_next
179 arg6_doublep:   
180         l.d     $f17, 5*FFI_SIZEOF_ARG(t9)      
181 arg6_next:      
182         
183         SRL     t4, t6, 6*FFI_FLAG_BITS
184         and     t4, ((1<<FFI_FLAG_BITS)-1)
185         bnez    t4, arg7_floatp
186         REG_L   a6, 6*FFI_SIZEOF_ARG(t9)
187         b       arg7_next
188 arg7_floatp:
189         bne     t4, FFI_TYPE_FLOAT, arg7_doublep
190         l.s     $f18, 6*FFI_SIZEOF_ARG(t9)      
191         b       arg7_next
192 arg7_doublep:   
193         l.d     $f18, 6*FFI_SIZEOF_ARG(t9)      
194 arg7_next:      
195         
196         SRL     t4, t6, 7*FFI_FLAG_BITS
197         and     t4, ((1<<FFI_FLAG_BITS)-1)
198         bnez    t4, arg8_floatp
199         REG_L   a7, 7*FFI_SIZEOF_ARG(t9)
200         b       arg8_next
201 arg8_floatp:
202         bne     t4, FFI_TYPE_FLOAT, arg8_doublep
203         l.s     $f19, 7*FFI_SIZEOF_ARG(t9)      
204         b       arg8_next
205 arg8_doublep:   
206         l.d     $f19, 7*FFI_SIZEOF_ARG(t9)      
207 arg8_next:      
208
209 callit:         
210         # Load the function pointer
211         REG_L   t9, 5*FFI_SIZEOF_ARG($fp)
212
213         # If the return value pointer is NULL, assume no return value.
214         REG_L   t5, 4*FFI_SIZEOF_ARG($fp)
215         beqz    t5, noretval
216
217         # Shift the return type flag over
218         SRL     t6, 8*FFI_FLAG_BITS
219         
220         bne     t6, FFI_TYPE_INT, retfloat
221         jal     t9
222         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
223         REG_S   v0, 0(t4)
224         b       epilogue
225
226 retfloat:
227         bne     t6, FFI_TYPE_FLOAT, retdouble
228         jal     t9
229         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
230         s.s     $f0, 0(t4)
231         b       epilogue
232
233 retdouble:      
234         bne     t6, FFI_TYPE_DOUBLE, retstruct_d
235         jal     t9
236         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
237         s.d     $f0, 0(t4)
238         b       epilogue
239
240 retstruct_d:    
241         bne     t6, FFI_TYPE_STRUCT_D, retstruct_f
242         jal     t9
243         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
244         s.d     $f0, 0(t4)
245         b       epilogue
246         
247 retstruct_f:    
248         bne     t6, FFI_TYPE_STRUCT_F, retstruct_d_d
249         jal     t9
250         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
251         s.s     $f0, 0(t4)
252         b       epilogue
253         
254 retstruct_d_d:  
255         bne     t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
256         jal     t9
257         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
258         s.d     $f0, 0(t4)
259         s.d     $f2, 8(t4)
260         b       epilogue
261         
262 retstruct_f_f:  
263         bne     t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
264         jal     t9
265         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
266         s.s     $f0, 0(t4)
267         s.s     $f2, 4(t4)
268         b       epilogue
269         
270 retstruct_d_f:  
271         bne     t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
272         jal     t9
273         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
274         s.d     $f0, 0(t4)
275         s.s     $f2, 8(t4)
276         b       epilogue
277         
278 retstruct_f_d:  
279         bne     t6, FFI_TYPE_STRUCT_FD, retstruct_small
280         jal     t9
281         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
282         s.s     $f0, 0(t4)
283         s.d     $f2, 8(t4)
284         b       epilogue
285         
286 retstruct_small:        
287         bne     t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
288         jal     t9
289         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
290         REG_S   v0, 0(t4)
291         b       epilogue
292         
293 retstruct_small2:       
294         bne     t6, FFI_TYPE_STRUCT_SMALL2, retstruct
295         jal     t9
296         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
297         REG_S   v0, 0(t4)
298         REG_S   v1, 8(t4)
299         b       epilogue
300         
301 retstruct:      
302 noretval:       
303         jal     t9
304         
305         # Epilogue
306 epilogue:       
307         move    $sp, $fp        
308         REG_L   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
309         REG_L   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)  # Restore return address
310         ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
311         j       ra
312
313 .LFE3:
314         .end    ffi_call_N32
315
316 /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
317    ($12). Stores any arguments passed in registers onto the stack,
318    then calls ffi_closure_mips_inner_N32, which then decodes
319    them.
320         
321         Stack layout:
322
323         20 - Start of parameters, original sp
324         19 - Called function a7 save
325         18 - Called function a6 save
326         17 - Called function a5 save
327         16 - Called function a4 save
328         15 - Called function a3 save
329         14 - Called function a2 save
330         13 - Called function a1 save
331         12 - Called function a0 save
332         11 - Called function f19
333         10 - Called function f18
334          9 - Called function f17
335          8 - Called function f16
336          7 - Called function f15
337          6 - Called function f14
338          5 - Called function f13
339          4 - Called function f12
340          3 - return value high (v1 or $f2)
341          2 - return value low (v0 or $f0)
342          1 - ra save
343          0 - gp save our sp  points here
344          */
345
346 #define SIZEOF_FRAME2   (20 * FFI_SIZEOF_ARG)
347         
348 #define A7_OFF2         (19 * FFI_SIZEOF_ARG)
349 #define A6_OFF2         (18 * FFI_SIZEOF_ARG)
350 #define A5_OFF2         (17 * FFI_SIZEOF_ARG)
351 #define A4_OFF2         (16 * FFI_SIZEOF_ARG)
352 #define A3_OFF2         (15 * FFI_SIZEOF_ARG)
353 #define A2_OFF2         (14 * FFI_SIZEOF_ARG)
354 #define A1_OFF2         (13 * FFI_SIZEOF_ARG)
355 #define A0_OFF2         (12 * FFI_SIZEOF_ARG)   
356
357 #define F19_OFF2        (11 * FFI_SIZEOF_ARG)
358 #define F18_OFF2        (10 * FFI_SIZEOF_ARG)
359 #define F17_OFF2        (9  * FFI_SIZEOF_ARG)
360 #define F16_OFF2        (8  * FFI_SIZEOF_ARG)
361 #define F15_OFF2        (7  * FFI_SIZEOF_ARG)
362 #define F14_OFF2        (6  * FFI_SIZEOF_ARG)
363 #define F13_OFF2        (5  * FFI_SIZEOF_ARG)
364 #define F12_OFF2        (4  * FFI_SIZEOF_ARG)
365
366 #define V1_OFF2         (3  * FFI_SIZEOF_ARG)
367 #define V0_OFF2         (2  * FFI_SIZEOF_ARG)
368
369 #define RA_OFF2         (1  * FFI_SIZEOF_ARG)
370 #define GP_OFF2         (0  * FFI_SIZEOF_ARG)
371
372         .align  2
373         .globl  ffi_closure_N32
374         .ent    ffi_closure_N32
375 ffi_closure_N32:
376 .LFB2:
377         .frame  $sp, SIZEOF_FRAME2, ra
378         .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
379         .fmask  0x00000000,0
380         SUBU    $sp, SIZEOF_FRAME2
381 .LCFI5:
382         .cpsetup t9, GP_OFF2, ffi_closure_N32
383         REG_S   ra, RA_OFF2($sp)        # Save return address
384 .LCFI6:
385         # Store all possible argument registers. If there are more than
386         # fit in registers, then they were stored on the stack.
387         REG_S   a0, A0_OFF2($sp)
388         REG_S   a1, A1_OFF2($sp)
389         REG_S   a2, A2_OFF2($sp)
390         REG_S   a3, A3_OFF2($sp)
391         REG_S   a4, A4_OFF2($sp)
392         REG_S   a5, A5_OFF2($sp)
393         REG_S   a6, A6_OFF2($sp)
394         REG_S   a7, A7_OFF2($sp)
395
396         # Store all possible float/double registers.
397         s.d     $f12, F12_OFF2($sp)
398         s.d     $f13, F13_OFF2($sp)
399         s.d     $f14, F14_OFF2($sp)
400         s.d     $f15, F15_OFF2($sp)
401         s.d     $f16, F16_OFF2($sp)
402         s.d     $f17, F17_OFF2($sp)
403         s.d     $f18, F18_OFF2($sp)
404         s.d     $f19, F19_OFF2($sp)
405
406         # Call ffi_closure_mips_inner_N32 to do the real work.
407         LA      t9, ffi_closure_mips_inner_N32
408         move    a0, $12  # Pointer to the ffi_closure
409         ADDU    a1, $sp, V0_OFF2
410         ADDU    a2, $sp, A0_OFF2
411         ADDU    a3, $sp, F12_OFF2
412         jalr    t9
413
414         # Return flags are in v0
415         bne     v0, FFI_TYPE_INT, cls_retfloat
416         REG_L   v0, V0_OFF2($sp)
417         b       cls_epilogue
418
419 cls_retfloat:
420         bne     v0, FFI_TYPE_FLOAT, cls_retdouble
421         l.s     $f0, V0_OFF2($sp)
422         b       cls_epilogue
423
424 cls_retdouble:  
425         bne     v0, FFI_TYPE_DOUBLE, cls_retstruct_d
426         l.d     $f0, V0_OFF2($sp)
427         b       cls_epilogue
428
429 cls_retstruct_d:        
430         bne     v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
431         l.d     $f0, V0_OFF2($sp)
432         b       cls_epilogue
433         
434 cls_retstruct_f:        
435         bne     v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
436         l.s     $f0, V0_OFF2($sp)
437         b       cls_epilogue
438         
439 cls_retstruct_d_d:      
440         bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
441         l.d     $f0, V0_OFF2($sp)
442         l.d     $f2, V1_OFF2($sp)
443         b       cls_epilogue
444         
445 cls_retstruct_f_f:      
446         bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
447         l.s     $f0, V0_OFF2($sp)
448         l.s     $f2, V1_OFF2($sp)
449         b       cls_epilogue
450         
451 cls_retstruct_d_f:      
452         bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
453         l.d     $f0, V0_OFF2($sp)
454         l.s     $f2, V1_OFF2($sp)
455         b       cls_epilogue
456         
457 cls_retstruct_f_d:      
458         bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
459         l.s     $f0, V0_OFF2($sp)
460         l.d     $f2, V1_OFF2($sp)
461         b       cls_epilogue
462         
463 cls_retstruct_small2:   
464         REG_L   v0, V0_OFF2($sp)
465         REG_L   v1, V1_OFF2($sp)
466         
467         # Epilogue
468 cls_epilogue:   
469         REG_L   ra,  RA_OFF2($sp)        # Restore return address
470         .cpreturn
471         ADDU    $sp, SIZEOF_FRAME2
472         j       ra
473 .LFE2:  
474         .end    ffi_closure_N32
475
476         .section        .eh_frame,"aw",@progbits
477 .Lframe1:
478         .4byte  .LECIE1-.LSCIE1         # length
479 .LSCIE1:
480         .4byte  0x0                     # CIE
481         .byte   0x1                     # Version 1
482         .ascii  "\000"                  # Augmentation
483         .uleb128 0x1                    # Code alignment 1
484         .sleb128 -4                     # Data alignment -4
485         .byte   0x1f                    # Return Address $31
486         .byte   0xc                     # DW_CFA_def_cfa
487         .uleb128 0x1d                   # in $sp
488         .uleb128 0x0                    # offset 0
489         .align  EH_FRAME_ALIGN
490 .LECIE1:
491
492 .LSFDE1:
493         .4byte  .LEFDE1-.LASFDE1        # length.
494 .LASFDE1:
495         .4byte  .LASFDE1-.Lframe1       # CIE_pointer.
496         FDE_ADDR_BYTES  .LFB3           # initial_location.
497         FDE_ADDR_BYTES  .LFE3-.LFB3     # address_range.
498         .byte   0x4                     # DW_CFA_advance_loc4
499         .4byte  .LCFI0-.LFB3            # to .LCFI0
500         .byte   0xe                     # DW_CFA_def_cfa_offset
501         .uleb128 SIZEOF_FRAME           # adjust stack.by SIZEOF_FRAME
502         .byte   0x4                     # DW_CFA_advance_loc4
503         .4byte  .LCFI1-.LCFI0           # to .LCFI1
504         .byte   0x9e                    # DW_CFA_offset of $fp
505         .uleb128 2*FFI_SIZEOF_ARG/4     # 
506         .byte   0x9f                    # DW_CFA_offset of ra
507         .uleb128 1*FFI_SIZEOF_ARG/4     # 
508         .byte   0x4                     # DW_CFA_advance_loc4
509         .4byte  .LCFI3-.LCFI1           # to .LCFI3
510         .byte   0xd                     # DW_CFA_def_cfa_register
511         .uleb128 0x1e                   # in $fp
512         .align  EH_FRAME_ALIGN
513 .LEFDE1:
514 .LSFDE3:
515         .4byte  .LEFDE3-.LASFDE3        # length
516 .LASFDE3:
517         .4byte  .LASFDE3-.Lframe1       # CIE_pointer.
518         FDE_ADDR_BYTES  .LFB2           # initial_location.
519         FDE_ADDR_BYTES  .LFE2-.LFB2     # address_range.
520         .byte   0x4                     # DW_CFA_advance_loc4
521         .4byte  .LCFI5-.LFB2            # to .LCFI5
522         .byte   0xe                     # DW_CFA_def_cfa_offset
523         .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
524         .byte   0x4                     # DW_CFA_advance_loc4
525         .4byte  .LCFI6-.LCFI5           # to .LCFI6
526         .byte   0x9c                    # DW_CFA_offset of $gp ($28)
527         .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
528         .byte   0x9f                    # DW_CFA_offset of ra ($31)
529         .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
530         .align  EH_FRAME_ALIGN
531 .LEFDE3:
532         
533 #endif