#include <ffi_common.h>
#include <stdlib.h>
+#include <sys/cachectl.h>
#if _MIPS_SIM == _ABIN32
#define FIX_ARGP \
case FFI_TYPE_DOUBLE:
cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
+ break;
default:
cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
break;
}
}
+
+#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if defined(FFI_MIPS_O32)
+extern void ffi_closure_O32(void);
+#endif /* FFI_MIPS_O32 */
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+ unsigned int fn;
+ unsigned int ctx = (unsigned int) closure;
+
+#if defined(FFI_MIPS_O32)
+ FFI_ASSERT(cif->abi == FFI_O32);
+ fn = (unsigned int) ffi_closure_O32;
+#else /* FFI_MIPS_N32 */
+ FFI_ASSERT(cif->abi == FFI_N32);
+ FFI_ASSERT(!"not implemented");
+#endif /* FFI_MIPS_O32 */
+
+ tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */
+ tramp[1] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */
+ tramp[2] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */
+ tramp[3] = 0x03200008; /* jr $25 */
+ tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* XXX this is available on Linux, but anything else? */
+ cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
+
+ return FFI_OK;
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer arguments
+ * (and, depending upon the arguments, some floating-point arguments
+ * as well). FPR is a pointer to the area where floating point
+ * registers have been saved, if any.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return type.
+ *
+ * Based on the similar routine for sparc.
+ */
+int
+ffi_closure_mips_inner_O32 (ffi_closure *closure,
+ void *rvalue, unsigned long *ar,
+ double *fpr)
+{
+ ffi_cif *cif;
+ void **avalue;
+ ffi_type **arg_types;
+ int i, avn, argn, seen_int;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (void *));
+
+ seen_int = 0;
+ argn = 0;
+
+ if (cif->flags == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) ar[0];
+ argn = 1;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ while (i < avn)
+ {
+ if (i < 2 && !seen_int &&
+ (arg_types[i]->type == FFI_TYPE_FLOAT ||
+ arg_types[i]->type == FFI_TYPE_DOUBLE))
+ {
+ avalue[i] = ((char *) &fpr[i]);
+ }
+ else
+ {
+ /* 8-byte arguments are always 8-byte aligned. */
+ if (arg_types[i]->size == 8 && (argn & 0x1))
+ argn++;
+ /* Float arguments take up two register slots. The float word
+ is the upper one. */
+ if (argn == 2 && arg_types[i]->type == FFI_TYPE_FLOAT)
+ argn++;
+ avalue[i] = ((char *) &ar[argn]);
+ seen_int = 1;
+ }
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ return cif->rtype->type;
+}
+
+#endif /* FFI_CLOSURES */
#define flags a3
#define SIZEOF_FRAME ( 4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
+#define SIZEOF_FRAME2 ( 8 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
.text
.align 2
.globl ffi_call_O32
.ent ffi_call_O32
ffi_call_O32:
-
+$LFB0:
# Prologue
SUBU $sp, SIZEOF_FRAME # Frame size
+$LCFI0:
REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+$LCFI1:
REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+$LCFI2:
move $fp, $sp
+$LCFI3:
move t9, callback # callback function pointer
REG_S flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
beqz t1, noretval
- bne t2, FFI_TYPE_INT, retfloat
+ bne t2, FFI_TYPE_INT, retlonglong
+ jal t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t0)
+ b epilogue
+
+retlonglong:
+ # Really any 64-bit int, signed or not.
+ bne t2, FFI_TYPE_UINT64, retfloat
jal t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ REG_S v1, 4(t0)
REG_S v0, 0(t0)
b epilogue
ADDU $sp, SIZEOF_FRAME # Fix stack pointer
j ra
+$LFE0:
.end ffi_call_O32
-
+
+
+/* ffi_closure_O32. Expects address of the passed-in ffi_closure
+ in t0. Stores any arguments passed in registers onto the
+ stack, then calls ffi_closure_mips_inner_O32, which
+ then decodes them. */
+
+ .text
+ .align 2
+ .globl ffi_closure_O32
+ .ent ffi_closure_O32
+ffi_closure_O32:
+$LFB1:
+ # Prologue
+ .frame $fp, SIZEOF_FRAME2, $31
+ .set noreorder
+ .cpload $25
+ .set reorder
+ SUBU $sp, SIZEOF_FRAME2
+ .cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG
+$LCFI4:
+ REG_S $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+$LCFI5:
+ REG_S ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Save return address
+$LCFI6:
+ move $fp, $sp
+
+$LCFI7:
+ # Store all possible argument registers. If there are more than
+ # four arguments, then they should be stored above where we put $7.
+ REG_S $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
+ REG_S $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
+ REG_S $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
+ REG_S $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
+
+ # Store all possible float/double registers.
+ s.d $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
+ s.d $f14, SIZEOF_FRAME2 - 8*FFI_SIZEOF_ARG($fp)
+
+ # Call ffi_closure_mips_inner_O32 to do the work.
+ la $25, ffi_closure_mips_inner_O32
+ move $4, $8 # Pointer to the ffi_closure
+ addu $5, $fp, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG
+ addu $6, $fp, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG
+ addu $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
+ jal $31, $25
+
+ # Load the return value into the appropriate register.
+ move $8, $2
+ li $9, FFI_TYPE_VOID
+ beq $8, $9, closure_done
+
+ li $9, FFI_TYPE_FLOAT
+ l.s $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+ beq $8, $9, closure_done
+
+ li $9, FFI_TYPE_DOUBLE
+ l.d $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+ beq $8, $9, closure_done
+
+ li $9, FFI_TYPE_SINT64
+ REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+ beq $8, $9, integer
+
+ li $9, FFI_TYPE_UINT64
+ REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
+ beq $8, $9, integer
+
+integer:
+ REG_L $2, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+
+closure_done:
+ # Epilogue
+ move $sp, $fp
+ REG_L $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
+ REG_L ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME2
+ j ra
+$LFE1:
+ .end ffi_closure_O32
+
+/* DWARF-2 unwind info. */
+
+ .section .eh_frame,"a",@progbits
+$Lframe0:
+ .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
+$LSCIE0:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 4 # CIE Data Alignment Factor
+ .byte 0x1f # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x1b # FDE Encoding (pcrel sdata4)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1d
+ .uleb128 0x0
+ .align 2
+$LECIE0:
+$LSFDE0:
+ .4byte $LEFDE0-$LASFDE0 # FDE Length
+$LASFDE0:
+ .4byte $LASFDE0-$Lframe0 # FDE CIE offset
+ .4byte $LFB0-. # FDE initial location
+ .4byte $LFE0-$LFB0 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI0-$LFB0
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x18
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI2-$LCFI0
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI3-$LCFI2
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 0x18
+ .align 2
+$LEFDE0:
+$LSFDE1:
+ .4byte $LEFDE1-$LASFDE1 # FDE Length
+$LASFDE1:
+ .4byte $LASFDE1-$Lframe0 # FDE CIE offset
+ .4byte $LFB1-. # FDE initial location
+ .4byte $LFE1-$LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI4-$LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x28
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI6-$LCFI4
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI7-$LCFI6
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 0x28
+ .align 2
+$LEFDE1:
+
#endif