github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/obj/loong64/obj.go (about) 1 // Copyright 2022 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 package loong64 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/internal/obj" 9 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 10 "github.com/bir3/gocompiler/src/cmd/internal/sys" 11 "github.com/bir3/gocompiler/src/internal/abi" 12 "log" 13 "math" 14 ) 15 16 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 17 // Rewrite JMP/JAL to symbol as TYPE_BRANCH. 18 switch p.As { 19 case AJMP, 20 AJAL, 21 ARET, 22 obj.ADUFFZERO, 23 obj.ADUFFCOPY: 24 if p.To.Sym != nil { 25 p.To.Type = obj.TYPE_BRANCH 26 } 27 } 28 29 // Rewrite float constants to values stored in memory. 30 switch p.As { 31 case AMOVF: 32 if p.From.Type == obj.TYPE_FCONST { 33 f32 := float32(p.From.Val.(float64)) 34 if math.Float32bits(f32) == 0 { 35 p.As = AMOVW 36 p.From.Type = obj.TYPE_REG 37 p.From.Reg = REGZERO 38 break 39 } 40 p.From.Type = obj.TYPE_MEM 41 p.From.Sym = ctxt.Float32Sym(f32) 42 p.From.Name = obj.NAME_EXTERN 43 p.From.Offset = 0 44 } 45 46 case AMOVD: 47 if p.From.Type == obj.TYPE_FCONST { 48 f64 := p.From.Val.(float64) 49 if math.Float64bits(f64) == 0 { 50 p.As = AMOVV 51 p.From.Type = obj.TYPE_REG 52 p.From.Reg = REGZERO 53 break 54 } 55 p.From.Type = obj.TYPE_MEM 56 p.From.Sym = ctxt.Float64Sym(f64) 57 p.From.Name = obj.NAME_EXTERN 58 p.From.Offset = 0 59 } 60 } 61 62 // Rewrite SUB constants into ADD. 63 switch p.As { 64 case ASUB: 65 if p.From.Type == obj.TYPE_CONST { 66 p.From.Offset = -p.From.Offset 67 p.As = AADD 68 } 69 70 case ASUBU: 71 if p.From.Type == obj.TYPE_CONST { 72 p.From.Offset = -p.From.Offset 73 p.As = AADDU 74 } 75 76 case ASUBV: 77 if p.From.Type == obj.TYPE_CONST { 78 p.From.Offset = -p.From.Offset 79 p.As = AADDV 80 } 81 82 case ASUBVU: 83 if p.From.Type == obj.TYPE_CONST { 84 p.From.Offset = -p.From.Offset 85 p.As = AADDVU 86 } 87 } 88 89 if ctxt.Flag_dynlink { 90 rewriteToUseGot(ctxt, p, newprog) 91 } 92 } 93 94 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 95 // ADUFFxxx $offset 96 // becomes 97 // MOVV runtime.duffxxx@GOT, REGTMP 98 // ADD $offset, REGTMP 99 // JAL REGTMP 100 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 101 var sym *obj.LSym 102 if p.As == obj.ADUFFZERO { 103 sym = ctxt.Lookup("runtime.duffzero") 104 } else { 105 sym = ctxt.Lookup("runtime.duffcopy") 106 } 107 offset := p.To.Offset 108 p.As = AMOVV 109 p.From.Type = obj.TYPE_MEM 110 p.From.Sym = sym 111 p.From.Name = obj.NAME_GOTREF 112 p.To.Type = obj.TYPE_REG 113 p.To.Reg = REGTMP 114 p.To.Name = obj.NAME_NONE 115 p.To.Offset = 0 116 p.To.Sym = nil 117 p1 := obj.Appendp(p, newprog) 118 p1.As = AADDV 119 p1.From.Type = obj.TYPE_CONST 120 p1.From.Offset = offset 121 p1.To.Type = obj.TYPE_REG 122 p1.To.Reg = REGTMP 123 p2 := obj.Appendp(p1, newprog) 124 p2.As = AJAL 125 p2.To.Type = obj.TYPE_MEM 126 p2.To.Reg = REGTMP 127 } 128 129 // We only care about global data: NAME_EXTERN means a global 130 // symbol in the Go sense, and p.Sym.Local is true for a few 131 // internally defined symbols. 132 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 133 // MOVV $sym, Rx becomes MOVV sym@GOT, Rx 134 // MOVV $sym+<off>, Rx becomes MOVV sym@GOT, Rx; ADD <off>, Rx 135 if p.As != AMOVV { 136 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -shared", p) 137 } 138 if p.To.Type != obj.TYPE_REG { 139 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -shared", p) 140 } 141 p.From.Type = obj.TYPE_MEM 142 p.From.Name = obj.NAME_GOTREF 143 if p.From.Offset != 0 { 144 q := obj.Appendp(p, newprog) 145 q.As = AADDV 146 q.From.Type = obj.TYPE_CONST 147 q.From.Offset = p.From.Offset 148 q.To = p.To 149 p.From.Offset = 0 150 } 151 } 152 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN { 153 ctxt.Diag("don't know how to handle %v with -shared", p) 154 } 155 156 var source *obj.Addr 157 // MOVx sym, Ry becomes MOVV sym@GOT, REGTMP; MOVx (REGTMP), Ry 158 // MOVx Ry, sym becomes MOVV sym@GOT, REGTMP; MOVx Ry, (REGTMP) 159 // An addition may be inserted between the two MOVs if there is an offset. 160 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 161 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 162 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -shared", p) 163 } 164 source = &p.From 165 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 166 source = &p.To 167 } else { 168 return 169 } 170 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 171 return 172 } 173 if source.Sym.Type == objabi.STLSBSS { 174 return 175 } 176 if source.Type != obj.TYPE_MEM { 177 ctxt.Diag("don't know how to handle %v with -shared", p) 178 } 179 p1 := obj.Appendp(p, newprog) 180 p2 := obj.Appendp(p1, newprog) 181 p1.As = AMOVV 182 p1.From.Type = obj.TYPE_MEM 183 p1.From.Sym = source.Sym 184 p1.From.Name = obj.NAME_GOTREF 185 p1.To.Type = obj.TYPE_REG 186 p1.To.Reg = REGTMP 187 188 p2.As = p.As 189 p2.From = p.From 190 p2.To = p.To 191 if p.From.Name == obj.NAME_EXTERN { 192 p2.From.Reg = REGTMP 193 p2.From.Name = obj.NAME_NONE 194 p2.From.Sym = nil 195 } else if p.To.Name == obj.NAME_EXTERN { 196 p2.To.Reg = REGTMP 197 p2.To.Name = obj.NAME_NONE 198 p2.To.Sym = nil 199 } else { 200 return 201 } 202 203 obj.Nopout(p) 204 } 205 206 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 207 c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym} 208 209 p := c.cursym.Func().Text 210 textstksiz := p.To.Offset 211 212 if textstksiz < 0 { 213 c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz) 214 } 215 if p.From.Sym.NoFrame() { 216 if textstksiz != 0 { 217 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 218 } 219 } 220 221 c.cursym.Func().Args = p.To.Val.(int32) 222 c.cursym.Func().Locals = int32(textstksiz) 223 224 /* 225 * find leaf subroutines 226 * expand RET 227 */ 228 229 for p := c.cursym.Func().Text; p != nil; p = p.Link { 230 switch p.As { 231 case obj.ATEXT: 232 p.Mark |= LABEL | LEAF | SYNC 233 if p.Link != nil { 234 p.Link.Mark |= LABEL 235 } 236 237 case AMOVW, 238 AMOVV: 239 if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL { 240 p.Mark |= LABEL | SYNC 241 break 242 } 243 if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL { 244 p.Mark |= LABEL | SYNC 245 } 246 247 case ASYSCALL, 248 AWORD: 249 p.Mark |= LABEL | SYNC 250 251 case ANOR: 252 if p.To.Type == obj.TYPE_REG { 253 if p.To.Reg == REGZERO { 254 p.Mark |= LABEL | SYNC 255 } 256 } 257 258 case AJAL, 259 obj.ADUFFZERO, 260 obj.ADUFFCOPY: 261 c.cursym.Func().Text.Mark &^= LEAF 262 fallthrough 263 264 case AJMP, 265 ABEQ, 266 ABGEU, 267 ABLTU, 268 ABLTZ, 269 ABNE, 270 ABFPT, ABFPF: 271 p.Mark |= BRANCH 272 q1 := p.To.Target() 273 if q1 != nil { 274 for q1.As == obj.ANOP { 275 q1 = q1.Link 276 p.To.SetTarget(q1) 277 } 278 279 if q1.Mark&LEAF == 0 { 280 q1.Mark |= LABEL 281 } 282 } 283 q1 = p.Link 284 if q1 != nil { 285 q1.Mark |= LABEL 286 } 287 288 case ARET: 289 if p.Link != nil { 290 p.Link.Mark |= LABEL 291 } 292 } 293 } 294 295 var mov, add obj.As 296 297 add = AADDV 298 mov = AMOVV 299 300 var q *obj.Prog 301 var q1 *obj.Prog 302 autosize := int32(0) 303 var p1 *obj.Prog 304 var p2 *obj.Prog 305 for p := c.cursym.Func().Text; p != nil; p = p.Link { 306 o := p.As 307 switch o { 308 case obj.ATEXT: 309 autosize = int32(textstksiz) 310 311 if p.Mark&LEAF != 0 && autosize == 0 { 312 // A leaf function with no locals has no frame. 313 p.From.Sym.Set(obj.AttrNoFrame, true) 314 } 315 316 if !p.From.Sym.NoFrame() { 317 // If there is a stack frame at all, it includes 318 // space to save the LR. 319 autosize += int32(c.ctxt.Arch.FixedFrameSize) 320 } 321 322 if autosize&4 != 0 { 323 autosize += 4 324 } 325 326 if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 { 327 if c.cursym.Func().Text.From.Sym.NoSplit() { 328 if ctxt.Debugvlog { 329 ctxt.Logf("save suppressed in: %s\n", c.cursym.Name) 330 } 331 332 c.cursym.Func().Text.Mark |= LEAF 333 } 334 } 335 336 p.To.Offset = int64(autosize) - ctxt.Arch.FixedFrameSize 337 338 if c.cursym.Func().Text.Mark&LEAF != 0 { 339 c.cursym.Set(obj.AttrLeaf, true) 340 if p.From.Sym.NoFrame() { 341 break 342 } 343 } 344 345 if !p.From.Sym.NoSplit() { 346 p = c.stacksplit(p, autosize) // emit split check 347 } 348 349 q = p 350 351 if autosize != 0 { 352 // Make sure to save link register for non-empty frame, even if 353 // it is a leaf function, so that traceback works. 354 // Store link register before decrement SP, so if a signal comes 355 // during the execution of the function prologue, the traceback 356 // code will not see a half-updated stack frame. 357 // This sequence is not async preemptible, as if we open a frame 358 // at the current SP, it will clobber the saved LR. 359 q = c.ctxt.StartUnsafePoint(q, c.newprog) 360 361 q = obj.Appendp(q, newprog) 362 q.As = mov 363 q.Pos = p.Pos 364 q.From.Type = obj.TYPE_REG 365 q.From.Reg = REGLINK 366 q.To.Type = obj.TYPE_MEM 367 q.To.Offset = int64(-autosize) 368 q.To.Reg = REGSP 369 370 q = obj.Appendp(q, newprog) 371 q.As = add 372 q.Pos = p.Pos 373 q.From.Type = obj.TYPE_CONST 374 q.From.Offset = int64(-autosize) 375 q.To.Type = obj.TYPE_REG 376 q.To.Reg = REGSP 377 q.Spadj = +autosize 378 379 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1) 380 381 // On Linux, in a cgo binary we may get a SIGSETXID signal early on 382 // before the signal stack is set, as glibc doesn't allow us to block 383 // SIGSETXID. So a signal may land on the current stack and clobber 384 // the content below the SP. We store the LR again after the SP is 385 // decremented. 386 q = obj.Appendp(q, newprog) 387 q.As = mov 388 q.Pos = p.Pos 389 q.From.Type = obj.TYPE_REG 390 q.From.Reg = REGLINK 391 q.To.Type = obj.TYPE_MEM 392 q.To.Offset = 0 393 q.To.Reg = REGSP 394 } 395 396 if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 { 397 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 398 // 399 // MOV g_panic(g), R20 400 // BEQ R20, end 401 // MOV panic_argp(R20), R24 402 // ADD $(autosize+FIXED_FRAME), R3, R30 403 // BNE R24, R30, end 404 // ADD $FIXED_FRAME, R3, R24 405 // MOV R24, panic_argp(R20) 406 // end: 407 // NOP 408 // 409 // The NOP is needed to give the jumps somewhere to land. 410 // It is a liblink NOP, not a hardware NOP: it encodes to 0 instruction bytes. 411 // 412 // We don't generate this for leafs because that means the wrapped 413 // function was inlined into the wrapper. 414 415 q = obj.Appendp(q, newprog) 416 417 q.As = mov 418 q.From.Type = obj.TYPE_MEM 419 q.From.Reg = REGG 420 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 421 q.To.Type = obj.TYPE_REG 422 q.To.Reg = REG_R20 423 424 q = obj.Appendp(q, newprog) 425 q.As = ABEQ 426 q.From.Type = obj.TYPE_REG 427 q.From.Reg = REG_R20 428 q.To.Type = obj.TYPE_BRANCH 429 q.Mark |= BRANCH 430 p1 = q 431 432 q = obj.Appendp(q, newprog) 433 q.As = mov 434 q.From.Type = obj.TYPE_MEM 435 q.From.Reg = REG_R20 436 q.From.Offset = 0 // Panic.argp 437 q.To.Type = obj.TYPE_REG 438 q.To.Reg = REG_R24 439 440 q = obj.Appendp(q, newprog) 441 q.As = add 442 q.From.Type = obj.TYPE_CONST 443 q.From.Offset = int64(autosize) + ctxt.Arch.FixedFrameSize 444 q.Reg = REGSP 445 q.To.Type = obj.TYPE_REG 446 q.To.Reg = REG_R30 447 448 q = obj.Appendp(q, newprog) 449 q.As = ABNE 450 q.From.Type = obj.TYPE_REG 451 q.From.Reg = REG_R24 452 q.Reg = REG_R30 453 q.To.Type = obj.TYPE_BRANCH 454 q.Mark |= BRANCH 455 p2 = q 456 457 q = obj.Appendp(q, newprog) 458 q.As = add 459 q.From.Type = obj.TYPE_CONST 460 q.From.Offset = ctxt.Arch.FixedFrameSize 461 q.Reg = REGSP 462 q.To.Type = obj.TYPE_REG 463 q.To.Reg = REG_R24 464 465 q = obj.Appendp(q, newprog) 466 q.As = mov 467 q.From.Type = obj.TYPE_REG 468 q.From.Reg = REG_R24 469 q.To.Type = obj.TYPE_MEM 470 q.To.Reg = REG_R20 471 q.To.Offset = 0 // Panic.argp 472 473 q = obj.Appendp(q, newprog) 474 475 q.As = obj.ANOP 476 p1.To.SetTarget(q) 477 p2.To.SetTarget(q) 478 } 479 480 case ARET: 481 if p.From.Type == obj.TYPE_CONST { 482 ctxt.Diag("using BECOME (%v) is not supported!", p) 483 break 484 } 485 486 retSym := p.To.Sym 487 p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction 488 p.To.Sym = nil 489 490 if c.cursym.Func().Text.Mark&LEAF != 0 { 491 if autosize == 0 { 492 p.As = AJMP 493 p.From = obj.Addr{} 494 if retSym != nil { // retjmp 495 p.To.Type = obj.TYPE_BRANCH 496 p.To.Name = obj.NAME_EXTERN 497 p.To.Sym = retSym 498 } else { 499 p.To.Type = obj.TYPE_MEM 500 p.To.Reg = REGLINK 501 p.To.Offset = 0 502 } 503 p.Mark |= BRANCH 504 break 505 } 506 507 p.As = add 508 p.From.Type = obj.TYPE_CONST 509 p.From.Offset = int64(autosize) 510 p.To.Type = obj.TYPE_REG 511 p.To.Reg = REGSP 512 p.Spadj = -autosize 513 514 q = c.newprog() 515 q.As = AJMP 516 q.Pos = p.Pos 517 if retSym != nil { // retjmp 518 q.To.Type = obj.TYPE_BRANCH 519 q.To.Name = obj.NAME_EXTERN 520 q.To.Sym = retSym 521 } else { 522 q.To.Type = obj.TYPE_MEM 523 q.To.Offset = 0 524 q.To.Reg = REGLINK 525 } 526 q.Mark |= BRANCH 527 q.Spadj = +autosize 528 529 q.Link = p.Link 530 p.Link = q 531 break 532 } 533 534 p.As = mov 535 p.From.Type = obj.TYPE_MEM 536 p.From.Offset = 0 537 p.From.Reg = REGSP 538 p.To.Type = obj.TYPE_REG 539 p.To.Reg = REGLINK 540 541 if autosize != 0 { 542 q = c.newprog() 543 q.As = add 544 q.Pos = p.Pos 545 q.From.Type = obj.TYPE_CONST 546 q.From.Offset = int64(autosize) 547 q.To.Type = obj.TYPE_REG 548 q.To.Reg = REGSP 549 q.Spadj = -autosize 550 551 q.Link = p.Link 552 p.Link = q 553 } 554 555 q1 = c.newprog() 556 q1.As = AJMP 557 q1.Pos = p.Pos 558 if retSym != nil { // retjmp 559 q1.To.Type = obj.TYPE_BRANCH 560 q1.To.Name = obj.NAME_EXTERN 561 q1.To.Sym = retSym 562 } else { 563 q1.To.Type = obj.TYPE_MEM 564 q1.To.Offset = 0 565 q1.To.Reg = REGLINK 566 } 567 q1.Mark |= BRANCH 568 q1.Spadj = +autosize 569 570 q1.Link = q.Link 571 q.Link = q1 572 573 case AADD, 574 AADDU, 575 AADDV, 576 AADDVU: 577 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 578 p.Spadj = int32(-p.From.Offset) 579 } 580 581 case obj.AGETCALLERPC: 582 if cursym.Leaf() { 583 // MOV LR, Rd 584 p.As = mov 585 p.From.Type = obj.TYPE_REG 586 p.From.Reg = REGLINK 587 } else { 588 // MOV (RSP), Rd 589 p.As = mov 590 p.From.Type = obj.TYPE_MEM 591 p.From.Reg = REGSP 592 } 593 } 594 595 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 { 596 f := c.cursym.Func() 597 if f.FuncFlag&abi.FuncFlagSPWrite == 0 { 598 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite 599 if ctxt.Debugvlog || !ctxt.IsAsm { 600 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p) 601 if !ctxt.IsAsm { 602 ctxt.Diag("invalid auto-SPWRITE in non-assembly") 603 ctxt.DiagFlush() 604 log.Fatalf("bad SPWRITE") 605 } 606 } 607 } 608 } 609 } 610 } 611 612 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { 613 var mov, add obj.As 614 615 add = AADDV 616 mov = AMOVV 617 if c.ctxt.Flag_maymorestack != "" { 618 // Save LR and REGCTXT. 619 frameSize := 2 * c.ctxt.Arch.PtrSize 620 621 p = c.ctxt.StartUnsafePoint(p, c.newprog) 622 623 // Spill Arguments. This has to happen before we open 624 // any more frame space. 625 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog) 626 627 // MOV REGLINK, -8/-16(SP) 628 p = obj.Appendp(p, c.newprog) 629 p.As = mov 630 p.From.Type = obj.TYPE_REG 631 p.From.Reg = REGLINK 632 p.To.Type = obj.TYPE_MEM 633 p.To.Offset = int64(-frameSize) 634 p.To.Reg = REGSP 635 636 // MOV REGCTXT, -4/-8(SP) 637 p = obj.Appendp(p, c.newprog) 638 p.As = mov 639 p.From.Type = obj.TYPE_REG 640 p.From.Reg = REGCTXT 641 p.To.Type = obj.TYPE_MEM 642 p.To.Offset = -int64(c.ctxt.Arch.PtrSize) 643 p.To.Reg = REGSP 644 645 // ADD $-8/$-16, SP 646 p = obj.Appendp(p, c.newprog) 647 p.As = add 648 p.From.Type = obj.TYPE_CONST 649 p.From.Offset = int64(-frameSize) 650 p.To.Type = obj.TYPE_REG 651 p.To.Reg = REGSP 652 p.Spadj = int32(frameSize) 653 654 // JAL maymorestack 655 p = obj.Appendp(p, c.newprog) 656 p.As = AJAL 657 p.To.Type = obj.TYPE_BRANCH 658 // See ../x86/obj6.go 659 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI()) 660 p.Mark |= BRANCH 661 662 // Restore LR and REGCTXT. 663 664 // MOV 0(SP), REGLINK 665 p = obj.Appendp(p, c.newprog) 666 p.As = mov 667 p.From.Type = obj.TYPE_MEM 668 p.From.Offset = 0 669 p.From.Reg = REGSP 670 p.To.Type = obj.TYPE_REG 671 p.To.Reg = REGLINK 672 673 // MOV 4/8(SP), REGCTXT 674 p = obj.Appendp(p, c.newprog) 675 p.As = mov 676 p.From.Type = obj.TYPE_MEM 677 p.From.Offset = int64(c.ctxt.Arch.PtrSize) 678 p.From.Reg = REGSP 679 p.To.Type = obj.TYPE_REG 680 p.To.Reg = REGCTXT 681 682 // ADD $8/$16, SP 683 p = obj.Appendp(p, c.newprog) 684 p.As = add 685 p.From.Type = obj.TYPE_CONST 686 p.From.Offset = int64(frameSize) 687 p.To.Type = obj.TYPE_REG 688 p.To.Reg = REGSP 689 p.Spadj = int32(-frameSize) 690 691 // Unspill arguments 692 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog) 693 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1) 694 } 695 696 // Jump back to here after morestack returns. 697 startPred := p 698 699 // MOV g_stackguard(g), R20 700 p = obj.Appendp(p, c.newprog) 701 702 p.As = mov 703 p.From.Type = obj.TYPE_MEM 704 p.From.Reg = REGG 705 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 706 if c.cursym.CFunc() { 707 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 708 } 709 p.To.Type = obj.TYPE_REG 710 p.To.Reg = REG_R20 711 712 // Mark the stack bound check and morestack call async nonpreemptible. 713 // If we get preempted here, when resumed the preemption request is 714 // cleared, but we'll still call morestack, which will double the stack 715 // unnecessarily. See issue #35470. 716 p = c.ctxt.StartUnsafePoint(p, c.newprog) 717 718 var q *obj.Prog 719 if framesize <= abi.StackSmall { 720 // small stack: SP < stackguard 721 // AGTU SP, stackguard, R20 722 p = obj.Appendp(p, c.newprog) 723 724 p.As = ASGTU 725 p.From.Type = obj.TYPE_REG 726 p.From.Reg = REGSP 727 p.Reg = REG_R20 728 p.To.Type = obj.TYPE_REG 729 p.To.Reg = REG_R20 730 } else { 731 // large stack: SP-framesize < stackguard-StackSmall 732 offset := int64(framesize) - abi.StackSmall 733 if framesize > abi.StackBig { 734 // Such a large stack we need to protect against underflow. 735 // The runtime guarantees SP > objabi.StackBig, but 736 // framesize is large enough that SP-framesize may 737 // underflow, causing a direct comparison with the 738 // stack guard to incorrectly succeed. We explicitly 739 // guard against underflow. 740 // 741 // SGTU $(framesize-StackSmall), SP, R24 742 // BNE R24, label-of-call-to-morestack 743 744 p = obj.Appendp(p, c.newprog) 745 p.As = ASGTU 746 p.From.Type = obj.TYPE_CONST 747 p.From.Offset = offset 748 p.Reg = REGSP 749 p.To.Type = obj.TYPE_REG 750 p.To.Reg = REG_R24 751 752 p = obj.Appendp(p, c.newprog) 753 q = p 754 p.As = ABNE 755 p.From.Type = obj.TYPE_REG 756 p.From.Reg = REG_R24 757 p.To.Type = obj.TYPE_BRANCH 758 p.Mark |= BRANCH 759 } 760 761 p = obj.Appendp(p, c.newprog) 762 763 p.As = add 764 p.From.Type = obj.TYPE_CONST 765 p.From.Offset = -offset 766 p.Reg = REGSP 767 p.To.Type = obj.TYPE_REG 768 p.To.Reg = REG_R24 769 770 p = obj.Appendp(p, c.newprog) 771 p.As = ASGTU 772 p.From.Type = obj.TYPE_REG 773 p.From.Reg = REG_R24 774 p.Reg = REG_R20 775 p.To.Type = obj.TYPE_REG 776 p.To.Reg = REG_R20 777 } 778 779 // q1: BNE R20, done 780 p = obj.Appendp(p, c.newprog) 781 q1 := p 782 783 p.As = ABNE 784 p.From.Type = obj.TYPE_REG 785 p.From.Reg = REG_R20 786 p.To.Type = obj.TYPE_BRANCH 787 p.Mark |= BRANCH 788 789 // MOV LINK, R31 790 p = obj.Appendp(p, c.newprog) 791 792 p.As = mov 793 p.From.Type = obj.TYPE_REG 794 p.From.Reg = REGLINK 795 p.To.Type = obj.TYPE_REG 796 p.To.Reg = REG_R31 797 if q != nil { 798 q.To.SetTarget(p) 799 p.Mark |= LABEL 800 } 801 802 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog) 803 804 // Spill the register args that could be clobbered by the 805 // morestack code 806 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog) 807 808 // JAL runtime.morestack(SB) 809 p = obj.Appendp(p, c.newprog) 810 811 p.As = AJAL 812 p.To.Type = obj.TYPE_BRANCH 813 if c.cursym.CFunc() { 814 p.To.Sym = c.ctxt.Lookup("runtime.morestackc") 815 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() { 816 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt") 817 } else { 818 p.To.Sym = c.ctxt.Lookup("runtime.morestack") 819 } 820 p.Mark |= BRANCH 821 822 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog) 823 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1) 824 825 // JMP start 826 p = obj.Appendp(p, c.newprog) 827 828 p.As = AJMP 829 p.To.Type = obj.TYPE_BRANCH 830 p.To.SetTarget(startPred.Link) 831 startPred.Link.Mark |= LABEL 832 p.Mark |= BRANCH 833 834 // placeholder for q1's jump target 835 p = obj.Appendp(p, c.newprog) 836 837 p.As = obj.ANOP // zero-width place holder 838 q1.To.SetTarget(p) 839 840 return p 841 } 842 843 func (c *ctxt0) addnop(p *obj.Prog) { 844 q := c.newprog() 845 q.As = ANOOP 846 q.Pos = p.Pos 847 q.Link = p.Link 848 p.Link = q 849 } 850 851 var Linkloong64 = obj.LinkArch{ 852 Arch: sys.ArchLoong64, 853 Init: buildop, 854 Preprocess: preprocess, 855 Assemble: span0, 856 Progedit: progedit, 857 DWARFRegisters: LOONG64DWARFRegisters, 858 }