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