Merge pull request #238 from KubaKaszycki/master
[libffi.git] / src / mips / n32.S
1 /* -----------------------------------------------------------------------
2    n32.S - Copyright (c) 1996, 1998, 2005, 2007, 2009, 2010  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 #define closure  a6
41
42 /* Note: to keep stack 16 byte aligned we need even number slots 
43    used 9 slots here
44 */
45 #define SIZEOF_FRAME    ( 10 * FFI_SIZEOF_ARG )
46
47 #ifdef __GNUC__
48         .abicalls
49 #endif
50         .set mips4
51         .text
52         .align  2
53         .globl  ffi_call_N32
54         .ent    ffi_call_N32
55 ffi_call_N32:   
56 .LFB0:
57         .frame  $fp, SIZEOF_FRAME, ra
58         .mask   0xc0000000,-FFI_SIZEOF_ARG
59         .fmask  0x00000000,0
60
61         # Prologue
62         SUBU    $sp, SIZEOF_FRAME                       # Frame size
63 .LCFI00:
64         REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
65         REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return address
66 .LCFI01:
67         move    $fp, $sp
68 .LCFI02:
69         move    t9, callback    # callback function pointer
70         REG_S   bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
71         REG_S   flags, 3*FFI_SIZEOF_ARG($fp) # flags
72         REG_S   raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
73         REG_S   fn,    5*FFI_SIZEOF_ARG($fp) # fn
74         REG_S   closure, 6*FFI_SIZEOF_ARG($fp) # closure
75
76         # Allocate at least 4 words in the argstack
77         move    v0, bytes
78         bge     bytes, 4 * FFI_SIZEOF_ARG, bigger       
79         LI      v0, 4 * FFI_SIZEOF_ARG
80         b       sixteen
81
82         bigger: 
83         ADDU    t4, v0, 2 * FFI_SIZEOF_ARG -1   # make sure it is aligned 
84         and     v0, t4, -2 * FFI_SIZEOF_ARG             # to a proper boundry.
85
86 sixteen:
87         SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
88                                 # arg space
89
90         move    a0, $sp         # 4 * FFI_SIZEOF_ARG
91         ADDU    a3, $fp, 3 * FFI_SIZEOF_ARG
92
93         # Call ffi_prep_args
94         jal     t9
95         
96         # Copy the stack pointer to t9
97         move    t9, $sp
98         
99         # Fix the stack if there are more than 8 64bit slots worth
100         # of arguments.
101
102         # Load the number of bytes
103         REG_L   t6, 2*FFI_SIZEOF_ARG($fp)
104
105         # Is it bigger than 8 * FFI_SIZEOF_ARG?
106         daddiu  t8, t6, -(8 * FFI_SIZEOF_ARG)
107         bltz    t8, loadregs
108
109         ADDU    t9, t9, t8
110         
111 loadregs:       
112
113         REG_L   t6, 3*FFI_SIZEOF_ARG($fp)  # load the flags word into t6.
114
115 #ifdef __mips_soft_float
116         REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
117         REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
118         REG_L   a2, 2*FFI_SIZEOF_ARG(t9)
119         REG_L   a3, 3*FFI_SIZEOF_ARG(t9)
120         REG_L   a4, 4*FFI_SIZEOF_ARG(t9)
121         REG_L   a5, 5*FFI_SIZEOF_ARG(t9)
122         REG_L   a6, 6*FFI_SIZEOF_ARG(t9)
123         REG_L   a7, 7*FFI_SIZEOF_ARG(t9)
124 #else
125         and     t4, t6, ((1<<FFI_FLAG_BITS)-1)
126         REG_L   a0, 0*FFI_SIZEOF_ARG(t9)
127         beqz    t4, arg1_next
128         bne     t4, FFI_TYPE_FLOAT, arg1_doublep
129         l.s     $f12, 0*FFI_SIZEOF_ARG(t9)
130         b       arg1_next
131 arg1_doublep:   
132         l.d     $f12, 0*FFI_SIZEOF_ARG(t9)
133 arg1_next:      
134         
135         SRL     t4, t6, 1*FFI_FLAG_BITS
136         and     t4, ((1<<FFI_FLAG_BITS)-1)
137         REG_L   a1, 1*FFI_SIZEOF_ARG(t9)
138         beqz    t4, arg2_next
139         bne     t4, FFI_TYPE_FLOAT, arg2_doublep
140         l.s     $f13, 1*FFI_SIZEOF_ARG(t9)      
141         b       arg2_next
142 arg2_doublep:   
143         l.d     $f13, 1*FFI_SIZEOF_ARG(t9)      
144 arg2_next:      
145         
146         SRL     t4, t6, 2*FFI_FLAG_BITS
147         and     t4, ((1<<FFI_FLAG_BITS)-1)
148         REG_L   a2, 2*FFI_SIZEOF_ARG(t9)
149         beqz    t4, arg3_next
150         bne     t4, FFI_TYPE_FLOAT, arg3_doublep
151         l.s     $f14, 2*FFI_SIZEOF_ARG(t9)      
152         b       arg3_next
153 arg3_doublep:   
154         l.d     $f14, 2*FFI_SIZEOF_ARG(t9)      
155 arg3_next:      
156         
157         SRL     t4, t6, 3*FFI_FLAG_BITS
158         and     t4, ((1<<FFI_FLAG_BITS)-1)
159         REG_L   a3, 3*FFI_SIZEOF_ARG(t9)
160         beqz    t4, arg4_next
161         bne     t4, FFI_TYPE_FLOAT, arg4_doublep
162         l.s     $f15, 3*FFI_SIZEOF_ARG(t9)      
163         b       arg4_next
164 arg4_doublep:   
165         l.d     $f15, 3*FFI_SIZEOF_ARG(t9)      
166 arg4_next:      
167         
168         SRL     t4, t6, 4*FFI_FLAG_BITS
169         and     t4, ((1<<FFI_FLAG_BITS)-1)
170         REG_L   a4, 4*FFI_SIZEOF_ARG(t9)
171         beqz    t4, arg5_next
172         bne     t4, FFI_TYPE_FLOAT, arg5_doublep
173         l.s     $f16, 4*FFI_SIZEOF_ARG(t9)      
174         b       arg5_next
175 arg5_doublep:   
176         l.d     $f16, 4*FFI_SIZEOF_ARG(t9)      
177 arg5_next:      
178         
179         SRL     t4, t6, 5*FFI_FLAG_BITS
180         and     t4, ((1<<FFI_FLAG_BITS)-1)
181         REG_L   a5, 5*FFI_SIZEOF_ARG(t9)
182         beqz    t4, arg6_next
183         bne     t4, FFI_TYPE_FLOAT, arg6_doublep
184         l.s     $f17, 5*FFI_SIZEOF_ARG(t9)      
185         b       arg6_next
186 arg6_doublep:   
187         l.d     $f17, 5*FFI_SIZEOF_ARG(t9)      
188 arg6_next:      
189         
190         SRL     t4, t6, 6*FFI_FLAG_BITS
191         and     t4, ((1<<FFI_FLAG_BITS)-1)
192         REG_L   a6, 6*FFI_SIZEOF_ARG(t9)
193         beqz    t4, arg7_next
194         bne     t4, FFI_TYPE_FLOAT, arg7_doublep
195         l.s     $f18, 6*FFI_SIZEOF_ARG(t9)      
196         b       arg7_next
197 arg7_doublep:   
198         l.d     $f18, 6*FFI_SIZEOF_ARG(t9)      
199 arg7_next:      
200         
201         SRL     t4, t6, 7*FFI_FLAG_BITS
202         and     t4, ((1<<FFI_FLAG_BITS)-1)
203         REG_L   a7, 7*FFI_SIZEOF_ARG(t9)
204         beqz    t4, arg8_next
205         bne     t4, FFI_TYPE_FLOAT, arg8_doublep
206         l.s     $f19, 7*FFI_SIZEOF_ARG(t9)      
207         b       arg8_next
208 arg8_doublep:   
209         l.d     $f19, 7*FFI_SIZEOF_ARG(t9)      
210 arg8_next:      
211 #endif
212
213 callit:         
214         # Load the function pointer
215         REG_L   t9, 5*FFI_SIZEOF_ARG($fp)
216
217         # install the static chain(t7=$15)
218         REG_L   t7, 6*FFI_SIZEOF_ARG($fp)
219
220         # If the return value pointer is NULL, assume no return value.
221         REG_L   t5, 4*FFI_SIZEOF_ARG($fp)
222         beqz    t5, noretval
223
224         # Shift the return type flag over
225         SRL     t6, 8*FFI_FLAG_BITS
226
227         beq     t6, FFI_TYPE_SINT32, retint     
228         bne     t6, FFI_TYPE_INT, retfloat
229 retint:
230         jal     t9
231         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
232         REG_S   v0, 0(t4)
233         b       epilogue
234
235 retfloat:
236 #ifndef __mips_soft_float
237         bne     t6, FFI_TYPE_FLOAT, retdouble
238         jal     t9
239         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
240         s.s     $f0, 0(t4)
241         b       epilogue
242
243 retdouble:      
244         bne     t6, FFI_TYPE_DOUBLE, retstruct_d
245         jal     t9
246         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
247         s.d     $f0, 0(t4)
248         b       epilogue
249
250 retstruct_d:    
251         bne     t6, FFI_TYPE_STRUCT_D, retstruct_f
252         jal     t9
253         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
254         s.d     $f0, 0(t4)
255         b       epilogue
256         
257 retstruct_f:    
258         bne     t6, FFI_TYPE_STRUCT_F, retstruct_d_d
259         jal     t9
260         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
261         s.s     $f0, 0(t4)
262         b       epilogue
263         
264 retstruct_d_d:  
265         bne     t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
266         jal     t9
267         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
268         s.d     $f0, 0(t4)
269         s.d     $f2, 8(t4)
270         b       epilogue
271         
272 retstruct_f_f:  
273         bne     t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
274         jal     t9
275         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
276         s.s     $f0, 0(t4)
277         s.s     $f2, 4(t4)
278         b       epilogue
279         
280 retstruct_d_f:  
281         bne     t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
282         jal     t9
283         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
284         s.d     $f0, 0(t4)
285         s.s     $f2, 8(t4)
286         b       epilogue
287         
288 retstruct_f_d:  
289         bne     t6, FFI_TYPE_STRUCT_FD, retstruct_d_soft
290         jal     t9
291         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
292         s.s     $f0, 0(t4)
293         s.d     $f2, 8(t4)
294         b       epilogue
295 #endif
296
297 retstruct_d_soft:
298         bne     t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
299         jal     t9
300         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
301         sd      v0, 0(t4)
302         b       epilogue
303         
304 retstruct_f_soft:       
305         bne     t6, FFI_TYPE_STRUCT_F_SOFT, retstruct_d_d_soft
306         jal     t9
307         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
308         sw      v0, 0(t4)
309         b       epilogue
310         
311 retstruct_d_d_soft:     
312         bne     t6, FFI_TYPE_STRUCT_DD_SOFT, retstruct_f_f_soft
313         jal     t9
314         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
315         sd      v0, 0(t4)
316         sd      v1, 8(t4)
317         b       epilogue
318         
319 retstruct_f_f_soft:     
320         bne     t6, FFI_TYPE_STRUCT_FF_SOFT, retstruct_d_f_soft
321         jal     t9
322         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
323         sw      v0, 0(t4)
324         sw      v1, 4(t4)
325         b       epilogue
326         
327 retstruct_d_f_soft:     
328         bne     t6, FFI_TYPE_STRUCT_DF_SOFT, retstruct_f_d_soft
329         jal     t9
330         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
331         sd      v0, 0(t4)
332         sw      v1, 8(t4)
333         b       epilogue
334         
335 retstruct_f_d_soft:     
336         bne     t6, FFI_TYPE_STRUCT_FD_SOFT, retstruct_small
337         jal     t9
338         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
339         sw      v0, 0(t4)
340         sd      v1, 8(t4)
341         b       epilogue
342         
343 retstruct_small:        
344         bne     t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
345         jal     t9
346         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
347         REG_S   v0, 0(t4)
348         b       epilogue
349         
350 retstruct_small2:       
351         bne     t6, FFI_TYPE_STRUCT_SMALL2, retstruct
352         jal     t9
353         REG_L   t4, 4*FFI_SIZEOF_ARG($fp)
354         REG_S   v0, 0(t4)
355         REG_S   v1, 8(t4)
356         b       epilogue
357         
358 retstruct:      
359 noretval:       
360         jal     t9
361         
362         # Epilogue
363 epilogue:       
364         move    $sp, $fp        
365         REG_L   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
366         REG_L   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)  # Restore return address
367         ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
368         j       ra
369
370 .LFE0:
371         .end    ffi_call_N32
372
373 /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
374    ($12). Stores any arguments passed in registers onto the stack,
375    then calls ffi_closure_mips_inner_N32, which then decodes
376    them.
377         
378         Stack layout:
379
380         20 - Start of parameters, original sp
381         19 - Called function a7 save
382         18 - Called function a6 save
383         17 - Called function a5 save
384         16 - Called function a4 save
385         15 - Called function a3 save
386         14 - Called function a2 save
387         13 - Called function a1 save
388         12 - Called function a0 save
389         11 - Called function f19
390         10 - Called function f18
391          9 - Called function f17
392          8 - Called function f16
393          7 - Called function f15
394          6 - Called function f14
395          5 - Called function f13
396          4 - Called function f12
397          3 - return value high (v1 or $f2)
398          2 - return value low (v0 or $f0)
399          1 - ra save
400          0 - gp save our sp  points here
401          */
402
403 #define SIZEOF_FRAME2   (20 * FFI_SIZEOF_ARG)
404         
405 #define A7_OFF2         (19 * FFI_SIZEOF_ARG)
406 #define A6_OFF2         (18 * FFI_SIZEOF_ARG)
407 #define A5_OFF2         (17 * FFI_SIZEOF_ARG)
408 #define A4_OFF2         (16 * FFI_SIZEOF_ARG)
409 #define A3_OFF2         (15 * FFI_SIZEOF_ARG)
410 #define A2_OFF2         (14 * FFI_SIZEOF_ARG)
411 #define A1_OFF2         (13 * FFI_SIZEOF_ARG)
412 #define A0_OFF2         (12 * FFI_SIZEOF_ARG)   
413
414 #define F19_OFF2        (11 * FFI_SIZEOF_ARG)
415 #define F18_OFF2        (10 * FFI_SIZEOF_ARG)
416 #define F17_OFF2        (9  * FFI_SIZEOF_ARG)
417 #define F16_OFF2        (8  * FFI_SIZEOF_ARG)
418 #define F15_OFF2        (7  * FFI_SIZEOF_ARG)
419 #define F14_OFF2        (6  * FFI_SIZEOF_ARG)
420 #define F13_OFF2        (5  * FFI_SIZEOF_ARG)
421 #define F12_OFF2        (4  * FFI_SIZEOF_ARG)
422
423 #define V1_OFF2         (3  * FFI_SIZEOF_ARG)
424 #define V0_OFF2         (2  * FFI_SIZEOF_ARG)
425
426 #define RA_OFF2         (1  * FFI_SIZEOF_ARG)
427 #define GP_OFF2         (0  * FFI_SIZEOF_ARG)
428
429         .align  2
430         .globl  ffi_go_closure_N32
431         .ent    ffi_go_closure_N32
432 ffi_go_closure_N32:
433 .LFB1:
434         .frame  $sp, SIZEOF_FRAME2, ra
435         .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
436         .fmask  0x00000000,0
437         SUBU    $sp, SIZEOF_FRAME2
438 .LCFI10:
439         .cpsetup t9, GP_OFF2, ffi_go_closure_N32
440         REG_S   ra, RA_OFF2($sp)        # Save return address
441 .LCFI11:
442
443         REG_S   a0, A0_OFF2($sp)
444         REG_S   a1, A1_OFF2($sp)
445         REG_S   a2, A2_OFF2($sp)
446         REG_S   a3, A3_OFF2($sp)
447         REG_S   a4, A4_OFF2($sp)
448         REG_S   a5, A5_OFF2($sp)
449
450         # Call ffi_closure_mips_inner_N32 to do the real work.
451         LA      t9, ffi_closure_mips_inner_N32
452         REG_L   a0, 8($15)   # cif
453         REG_L   a1, 16($15) # fun
454         move    a2, t7                     # userdata=closure
455         ADDU    a3, $sp, V0_OFF2           # rvalue
456         ADDU    a4, $sp, A0_OFF2           # ar
457         ADDU    a5, $sp, F12_OFF2          # fpr
458
459         b       $do_closure
460
461 .LFE1:  
462         .end    ffi_go_closure_N32
463
464         .align  2
465         .globl  ffi_closure_N32
466         .ent    ffi_closure_N32
467 ffi_closure_N32:
468 .LFB2:
469         .frame  $sp, SIZEOF_FRAME2, ra
470         .mask   0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
471         .fmask  0x00000000,0
472         SUBU    $sp, SIZEOF_FRAME2
473 .LCFI20:
474         .cpsetup t9, GP_OFF2, ffi_closure_N32
475         REG_S   ra, RA_OFF2($sp)        # Save return address
476 .LCFI21:
477         REG_S   a0, A0_OFF2($sp)
478         REG_S   a1, A1_OFF2($sp)
479         REG_S   a2, A2_OFF2($sp)
480         REG_S   a3, A3_OFF2($sp)
481         REG_S   a4, A4_OFF2($sp)
482         REG_S   a5, A5_OFF2($sp)
483
484         # Call ffi_closure_mips_inner_N32 to do the real work.
485         LA      t9, ffi_closure_mips_inner_N32
486         REG_L   a0, 56($12)   # cif
487         REG_L   a1, 64($12)   # fun
488         REG_L   a2, 72($12) # user_data
489         ADDU    a3, $sp, V0_OFF2
490         ADDU    a4, $sp, A0_OFF2
491         ADDU    a5, $sp, F12_OFF2
492
493 $do_closure:
494         # Store all possible argument registers. If there are more than
495         # fit in registers, then they were stored on the stack.
496         REG_S   a6, A6_OFF2($sp)
497         REG_S   a7, A7_OFF2($sp)
498
499 #ifndef __mips_soft_float
500         # Store all possible float/double registers.
501         s.d     $f12, F12_OFF2($sp)
502         s.d     $f13, F13_OFF2($sp)
503         s.d     $f14, F14_OFF2($sp)
504         s.d     $f15, F15_OFF2($sp)
505         s.d     $f16, F16_OFF2($sp)
506         s.d     $f17, F17_OFF2($sp)
507         s.d     $f18, F18_OFF2($sp)
508         s.d     $f19, F19_OFF2($sp)
509 #endif
510
511         jalr    t9
512
513         # Return flags are in v0
514         bne     v0, FFI_TYPE_SINT32, cls_retint
515         lw      v0, V0_OFF2($sp)
516         b       cls_epilogue
517
518 cls_retint:
519         bne     v0, FFI_TYPE_INT, cls_retfloat
520         REG_L   v0, V0_OFF2($sp)
521         b       cls_epilogue
522
523 cls_retfloat:
524 #ifndef __mips_soft_float
525         bne     v0, FFI_TYPE_FLOAT, cls_retdouble
526         l.s     $f0, V0_OFF2($sp)
527         b       cls_epilogue
528
529 cls_retdouble:  
530         bne     v0, FFI_TYPE_DOUBLE, cls_retstruct_d
531         l.d     $f0, V0_OFF2($sp)
532         b       cls_epilogue
533
534 cls_retstruct_d:        
535         bne     v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
536         l.d     $f0, V0_OFF2($sp)
537         b       cls_epilogue
538         
539 cls_retstruct_f:        
540         bne     v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
541         l.s     $f0, V0_OFF2($sp)
542         b       cls_epilogue
543         
544 cls_retstruct_d_d:      
545         bne     v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
546         l.d     $f0, V0_OFF2($sp)
547         l.d     $f2, V1_OFF2($sp)
548         b       cls_epilogue
549         
550 cls_retstruct_f_f:      
551         bne     v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
552         l.s     $f0, V0_OFF2($sp)
553         l.s     $f2, V1_OFF2($sp)
554         b       cls_epilogue
555         
556 cls_retstruct_d_f:      
557         bne     v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
558         l.d     $f0, V0_OFF2($sp)
559         l.s     $f2, V1_OFF2($sp)
560         b       cls_epilogue
561         
562 cls_retstruct_f_d:      
563         bne     v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
564         l.s     $f0, V0_OFF2($sp)
565         l.d     $f2, V1_OFF2($sp)
566         b       cls_epilogue
567 #endif
568         
569 cls_retstruct_small2:   
570         REG_L   v0, V0_OFF2($sp)
571         REG_L   v1, V1_OFF2($sp)
572         
573         # Epilogue
574 cls_epilogue:   
575         REG_L   ra,  RA_OFF2($sp)        # Restore return address
576         .cpreturn
577         ADDU    $sp, SIZEOF_FRAME2
578         j       ra
579 .LFE2:  
580         .end    ffi_closure_N32
581
582 #ifdef __GNUC__
583         .section        .eh_frame,"aw",@progbits
584 .Lframe1:
585         .4byte  .LECIE1-.LSCIE1         # length
586 .LSCIE1:
587         .4byte  0x0                     # CIE
588         .byte   0x1                     # Version 1
589         .ascii  "\000"                  # Augmentation
590         .uleb128 0x1                    # Code alignment 1
591         .sleb128 -4                     # Data alignment -4
592         .byte   0x1f                    # Return Address $31
593         .byte   0xc                     # DW_CFA_def_cfa
594         .uleb128 0x1d                   # in $sp
595         .uleb128 0x0                    # offset 0
596         .align  EH_FRAME_ALIGN
597 .LECIE1:
598
599 .LSFDE0:
600         .4byte  .LEFDE0-.LASFDE0        # length.
601 .LASFDE0:
602         .4byte  .LASFDE0-.Lframe1       # CIE_pointer.
603         FDE_ADDR_BYTES  .LFB0           # initial_location.
604         FDE_ADDR_BYTES  .LFE0-.LFB0     # address_range.
605         .byte   0x4                     # DW_CFA_advance_loc4
606         .4byte  .LCFI00-.LFB0           # to .LCFI00
607         .byte   0xe                     # DW_CFA_def_cfa_offset
608         .uleb128 SIZEOF_FRAME           # adjust stack.by SIZEOF_FRAME
609         .byte   0x4                     # DW_CFA_advance_loc4
610         .4byte  .LCFI01-.LCFI00         # to .LCFI01
611         .byte   0x9e                    # DW_CFA_offset of $fp
612         .uleb128 2*FFI_SIZEOF_ARG/4     # 
613         .byte   0x9f                    # DW_CFA_offset of ra
614         .uleb128 1*FFI_SIZEOF_ARG/4     # 
615         .byte   0x4                     # DW_CFA_advance_loc4
616         .4byte  .LCFI02-.LCFI01         # to .LCFI02
617         .byte   0xd                     # DW_CFA_def_cfa_register
618         .uleb128 0x1e                   # in $fp
619         .align  EH_FRAME_ALIGN
620 .LEFDE0:
621
622 .LSFDE1:
623         .4byte  .LEFDE1-.LASFDE1        # length
624 .LASFDE1:
625         .4byte  .LASFDE1-.Lframe1       # CIE_pointer.
626         FDE_ADDR_BYTES  .LFB1           # initial_location.
627         FDE_ADDR_BYTES  .LFE1-.LFB1     # address_range.
628         .byte   0x4                     # DW_CFA_advance_loc4
629         .4byte  .LCFI10-.LFB1           # to .LCFI10
630         .byte   0xe                     # DW_CFA_def_cfa_offset
631         .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
632         .byte   0x4                     # DW_CFA_advance_loc4
633         .4byte  .LCFI11-.LCFI10         # to .LCFI11
634         .byte   0x9c                    # DW_CFA_offset of $gp ($28)
635         .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
636         .byte   0x9f                    # DW_CFA_offset of ra ($31)
637         .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
638         .align  EH_FRAME_ALIGN
639 .LEFDE1:
640
641 .LSFDE2:
642         .4byte  .LEFDE2-.LASFDE2        # length
643 .LASFDE2:
644         .4byte  .LASFDE2-.Lframe1       # CIE_pointer.
645         FDE_ADDR_BYTES  .LFB2           # initial_location.
646         FDE_ADDR_BYTES  .LFE2-.LFB2     # address_range.
647         .byte   0x4                     # DW_CFA_advance_loc4
648         .4byte  .LCFI20-.LFB2           # to .LCFI20
649         .byte   0xe                     # DW_CFA_def_cfa_offset
650         .uleb128 SIZEOF_FRAME2          # adjust stack.by SIZEOF_FRAME
651         .byte   0x4                     # DW_CFA_advance_loc4
652         .4byte  .LCFI21-.LCFI20         # to .LCFI21
653         .byte   0x9c                    # DW_CFA_offset of $gp ($28)
654         .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
655         .byte   0x9f                    # DW_CFA_offset of ra ($31)
656         .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
657         .align  EH_FRAME_ALIGN
658 .LEFDE2:
659 #endif /* __GNUC__ */   
660         
661 #endif