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