OSDN Git Service

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