OSDN Git Service

2002-07-16 Bo Thorsen <bo@suse.de>
[pf3gnuchains/gcc-fork.git] / libffi / src / mips / o32.S
1 /* -----------------------------------------------------------------------
2    o32.S - Copyright (c) 1996, 1998  Cygnus Solutions
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 <ffi.h>
28
29 /* Only build this code if we are compiling for o32 */  
30
31 #if defined(FFI_MIPS_O32)
32         
33 #define callback a0
34 #define bytes    a2
35 #define flags    a3
36                 
37 #define SIZEOF_FRAME    ( 4 * SIZEOF_ARG + 2 * SIZEOF_ARG )
38
39         .text
40         .align  2
41         .globl  ffi_call_O32
42         .ent    ffi_call_O32
43 ffi_call_O32:   
44
45         # Prologue
46         SUBU    $sp, SIZEOF_FRAME                       # Frame size
47         REG_S   $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp)   # Save frame pointer
48         REG_S   ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp)    # Save return address
49         move    $fp, $sp
50
51         move    t9, callback    # callback function pointer
52         REG_S   flags, SIZEOF_FRAME + 3*SIZEOF_ARG($fp) # flags
53
54         # Allocate at least 4 words in the argstack
55         move    v0, bytes
56         bge     bytes, 4 * SIZEOF_ARG, bigger   
57         LI      v0, 4 * SIZEOF_ARG
58         b       sixteen
59
60 bigger: 
61         ADDU    t0, v0, 2 * SIZEOF_ARG -1       # make sure it is aligned 
62         and     v0, t0, -2 * SIZEOF_ARG         # to an 8 byte boundry
63
64 sixteen:
65         SUBU    $sp, $sp, v0    # move the stack pointer to reflect the
66                                 # arg space
67
68         ADDU    a0, $sp, 4 * SIZEOF_ARG
69         ADDU    a3, $fp, SIZEOF_FRAME + 3*SIZEOF_ARG
70
71         jal     t9
72         
73         REG_L   t0, SIZEOF_FRAME + 3*SIZEOF_ARG($fp)  # load the flags word
74         add     t2, t0, 0                          # and copy it into t2
75
76         and     t0, ((1<<4)-1)          # mask out the return type
77         SRL     t2, 4                   # shift our arg info
78                 
79         ADDU    $sp, $sp, 4 * SIZEOF_ARG        # adjust $sp to new args
80
81         bnez    t0, pass_d                      # make it quick for int
82         REG_L   a0, 0*SIZEOF_ARG($sp)           # just go ahead and load the
83         REG_L   a1, 1*SIZEOF_ARG($sp)           # four regs.
84         REG_L   a2, 2*SIZEOF_ARG($sp)
85         REG_L   a3, 3*SIZEOF_ARG($sp)
86         b       call_it
87
88 pass_d:
89         bne     t0, FFI_ARGS_D, pass_f
90         l.d     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
91         REG_L   a2,   2*SIZEOF_ARG($sp) # passing a double
92         REG_L   a3,   3*SIZEOF_ARG($sp)
93         b       call_it
94
95 pass_f: 
96         bne     t0, FFI_ARGS_F, pass_d_d
97         l.s     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
98         REG_L   a1,   1*SIZEOF_ARG($sp) # passing a float
99         REG_L   a2,   2*SIZEOF_ARG($sp)
100         REG_L   a3,   3*SIZEOF_ARG($sp)
101         b       call_it         
102
103 pass_d_d:               
104         bne     t0, FFI_ARGS_DD, pass_f_f
105         l.d     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
106         l.d     $f14, 2*SIZEOF_ARG($sp) # passing two doubles
107         b       call_it
108
109 pass_f_f:       
110         bne     t0, FFI_ARGS_FF, pass_d_f
111         l.s     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
112         l.s     $f14, 1*SIZEOF_ARG($sp) # passing two floats
113         REG_L   a2,   2*SIZEOF_ARG($sp)
114         REG_L   a3,   3*SIZEOF_ARG($sp)
115         b       call_it
116
117 pass_d_f:               
118         bne     t0, FFI_ARGS_DF, pass_f_d
119         l.d     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
120         l.s     $f14, 2*SIZEOF_ARG($sp) # passing double and float
121         REG_L   a3,   3*SIZEOF_ARG($sp)
122         b       call_it
123
124 pass_f_d:               
125  # assume that the only other combination must be float then double
126  #      bne     t0, FFI_ARGS_F_D, call_it
127         l.s     $f12, 0*SIZEOF_ARG($sp) # load $fp regs from args
128         l.d     $f14, 2*SIZEOF_ARG($sp) # passing double and float
129
130 call_it:        
131         # Load the function pointer
132         REG_L   t9, SIZEOF_FRAME + 5*SIZEOF_ARG($fp)
133
134         # If the return value pointer is NULL, assume no return value.
135         REG_L   t1, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
136         beqz    t1, noretval
137
138         bne     t2, FFI_TYPE_INT, retfloat
139         jal     t9
140         REG_L   t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
141         REG_S   v0, 0(t0)
142         b       epilogue
143
144 retfloat:
145         bne     t2, FFI_TYPE_FLOAT, retdouble
146         jal     t9
147         REG_L   t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
148         s.s     $f0, 0(t0)
149         b       epilogue
150
151 retdouble:      
152         bne     t2, FFI_TYPE_DOUBLE, noretval
153         jal     t9
154         REG_L   t0, SIZEOF_FRAME + 4*SIZEOF_ARG($fp)
155         s.d     $f0, 0(t0)
156         b       epilogue
157         
158 noretval:       
159         jal     t9
160         
161         # Epilogue
162 epilogue:       
163         move    $sp, $fp        
164         REG_L   $fp, SIZEOF_FRAME - 2*SIZEOF_ARG($sp) # Restore frame pointer
165         REG_L   ra, SIZEOF_FRAME - 1*SIZEOF_ARG($sp)  # Restore return address
166         ADDU    $sp, SIZEOF_FRAME                     # Fix stack pointer
167         j       ra
168
169         .end    ffi_call_O32
170         
171 #endif