github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/runtime/asm_ppc64x.s (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build ppc64 ppc64le
     6  
     7  #include "go_asm.h"
     8  #include "go_tls.h"
     9  #include "funcdata.h"
    10  #include "textflag.h"
    11  #include "asm_ppc64x.h"
    12  
    13  TEXT runtime·rt0_go(SB),NOSPLIT,$0
    14  	// R1 = stack; R3 = argc; R4 = argv; R13 = C TLS base pointer
    15  
    16  	// initialize essential registers
    17  	BL	runtime·reginit(SB)
    18  
    19  	SUB	$(FIXED_FRAME+16), R1
    20  	MOVD	R2, 24(R1)		// stash the TOC pointer away again now we've created a new frame
    21  	MOVW	R3, FIXED_FRAME+0(R1)	// argc
    22  	MOVD	R4, FIXED_FRAME+8(R1)	// argv
    23  
    24  	// create istack out of the given (operating system) stack.
    25  	// _cgo_init may update stackguard.
    26  	MOVD	$runtime·g0(SB), g
    27  	MOVD	$(-64*1024), R31
    28  	ADD	R31, R1, R3
    29  	MOVD	R3, g_stackguard0(g)
    30  	MOVD	R3, g_stackguard1(g)
    31  	MOVD	R3, (g_stack+stack_lo)(g)
    32  	MOVD	R1, (g_stack+stack_hi)(g)
    33  
    34  	// if there is a _cgo_init, call it using the gcc ABI.
    35  	MOVD	_cgo_init(SB), R12
    36  	CMP	R0, R12
    37  	BEQ	nocgo
    38  	MOVD	R12, CTR		// r12 = "global function entry point"
    39  	MOVD	R13, R5			// arg 2: TLS base pointer
    40  	MOVD	$setg_gcc<>(SB), R4 	// arg 1: setg
    41  	MOVD	g, R3			// arg 0: G
    42  	// C functions expect 32 bytes of space on caller stack frame
    43  	// and a 16-byte aligned R1
    44  	MOVD	R1, R14			// save current stack
    45  	SUB	$32, R1			// reserve 32 bytes
    46  	RLDCR	$0, R1, $~15, R1	// 16-byte align
    47  	BL	(CTR)			// may clobber R0, R3-R12
    48  	MOVD	R14, R1			// restore stack
    49  	MOVD	24(R1), R2
    50  	XOR	R0, R0			// fix R0
    51  
    52  nocgo:
    53  	// update stackguard after _cgo_init
    54  	MOVD	(g_stack+stack_lo)(g), R3
    55  	ADD	$const__StackGuard, R3
    56  	MOVD	R3, g_stackguard0(g)
    57  	MOVD	R3, g_stackguard1(g)
    58  
    59  	// set the per-goroutine and per-mach "registers"
    60  	MOVD	$runtime·m0(SB), R3
    61  
    62  	// save m->g0 = g0
    63  	MOVD	g, m_g0(R3)
    64  	// save m0 to g0->m
    65  	MOVD	R3, g_m(g)
    66  
    67  	BL	runtime·check(SB)
    68  
    69  	// args are already prepared
    70  	BL	runtime·args(SB)
    71  	BL	runtime·osinit(SB)
    72  	BL	runtime·schedinit(SB)
    73  
    74  	// create a new goroutine to start program
    75  	MOVD	$runtime·mainPC(SB), R3		// entry
    76  	MOVDU	R3, -8(R1)
    77  	MOVDU	R0, -8(R1)
    78  	MOVDU	R0, -8(R1)
    79  	MOVDU	R0, -8(R1)
    80  	MOVDU	R0, -8(R1)
    81  	MOVDU	R0, -8(R1)
    82  	BL	runtime·newproc(SB)
    83  	ADD	$(16+FIXED_FRAME), R1
    84  
    85  	// start this M
    86  	BL	runtime·mstart(SB)
    87  
    88  	MOVD	R0, 1(R0)
    89  	RET
    90  
    91  DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
    92  GLOBL	runtime·mainPC(SB),RODATA,$8
    93  
    94  TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
    95  	MOVD	R0, 2(R0) // TODO: TD
    96  	RET
    97  
    98  TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
    99  	RET
   100  
   101  TEXT _cgo_reginit(SB),NOSPLIT|NOFRAME,$0-0
   102  	// crosscall_ppc64 and crosscall2 need to reginit, but can't
   103  	// get at the 'runtime.reginit' symbol.
   104  	BR	runtime·reginit(SB)
   105  
   106  TEXT runtime·reginit(SB),NOSPLIT|NOFRAME,$0-0
   107  	// set R0 to zero, it's expected by the toolchain
   108  	XOR R0, R0
   109  	// initialize essential FP registers
   110  	FMOVD	$4503601774854144.0, F27
   111  	FMOVD	$0.5, F29
   112  	FSUB	F29, F29, F28
   113  	FADD	F29, F29, F30
   114  	FADD	F30, F30, F31
   115  	RET
   116  
   117  /*
   118   *  go-routine
   119   */
   120  
   121  // void gosave(Gobuf*)
   122  // save state in Gobuf; setjmp
   123  TEXT runtime·gosave(SB), NOSPLIT|NOFRAME, $0-8
   124  	MOVD	buf+0(FP), R3
   125  	MOVD	R1, gobuf_sp(R3)
   126  	MOVD	LR, R31
   127  	MOVD	R31, gobuf_pc(R3)
   128  	MOVD	g, gobuf_g(R3)
   129  	MOVD	R0, gobuf_lr(R3)
   130  	MOVD	R0, gobuf_ret(R3)
   131  	MOVD	R0, gobuf_ctxt(R3)
   132  	RET
   133  
   134  // void gogo(Gobuf*)
   135  // restore state from Gobuf; longjmp
   136  TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8
   137  	MOVD	buf+0(FP), R5
   138  	MOVD	gobuf_g(R5), g	// make sure g is not nil
   139  	BL	runtime·save_g(SB)
   140  
   141  	MOVD	0(g), R4
   142  	MOVD	gobuf_sp(R5), R1
   143  	MOVD	gobuf_lr(R5), R31
   144  	MOVD	R31, LR
   145  	MOVD	gobuf_ret(R5), R3
   146  	MOVD	gobuf_ctxt(R5), R11
   147  	MOVD	R0, gobuf_sp(R5)
   148  	MOVD	R0, gobuf_ret(R5)
   149  	MOVD	R0, gobuf_lr(R5)
   150  	MOVD	R0, gobuf_ctxt(R5)
   151  	CMP	R0, R0 // set condition codes for == test, needed by stack split
   152  	MOVD	gobuf_pc(R5), R12
   153  	MOVD	R12, CTR
   154  	BR	(CTR)
   155  
   156  // void mcall(fn func(*g))
   157  // Switch to m->g0's stack, call fn(g).
   158  // Fn must never return.  It should gogo(&g->sched)
   159  // to keep running g.
   160  TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
   161  	// Save caller state in g->sched
   162  	MOVD	R1, (g_sched+gobuf_sp)(g)
   163  	MOVD	LR, R31
   164  	MOVD	R31, (g_sched+gobuf_pc)(g)
   165  	MOVD	R0, (g_sched+gobuf_lr)(g)
   166  	MOVD	g, (g_sched+gobuf_g)(g)
   167  
   168  	// Switch to m->g0 & its stack, call fn.
   169  	MOVD	g, R3
   170  	MOVD	g_m(g), R8
   171  	MOVD	m_g0(R8), g
   172  	BL	runtime·save_g(SB)
   173  	CMP	g, R3
   174  	BNE	2(PC)
   175  	BR	runtime·badmcall(SB)
   176  	MOVD	fn+0(FP), R11			// context
   177  	MOVD	0(R11), R12			// code pointer
   178  	MOVD	R12, CTR
   179  	MOVD	(g_sched+gobuf_sp)(g), R1	// sp = m->g0->sched.sp
   180  	MOVDU	R3, -8(R1)
   181  	MOVDU	R0, -8(R1)
   182  	MOVDU	R0, -8(R1)
   183  	MOVDU	R0, -8(R1)
   184  	MOVDU	R0, -8(R1)
   185  	BL	(CTR)
   186  	MOVD	24(R1), R2
   187  	BR	runtime·badmcall2(SB)
   188  
   189  // systemstack_switch is a dummy routine that systemstack leaves at the bottom
   190  // of the G stack.  We need to distinguish the routine that
   191  // lives at the bottom of the G stack from the one that lives
   192  // at the top of the system stack because the one at the top of
   193  // the system stack terminates the stack walk (see topofstack()).
   194  TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
   195  	// We have several undefs here so that 16 bytes past
   196  	// $runtime·systemstack_switch lies within them whether or not the
   197          // instructions that derive r2 from r12 are there.
   198  	UNDEF
   199  	UNDEF
   200  	UNDEF
   201  	BL	(LR)	// make sure this function is not leaf
   202  	RET
   203  
   204  // func systemstack(fn func())
   205  TEXT runtime·systemstack(SB), NOSPLIT, $0-8
   206  	MOVD	fn+0(FP), R3	// R3 = fn
   207  	MOVD	R3, R11		// context
   208  	MOVD	g_m(g), R4	// R4 = m
   209  
   210  	MOVD	m_gsignal(R4), R5	// R5 = gsignal
   211  	CMP	g, R5
   212  	BEQ	noswitch
   213  
   214  	MOVD	m_g0(R4), R5	// R5 = g0
   215  	CMP	g, R5
   216  	BEQ	noswitch
   217  
   218  	MOVD	m_curg(R4), R6
   219  	CMP	g, R6
   220  	BEQ	switch
   221  
   222  	// Bad: g is not gsignal, not g0, not curg. What is it?
   223  	// Hide call from linker nosplit analysis.
   224  	MOVD	$runtime·badsystemstack(SB), R12
   225  	MOVD	R12, CTR
   226  	BL	(CTR)
   227  
   228  switch:
   229  	// save our state in g->sched.  Pretend to
   230  	// be systemstack_switch if the G stack is scanned.
   231  	MOVD	$runtime·systemstack_switch(SB), R6
   232  	ADD     $16, R6 // get past prologue (including r2-setting instructions when they're there)
   233  	MOVD	R6, (g_sched+gobuf_pc)(g)
   234  	MOVD	R1, (g_sched+gobuf_sp)(g)
   235  	MOVD	R0, (g_sched+gobuf_lr)(g)
   236  	MOVD	g, (g_sched+gobuf_g)(g)
   237  
   238  	// switch to g0
   239  	MOVD	R5, g
   240  	BL	runtime·save_g(SB)
   241  	MOVD	(g_sched+gobuf_sp)(g), R3
   242  	// make it look like mstart called systemstack on g0, to stop traceback
   243  	SUB	$FIXED_FRAME, R3
   244  	MOVD	$runtime·mstart(SB), R4
   245  	MOVD	R4, 0(R3)
   246  	MOVD	R3, R1
   247  
   248  	// call target function
   249  	MOVD	0(R11), R12	// code pointer
   250  	MOVD	R12, CTR
   251  	BL	(CTR)
   252  
   253  	// restore TOC pointer. It seems unlikely that we will use systemstack
   254  	// to call a function defined in another module, but the results of
   255  	// doing so would be so confusing that it's worth doing this.
   256  	MOVD	g_m(g), R3
   257  	MOVD	m_curg(R3), g
   258  	MOVD	(g_sched+gobuf_sp)(g), R3
   259  	MOVD	24(R3), R2
   260  	// switch back to g
   261  	MOVD	g_m(g), R3
   262  	MOVD	m_curg(R3), g
   263  	BL	runtime·save_g(SB)
   264  	MOVD	(g_sched+gobuf_sp)(g), R1
   265  	MOVD	R0, (g_sched+gobuf_sp)(g)
   266  	RET
   267  
   268  noswitch:
   269  	// already on m stack, just call directly
   270  	MOVD	0(R11), R12	// code pointer
   271  	MOVD	R12, CTR
   272  	BL	(CTR)
   273  	MOVD	24(R1), R2
   274  	RET
   275  
   276  /*
   277   * support for morestack
   278   */
   279  
   280  // Called during function prolog when more stack is needed.
   281  // Caller has already loaded:
   282  // R3: framesize, R4: argsize, R5: LR
   283  //
   284  // The traceback routines see morestack on a g0 as being
   285  // the top of a stack (for example, morestack calling newstack
   286  // calling the scheduler calling newm calling gc), so we must
   287  // record an argument size. For that purpose, it has no arguments.
   288  TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
   289  	// Cannot grow scheduler stack (m->g0).
   290  	MOVD	g_m(g), R7
   291  	MOVD	m_g0(R7), R8
   292  	CMP	g, R8
   293  	BNE	2(PC)
   294  	BL	runtime·abort(SB)
   295  
   296  	// Cannot grow signal stack (m->gsignal).
   297  	MOVD	m_gsignal(R7), R8
   298  	CMP	g, R8
   299  	BNE	2(PC)
   300  	BL	runtime·abort(SB)
   301  
   302  	// Called from f.
   303  	// Set g->sched to context in f.
   304  	MOVD	R11, (g_sched+gobuf_ctxt)(g)
   305  	MOVD	R1, (g_sched+gobuf_sp)(g)
   306  	MOVD	LR, R8
   307  	MOVD	R8, (g_sched+gobuf_pc)(g)
   308  	MOVD	R5, (g_sched+gobuf_lr)(g)
   309  
   310  	// Called from f.
   311  	// Set m->morebuf to f's caller.
   312  	MOVD	R5, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
   313  	MOVD	R1, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
   314  	MOVD	g, (m_morebuf+gobuf_g)(R7)
   315  
   316  	// Call newstack on m->g0's stack.
   317  	MOVD	m_g0(R7), g
   318  	BL	runtime·save_g(SB)
   319  	MOVD	(g_sched+gobuf_sp)(g), R1
   320  	BL	runtime·newstack(SB)
   321  
   322  	// Not reached, but make sure the return PC from the call to newstack
   323  	// is still in this function, and not the beginning of the next.
   324  	UNDEF
   325  
   326  TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0
   327  	MOVD	R0, R11
   328  	BR	runtime·morestack(SB)
   329  
   330  TEXT runtime·stackBarrier(SB),NOSPLIT,$0
   331  	// We came here via a RET to an overwritten LR.
   332  	// R3 may be live. Other registers are available.
   333  
   334  	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
   335  	MOVD	(g_stkbar+slice_array)(g), R4
   336  	MOVD	g_stkbarPos(g), R5
   337  	MOVD	$stkbar__size, R6
   338  	MULLD	R5, R6
   339  	ADD	R4, R6
   340  	MOVD	stkbar_savedLRVal(R6), R6
   341  	// Record that this stack barrier was hit.
   342  	ADD	$1, R5
   343  	MOVD	R5, g_stkbarPos(g)
   344  	// Jump to the original return PC.
   345  	MOVD	R6, CTR
   346  	BR	(CTR)
   347  
   348  // reflectcall: call a function with the given argument list
   349  // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
   350  // we don't have variable-sized frames, so we use a small number
   351  // of constant-sized-frame functions to encode a few bits of size in the pc.
   352  // Caution: ugly multiline assembly macros in your future!
   353  
   354  #define DISPATCH(NAME,MAXSIZE)		\
   355  	MOVD	$MAXSIZE, R31;		\
   356  	CMP	R3, R31;		\
   357  	BGT	4(PC);			\
   358  	MOVD	$NAME(SB), R12;		\
   359  	MOVD	R12, CTR;		\
   360  	BR	(CTR)
   361  // Note: can't just "BR NAME(SB)" - bad inlining results.
   362  
   363  TEXT reflect·call(SB), NOSPLIT, $0-0
   364  	BR	·reflectcall(SB)
   365  
   366  TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-32
   367  	MOVWZ argsize+24(FP), R3
   368  	// NOTE(rsc): No call16, because CALLFN needs four words
   369  	// of argument space to invoke callwritebarrier.
   370  	DISPATCH(runtime·call32, 32)
   371  	DISPATCH(runtime·call64, 64)
   372  	DISPATCH(runtime·call128, 128)
   373  	DISPATCH(runtime·call256, 256)
   374  	DISPATCH(runtime·call512, 512)
   375  	DISPATCH(runtime·call1024, 1024)
   376  	DISPATCH(runtime·call2048, 2048)
   377  	DISPATCH(runtime·call4096, 4096)
   378  	DISPATCH(runtime·call8192, 8192)
   379  	DISPATCH(runtime·call16384, 16384)
   380  	DISPATCH(runtime·call32768, 32768)
   381  	DISPATCH(runtime·call65536, 65536)
   382  	DISPATCH(runtime·call131072, 131072)
   383  	DISPATCH(runtime·call262144, 262144)
   384  	DISPATCH(runtime·call524288, 524288)
   385  	DISPATCH(runtime·call1048576, 1048576)
   386  	DISPATCH(runtime·call2097152, 2097152)
   387  	DISPATCH(runtime·call4194304, 4194304)
   388  	DISPATCH(runtime·call8388608, 8388608)
   389  	DISPATCH(runtime·call16777216, 16777216)
   390  	DISPATCH(runtime·call33554432, 33554432)
   391  	DISPATCH(runtime·call67108864, 67108864)
   392  	DISPATCH(runtime·call134217728, 134217728)
   393  	DISPATCH(runtime·call268435456, 268435456)
   394  	DISPATCH(runtime·call536870912, 536870912)
   395  	DISPATCH(runtime·call1073741824, 1073741824)
   396  	MOVD	$runtime·badreflectcall(SB), R12
   397  	MOVD	R12, CTR
   398  	BR	(CTR)
   399  
   400  #define CALLFN(NAME,MAXSIZE)			\
   401  TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
   402  	NO_LOCAL_POINTERS;			\
   403  	/* copy arguments to stack */		\
   404  	MOVD	arg+16(FP), R3;			\
   405  	MOVWZ	argsize+24(FP), R4;			\
   406  	MOVD	R1, R5;				\
   407  	ADD	$(FIXED_FRAME-1), R5;			\
   408  	SUB	$1, R3;				\
   409  	ADD	R5, R4;				\
   410  	CMP	R5, R4;				\
   411  	BEQ	4(PC);				\
   412  	MOVBZU	1(R3), R6;			\
   413  	MOVBZU	R6, 1(R5);			\
   414  	BR	-4(PC);				\
   415  	/* call function */			\
   416  	MOVD	f+8(FP), R11;			\
   417  	MOVD	(R11), R12;			\
   418  	MOVD	R12, CTR;			\
   419  	PCDATA  $PCDATA_StackMapIndex, $0;	\
   420  	BL	(CTR);				\
   421  	MOVD	24(R1), R2;			\
   422  	/* copy return values back */		\
   423  	MOVD	arg+16(FP), R3;			\
   424  	MOVWZ	n+24(FP), R4;			\
   425  	MOVWZ	retoffset+28(FP), R6;		\
   426  	MOVD	R1, R5;				\
   427  	ADD	R6, R5; 			\
   428  	ADD	R6, R3;				\
   429  	SUB	R6, R4;				\
   430  	ADD	$(FIXED_FRAME-1), R5;			\
   431  	SUB	$1, R3;				\
   432  	ADD	R5, R4;				\
   433  loop:						\
   434  	CMP	R5, R4;				\
   435  	BEQ	end;				\
   436  	MOVBZU	1(R5), R6;			\
   437  	MOVBZU	R6, 1(R3);			\
   438  	BR	loop;				\
   439  end:						\
   440  	/* execute write barrier updates */	\
   441  	MOVD	argtype+0(FP), R7;		\
   442  	MOVD	arg+16(FP), R3;			\
   443  	MOVWZ	n+24(FP), R4;			\
   444  	MOVWZ	retoffset+28(FP), R6;		\
   445  	MOVD	R7, FIXED_FRAME+0(R1);			\
   446  	MOVD	R3, FIXED_FRAME+8(R1);			\
   447  	MOVD	R4, FIXED_FRAME+16(R1);			\
   448  	MOVD	R6, FIXED_FRAME+24(R1);			\
   449  	BL	runtime·callwritebarrier(SB);	\
   450  	RET
   451  
   452  CALLFN(·call32, 32)
   453  CALLFN(·call64, 64)
   454  CALLFN(·call128, 128)
   455  CALLFN(·call256, 256)
   456  CALLFN(·call512, 512)
   457  CALLFN(·call1024, 1024)
   458  CALLFN(·call2048, 2048)
   459  CALLFN(·call4096, 4096)
   460  CALLFN(·call8192, 8192)
   461  CALLFN(·call16384, 16384)
   462  CALLFN(·call32768, 32768)
   463  CALLFN(·call65536, 65536)
   464  CALLFN(·call131072, 131072)
   465  CALLFN(·call262144, 262144)
   466  CALLFN(·call524288, 524288)
   467  CALLFN(·call1048576, 1048576)
   468  CALLFN(·call2097152, 2097152)
   469  CALLFN(·call4194304, 4194304)
   470  CALLFN(·call8388608, 8388608)
   471  CALLFN(·call16777216, 16777216)
   472  CALLFN(·call33554432, 33554432)
   473  CALLFN(·call67108864, 67108864)
   474  CALLFN(·call134217728, 134217728)
   475  CALLFN(·call268435456, 268435456)
   476  CALLFN(·call536870912, 536870912)
   477  CALLFN(·call1073741824, 1073741824)
   478  
   479  TEXT runtime·procyield(SB),NOSPLIT,$0-0
   480  	RET
   481  
   482  // void jmpdefer(fv, sp);
   483  // called from deferreturn.
   484  // 1. grab stored LR for caller
   485  // 2. sub 8 bytes to get back to either nop or toc reload before deferreturn
   486  // 3. BR to fn
   487  // When dynamically linking Go, it is not sufficient to rewind to the BL
   488  // deferreturn -- we might be jumping between modules and so we need to reset
   489  // the TOC pointer in r2. To do this, codegen inserts MOVD 24(R1), R2 *before*
   490  // the BL deferreturn and jmpdefer rewinds to that.
   491  TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
   492  	MOVD	0(R1), R31
   493  	SUB     $8, R31
   494  	MOVD	R31, LR
   495  
   496  	MOVD	fv+0(FP), R11
   497  	MOVD	argp+8(FP), R1
   498  	SUB	$FIXED_FRAME, R1
   499  	MOVD	0(R11), R12
   500  	MOVD	R12, CTR
   501  	BR	(CTR)
   502  
   503  // Save state of caller into g->sched. Smashes R31.
   504  TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
   505  	MOVD	LR, R31
   506  	MOVD	R31, (g_sched+gobuf_pc)(g)
   507  	MOVD	R1, (g_sched+gobuf_sp)(g)
   508  	MOVD	R0, (g_sched+gobuf_lr)(g)
   509  	MOVD	R0, (g_sched+gobuf_ret)(g)
   510  	MOVD	R0, (g_sched+gobuf_ctxt)(g)
   511  	RET
   512  
   513  // func asmcgocall(fn, arg unsafe.Pointer) int32
   514  // Call fn(arg) on the scheduler stack,
   515  // aligned appropriately for the gcc ABI.
   516  // See cgocall.go for more details.
   517  TEXT ·asmcgocall(SB),NOSPLIT,$0-20
   518  	MOVD	fn+0(FP), R3
   519  	MOVD	arg+8(FP), R4
   520  
   521  	MOVD	R1, R7		// save original stack pointer
   522  	MOVD	g, R5
   523  
   524  	// Figure out if we need to switch to m->g0 stack.
   525  	// We get called to create new OS threads too, and those
   526  	// come in on the m->g0 stack already.
   527  	MOVD	g_m(g), R6
   528  	MOVD	m_g0(R6), R6
   529  	CMP	R6, g
   530  	BEQ	g0
   531  	BL	gosave<>(SB)
   532  	MOVD	R6, g
   533  	BL	runtime·save_g(SB)
   534  	MOVD	(g_sched+gobuf_sp)(g), R1
   535  
   536  	// Now on a scheduling stack (a pthread-created stack).
   537  g0:
   538  	// Save room for two of our pointers, plus 32 bytes of callee
   539  	// save area that lives on the caller stack.
   540  	SUB	$48, R1
   541  	RLDCR	$0, R1, $~15, R1	// 16-byte alignment for gcc ABI
   542  	MOVD	R5, 40(R1)	// save old g on stack
   543  	MOVD	(g_stack+stack_hi)(R5), R5
   544  	SUB	R7, R5
   545  	MOVD	R5, 32(R1)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
   546  	MOVD	R0, 0(R1)	// clear back chain pointer (TODO can we give it real back trace information?)
   547  	// This is a "global call", so put the global entry point in r12
   548  	MOVD	R3, R12
   549  	MOVD	R12, CTR
   550  	MOVD	R4, R3		// arg in r3
   551  	BL	(CTR)
   552  
   553  	// C code can clobber R0, so set it back to 0.  F27-F31 are
   554  	// callee save, so we don't need to recover those.
   555  	XOR	R0, R0
   556  	// Restore g, stack pointer, toc pointer.
   557  	// R3 is errno, so don't touch it
   558  	MOVD	40(R1), g
   559  	MOVD    (g_stack+stack_hi)(g), R5
   560  	MOVD    32(R1), R6
   561  	SUB     R6, R5
   562  	MOVD    24(R5), R2
   563  	BL	runtime·save_g(SB)
   564  	MOVD	(g_stack+stack_hi)(g), R5
   565  	MOVD	32(R1), R6
   566  	SUB	R6, R5
   567  	MOVD	R5, R1
   568  
   569  	MOVW	R3, ret+16(FP)
   570  	RET
   571  
   572  // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
   573  // Turn the fn into a Go func (by taking its address) and call
   574  // cgocallback_gofunc.
   575  TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
   576  	MOVD	$fn+0(FP), R3
   577  	MOVD	R3, FIXED_FRAME+0(R1)
   578  	MOVD	frame+8(FP), R3
   579  	MOVD	R3, FIXED_FRAME+8(R1)
   580  	MOVD	framesize+16(FP), R3
   581  	MOVD	R3, FIXED_FRAME+16(R1)
   582  	MOVD	$runtime·cgocallback_gofunc(SB), R12
   583  	MOVD	R12, CTR
   584  	BL	(CTR)
   585  	RET
   586  
   587  // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
   588  // See cgocall.go for more details.
   589  TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
   590  	NO_LOCAL_POINTERS
   591  
   592  	// Load m and g from thread-local storage.
   593  	MOVB	runtime·iscgo(SB), R3
   594  	CMP	R3, $0
   595  	BEQ	nocgo
   596  	BL	runtime·load_g(SB)
   597  nocgo:
   598  
   599  	// If g is nil, Go did not create the current thread.
   600  	// Call needm to obtain one for temporary use.
   601  	// In this case, we're running on the thread stack, so there's
   602  	// lots of space, but the linker doesn't know. Hide the call from
   603  	// the linker analysis by using an indirect call.
   604  	CMP	g, $0
   605  	BNE	havem
   606  	MOVD	g, savedm-8(SP) // g is zero, so is m.
   607  	MOVD	$runtime·needm(SB), R12
   608  	MOVD	R12, CTR
   609  	BL	(CTR)
   610  
   611  	// Set m->sched.sp = SP, so that if a panic happens
   612  	// during the function we are about to execute, it will
   613  	// have a valid SP to run on the g0 stack.
   614  	// The next few lines (after the havem label)
   615  	// will save this SP onto the stack and then write
   616  	// the same SP back to m->sched.sp. That seems redundant,
   617  	// but if an unrecovered panic happens, unwindm will
   618  	// restore the g->sched.sp from the stack location
   619  	// and then systemstack will try to use it. If we don't set it here,
   620  	// that restored SP will be uninitialized (typically 0) and
   621  	// will not be usable.
   622  	MOVD	g_m(g), R3
   623  	MOVD	m_g0(R3), R3
   624  	MOVD	R1, (g_sched+gobuf_sp)(R3)
   625  
   626  havem:
   627  	MOVD	g_m(g), R8
   628  	MOVD	R8, savedm-8(SP)
   629  	// Now there's a valid m, and we're running on its m->g0.
   630  	// Save current m->g0->sched.sp on stack and then set it to SP.
   631  	// Save current sp in m->g0->sched.sp in preparation for
   632  	// switch back to m->curg stack.
   633  	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP).
   634  	MOVD	m_g0(R8), R3
   635  	MOVD	(g_sched+gobuf_sp)(R3), R4
   636  	MOVD	R4, savedsp-16(SP)
   637  	MOVD	R1, (g_sched+gobuf_sp)(R3)
   638  
   639  	// Switch to m->curg stack and call runtime.cgocallbackg.
   640  	// Because we are taking over the execution of m->curg
   641  	// but *not* resuming what had been running, we need to
   642  	// save that information (m->curg->sched) so we can restore it.
   643  	// We can restore m->curg->sched.sp easily, because calling
   644  	// runtime.cgocallbackg leaves SP unchanged upon return.
   645  	// To save m->curg->sched.pc, we push it onto the stack.
   646  	// This has the added benefit that it looks to the traceback
   647  	// routine like cgocallbackg is going to return to that
   648  	// PC (because the frame we allocate below has the same
   649  	// size as cgocallback_gofunc's frame declared above)
   650  	// so that the traceback will seamlessly trace back into
   651  	// the earlier calls.
   652  	//
   653  	// In the new goroutine, -16(SP) and -8(SP) are unused.
   654  	MOVD	m_curg(R8), g
   655  	BL	runtime·save_g(SB)
   656  	MOVD	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4
   657  	MOVD	(g_sched+gobuf_pc)(g), R5
   658  	MOVD	R5, -(FIXED_FRAME+16)(R4)
   659  	MOVD	$-(FIXED_FRAME+16)(R4), R1
   660  	BL	runtime·cgocallbackg(SB)
   661  
   662  	// Restore g->sched (== m->curg->sched) from saved values.
   663  	MOVD	0(R1), R5
   664  	MOVD	R5, (g_sched+gobuf_pc)(g)
   665  	MOVD	$(FIXED_FRAME+16)(R1), R4
   666  	MOVD	R4, (g_sched+gobuf_sp)(g)
   667  
   668  	// Switch back to m->g0's stack and restore m->g0->sched.sp.
   669  	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
   670  	// so we do not have to restore it.)
   671  	MOVD	g_m(g), R8
   672  	MOVD	m_g0(R8), g
   673  	BL	runtime·save_g(SB)
   674  	MOVD	(g_sched+gobuf_sp)(g), R1
   675  	MOVD	savedsp-16(SP), R4
   676  	MOVD	R4, (g_sched+gobuf_sp)(g)
   677  
   678  	// If the m on entry was nil, we called needm above to borrow an m
   679  	// for the duration of the call. Since the call is over, return it with dropm.
   680  	MOVD	savedm-8(SP), R6
   681  	CMP	R6, $0
   682  	BNE	droppedm
   683  	MOVD	$runtime·dropm(SB), R12
   684  	MOVD	R12, CTR
   685  	BL	(CTR)
   686  droppedm:
   687  
   688  	// Done!
   689  	RET
   690  
   691  // void setg(G*); set g. for use by needm.
   692  TEXT runtime·setg(SB), NOSPLIT, $0-8
   693  	MOVD	gg+0(FP), g
   694  	// This only happens if iscgo, so jump straight to save_g
   695  	BL	runtime·save_g(SB)
   696  	RET
   697  
   698  // void setg_gcc(G*); set g in C TLS.
   699  // Must obey the gcc calling convention.
   700  TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0
   701  	// The standard prologue clobbers R31, which is callee-save in
   702  	// the C ABI, so we have to use $-8-0 and save LR ourselves.
   703  	MOVD	LR, R4
   704  	// Also save g and R31, since they're callee-save in C ABI
   705  	MOVD	R31, R5
   706  	MOVD	g, R6
   707  
   708  	MOVD	R3, g
   709  	BL	runtime·save_g(SB)
   710  
   711  	MOVD	R6, g
   712  	MOVD	R5, R31
   713  	MOVD	R4, LR
   714  	RET
   715  
   716  TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
   717  	MOVD	FIXED_FRAME+8(R1), R3		// LR saved by caller
   718  	MOVD	runtime·stackBarrierPC(SB), R4
   719  	CMP	R3, R4
   720  	BNE	nobar
   721  	// Get original return PC.
   722  	BL	runtime·nextBarrierPC(SB)
   723  	MOVD	FIXED_FRAME+0(R1), R3
   724  nobar:
   725  	MOVD	R3, ret+8(FP)
   726  	RET
   727  
   728  TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
   729  	MOVD	pc+8(FP), R3
   730  	MOVD	FIXED_FRAME+8(R1), R4
   731  	MOVD	runtime·stackBarrierPC(SB), R5
   732  	CMP	R4, R5
   733  	BEQ	setbar
   734  	MOVD	R3, FIXED_FRAME+8(R1)		// set LR in caller
   735  	RET
   736  setbar:
   737  	// Set the stack barrier return PC.
   738  	MOVD	R3, FIXED_FRAME+0(R1)
   739  	BL	runtime·setNextBarrierPC(SB)
   740  	RET
   741  
   742  TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
   743  	MOVD	argp+0(FP), R3
   744  	SUB	$FIXED_FRAME, R3
   745  	MOVD	R3, ret+8(FP)
   746  	RET
   747  
   748  TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
   749  	MOVW	(R0), R0
   750  	UNDEF
   751  
   752  #define	TBRL	268
   753  #define	TBRU	269		/* Time base Upper/Lower */
   754  
   755  // int64 runtime·cputicks(void)
   756  TEXT runtime·cputicks(SB),NOSPLIT,$0-8
   757  	MOVW	SPR(TBRU), R4
   758  	MOVW	SPR(TBRL), R3
   759  	MOVW	SPR(TBRU), R5
   760  	CMPW	R4, R5
   761  	BNE	-4(PC)
   762  	SLD	$32, R5
   763  	OR	R5, R3
   764  	MOVD	R3, ret+0(FP)
   765  	RET
   766  
   767  // memhash_varlen(p unsafe.Pointer, h seed) uintptr
   768  // redirects to memhash(p, h, size) using the size
   769  // stored in the closure.
   770  TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24
   771  	GO_ARGS
   772  	NO_LOCAL_POINTERS
   773  	MOVD	p+0(FP), R3
   774  	MOVD	h+8(FP), R4
   775  	MOVD	8(R11), R5
   776  	MOVD	R3, FIXED_FRAME+0(R1)
   777  	MOVD	R4, FIXED_FRAME+8(R1)
   778  	MOVD	R5, FIXED_FRAME+16(R1)
   779  	BL	runtime·memhash(SB)
   780  	MOVD	FIXED_FRAME+24(R1), R3
   781  	MOVD	R3, ret+16(FP)
   782  	RET
   783  
   784  // AES hashing not implemented for ppc64
   785  TEXT runtime·aeshash(SB),NOSPLIT|NOFRAME,$0-0
   786  	MOVW	(R0), R1
   787  TEXT runtime·aeshash32(SB),NOSPLIT|NOFRAME,$0-0
   788  	MOVW	(R0), R1
   789  TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0
   790  	MOVW	(R0), R1
   791  TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0
   792  	MOVW	(R0), R1
   793  
   794  TEXT runtime·memeq(SB),NOSPLIT|NOFRAME,$0-25
   795  	MOVD	a+0(FP), R3
   796  	MOVD	b+8(FP), R4
   797  	MOVD	size+16(FP), R5
   798  	SUB	$1, R3
   799  	SUB	$1, R4
   800  	ADD	R3, R5, R8
   801  loop:
   802  	CMP	R3, R8
   803  	BNE	test
   804  	MOVD	$1, R3
   805  	MOVB	R3, ret+24(FP)
   806  	RET
   807  test:
   808  	MOVBZU	1(R3), R6
   809  	MOVBZU	1(R4), R7
   810  	CMP	R6, R7
   811  	BEQ	loop
   812  
   813  	MOVB	R0, ret+24(FP)
   814  	RET
   815  
   816  // memequal_varlen(a, b unsafe.Pointer) bool
   817  TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
   818  	MOVD	a+0(FP), R3
   819  	MOVD	b+8(FP), R4
   820  	CMP	R3, R4
   821  	BEQ	eq
   822  	MOVD	8(R11), R5    // compiler stores size at offset 8 in the closure
   823  	MOVD	R3, FIXED_FRAME+0(R1)
   824  	MOVD	R4, FIXED_FRAME+8(R1)
   825  	MOVD	R5, FIXED_FRAME+16(R1)
   826  	BL	runtime·memeq(SB)
   827  	MOVBZ	FIXED_FRAME+24(R1), R3
   828  	MOVB	R3, ret+16(FP)
   829  	RET
   830  eq:
   831  	MOVD	$1, R3
   832  	MOVB	R3, ret+16(FP)
   833  	RET
   834  
   835  // eqstring tests whether two strings are equal.
   836  // The compiler guarantees that strings passed
   837  // to eqstring have equal length.
   838  // See runtime_test.go:eqstring_generic for
   839  // equivalent Go code.
   840  TEXT runtime·eqstring(SB),NOSPLIT,$0-33
   841  	MOVD	s1str+0(FP), R3
   842  	MOVD	s2str+16(FP), R4
   843  	MOVD	$1, R5
   844  	MOVB	R5, ret+32(FP)
   845  	CMP	R3, R4
   846  	BNE	2(PC)
   847  	RET
   848  	MOVD	s1len+8(FP), R5
   849  	SUB	$1, R3
   850  	SUB	$1, R4
   851  	ADD	R3, R5, R8
   852  loop:
   853  	CMP	R3, R8
   854  	BNE	2(PC)
   855  	RET
   856  	MOVBZU	1(R3), R6
   857  	MOVBZU	1(R4), R7
   858  	CMP	R6, R7
   859  	BEQ	loop
   860  	MOVB	R0, ret+32(FP)
   861  	RET
   862  
   863  // TODO: share code with memeq?
   864  TEXT bytes·Equal(SB),NOSPLIT,$0-49
   865  	MOVD	a_len+8(FP), R3
   866  	MOVD	b_len+32(FP), R4
   867  
   868  	CMP	R3, R4		// unequal lengths are not equal
   869  	BNE	noteq
   870  
   871  	MOVD	a+0(FP), R5
   872  	MOVD	b+24(FP), R6
   873  	SUB	$1, R5
   874  	SUB	$1, R6
   875  	ADD	R5, R3		// end-1
   876  
   877  loop:
   878  	CMP	R5, R3
   879  	BEQ	equal		// reached the end
   880  	MOVBZU	1(R5), R4
   881  	MOVBZU	1(R6), R7
   882  	CMP	R4, R7
   883  	BEQ	loop
   884  
   885  noteq:
   886  	MOVBZ	R0, ret+48(FP)
   887  	RET
   888  
   889  equal:
   890  	MOVD	$1, R3
   891  	MOVBZ	R3, ret+48(FP)
   892  	RET
   893  
   894  TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
   895  	MOVD	s+0(FP), R3
   896  	MOVD	s_len+8(FP), R4
   897  	MOVBZ	c+24(FP), R5	// byte to find
   898  	MOVD	R3, R6		// store base for later
   899  	SUB	$1, R3
   900  	ADD	R3, R4		// end-1
   901  
   902  loop:
   903  	CMP	R3, R4
   904  	BEQ	notfound
   905  	MOVBZU	1(R3), R7
   906  	CMP	R7, R5
   907  	BNE	loop
   908  
   909  	SUB	R6, R3		// remove base
   910  	MOVD	R3, ret+32(FP)
   911  	RET
   912  
   913  notfound:
   914  	MOVD	$-1, R3
   915  	MOVD	R3, ret+32(FP)
   916  	RET
   917  
   918  TEXT strings·IndexByte(SB),NOSPLIT,$0-32
   919  	MOVD	p+0(FP), R3
   920  	MOVD	b_len+8(FP), R4
   921  	MOVBZ	c+16(FP), R5	// byte to find
   922  	MOVD	R3, R6		// store base for later
   923  	SUB	$1, R3
   924  	ADD	R3, R4		// end-1
   925  
   926  loop:
   927  	CMP	R3, R4
   928  	BEQ	notfound
   929  	MOVBZU	1(R3), R7
   930  	CMP	R7, R5
   931  	BNE	loop
   932  
   933  	SUB	R6, R3		// remove base
   934  	MOVD	R3, ret+24(FP)
   935  	RET
   936  
   937  notfound:
   938  	MOVD	$-1, R3
   939  	MOVD	R3, ret+24(FP)
   940  	RET
   941  
   942  TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
   943  	MOVD	s1_base+0(FP), R5
   944  	MOVD	s1_len+8(FP), R3
   945  	MOVD	s2_base+16(FP), R6
   946  	MOVD	s2_len+24(FP), R4
   947  	MOVD	$ret+32(FP), R7
   948  	BR	runtime·cmpbody<>(SB)
   949  
   950  TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56
   951  	MOVD	s1+0(FP), R5
   952  	MOVD	s1+8(FP), R3
   953  	MOVD	s2+24(FP), R6
   954  	MOVD	s2+32(FP), R4
   955  	MOVD	$ret+48(FP), R7
   956  	BR	runtime·cmpbody<>(SB)
   957  
   958  // On entry:
   959  // R3 is the length of s1
   960  // R4 is the length of s2
   961  // R5 points to the start of s1
   962  // R6 points to the start of s2
   963  // R7 points to return value (-1/0/1 will be written here)
   964  //
   965  // On exit:
   966  // R5, R6, R8, R9 and R10 are clobbered
   967  TEXT runtime·cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0
   968  	CMP	R5, R6
   969  	BEQ	samebytes // same starting pointers; compare lengths
   970  	SUB	$1, R5
   971  	SUB	$1, R6
   972  	MOVD	R4, R8
   973  	CMP	R3, R4
   974  	BGE	2(PC)
   975  	MOVD	R3, R8	// R8 is min(R3, R4)
   976  	ADD	R5, R8	// R5 is current byte in s1, R8 is last byte in s1 to compare
   977  loop:
   978  	CMP	R5, R8
   979  	BEQ	samebytes // all compared bytes were the same; compare lengths
   980  	MOVBZU	1(R5), R9
   981  	MOVBZU	1(R6), R10
   982  	CMP	R9, R10
   983  	BEQ	loop
   984  	// bytes differed
   985  	MOVD	$1, R4
   986  	BGT	2(PC)
   987  	NEG	R4
   988  	MOVD	R4, (R7)
   989  	RET
   990  samebytes:
   991  	MOVD	$1, R8
   992  	CMP	R3, R4
   993  	BNE	3(PC)
   994  	MOVD	R0, (R7)
   995  	RET
   996  	BGT	2(PC)
   997  	NEG	R8
   998  	MOVD	R8, (R7)
   999  	RET
  1000  
  1001  TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
  1002  	MOVD	g_m(g), R4
  1003  	MOVWZ	m_fastrand(R4), R3
  1004  	ADD	R3, R3
  1005  	CMPW	R3, $0
  1006  	BGE	2(PC)
  1007  	XOR	$0x88888eef, R3
  1008  	MOVW	R3, m_fastrand(R4)
  1009  	MOVW	R3, ret+0(FP)
  1010  	RET
  1011  
  1012  TEXT runtime·return0(SB), NOSPLIT, $0
  1013  	MOVW	$0, R3
  1014  	RET
  1015  
  1016  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
  1017  // Must obey the gcc calling convention.
  1018  TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0
  1019  	// g (R30) and R31 are callee-save in the C ABI, so save them
  1020  	MOVD	g, R4
  1021  	MOVD	R31, R5
  1022  	MOVD	LR, R6
  1023  
  1024  	BL	runtime·load_g(SB)	// clobbers g (R30), R31
  1025  	MOVD	g_m(g), R3
  1026  	MOVD	m_curg(R3), R3
  1027  	MOVD	(g_stack+stack_hi)(R3), R3
  1028  
  1029  	MOVD	R4, g
  1030  	MOVD	R5, R31
  1031  	MOVD	R6, LR
  1032  	RET
  1033  
  1034  // The top-most function running on a goroutine
  1035  // returns to goexit+PCQuantum.
  1036  //
  1037  // When dynamically linking Go, it can be returned to from a function
  1038  // implemented in a different module and so needs to reload the TOC pointer
  1039  // from the stack (although this function declares that it does not set up x-a
  1040  // frame, newproc1 does in fact allocate one for goexit and saves the TOC
  1041  // pointer in the correct place).
  1042  // goexit+_PCQuantum is halfway through the usual global entry point prologue
  1043  // that derives r2 from r12 which is a bit silly, but not harmful.
  1044  TEXT runtime·goexit(SB),NOSPLIT|NOFRAME,$0-0
  1045  	MOVD	24(R1), R2
  1046  	BL	runtime·goexit1(SB)	// does not return
  1047  	// traceback from goexit1 must hit code range of goexit
  1048  	MOVD	R0, R0	// NOP
  1049  
  1050  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
  1051  	RET
  1052  
  1053  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8
  1054  	RET
  1055  
  1056  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
  1057  	RET
  1058  
  1059  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
  1060  	RET
  1061  
  1062  TEXT runtime·sigreturn(SB),NOSPLIT,$0-8
  1063          RET
  1064  
  1065  // prepGoExitFrame saves the current TOC pointer (i.e. the TOC pointer for the
  1066  // module containing runtime) to the frame that goexit will execute in when
  1067  // the goroutine exits. It's implemented in assembly mainly because that's the
  1068  // easiest way to get access to R2.
  1069  TEXT runtime·prepGoExitFrame(SB),NOSPLIT,$0-8
  1070        MOVD    sp+0(FP), R3
  1071        MOVD    R2, 24(R3)
  1072        RET
  1073  
  1074  TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0
  1075  	ADD	$-8, R1
  1076  	MOVD	R31, 0(R1)
  1077  	MOVD	runtime·lastmoduledatap(SB), R4
  1078  	MOVD	R3, moduledata_next(R4)
  1079  	MOVD	R3, runtime·lastmoduledatap(SB)
  1080  	MOVD	0(R1), R31
  1081  	ADD	$8, R1
  1082  	RET
  1083  
  1084  TEXT ·checkASM(SB),NOSPLIT,$0-1
  1085  	MOVW	$1, R3
  1086  	MOVB	R3, ret+0(FP)
  1087  	RET