/* -----------------------------------------------------------------------
- o32.S - Copyright (c) 1996, 1998 Red Hat, Inc.
+ o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
MIPS Foreign Function Interface
#define bytes a2
#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 )
+#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
+#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
+#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
+#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
+ .abicalls
.text
.align 2
.globl ffi_call_O32
ffi_call_O32:
$LFB0:
# Prologue
- SUBU $sp, SIZEOF_FRAME # Frame size
+ SUBU $sp, SIZEOF_FRAME # Frame size
$LCFI0:
- REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+ REG_S $fp, FP_OFF($sp) # Save frame pointer
$LCFI1:
- REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+ REG_S ra, RA_OFF($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
+ move t9, callback # callback function pointer
+ REG_S flags, A3_OFF($fp) # flags
# 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
+ blt bytes, v0, sixteen
-bigger:
- ADDU t0, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
- and v0, t0, -2 * FFI_SIZEOF_ARG # to an 8 byte boundry
+ ADDU v0, bytes, 7 # make sure it is aligned
+ and v0, -8 # to an 8 byte boundry
sixteen:
- SUBU $sp, $sp, v0 # move the stack pointer to reflect the
+ SUBU $sp, v0 # move the stack pointer to reflect the
# arg space
ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
- ADDU a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
- jal t9
+ jalr t9
- REG_L t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # load the flags word
- add t2, t0, 0 # and copy it into t2
-
+ REG_L t0, A3_OFF($fp) # load the flags word
+ SRL t2, t0, 4 # shift our arg info
and t0, ((1<<4)-1) # mask out the return type
- SRL t2, 4 # shift our arg info
- ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+ ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
bnez t0, pass_d # make it quick for int
- REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
- REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
+ REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
+ REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
REG_L a2, 2*FFI_SIZEOF_ARG($sp)
REG_L a3, 3*FFI_SIZEOF_ARG($sp)
b call_it
beqz t1, noretval
bne t2, FFI_TYPE_INT, retlonglong
- jal t9
+ jalr 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
+ jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
REG_S v1, 4(t0)
REG_S v0, 0(t0)
retfloat:
bne t2, FFI_TYPE_FLOAT, retdouble
- jal t9
+ jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
s.s $f0, 0(t0)
b epilogue
retdouble:
bne t2, FFI_TYPE_DOUBLE, noretval
- jal t9
+ jalr t9
REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
s.d $f0, 0(t0)
b epilogue
noretval:
- jal t9
+ jalr 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
+ REG_L $fp, FP_OFF($sp) # Restore frame pointer
+ REG_L ra, RA_OFF($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
j ra
$LFE0:
/* 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. */
+ then decodes them.
+
+ Stack layout:
+
+ 14 - Start of parameters, original sp
+ 13 - ra save
+ 12 - fp save
+ 11 - $16 (s0) save
+ 10 - cprestore
+ 9 - return value high (v1)
+ 8 - return value low (v0)
+ 7 - f14 (le high, be low)
+ 6 - f14 (le low, be high)
+ 5 - f12 (le high, be low)
+ 4 - f12 (le low, be high)
+ 3 - Called function a3 save
+ 2 - Called function a2 save
+ 1 - Called function a1 save
+ 0 - Called function a0 save our sp, fp point here
+ */
+
+#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
+#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
+#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
+#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
+#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
+#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
+#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
+#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
+#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
+#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
+#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
+#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
+#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
+#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
+#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
.text
.align 2
ffi_closure_O32:
$LFB1:
# Prologue
- .frame $fp, SIZEOF_FRAME2, $31
+ .frame $fp, SIZEOF_FRAME2, ra
.set noreorder
- .cpload $25
+ .cpload t9
.set reorder
SUBU $sp, SIZEOF_FRAME2
- .cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG
+ .cprestore GP_OFF2
$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
+ REG_S $16, S0_OFF2($sp) # Save s0
+ REG_S $fp, FP_OFF2($sp) # Save frame pointer
+ REG_S ra, RA_OFF2($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)
-
+ # four arguments, then they are stored above where we put a3.
+ REG_S a0, A0_OFF2($fp)
+ REG_S a1, A1_OFF2($fp)
+ REG_S a2, A2_OFF2($fp)
+ REG_S a3, A3_OFF2($fp)
+
+ # Load ABI enum to s0
+ REG_L $16, 20($8) # cif pointer follows tramp.
+ REG_L $16, 0($16) # abi is first member.
+
+ li $13, 1 # FFI_O32
+ bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
+
# 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)
-
+ s.d $f12, FA_0_0_OFF2($fp)
+ s.d $f14, FA_1_0_OFF2($fp)
+1:
# 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
+ la t9, ffi_closure_mips_inner_O32
+ move a0, $8 # Pointer to the ffi_closure
+ addu a1, $fp, V0_OFF2
+ addu a2, $fp, A0_OFF2
+ addu a3, $fp, FA_0_0_OFF2
+ jalr t9
# Load the return value into the appropriate register.
move $8, $2
li $9, FFI_TYPE_VOID
beq $8, $9, closure_done
+ li $13, 1 # FFI_O32
+ bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
+
li $9, FFI_TYPE_FLOAT
- l.s $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+ l.s $f0, V0_OFF2($fp)
beq $8, $9, closure_done
li $9, FFI_TYPE_DOUBLE
- l.d $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
+ l.d $f0, V0_OFF2($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)
+1:
+ REG_L $3, V1_OFF2($fp)
+ REG_L $2, V0_OFF2($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
+ REG_L $16, S0_OFF2($sp) # Restore s0
+ REG_L $fp, FP_OFF2($sp) # Restore frame pointer
+ REG_L ra, RA_OFF2($sp) # Restore return address
ADDU $sp, SIZEOF_FRAME2
j ra
$LFE1:
.sleb128 4 # CIE Data Alignment Factor
.byte 0x1f # CIE RA Column
.uleb128 0x1 # Augmentation size
- .byte 0x1b # FDE Encoding (pcrel sdata4)
+ .byte 0x00 # FDE Encoding (absptr)
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1d
.uleb128 0x0
.4byte $LEFDE0-$LASFDE0 # FDE Length
$LASFDE0:
.4byte $LASFDE0-$Lframe0 # FDE CIE offset
- .4byte $LFB0-. # FDE initial location
+ .4byte $LFB0 # FDE initial location
.4byte $LFE0-$LFB0 # FDE address range
.uleb128 0x0 # Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LEFDE1-$LASFDE1 # FDE Length
$LASFDE1:
.4byte $LASFDE1-$Lframe0 # FDE CIE offset
- .4byte $LFB1-. # FDE initial location
+ .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
+ .uleb128 0x38
.byte 0x4 # DW_CFA_advance_loc4
.4byte $LCFI6-$LCFI4
.byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x10 # $16
+ .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
+ .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
.4byte $LCFI7-$LCFI6
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1e
- .uleb128 0x28
+ .uleb128 0x38
.align 2
$LEFDE1: