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