n32.S revision 056e203a7aec4c87c077192ad776b532a3d0305f
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, 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 n32 */ 31 32#if defined(FFI_MIPS_N32) 33 34#define callback a0 35#define bytes a2 36#define flags a3 37#define raddr a4 38#define fn a5 39 40#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) 41 42 .abicalls 43 .text 44 .align 2 45 .globl ffi_call_N32 46 .ent ffi_call_N32 47ffi_call_N32: 48 49 # Prologue 50 SUBU $sp, SIZEOF_FRAME # Frame size 51 REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer 52 REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address 53 move $fp, $sp 54 55 move t9, callback # callback function pointer 56 REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes 57 REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags 58 REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr 59 REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn 60 61 # Allocate at least 4 words in the argstack 62 move v0, bytes 63 bge bytes, 4 * FFI_SIZEOF_ARG, bigger 64 LI v0, 4 * FFI_SIZEOF_ARG 65 b sixteen 66 67 bigger: 68 ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned 69 and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. 70 71sixteen: 72 SUBU $sp, $sp, v0 # move the stack pointer to reflect the 73 # arg space 74 75 ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG 76 ADDU a3, $fp, 3 * FFI_SIZEOF_ARG 77 78 # Call ffi_prep_args 79 jal t9 80 81 # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args 82 83 # Copy the stack pointer to t9 84 move t9, $sp 85 86 # Fix the stack if there are more than 8 64bit slots worth 87 # of arguments. 88 89 # Load the number of bytes 90 REG_L t6, 2*FFI_SIZEOF_ARG($fp) 91 92 # Is it bigger than 8 * FFI_SIZEOF_ARG? 93 dadd t7, $0, 8 * FFI_SIZEOF_ARG 94 dsub t8, t6, t7 95 bltz t8, loadregs 96 97 add t9, t9, t8 98 99loadregs: 100 101 REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word 102 add t6, t4, 0 # and copy it into t6 103 104 and t4, ((1<<FFI_FLAG_BITS)-1) 105 bnez t4, arg1_floatp 106 REG_L a0, 0*FFI_SIZEOF_ARG(t9) 107 b arg1_next 108arg1_floatp: 109 bne t4, FFI_TYPE_FLOAT, arg1_doublep 110 l.s $f12, 0*FFI_SIZEOF_ARG(t9) 111 b arg1_next 112arg1_doublep: 113 l.d $f12, 0*FFI_SIZEOF_ARG(t9) 114arg1_next: 115 116 add t4, t6, 0 117 SRL t4, 1*FFI_FLAG_BITS 118 and t4, ((1<<FFI_FLAG_BITS)-1) 119 bnez t4, arg2_floatp 120 REG_L a1, 1*FFI_SIZEOF_ARG(t9) 121 b arg2_next 122arg2_floatp: 123 bne t4, FFI_TYPE_FLOAT, arg2_doublep 124 l.s $f13, 1*FFI_SIZEOF_ARG(t9) 125 b arg2_next 126arg2_doublep: 127 l.d $f13, 1*FFI_SIZEOF_ARG(t9) 128arg2_next: 129 130 add t4, t6, 0 131 SRL t4, 2*FFI_FLAG_BITS 132 and t4, ((1<<FFI_FLAG_BITS)-1) 133 bnez t4, arg3_floatp 134 REG_L a2, 2*FFI_SIZEOF_ARG(t9) 135 b arg3_next 136arg3_floatp: 137 bne t4, FFI_TYPE_FLOAT, arg3_doublep 138 l.s $f14, 2*FFI_SIZEOF_ARG(t9) 139 b arg3_next 140arg3_doublep: 141 l.d $f14, 2*FFI_SIZEOF_ARG(t9) 142arg3_next: 143 144 add t4, t6, 0 145 SRL t4, 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 150arg4_floatp: 151 bne t4, FFI_TYPE_FLOAT, arg4_doublep 152 l.s $f15, 3*FFI_SIZEOF_ARG(t9) 153 b arg4_next 154arg4_doublep: 155 l.d $f15, 3*FFI_SIZEOF_ARG(t9) 156arg4_next: 157 158 add t4, t6, 0 159 SRL t4, 4*FFI_FLAG_BITS 160 and t4, ((1<<FFI_FLAG_BITS)-1) 161 bnez t4, arg5_floatp 162 REG_L a4, 4*FFI_SIZEOF_ARG(t9) 163 b arg5_next 164arg5_floatp: 165 bne t4, FFI_TYPE_FLOAT, arg5_doublep 166 l.s $f16, 4*FFI_SIZEOF_ARG(t9) 167 b arg5_next 168arg5_doublep: 169 l.d $f16, 4*FFI_SIZEOF_ARG(t9) 170arg5_next: 171 172 add t4, t6, 0 173 SRL t4, 5*FFI_FLAG_BITS 174 and t4, ((1<<FFI_FLAG_BITS)-1) 175 bnez t4, arg6_floatp 176 REG_L a5, 5*FFI_SIZEOF_ARG(t9) 177 b arg6_next 178arg6_floatp: 179 bne t4, FFI_TYPE_FLOAT, arg6_doublep 180 l.s $f17, 5*FFI_SIZEOF_ARG(t9) 181 b arg6_next 182arg6_doublep: 183 l.d $f17, 5*FFI_SIZEOF_ARG(t9) 184arg6_next: 185 186 add t4, t6, 0 187 SRL t4, 6*FFI_FLAG_BITS 188 and t4, ((1<<FFI_FLAG_BITS)-1) 189 bnez t4, arg7_floatp 190 REG_L a6, 6*FFI_SIZEOF_ARG(t9) 191 b arg7_next 192arg7_floatp: 193 bne t4, FFI_TYPE_FLOAT, arg7_doublep 194 l.s $f18, 6*FFI_SIZEOF_ARG(t9) 195 b arg7_next 196arg7_doublep: 197 l.d $f18, 6*FFI_SIZEOF_ARG(t9) 198arg7_next: 199 200 add t4, t6, 0 201 SRL t4, 7*FFI_FLAG_BITS 202 and t4, ((1<<FFI_FLAG_BITS)-1) 203 bnez t4, arg8_floatp 204 REG_L a7, 7*FFI_SIZEOF_ARG(t9) 205 b arg8_next 206arg8_floatp: 207 bne t4, FFI_TYPE_FLOAT, arg8_doublep 208 l.s $f19, 7*FFI_SIZEOF_ARG(t9) 209 b arg8_next 210arg8_doublep: 211 l.d $f19, 7*FFI_SIZEOF_ARG(t9) 212arg8_next: 213 214callit: 215 # Load the function pointer 216 REG_L t9, 5*FFI_SIZEOF_ARG($fp) 217 218 # If the return value pointer is NULL, assume no return value. 219 REG_L t5, 4*FFI_SIZEOF_ARG($fp) 220 beqz t5, noretval 221 222 # Shift the return type flag over 223 SRL t6, 8*FFI_FLAG_BITS 224 225 bne t6, FFI_TYPE_INT, retfloat 226 jal t9 227 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 228 REG_S v0, 0(t4) 229 b epilogue 230 231retfloat: 232 bne t6, FFI_TYPE_FLOAT, retdouble 233 jal t9 234 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 235 s.s $f0, 0(t4) 236 b epilogue 237 238retdouble: 239 bne t6, FFI_TYPE_DOUBLE, retstruct_d 240 jal t9 241 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 242 s.d $f0, 0(t4) 243 b epilogue 244 245retstruct_d: 246 bne t6, FFI_TYPE_STRUCT_D, retstruct_f 247 jal t9 248 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 249 s.d $f0, 0(t4) 250 b epilogue 251 252retstruct_f: 253 bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d 254 jal t9 255 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 256 s.s $f0, 0(t4) 257 b epilogue 258 259retstruct_d_d: 260 bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f 261 jal t9 262 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 263 s.d $f0, 0(t4) 264 s.d $f2, 8(t4) 265 b epilogue 266 267retstruct_f_f: 268 bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f 269 jal t9 270 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 271 s.s $f0, 0(t4) 272 s.s $f2, 4(t4) 273 b epilogue 274 275retstruct_d_f: 276 bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d 277 jal t9 278 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 279 s.d $f0, 0(t4) 280 s.s $f2, 8(t4) 281 b epilogue 282 283retstruct_f_d: 284 bne t6, FFI_TYPE_STRUCT_FD, retstruct_small 285 jal t9 286 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 287 s.s $f0, 0(t4) 288 s.d $f2, 8(t4) 289 b epilogue 290 291retstruct_small: 292 bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2 293 jal t9 294 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 295 REG_S v0, 0(t4) 296 b epilogue 297 298retstruct_small2: 299 bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct 300 jal t9 301 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 302 REG_S v0, 0(t4) 303 REG_S v1, 8(t4) 304 b epilogue 305 306retstruct: 307noretval: 308 jal t9 309 310 # Epilogue 311epilogue: 312 move $sp, $fp 313 REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer 314 REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address 315 ADDU $sp, SIZEOF_FRAME # Fix stack pointer 316 j ra 317 318 .end ffi_call_N32 319 320#endif 321