OSDN Git Service

2004-08-23 David Daney <daney@avtrex.com>
[pf3gnuchains/gcc-fork.git] / libffi / src / mips / o32.S
1 /* -----------------------------------------------------------------------
2    o32.S - Copyright (c) 1996, 1998  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 o32 */  
31
32 #if defined(FFI_MIPS_O32)
33         
34 #define callback a0
35 #define bytes    a2
36 #define flags    a3
37                 
38 #define SIZEOF_FRAME    ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
39
40         .text
41         .align  2
42         .globl  ffi_call_O32
43         .ent    ffi_call_O32
44 ffi_call_O32:   
45 $LFB0:
46         # Prologue
47         SUBU    $sp, SIZEOF_FRAME                       # Frame size
48 $LCFI0:
49         REG_S   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
50 $LCFI1:
51         REG_S   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)        # Save return address
52 $LCFI2:
53         move    $fp, $sp
54
55 $LCFI3:
56         move    t9, callback    # callback function pointer
57         REG_S   flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
58
59         # Allocate at least 4 words in the argstack
60         move    v0, bytes
61         bge     bytes, 4 * FFI_SIZEOF_ARG, bigger       
62         LI      v0, 4 * FFI_SIZEOF_ARG
63         b       sixteen
64
65 bigger: 
66         ADDU    t0, v0, 2 * FFI_SIZEOF_ARG -1   # make sure it is aligned 
67         and     v0, t0, -2 * FFI_SIZEOF_ARG             # to an 8 byte boundry
68
69 sixteen:
70         SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
71                                 # arg space
72
73         ADDU    a0, $sp, 4 * FFI_SIZEOF_ARG
74         ADDU    a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
75
76         jal     t9
77         
78         REG_L   t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp)  # load the flags word
79         add     t2, t0, 0                          # and copy it into t2
80
81         and     t0, ((1<<4)-1)          # mask out the return type
82         SRL     t2, 4                   # shift our arg info
83                 
84         ADDU    $sp, $sp, 4 * FFI_SIZEOF_ARG    # adjust $sp to new args
85
86         bnez    t0, pass_d                      # make it quick for int
87         REG_L   a0, 0*FFI_SIZEOF_ARG($sp)               # just go ahead and load the
88         REG_L   a1, 1*FFI_SIZEOF_ARG($sp)               # four regs.
89         REG_L   a2, 2*FFI_SIZEOF_ARG($sp)
90         REG_L   a3, 3*FFI_SIZEOF_ARG($sp)
91         b       call_it
92
93 pass_d:
94         bne     t0, FFI_ARGS_D, pass_f
95         l.d     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
96         REG_L   a2,   2*FFI_SIZEOF_ARG($sp)     # passing a double
97         REG_L   a3,   3*FFI_SIZEOF_ARG($sp)
98         b       call_it
99
100 pass_f: 
101         bne     t0, FFI_ARGS_F, pass_d_d
102         l.s     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
103         REG_L   a1,   1*FFI_SIZEOF_ARG($sp)     # passing a float
104         REG_L   a2,   2*FFI_SIZEOF_ARG($sp)
105         REG_L   a3,   3*FFI_SIZEOF_ARG($sp)
106         b       call_it         
107
108 pass_d_d:               
109         bne     t0, FFI_ARGS_DD, pass_f_f
110         l.d     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
111         l.d     $f14, 2*FFI_SIZEOF_ARG($sp)     # passing two doubles
112         b       call_it
113
114 pass_f_f:       
115         bne     t0, FFI_ARGS_FF, pass_d_f
116         l.s     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
117         l.s     $f14, 1*FFI_SIZEOF_ARG($sp)     # passing two floats
118         REG_L   a2,   2*FFI_SIZEOF_ARG($sp)
119         REG_L   a3,   3*FFI_SIZEOF_ARG($sp)
120         b       call_it
121
122 pass_d_f:               
123         bne     t0, FFI_ARGS_DF, pass_f_d
124         l.d     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
125         l.s     $f14, 2*FFI_SIZEOF_ARG($sp)     # passing double and float
126         REG_L   a3,   3*FFI_SIZEOF_ARG($sp)
127         b       call_it
128
129 pass_f_d:               
130  # assume that the only other combination must be float then double
131  #      bne     t0, FFI_ARGS_F_D, call_it
132         l.s     $f12, 0*FFI_SIZEOF_ARG($sp)     # load $fp regs from args
133         l.d     $f14, 2*FFI_SIZEOF_ARG($sp)     # passing double and float
134
135 call_it:        
136         # Load the function pointer
137         REG_L   t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
138
139         # If the return value pointer is NULL, assume no return value.
140         REG_L   t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
141         beqz    t1, noretval
142
143         bne     t2, FFI_TYPE_INT, retlonglong
144         jal     t9
145         REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
146         REG_S   v0, 0(t0)
147         b       epilogue
148
149 retlonglong:
150         # Really any 64-bit int, signed or not.
151         bne     t2, FFI_TYPE_UINT64, retfloat
152         jal     t9
153         REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
154         REG_S   v1, 4(t0)
155         REG_S   v0, 0(t0)
156         b       epilogue
157
158 retfloat:
159         bne     t2, FFI_TYPE_FLOAT, retdouble
160         jal     t9
161         REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
162         s.s     $f0, 0(t0)
163         b       epilogue
164
165 retdouble:      
166         bne     t2, FFI_TYPE_DOUBLE, noretval
167         jal     t9
168         REG_L   t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
169         s.d     $f0, 0(t0)
170         b       epilogue
171         
172 noretval:       
173         jal     t9
174         
175         # Epilogue
176 epilogue:       
177         move    $sp, $fp        
178         REG_L   $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
179         REG_L   ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)  # Restore return address
180         ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
181         j       ra
182
183 $LFE0:
184         .end    ffi_call_O32
185
186
187 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
188         in t0. Stores any arguments passed in registers onto the
189         stack, then calls ffi_closure_mips_inner_O32, which
190         then decodes them.
191         
192         Stack layout:
193
194         14 - Start of parameters, original sp
195         13 - ra save
196         12 - fp save
197         11 - $16 (s0) save
198         10 - cprestore
199          9 - return value high (v1)
200          8 - return value low (v0)
201          7 - f14 (le high, be low)
202          6 - f14 (le low, be high)
203          5 - f12 (le high, be low)
204          4 - f12 (le low, be high)
205          3 - Called function a3 save
206          2 - Called function a2 save
207          1 - Called function a1 save
208          0 - Called function a0 save our sp, fp point here
209          */
210         
211 #define SIZEOF_FRAME2   ( 14 * FFI_SIZEOF_ARG )
212
213         .text
214         .align  2
215         .globl  ffi_closure_O32
216         .ent    ffi_closure_O32
217 ffi_closure_O32:
218 $LFB1:
219         # Prologue
220         .frame  $fp, SIZEOF_FRAME2, $31
221         .set    noreorder
222         .cpload $25
223         .set    reorder
224         SUBU    $sp, SIZEOF_FRAME2
225         .cprestore SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG
226 $LCFI4:
227         REG_S   $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)       # Save s0
228         REG_S   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Save frame pointer
229         REG_S   ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)        # Save return address
230 $LCFI6:
231         move    $fp, $sp
232
233 $LCFI7:
234         # Store all possible argument registers. If there are more than
235         # four arguments, then they should be stored above where we put $7.
236         REG_S   $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
237         REG_S   $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
238         REG_S   $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
239         REG_S   $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
240
241         # Load ABI enum to $16
242         REG_L   $16, 20($8)     # cif pointer follows tramp.
243         REG_L   $16, 0($16)     # abi is first member.
244
245         li      $13, 1          # FFI_O32
246         bne     $16, $13, 1f    # Skip fp save if FFI_O32_SOFT_FLOAT
247         
248         # Store all possible float/double registers.
249         s.d     $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
250         s.d     $f14, SIZEOF_FRAME2 -  8*FFI_SIZEOF_ARG($fp)
251 1:      
252         # Call ffi_closure_mips_inner_O32 to do the work.
253         la      $25, ffi_closure_mips_inner_O32
254         move    $4, $8   # Pointer to the ffi_closure
255         addu    $5, $fp, SIZEOF_FRAME2 -  6*FFI_SIZEOF_ARG
256         addu    $6, $fp, SIZEOF_FRAME2 +  0*FFI_SIZEOF_ARG
257         addu    $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
258         jal     $31, $25
259
260         # Load the return value into the appropriate register.
261         move    $8, $2
262         li      $9, FFI_TYPE_VOID
263         beq     $8, $9, closure_done
264
265         li      $13, 1          # FFI_O32
266         bne     $16, $13, 1f    # Skip fp restore if FFI_O32_SOFT_FLOAT
267
268         li      $9, FFI_TYPE_FLOAT
269         l.s     $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
270         beq     $8, $9, closure_done
271
272         li      $9, FFI_TYPE_DOUBLE
273         l.d     $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
274         beq     $8, $9, closure_done
275 1:      
276         li      $9, FFI_TYPE_SINT64
277         REG_L   $3, SIZEOF_FRAME2 - 5*FFI_SIZEOF_ARG($fp)
278         beq     $8, $9, integer
279         li      $9, FFI_TYPE_UINT64
280         beq     $8, $9, integer
281
282 integer:
283         REG_L   $2, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
284
285 closure_done:
286         # Epilogue
287         move    $sp, $fp
288         REG_L   $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)       # Restore s0
289         REG_L   $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)       # Restore frame pointer
290         REG_L   ra,  SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)       # Restore return address
291         ADDU    $sp, SIZEOF_FRAME2
292         j       ra
293 $LFE1:
294         .end    ffi_closure_O32
295
296 /* DWARF-2 unwind info. */
297
298         .section        .eh_frame,"a",@progbits
299 $Lframe0:
300         .4byte  $LECIE0-$LSCIE0  # Length of Common Information Entry
301 $LSCIE0:
302         .4byte  0x0      # CIE Identifier Tag
303         .byte   0x1      # CIE Version
304         .ascii "zR\0"    # CIE Augmentation
305         .uleb128 0x1     # CIE Code Alignment Factor
306         .sleb128 4       # CIE Data Alignment Factor
307         .byte   0x1f     # CIE RA Column
308         .uleb128 0x1     # Augmentation size
309         .byte   0x1b     # FDE Encoding (pcrel sdata4)
310         .byte   0xc      # DW_CFA_def_cfa
311         .uleb128 0x1d
312         .uleb128 0x0
313         .align  2
314 $LECIE0:
315 $LSFDE0:
316         .4byte  $LEFDE0-$LASFDE0         # FDE Length
317 $LASFDE0:
318         .4byte  $LASFDE0-$Lframe0        # FDE CIE offset
319         .4byte  $LFB0-.  # FDE initial location
320         .4byte  $LFE0-$LFB0      # FDE address range
321         .uleb128 0x0     # Augmentation size
322         .byte   0x4      # DW_CFA_advance_loc4
323         .4byte  $LCFI0-$LFB0
324         .byte   0xe      # DW_CFA_def_cfa_offset
325         .uleb128 0x18
326         .byte   0x4      # DW_CFA_advance_loc4
327         .4byte  $LCFI2-$LCFI0
328         .byte   0x11     # DW_CFA_offset_extended_sf
329         .uleb128 0x1e    # $fp
330         .sleb128 -2      # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
331         .byte   0x11     # DW_CFA_offset_extended_sf
332         .uleb128 0x1f    # $ra
333         .sleb128 -1      # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
334         .byte   0x4      # DW_CFA_advance_loc4
335         .4byte  $LCFI3-$LCFI2
336         .byte   0xc      # DW_CFA_def_cfa
337         .uleb128 0x1e
338         .uleb128 0x18
339         .align  2
340 $LEFDE0:
341 $LSFDE1:
342         .4byte  $LEFDE1-$LASFDE1         # FDE Length
343 $LASFDE1:
344         .4byte  $LASFDE1-$Lframe0        # FDE CIE offset
345         .4byte  $LFB1-.  # FDE initial location
346         .4byte  $LFE1-$LFB1      # FDE address range
347         .uleb128 0x0     # Augmentation size
348         .byte   0x4      # DW_CFA_advance_loc4
349         .4byte  $LCFI4-$LFB1
350         .byte   0xe      # DW_CFA_def_cfa_offset
351         .uleb128 0x38
352         .byte   0x4      # DW_CFA_advance_loc4
353         .4byte  $LCFI6-$LCFI4
354         .byte   0x11     # DW_CFA_offset_extended_sf
355         .uleb128 0x10    # $16
356         .sleb128 -3      # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
357         .byte   0x11     # DW_CFA_offset_extended_sf
358         .uleb128 0x1e    # $fp
359         .sleb128 -2      # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
360         .byte   0x11     # DW_CFA_offset_extended_sf
361         .uleb128 0x1f    # $ra
362         .sleb128 -1      # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
363         .byte   0x4      # DW_CFA_advance_loc4
364         .4byte  $LCFI7-$LCFI6
365         .byte   0xc      # DW_CFA_def_cfa
366         .uleb128 0x1e
367         .uleb128 0x38
368         .align  2
369 $LEFDE1:
370
371 #endif