| /* ----------------------------------------------------------------------- |
| n32.S - Copyright (c) 1996, 1998 Red Hat, Inc. |
| |
| MIPS Foreign Function Interface |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| ``Software''), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be included |
| in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| ----------------------------------------------------------------------- */ |
| |
| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| |
| /* Only build this code if we are compiling for n32 */ |
| |
| #if defined(FFI_MIPS_N32) |
| |
| #define callback a0 |
| #define bytes a2 |
| #define flags a3 |
| #define raddr a4 |
| #define fn a5 |
| |
| #define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) |
| |
| .text |
| .align 2 |
| .globl ffi_call_N32 |
| .ent ffi_call_N32 |
| ffi_call_N32: |
| |
| # Prologue |
| SUBU $sp, SIZEOF_FRAME # Frame size |
| REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer |
| REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address |
| move $fp, $sp |
| |
| move t9, callback # callback function pointer |
| REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes |
| REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags |
| REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr |
| REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn |
| |
| # Allocate at least 4 words in the argstack |
| move v0, bytes |
| bge bytes, 4 * FFI_SIZEOF_ARG, bigger |
| LI v0, 4 * FFI_SIZEOF_ARG |
| b sixteen |
| |
| bigger: |
| ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned |
| and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. |
| |
| sixteen: |
| SUBU $sp, $sp, v0 # move the stack pointer to reflect the |
| # arg space |
| |
| ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG |
| ADDU a3, $fp, 3 * FFI_SIZEOF_ARG |
| |
| # Call ffi_prep_args |
| jal t9 |
| |
| # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args |
| |
| # Copy the stack pointer to t9 |
| move t9, $sp |
| |
| # Fix the stack if there are more than 8 64bit slots worth |
| # of arguments. |
| |
| # Load the number of bytes |
| REG_L t6, 2*FFI_SIZEOF_ARG($fp) |
| |
| # Is it bigger than 8 * FFI_SIZEOF_ARG? |
| dadd t7, $0, 8 * FFI_SIZEOF_ARG |
| dsub t8, t6, t7 |
| bltz t8, loadregs |
| |
| add t9, t9, t8 |
| |
| loadregs: |
| |
| REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word |
| add t6, t4, 0 # and copy it into t6 |
| |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg1_floatp |
| REG_L a0, 0*FFI_SIZEOF_ARG(t9) |
| b arg1_next |
| arg1_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg1_doublep |
| l.s $f12, 0*FFI_SIZEOF_ARG(t9) |
| b arg1_next |
| arg1_doublep: |
| l.d $f12, 0*FFI_SIZEOF_ARG(t9) |
| arg1_next: |
| |
| add t4, t6, 0 |
| SRL t4, 1*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg2_floatp |
| REG_L a1, 1*FFI_SIZEOF_ARG(t9) |
| b arg2_next |
| arg2_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg2_doublep |
| l.s $f13, 1*FFI_SIZEOF_ARG(t9) |
| b arg2_next |
| arg2_doublep: |
| l.d $f13, 1*FFI_SIZEOF_ARG(t9) |
| arg2_next: |
| |
| add t4, t6, 0 |
| SRL t4, 2*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg3_floatp |
| REG_L a2, 2*FFI_SIZEOF_ARG(t9) |
| b arg3_next |
| arg3_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg3_doublep |
| l.s $f14, 2*FFI_SIZEOF_ARG(t9) |
| b arg3_next |
| arg3_doublep: |
| l.d $f14, 2*FFI_SIZEOF_ARG(t9) |
| arg3_next: |
| |
| add t4, t6, 0 |
| SRL t4, 3*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg4_floatp |
| REG_L a3, 3*FFI_SIZEOF_ARG(t9) |
| b arg4_next |
| arg4_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg4_doublep |
| l.s $f15, 3*FFI_SIZEOF_ARG(t9) |
| b arg4_next |
| arg4_doublep: |
| l.d $f15, 3*FFI_SIZEOF_ARG(t9) |
| arg4_next: |
| |
| add t4, t6, 0 |
| SRL t4, 4*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg5_floatp |
| REG_L a4, 4*FFI_SIZEOF_ARG(t9) |
| b arg5_next |
| arg5_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg5_doublep |
| l.s $f16, 4*FFI_SIZEOF_ARG(t9) |
| b arg5_next |
| arg5_doublep: |
| l.d $f16, 4*FFI_SIZEOF_ARG(t9) |
| arg5_next: |
| |
| add t4, t6, 0 |
| SRL t4, 5*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg6_floatp |
| REG_L a5, 5*FFI_SIZEOF_ARG(t9) |
| b arg6_next |
| arg6_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg6_doublep |
| l.s $f17, 5*FFI_SIZEOF_ARG(t9) |
| b arg6_next |
| arg6_doublep: |
| l.d $f17, 5*FFI_SIZEOF_ARG(t9) |
| arg6_next: |
| |
| add t4, t6, 0 |
| SRL t4, 6*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg7_floatp |
| REG_L a6, 6*FFI_SIZEOF_ARG(t9) |
| b arg7_next |
| arg7_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg7_doublep |
| l.s $f18, 6*FFI_SIZEOF_ARG(t9) |
| b arg7_next |
| arg7_doublep: |
| l.d $f18, 6*FFI_SIZEOF_ARG(t9) |
| arg7_next: |
| |
| add t4, t6, 0 |
| SRL t4, 7*FFI_FLAG_BITS |
| and t4, ((1<<FFI_FLAG_BITS)-1) |
| bnez t4, arg8_floatp |
| REG_L a7, 7*FFI_SIZEOF_ARG(t9) |
| b arg8_next |
| arg8_floatp: |
| bne t4, FFI_TYPE_FLOAT, arg8_doublep |
| l.s $f19, 7*FFI_SIZEOF_ARG(t9) |
| b arg8_next |
| arg8_doublep: |
| l.d $f19, 7*FFI_SIZEOF_ARG(t9) |
| arg8_next: |
| |
| callit: |
| # Load the function pointer |
| REG_L t9, 5*FFI_SIZEOF_ARG($fp) |
| |
| # If the return value pointer is NULL, assume no return value. |
| REG_L t5, 4*FFI_SIZEOF_ARG($fp) |
| beqz t5, noretval |
| |
| # Shift the return type flag over |
| SRL t6, 8*FFI_FLAG_BITS |
| |
| bne t6, FFI_TYPE_INT, retfloat |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| REG_S v0, 0(t4) |
| b epilogue |
| |
| retfloat: |
| bne t6, FFI_TYPE_FLOAT, retdouble |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.s $f0, 0(t4) |
| b epilogue |
| |
| retdouble: |
| bne t6, FFI_TYPE_DOUBLE, retstruct_d |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.d $f0, 0(t4) |
| b epilogue |
| |
| retstruct_d: |
| bne t6, FFI_TYPE_STRUCT_D, retstruct_f |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.d $f0, 0(t4) |
| b epilogue |
| |
| retstruct_f: |
| bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.s $f0, 0(t4) |
| b epilogue |
| |
| retstruct_d_d: |
| bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.d $f0, 0(t4) |
| s.d $f2, 8(t4) |
| b epilogue |
| |
| retstruct_f_f: |
| bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.s $f0, 0(t4) |
| s.s $f2, 4(t4) |
| b epilogue |
| |
| retstruct_d_f: |
| bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.d $f0, 0(t4) |
| s.s $f2, 8(t4) |
| b epilogue |
| |
| retstruct_f_d: |
| bne t6, FFI_TYPE_STRUCT_FD, retstruct_small |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| s.s $f0, 0(t4) |
| s.d $f2, 8(t4) |
| b epilogue |
| |
| retstruct_small: |
| bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2 |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| REG_S v0, 0(t4) |
| b epilogue |
| |
| retstruct_small2: |
| bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct |
| jal t9 |
| REG_L t4, 4*FFI_SIZEOF_ARG($fp) |
| REG_S v0, 0(t4) |
| REG_S v1, 8(t4) |
| b epilogue |
| |
| retstruct: |
| noretval: |
| jal t9 |
| |
| # Epilogue |
| epilogue: |
| move $sp, $fp |
| REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer |
| REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address |
| ADDU $sp, SIZEOF_FRAME # Fix stack pointer |
| j ra |
| |
| .end ffi_call_N32 |
| |
| #endif |