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