github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 BEQ needm 606 607 MOVD g_m(g), R8 608 MOVD R8, savedm-8(SP) 609 BR havem 610 611 needm: 612 MOVD g, savedm-8(SP) // g is zero, so is m. 613 MOVD $runtime·needm(SB), R12 614 MOVD R12, CTR 615 BL (CTR) 616 617 // Set m->sched.sp = SP, so that if a panic happens 618 // during the function we are about to execute, it will 619 // have a valid SP to run on the g0 stack. 620 // The next few lines (after the havem label) 621 // will save this SP onto the stack and then write 622 // the same SP back to m->sched.sp. That seems redundant, 623 // but if an unrecovered panic happens, unwindm will 624 // restore the g->sched.sp from the stack location 625 // and then systemstack will try to use it. If we don't set it here, 626 // that restored SP will be uninitialized (typically 0) and 627 // will not be usable. 628 MOVD g_m(g), R8 629 MOVD m_g0(R8), R3 630 MOVD R1, (g_sched+gobuf_sp)(R3) 631 632 havem: 633 // Now there's a valid m, and we're running on its m->g0. 634 // Save current m->g0->sched.sp on stack and then set it to SP. 635 // Save current sp in m->g0->sched.sp in preparation for 636 // switch back to m->curg stack. 637 // NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP). 638 MOVD m_g0(R8), R3 639 MOVD (g_sched+gobuf_sp)(R3), R4 640 MOVD R4, savedsp-16(SP) 641 MOVD R1, (g_sched+gobuf_sp)(R3) 642 643 // Switch to m->curg stack and call runtime.cgocallbackg. 644 // Because we are taking over the execution of m->curg 645 // but *not* resuming what had been running, we need to 646 // save that information (m->curg->sched) so we can restore it. 647 // We can restore m->curg->sched.sp easily, because calling 648 // runtime.cgocallbackg leaves SP unchanged upon return. 649 // To save m->curg->sched.pc, we push it onto the stack. 650 // This has the added benefit that it looks to the traceback 651 // routine like cgocallbackg is going to return to that 652 // PC (because the frame we allocate below has the same 653 // size as cgocallback_gofunc's frame declared above) 654 // so that the traceback will seamlessly trace back into 655 // the earlier calls. 656 // 657 // In the new goroutine, -16(SP) and -8(SP) are unused. 658 MOVD m_curg(R8), g 659 BL runtime·save_g(SB) 660 MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 661 MOVD (g_sched+gobuf_pc)(g), R5 662 MOVD R5, -(FIXED_FRAME+16)(R4) 663 MOVD $-(FIXED_FRAME+16)(R4), R1 664 BL runtime·cgocallbackg(SB) 665 666 // Restore g->sched (== m->curg->sched) from saved values. 667 MOVD 0(R1), R5 668 MOVD R5, (g_sched+gobuf_pc)(g) 669 MOVD $(FIXED_FRAME+16)(R1), R4 670 MOVD R4, (g_sched+gobuf_sp)(g) 671 672 // Switch back to m->g0's stack and restore m->g0->sched.sp. 673 // (Unlike m->curg, the g0 goroutine never uses sched.pc, 674 // so we do not have to restore it.) 675 MOVD g_m(g), R8 676 MOVD m_g0(R8), g 677 BL runtime·save_g(SB) 678 MOVD (g_sched+gobuf_sp)(g), R1 679 MOVD savedsp-16(SP), R4 680 MOVD R4, (g_sched+gobuf_sp)(g) 681 682 // If the m on entry was nil, we called needm above to borrow an m 683 // for the duration of the call. Since the call is over, return it with dropm. 684 MOVD savedm-8(SP), R6 685 CMP R6, $0 686 BNE droppedm 687 MOVD $runtime·dropm(SB), R12 688 MOVD R12, CTR 689 BL (CTR) 690 droppedm: 691 692 // Done! 693 RET 694 695 // void setg(G*); set g. for use by needm. 696 TEXT runtime·setg(SB), NOSPLIT, $0-8 697 MOVD gg+0(FP), g 698 // This only happens if iscgo, so jump straight to save_g 699 BL runtime·save_g(SB) 700 RET 701 702 // void setg_gcc(G*); set g in C TLS. 703 // Must obey the gcc calling convention. 704 TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0 705 // The standard prologue clobbers R31, which is callee-save in 706 // the C ABI, so we have to use $-8-0 and save LR ourselves. 707 MOVD LR, R4 708 // Also save g and R31, since they're callee-save in C ABI 709 MOVD R31, R5 710 MOVD g, R6 711 712 MOVD R3, g 713 BL runtime·save_g(SB) 714 715 MOVD R6, g 716 MOVD R5, R31 717 MOVD R4, LR 718 RET 719 720 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16 721 MOVD FIXED_FRAME+8(R1), R3 // LR saved by caller 722 MOVD runtime·stackBarrierPC(SB), R4 723 CMP R3, R4 724 BNE nobar 725 // Get original return PC. 726 BL runtime·nextBarrierPC(SB) 727 MOVD FIXED_FRAME+0(R1), R3 728 nobar: 729 MOVD R3, ret+8(FP) 730 RET 731 732 TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16 733 MOVD pc+8(FP), R3 734 MOVD FIXED_FRAME+8(R1), R4 735 MOVD runtime·stackBarrierPC(SB), R5 736 CMP R4, R5 737 BEQ setbar 738 MOVD R3, FIXED_FRAME+8(R1) // set LR in caller 739 RET 740 setbar: 741 // Set the stack barrier return PC. 742 MOVD R3, FIXED_FRAME+0(R1) 743 BL runtime·setNextBarrierPC(SB) 744 RET 745 746 TEXT runtime·getcallersp(SB),NOSPLIT,$0-16 747 MOVD argp+0(FP), R3 748 SUB $FIXED_FRAME, R3 749 MOVD R3, ret+8(FP) 750 RET 751 752 TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 753 MOVW (R0), R0 754 UNDEF 755 756 #define TBRL 268 757 #define TBRU 269 /* Time base Upper/Lower */ 758 759 // int64 runtime·cputicks(void) 760 TEXT runtime·cputicks(SB),NOSPLIT,$0-8 761 MOVW SPR(TBRU), R4 762 MOVW SPR(TBRL), R3 763 MOVW SPR(TBRU), R5 764 CMPW R4, R5 765 BNE -4(PC) 766 SLD $32, R5 767 OR R5, R3 768 MOVD R3, ret+0(FP) 769 RET 770 771 // memhash_varlen(p unsafe.Pointer, h seed) uintptr 772 // redirects to memhash(p, h, size) using the size 773 // stored in the closure. 774 TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24 775 GO_ARGS 776 NO_LOCAL_POINTERS 777 MOVD p+0(FP), R3 778 MOVD h+8(FP), R4 779 MOVD 8(R11), R5 780 MOVD R3, FIXED_FRAME+0(R1) 781 MOVD R4, FIXED_FRAME+8(R1) 782 MOVD R5, FIXED_FRAME+16(R1) 783 BL runtime·memhash(SB) 784 MOVD FIXED_FRAME+24(R1), R3 785 MOVD R3, ret+16(FP) 786 RET 787 788 // AES hashing not implemented for ppc64 789 TEXT runtime·aeshash(SB),NOSPLIT|NOFRAME,$0-0 790 MOVW (R0), R1 791 TEXT runtime·aeshash32(SB),NOSPLIT|NOFRAME,$0-0 792 MOVW (R0), R1 793 TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0 794 MOVW (R0), R1 795 TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0 796 MOVW (R0), R1 797 798 TEXT runtime·memequal(SB),NOSPLIT,$0-25 799 MOVD a+0(FP), R3 800 MOVD b+8(FP), R4 801 MOVD size+16(FP), R5 802 803 BL runtime·memeqbody(SB) 804 MOVB R9, ret+24(FP) 805 RET 806 807 // memequal_varlen(a, b unsafe.Pointer) bool 808 TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 809 MOVD a+0(FP), R3 810 MOVD b+8(FP), R4 811 CMP R3, R4 812 BEQ eq 813 MOVD 8(R11), R5 // compiler stores size at offset 8 in the closure 814 BL runtime·memeqbody(SB) 815 MOVB R9, ret+16(FP) 816 RET 817 eq: 818 MOVD $1, R3 819 MOVB R3, ret+16(FP) 820 RET 821 822 // Do an efficieint memequal for ppc64 823 // for reuse where possible. 824 // R3 = s1 825 // R4 = s2 826 // R5 = len 827 // R9 = return value 828 // R6, R7 clobbered 829 TEXT runtime·memeqbody(SB),NOSPLIT|NOFRAME,$0-0 830 MOVD R5,CTR 831 CMP R5,$8 // only optimize >=8 832 BLT simplecheck 833 DCBT (R3) // cache hint 834 DCBT (R4) 835 CMP R5,$32 // optimize >= 32 836 MOVD R5,R6 // needed if setup8a branch 837 BLT setup8a // 8 byte moves only 838 setup32a: // 8 byte aligned, >= 32 bytes 839 SRADCC $5,R5,R6 // number of 32 byte chunks to compare 840 MOVD R6,CTR 841 loop32a: 842 MOVD 0(R3),R6 // doublewords to compare 843 MOVD 0(R4),R7 844 MOVD 8(R3),R8 // 845 MOVD 8(R4),R9 846 CMP R6,R7 // bytes batch? 847 BNE noteq 848 MOVD 16(R3),R6 849 MOVD 16(R4),R7 850 CMP R8,R9 // bytes match? 851 MOVD 24(R3),R8 852 MOVD 24(R4),R9 853 BNE noteq 854 CMP R6,R7 // bytes match? 855 BNE noteq 856 ADD $32,R3 // bump up to next 32 857 ADD $32,R4 858 CMP R8,R9 // bytes match? 859 BC 8,2,loop32a // br ctr and cr 860 BNE noteq 861 ANDCC $24,R5,R6 // Any 8 byte chunks? 862 BEQ leftover // and result is 0 863 setup8a: 864 SRADCC $3,R6,R6 // get the 8 byte count 865 BEQ leftover // shifted value is 0 866 MOVD R6,CTR 867 loop8: 868 MOVD 0(R3),R6 // doublewords to compare 869 ADD $8,R3 870 MOVD 0(R4),R7 871 ADD $8,R4 872 CMP R6,R7 // match? 873 BC 8,2,loop8 // bt ctr <> 0 && cr 874 BNE noteq 875 leftover: 876 ANDCC $7,R5,R6 // check for leftover bytes 877 BEQ equal 878 MOVD R6,CTR 879 BR simple 880 simplecheck: 881 CMP R5,$0 882 BEQ equal 883 simple: 884 MOVBZ 0(R3), R6 885 ADD $1,R3 886 MOVBZ 0(R4), R7 887 ADD $1,R4 888 CMP R6, R7 889 BNE noteq 890 BC 8,2,simple 891 BNE noteq 892 BR equal 893 noteq: 894 MOVD $0, R9 895 RET 896 equal: 897 MOVD $1, R9 898 RET 899 900 // eqstring tests whether two strings are equal. 901 // The compiler guarantees that strings passed 902 // to eqstring have equal length. 903 // See runtime_test.go:eqstring_generic for 904 // equivalent Go code. 905 TEXT runtime·eqstring(SB),NOSPLIT,$0-33 906 MOVD s1str+0(FP), R3 907 MOVD s2str+16(FP), R4 908 MOVD $1, R5 909 MOVB R5, ret+32(FP) 910 CMP R3, R4 911 BNE 2(PC) 912 RET 913 MOVD s1len+8(FP), R5 914 BL runtime·memeqbody(SB) 915 MOVB R9, ret+32(FP) 916 RET 917 918 TEXT bytes·Equal(SB),NOSPLIT,$0-49 919 MOVD a_len+8(FP), R4 920 MOVD b_len+32(FP), R5 921 CMP R5, R4 // unequal lengths are not equal 922 BNE noteq 923 MOVD a+0(FP), R3 924 MOVD b+24(FP), R4 925 BL runtime·memeqbody(SB) 926 927 MOVBZ R9,ret+48(FP) 928 RET 929 930 noteq: 931 MOVBZ $0,ret+48(FP) 932 RET 933 934 equal: 935 MOVD $1,R3 936 MOVBZ R3,ret+48(FP) 937 RET 938 939 TEXT bytes·IndexByte(SB),NOSPLIT,$0-40 940 MOVD s+0(FP), R3 941 MOVD s_len+8(FP), R4 942 MOVBZ c+24(FP), R5 // byte to find 943 MOVD R3, R6 // store base for later 944 SUB $1, R3 945 ADD R3, R4 // end-1 946 947 loop: 948 CMP R3, R4 949 BEQ notfound 950 MOVBZU 1(R3), R7 951 CMP R7, R5 952 BNE loop 953 954 SUB R6, R3 // remove base 955 MOVD R3, ret+32(FP) 956 RET 957 958 notfound: 959 MOVD $-1, R3 960 MOVD R3, ret+32(FP) 961 RET 962 963 TEXT strings·IndexByte(SB),NOSPLIT,$0-32 964 MOVD p+0(FP), R3 965 MOVD b_len+8(FP), R4 966 MOVBZ c+16(FP), R5 // byte to find 967 MOVD R3, R6 // store base for later 968 SUB $1, R3 969 ADD R3, R4 // end-1 970 971 loop: 972 CMP R3, R4 973 BEQ notfound 974 MOVBZU 1(R3), R7 975 CMP R7, R5 976 BNE loop 977 978 SUB R6, R3 // remove base 979 MOVD R3, ret+24(FP) 980 RET 981 982 notfound: 983 MOVD $-1, R3 984 MOVD R3, ret+24(FP) 985 RET 986 987 TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40 988 MOVD s1_base+0(FP), R5 989 MOVD s1_len+8(FP), R3 990 MOVD s2_base+16(FP), R6 991 MOVD s2_len+24(FP), R4 992 MOVD $ret+32(FP), R7 993 BR runtime·cmpbody<>(SB) 994 995 TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56 996 MOVD s1+0(FP), R5 997 MOVD s1+8(FP), R3 998 MOVD s2+24(FP), R6 999 MOVD s2+32(FP), R4 1000 MOVD $ret+48(FP), R7 1001 BR runtime·cmpbody<>(SB) 1002 1003 // On entry: 1004 // R3 is the length of s1 1005 // R4 is the length of s2 1006 // R5 points to the start of s1 1007 // R6 points to the start of s2 1008 // R7 points to return value (-1/0/1 will be written here) 1009 // 1010 // On exit: 1011 // R5, R6, R8, R9 and R10 are clobbered 1012 TEXT runtime·cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0 1013 CMP R5, R6 1014 BEQ samebytes // same starting pointers; compare lengths 1015 SUB $1, R5 1016 SUB $1, R6 1017 MOVD R4, R8 1018 CMP R3, R4 1019 BGE 2(PC) 1020 MOVD R3, R8 // R8 is min(R3, R4) 1021 ADD R5, R8 // R5 is current byte in s1, R8 is last byte in s1 to compare 1022 loop: 1023 CMP R5, R8 1024 BEQ samebytes // all compared bytes were the same; compare lengths 1025 MOVBZU 1(R5), R9 1026 MOVBZU 1(R6), R10 1027 CMP R9, R10 1028 BEQ loop 1029 // bytes differed 1030 MOVD $1, R4 1031 BGT 2(PC) 1032 NEG R4 1033 MOVD R4, (R7) 1034 RET 1035 samebytes: 1036 MOVD $1, R8 1037 CMP R3, R4 1038 BNE 3(PC) 1039 MOVD R0, (R7) 1040 RET 1041 BGT 2(PC) 1042 NEG R8 1043 MOVD R8, (R7) 1044 RET 1045 1046 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 1047 MOVD g_m(g), R4 1048 MOVWZ m_fastrand(R4), R3 1049 ADD R3, R3 1050 CMPW R3, $0 1051 BGE 2(PC) 1052 XOR $0x88888eef, R3 1053 MOVW R3, m_fastrand(R4) 1054 MOVW R3, ret+0(FP) 1055 RET 1056 1057 TEXT runtime·return0(SB), NOSPLIT, $0 1058 MOVW $0, R3 1059 RET 1060 1061 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. 1062 // Must obey the gcc calling convention. 1063 TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0 1064 // g (R30) and R31 are callee-save in the C ABI, so save them 1065 MOVD g, R4 1066 MOVD R31, R5 1067 MOVD LR, R6 1068 1069 BL runtime·load_g(SB) // clobbers g (R30), R31 1070 MOVD g_m(g), R3 1071 MOVD m_curg(R3), R3 1072 MOVD (g_stack+stack_hi)(R3), R3 1073 1074 MOVD R4, g 1075 MOVD R5, R31 1076 MOVD R6, LR 1077 RET 1078 1079 // The top-most function running on a goroutine 1080 // returns to goexit+PCQuantum. 1081 // 1082 // When dynamically linking Go, it can be returned to from a function 1083 // implemented in a different module and so needs to reload the TOC pointer 1084 // from the stack (although this function declares that it does not set up x-a 1085 // frame, newproc1 does in fact allocate one for goexit and saves the TOC 1086 // pointer in the correct place). 1087 // goexit+_PCQuantum is halfway through the usual global entry point prologue 1088 // that derives r2 from r12 which is a bit silly, but not harmful. 1089 TEXT runtime·goexit(SB),NOSPLIT|NOFRAME,$0-0 1090 MOVD 24(R1), R2 1091 BL runtime·goexit1(SB) // does not return 1092 // traceback from goexit1 must hit code range of goexit 1093 MOVD R0, R0 // NOP 1094 1095 TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8 1096 RET 1097 1098 TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8 1099 RET 1100 1101 TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8 1102 RET 1103 1104 TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8 1105 RET 1106 1107 TEXT runtime·sigreturn(SB),NOSPLIT,$0-8 1108 RET 1109 1110 // prepGoExitFrame saves the current TOC pointer (i.e. the TOC pointer for the 1111 // module containing runtime) to the frame that goexit will execute in when 1112 // the goroutine exits. It's implemented in assembly mainly because that's the 1113 // easiest way to get access to R2. 1114 TEXT runtime·prepGoExitFrame(SB),NOSPLIT,$0-8 1115 MOVD sp+0(FP), R3 1116 MOVD R2, 24(R3) 1117 RET 1118 1119 TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0 1120 ADD $-8, R1 1121 MOVD R31, 0(R1) 1122 MOVD runtime·lastmoduledatap(SB), R4 1123 MOVD R3, moduledata_next(R4) 1124 MOVD R3, runtime·lastmoduledatap(SB) 1125 MOVD 0(R1), R31 1126 ADD $8, R1 1127 RET 1128 1129 TEXT ·checkASM(SB),NOSPLIT,$0-1 1130 MOVW $1, R3 1131 MOVB R3, ret+0(FP) 1132 RET