github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/mips/o32.S (about)

     1  /* -----------------------------------------------------------------------
     2     o32.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,
    18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    24     DEALINGS IN THE SOFTWARE.
    25     ----------------------------------------------------------------------- */
    26  
    27  #define LIBFFI_ASM	
    28  #include <fficonfig.h>
    29  #include <ffi.h>
    30  
    31  /* Only build this code if we are compiling for o32 */	
    32  
    33  #if defined(FFI_MIPS_O32)
    34  	
    35  #define callback a0
    36  #define bytes	 a2
    37  #define flags	 a3
    38  		
    39  #define SIZEOF_FRAME	(4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
    40  #define A3_OFF		(SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
    41  #define FP_OFF		(SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
    42  #define RA_OFF		(SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
    43  
    44  	.abicalls
    45  	.text
    46  	.align	2
    47  	.globl	ffi_call_O32
    48  	.ent	ffi_call_O32
    49  ffi_call_O32:	
    50  $LFB0:
    51  	# Prologue
    52  	SUBU	$sp, SIZEOF_FRAME	# Frame size
    53  $LCFI0:
    54  	REG_S	$fp, FP_OFF($sp)	# Save frame pointer
    55  $LCFI1:
    56  	REG_S	ra, RA_OFF($sp)		# Save return address
    57  $LCFI2:
    58  	move	$fp, $sp
    59  
    60  $LCFI3:
    61  	move	t9, callback		# callback function pointer
    62  	REG_S	flags, A3_OFF($fp)	# flags
    63  
    64  	# Allocate at least 4 words in the argstack
    65  	LI	v0, 4 * FFI_SIZEOF_ARG
    66  	blt	bytes, v0, sixteen
    67  
    68  	ADDU	v0, bytes, 7	# make sure it is aligned 
    69  	and	v0, -8		# to an 8 byte boundry
    70  
    71  sixteen:
    72  	SUBU	$sp, v0		# move the stack pointer to reflect the
    73  				# arg space
    74  
    75  	ADDU	a0, $sp, 4 * FFI_SIZEOF_ARG
    76  
    77  	jalr	t9
    78  	
    79  	REG_L	t0, A3_OFF($fp)		# load the flags word
    80  	SRL	t2, t0, 4		# shift our arg info
    81  	and     t0, ((1<<4)-1)          # mask out the return type
    82  		
    83  	ADDU	$sp, 4 * FFI_SIZEOF_ARG		# adjust $sp to new args
    84  
    85  	bnez	t0, pass_d			# make it quick for int
    86  	REG_L	a0, 0*FFI_SIZEOF_ARG($sp)	# just go ahead and load the
    87  	REG_L	a1, 1*FFI_SIZEOF_ARG($sp)	# four regs.
    88  	REG_L	a2, 2*FFI_SIZEOF_ARG($sp)
    89  	REG_L	a3, 3*FFI_SIZEOF_ARG($sp)
    90  	b	call_it
    91  
    92  pass_d:
    93  	bne	t0, FFI_ARGS_D, pass_f
    94  	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    95  	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)	# passing a double
    96  	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
    97  	b	call_it
    98  
    99  pass_f:	
   100  	bne	t0, FFI_ARGS_F, pass_d_d
   101  	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
   102  	REG_L	a1,   1*FFI_SIZEOF_ARG($sp)	# passing a float
   103  	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)
   104  	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
   105  	b	call_it		
   106  
   107  pass_d_d:		
   108  	bne	t0, FFI_ARGS_DD, pass_f_f
   109  	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
   110  	l.d	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing two doubles
   111  	b	call_it
   112  
   113  pass_f_f:	
   114  	bne	t0, FFI_ARGS_FF, pass_d_f
   115  	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
   116  	l.s	$f14, 1*FFI_SIZEOF_ARG($sp)	# passing two floats
   117  	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)
   118  	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
   119  	b	call_it
   120  
   121  pass_d_f:		
   122  	bne	t0, FFI_ARGS_DF, pass_f_d
   123  	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
   124  	l.s	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing double and float
   125  	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
   126  	b	call_it
   127  
   128  pass_f_d:		
   129   # assume that the only other combination must be float then double
   130   #	bne	t0, FFI_ARGS_F_D, call_it
   131  	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
   132  	l.d	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing double and float
   133  
   134  call_it:	
   135  	# Load the function pointer
   136  	REG_L	t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
   137  
   138  	# If the return value pointer is NULL, assume no return value.
   139  	REG_L	t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
   140  	beqz	t1, noretval
   141  
   142  	bne     t2, FFI_TYPE_INT, retlonglong
   143  	jalr	t9
   144  	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
   145  	REG_S	v0, 0(t0)
   146  	b	epilogue
   147  
   148  retlonglong:
   149  	# Really any 64-bit int, signed or not.
   150  	bne	t2, FFI_TYPE_UINT64, retfloat
   151  	jalr	t9
   152  	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
   153  	REG_S	v1, 4(t0)
   154  	REG_S	v0, 0(t0)
   155  	b	epilogue
   156  
   157  retfloat:
   158  	bne     t2, FFI_TYPE_FLOAT, retdouble
   159  	jalr	t9
   160  	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
   161  	s.s	$f0, 0(t0)
   162  	b	epilogue
   163  
   164  retdouble:	
   165  	bne	t2, FFI_TYPE_DOUBLE, noretval
   166  	jalr	t9
   167  	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
   168  	s.d	$f0, 0(t0)
   169  	b	epilogue
   170  	
   171  noretval:	
   172  	jalr	t9
   173  	
   174  	# Epilogue
   175  epilogue:	
   176  	move	$sp, $fp	
   177  	REG_L	$fp, FP_OFF($sp)	# Restore frame pointer
   178  	REG_L	ra, RA_OFF($sp)		# Restore return address
   179  	ADDU	$sp, SIZEOF_FRAME	# Fix stack pointer
   180  	j	ra
   181  
   182  $LFE0:
   183  	.end	ffi_call_O32
   184  
   185  
   186  /* ffi_closure_O32. Expects address of the passed-in ffi_closure
   187  	in t4 ($12). Stores any arguments passed in registers onto the
   188  	stack, then calls ffi_closure_mips_inner_O32, which
   189  	then decodes them.
   190  	
   191  	Stack layout:
   192  
   193  	 3 - a3 save
   194  	 2 - a2 save
   195  	 1 - a1 save
   196  	 0 - a0 save, original sp
   197  	-1 - ra save
   198  	-2 - fp save
   199  	-3 - $16 (s0) save
   200  	-4 - cprestore
   201  	-5 - return value high (v1)
   202  	-6 - return value low (v0)
   203  	-7 - f14 (le high, be low)
   204  	-8 - f14 (le low, be high)
   205  	-9 - f12 (le high, be low)
   206         -10 - f12 (le low, be high)
   207         -11 - Called function a3 save
   208         -12 - Called function a2 save
   209         -13 - Called function a1 save
   210         -14 - Called function a0 save, our sp and fp point here
   211  	 */
   212  	
   213  #define SIZEOF_FRAME2	(14 * FFI_SIZEOF_ARG)
   214  #define A3_OFF2		(SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
   215  #define A2_OFF2		(SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
   216  #define A1_OFF2		(SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
   217  #define A0_OFF2		(SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
   218  #define RA_OFF2		(SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
   219  #define FP_OFF2		(SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
   220  #define S0_OFF2		(SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
   221  #define GP_OFF2		(SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
   222  #define V1_OFF2		(SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
   223  #define V0_OFF2		(SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
   224  #define FA_1_1_OFF2	(SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
   225  #define FA_1_0_OFF2	(SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
   226  #define FA_0_1_OFF2	(SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
   227  #define FA_0_0_OFF2	(SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
   228  
   229  	.text
   230  	.align	2
   231  	.globl	ffi_closure_O32
   232  	.ent	ffi_closure_O32
   233  ffi_closure_O32:
   234  $LFB1:
   235  	# Prologue
   236  	.frame	$fp, SIZEOF_FRAME2, ra
   237  	.set	noreorder
   238  	.cpload	t9
   239  	.set	reorder
   240  	SUBU	$sp, SIZEOF_FRAME2
   241  	.cprestore GP_OFF2
   242  $LCFI4:
   243  	REG_S	$16, S0_OFF2($sp)	 # Save s0
   244  	REG_S	$fp, FP_OFF2($sp)	 # Save frame pointer
   245  	REG_S	ra, RA_OFF2($sp)	 # Save return address
   246  $LCFI6:
   247  	move	$fp, $sp
   248  
   249  $LCFI7:
   250  	# Store all possible argument registers. If there are more than
   251  	# four arguments, then they are stored above where we put a3.
   252  	REG_S	a0, A0_OFF2($fp)
   253  	REG_S	a1, A1_OFF2($fp)
   254  	REG_S	a2, A2_OFF2($fp)
   255  	REG_S	a3, A3_OFF2($fp)
   256  
   257  	# Load ABI enum to s0
   258  	REG_L	$16, 20($12)	# cif pointer follows tramp.
   259  	REG_L	$16, 0($16)	# abi is first member.
   260  
   261  	li	$13, 1		# FFI_O32
   262  	bne	$16, $13, 1f	# Skip fp save if FFI_O32_SOFT_FLOAT
   263  	
   264  	# Store all possible float/double registers.
   265  	s.d	$f12, FA_0_0_OFF2($fp)
   266  	s.d	$f14, FA_1_0_OFF2($fp)
   267  1:	
   268  	# Call ffi_closure_mips_inner_O32 to do the work.
   269  	la	t9, ffi_closure_mips_inner_O32
   270  	move	a0, $12	 # Pointer to the ffi_closure
   271  	addu	a1, $fp, V0_OFF2
   272  	addu	a2, $fp, A0_OFF2
   273  	addu	a3, $fp, FA_0_0_OFF2
   274  	jalr	t9
   275  
   276  	# Load the return value into the appropriate register.
   277  	move	$8, $2
   278  	li	$9, FFI_TYPE_VOID
   279  	beq	$8, $9, closure_done
   280  
   281  	li	$13, 1		# FFI_O32
   282  	bne	$16, $13, 1f	# Skip fp restore if FFI_O32_SOFT_FLOAT
   283  
   284  	li	$9, FFI_TYPE_FLOAT
   285  	l.s	$f0, V0_OFF2($fp)
   286  	beq	$8, $9, closure_done
   287  
   288  	li	$9, FFI_TYPE_DOUBLE
   289  	l.d	$f0, V0_OFF2($fp)
   290  	beq	$8, $9, closure_done
   291  1:	
   292  	REG_L	$3, V1_OFF2($fp)
   293  	REG_L	$2, V0_OFF2($fp)
   294  
   295  closure_done:
   296  	# Epilogue
   297  	move	$sp, $fp
   298  	REG_L	$16, S0_OFF2($sp)	 # Restore s0
   299  	REG_L	$fp, FP_OFF2($sp)	 # Restore frame pointer
   300  	REG_L	ra,  RA_OFF2($sp)	 # Restore return address
   301  	ADDU	$sp, SIZEOF_FRAME2
   302  	j	ra
   303  $LFE1:
   304  	.end	ffi_closure_O32
   305  
   306  /* DWARF-2 unwind info. */
   307  
   308  	.section	.eh_frame,"a",@progbits
   309  $Lframe0:
   310  	.4byte	$LECIE0-$LSCIE0	 # Length of Common Information Entry
   311  $LSCIE0:
   312  	.4byte	0x0	 # CIE Identifier Tag
   313  	.byte	0x1	 # CIE Version
   314  	.ascii "zR\0"	 # CIE Augmentation
   315  	.uleb128 0x1	 # CIE Code Alignment Factor
   316  	.sleb128 4	 # CIE Data Alignment Factor
   317  	.byte	0x1f	 # CIE RA Column
   318  	.uleb128 0x1	 # Augmentation size
   319  	.byte	0x00	 # FDE Encoding (absptr)
   320  	.byte	0xc	 # DW_CFA_def_cfa
   321  	.uleb128 0x1d
   322  	.uleb128 0x0
   323  	.align	2
   324  $LECIE0:
   325  $LSFDE0:
   326  	.4byte	$LEFDE0-$LASFDE0	 # FDE Length
   327  $LASFDE0:
   328  	.4byte	$LASFDE0-$Lframe0	 # FDE CIE offset
   329  	.4byte	$LFB0	 # FDE initial location
   330  	.4byte	$LFE0-$LFB0	 # FDE address range
   331  	.uleb128 0x0	 # Augmentation size
   332  	.byte	0x4	 # DW_CFA_advance_loc4
   333  	.4byte	$LCFI0-$LFB0
   334  	.byte	0xe	 # DW_CFA_def_cfa_offset
   335  	.uleb128 0x18
   336  	.byte	0x4	 # DW_CFA_advance_loc4
   337  	.4byte	$LCFI2-$LCFI0
   338  	.byte	0x11	 # DW_CFA_offset_extended_sf
   339  	.uleb128 0x1e	 # $fp
   340  	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
   341  	.byte	0x11	 # DW_CFA_offset_extended_sf
   342  	.uleb128 0x1f	 # $ra
   343  	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
   344  	.byte	0x4	 # DW_CFA_advance_loc4
   345  	.4byte	$LCFI3-$LCFI2
   346  	.byte	0xc	 # DW_CFA_def_cfa
   347  	.uleb128 0x1e
   348  	.uleb128 0x18
   349  	.align	2
   350  $LEFDE0:
   351  $LSFDE1:
   352  	.4byte	$LEFDE1-$LASFDE1	 # FDE Length
   353  $LASFDE1:
   354  	.4byte	$LASFDE1-$Lframe0	 # FDE CIE offset
   355  	.4byte	$LFB1	 # FDE initial location
   356  	.4byte	$LFE1-$LFB1	 # FDE address range
   357  	.uleb128 0x0	 # Augmentation size
   358  	.byte	0x4	 # DW_CFA_advance_loc4
   359  	.4byte	$LCFI4-$LFB1
   360  	.byte	0xe	 # DW_CFA_def_cfa_offset
   361  	.uleb128 0x38
   362  	.byte	0x4	 # DW_CFA_advance_loc4
   363  	.4byte	$LCFI6-$LCFI4
   364  	.byte	0x11	 # DW_CFA_offset_extended_sf
   365  	.uleb128 0x10	 # $16
   366  	.sleb128 -3	 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
   367  	.byte	0x11	 # DW_CFA_offset_extended_sf
   368  	.uleb128 0x1e	 # $fp
   369  	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
   370  	.byte	0x11	 # DW_CFA_offset_extended_sf
   371  	.uleb128 0x1f	 # $ra
   372  	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
   373  	.byte	0x4	 # DW_CFA_advance_loc4
   374  	.4byte	$LCFI7-$LCFI6
   375  	.byte	0xc	 # DW_CFA_def_cfa
   376  	.uleb128 0x1e
   377  	.uleb128 0x38
   378  	.align	2
   379  $LEFDE1:
   380  
   381  #endif