github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/internal/obj/mips/obj0.go (about) 1 // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova. 2 // 3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 5 // Portions Copyright © 1997-1999 Vita Nuova Limited 6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) 7 // Portions Copyright © 2004,2006 Bruce Ellis 8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others 10 // Portions Copyright © 2009 The Go Authors. All rights reserved. 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // of this software and associated documentation files (the "Software"), to deal 14 // in the Software without restriction, including without limitation the rights 15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 // copies of the Software, and to permit persons to whom the Software is 17 // furnished to do so, subject to the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be included in 20 // all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 // THE SOFTWARE. 29 30 package mips 31 32 import ( 33 "cmd/internal/obj" 34 "cmd/internal/sys" 35 "encoding/binary" 36 "fmt" 37 "math" 38 ) 39 40 func progedit(ctxt *obj.Link, p *obj.Prog) { 41 // Maintain information about code generation mode. 42 if ctxt.Mode == 0 { 43 switch ctxt.Arch.Family { 44 default: 45 ctxt.Diag("unsupported arch family") 46 case sys.MIPS: 47 ctxt.Mode = Mips32 48 case sys.MIPS64: 49 ctxt.Mode = Mips64 50 } 51 } 52 53 p.From.Class = 0 54 p.To.Class = 0 55 56 // Rewrite JMP/JAL to symbol as TYPE_BRANCH. 57 switch p.As { 58 case AJMP, 59 AJAL, 60 ARET, 61 obj.ADUFFZERO, 62 obj.ADUFFCOPY: 63 if p.To.Sym != nil { 64 p.To.Type = obj.TYPE_BRANCH 65 } 66 } 67 68 // Rewrite float constants to values stored in memory. 69 switch p.As { 70 case AMOVF: 71 if p.From.Type == obj.TYPE_FCONST { 72 f32 := float32(p.From.Val.(float64)) 73 i32 := math.Float32bits(f32) 74 if i32 == 0 { 75 p.As = AMOVW 76 p.From.Type = obj.TYPE_REG 77 p.From.Reg = REGZERO 78 break 79 } 80 literal := fmt.Sprintf("$f32.%08x", i32) 81 s := obj.Linklookup(ctxt, literal, 0) 82 s.Size = 4 83 p.From.Type = obj.TYPE_MEM 84 p.From.Sym = s 85 p.From.Name = obj.NAME_EXTERN 86 p.From.Offset = 0 87 } 88 89 case AMOVD: 90 if p.From.Type == obj.TYPE_FCONST { 91 i64 := math.Float64bits(p.From.Val.(float64)) 92 if i64 == 0 && ctxt.Mode&Mips64 != 0 { 93 p.As = AMOVV 94 p.From.Type = obj.TYPE_REG 95 p.From.Reg = REGZERO 96 break 97 } 98 literal := fmt.Sprintf("$f64.%016x", i64) 99 s := obj.Linklookup(ctxt, literal, 0) 100 s.Size = 8 101 p.From.Type = obj.TYPE_MEM 102 p.From.Sym = s 103 p.From.Name = obj.NAME_EXTERN 104 p.From.Offset = 0 105 } 106 107 // Put >32-bit constants in memory and load them 108 case AMOVV: 109 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset { 110 literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset)) 111 s := obj.Linklookup(ctxt, literal, 0) 112 s.Size = 8 113 p.From.Type = obj.TYPE_MEM 114 p.From.Sym = s 115 p.From.Name = obj.NAME_EXTERN 116 p.From.Offset = 0 117 } 118 } 119 120 // Rewrite SUB constants into ADD. 121 switch p.As { 122 case ASUB: 123 if p.From.Type == obj.TYPE_CONST { 124 p.From.Offset = -p.From.Offset 125 p.As = AADD 126 } 127 128 case ASUBU: 129 if p.From.Type == obj.TYPE_CONST { 130 p.From.Offset = -p.From.Offset 131 p.As = AADDU 132 } 133 134 case ASUBV: 135 if p.From.Type == obj.TYPE_CONST { 136 p.From.Offset = -p.From.Offset 137 p.As = AADDV 138 } 139 140 case ASUBVU: 141 if p.From.Type == obj.TYPE_CONST { 142 p.From.Offset = -p.From.Offset 143 p.As = AADDVU 144 } 145 } 146 } 147 148 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 149 // TODO(minux): add morestack short-cuts with small fixed frame-size. 150 ctxt.Cursym = cursym 151 152 // a switch for enabling/disabling instruction scheduling 153 nosched := true 154 155 if cursym.Text == nil || cursym.Text.Link == nil { 156 return 157 } 158 159 p := cursym.Text 160 textstksiz := p.To.Offset 161 162 cursym.Args = p.To.Val.(int32) 163 cursym.Locals = int32(textstksiz) 164 165 /* 166 * find leaf subroutines 167 * strip NOPs 168 * expand RET 169 * expand BECOME pseudo 170 */ 171 if ctxt.Debugvlog != 0 { 172 ctxt.Logf("%5.2f noops\n", obj.Cputime()) 173 } 174 175 var q *obj.Prog 176 var q1 *obj.Prog 177 for p := cursym.Text; p != nil; p = p.Link { 178 switch p.As { 179 /* too hard, just leave alone */ 180 case obj.ATEXT: 181 q = p 182 183 p.Mark |= LABEL | LEAF | SYNC 184 if p.Link != nil { 185 p.Link.Mark |= LABEL 186 } 187 188 /* too hard, just leave alone */ 189 case AMOVW, 190 AMOVV: 191 q = p 192 if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL { 193 p.Mark |= LABEL | SYNC 194 break 195 } 196 if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL { 197 p.Mark |= LABEL | SYNC 198 } 199 200 /* too hard, just leave alone */ 201 case ASYSCALL, 202 AWORD, 203 ATLBWR, 204 ATLBWI, 205 ATLBP, 206 ATLBR: 207 q = p 208 p.Mark |= LABEL | SYNC 209 210 case ANOR: 211 q = p 212 if p.To.Type == obj.TYPE_REG { 213 if p.To.Reg == REGZERO { 214 p.Mark |= LABEL | SYNC 215 } 216 } 217 218 case ABGEZAL, 219 ABLTZAL, 220 AJAL, 221 obj.ADUFFZERO, 222 obj.ADUFFCOPY: 223 cursym.Text.Mark &^= LEAF 224 fallthrough 225 226 case AJMP, 227 ABEQ, 228 ABGEZ, 229 ABGTZ, 230 ABLEZ, 231 ABLTZ, 232 ABNE, 233 ABFPT, ABFPF: 234 if p.As == ABFPT || p.As == ABFPF { 235 // We don't treat ABFPT and ABFPF as branches here, 236 // so that we will always fill nop (0x0) in their 237 // delay slot during assembly. 238 // This is to workaround a kernel FPU emulator bug 239 // where it uses the user stack to simulate the 240 // instruction in the delay slot if it's not 0x0, 241 // and somehow that leads to SIGSEGV when the kernel 242 // jump to the stack. 243 p.Mark |= SYNC 244 } else { 245 p.Mark |= BRANCH 246 } 247 q = p 248 q1 = p.Pcond 249 if q1 != nil { 250 for q1.As == obj.ANOP { 251 q1 = q1.Link 252 p.Pcond = q1 253 } 254 255 if q1.Mark&LEAF == 0 { 256 q1.Mark |= LABEL 257 } 258 } 259 //else { 260 // p.Mark |= LABEL 261 //} 262 q1 = p.Link 263 if q1 != nil { 264 q1.Mark |= LABEL 265 } 266 continue 267 268 case ARET: 269 q = p 270 if p.Link != nil { 271 p.Link.Mark |= LABEL 272 } 273 continue 274 275 case obj.ANOP: 276 q1 = p.Link 277 q.Link = q1 /* q is non-nop */ 278 q1.Mark |= p.Mark 279 continue 280 281 default: 282 q = p 283 continue 284 } 285 } 286 287 var mov, add obj.As 288 if ctxt.Mode&Mips64 != 0 { 289 add = AADDV 290 mov = AMOVV 291 } else { 292 add = AADDU 293 mov = AMOVW 294 } 295 296 autosize := int32(0) 297 var p1 *obj.Prog 298 var p2 *obj.Prog 299 for p := cursym.Text; p != nil; p = p.Link { 300 o := p.As 301 switch o { 302 case obj.ATEXT: 303 autosize = int32(textstksiz + ctxt.FixedFrameSize()) 304 if (p.Mark&LEAF != 0) && autosize <= int32(ctxt.FixedFrameSize()) { 305 autosize = 0 306 } else if autosize&4 != 0 && ctxt.Mode&Mips64 != 0 { 307 autosize += 4 308 } 309 310 p.To.Offset = int64(autosize) - ctxt.FixedFrameSize() 311 312 if p.From3.Offset&obj.NOSPLIT == 0 { 313 p = stacksplit(ctxt, p, autosize) // emit split check 314 } 315 316 q = p 317 318 if autosize != 0 { 319 // Make sure to save link register for non-empty frame, even if 320 // it is a leaf function, so that traceback works. 321 // Store link register before decrement SP, so if a signal comes 322 // during the execution of the function prologue, the traceback 323 // code will not see a half-updated stack frame. 324 q = obj.Appendp(ctxt, q) 325 q.As = mov 326 q.Pos = p.Pos 327 q.From.Type = obj.TYPE_REG 328 q.From.Reg = REGLINK 329 q.To.Type = obj.TYPE_MEM 330 q.To.Offset = int64(-autosize) 331 q.To.Reg = REGSP 332 333 q = obj.Appendp(ctxt, q) 334 q.As = add 335 q.Pos = p.Pos 336 q.From.Type = obj.TYPE_CONST 337 q.From.Offset = int64(-autosize) 338 q.To.Type = obj.TYPE_REG 339 q.To.Reg = REGSP 340 q.Spadj = +autosize 341 } else if cursym.Text.Mark&LEAF == 0 { 342 if cursym.Text.From3.Offset&obj.NOSPLIT != 0 { 343 if ctxt.Debugvlog != 0 { 344 ctxt.Logf("save suppressed in: %s\n", cursym.Name) 345 } 346 347 cursym.Text.Mark |= LEAF 348 } 349 } 350 351 if cursym.Text.Mark&LEAF != 0 { 352 cursym.Set(obj.AttrLeaf, true) 353 break 354 } 355 356 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 357 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 358 // 359 // MOV g_panic(g), R1 360 // BEQ R1, end 361 // MOV panic_argp(R1), R2 362 // ADD $(autosize+FIXED_FRAME), R29, R3 363 // BNE R2, R3, end 364 // ADD $FIXED_FRAME, R29, R2 365 // MOV R2, panic_argp(R1) 366 // end: 367 // NOP 368 // 369 // The NOP is needed to give the jumps somewhere to land. 370 // It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes. 371 372 q = obj.Appendp(ctxt, q) 373 374 q.As = mov 375 q.From.Type = obj.TYPE_MEM 376 q.From.Reg = REGG 377 q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic 378 q.To.Type = obj.TYPE_REG 379 q.To.Reg = REG_R1 380 381 q = obj.Appendp(ctxt, q) 382 q.As = ABEQ 383 q.From.Type = obj.TYPE_REG 384 q.From.Reg = REG_R1 385 q.To.Type = obj.TYPE_BRANCH 386 q.Mark |= BRANCH 387 p1 = q 388 389 q = obj.Appendp(ctxt, q) 390 q.As = mov 391 q.From.Type = obj.TYPE_MEM 392 q.From.Reg = REG_R1 393 q.From.Offset = 0 // Panic.argp 394 q.To.Type = obj.TYPE_REG 395 q.To.Reg = REG_R2 396 397 q = obj.Appendp(ctxt, q) 398 q.As = add 399 q.From.Type = obj.TYPE_CONST 400 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 401 q.Reg = REGSP 402 q.To.Type = obj.TYPE_REG 403 q.To.Reg = REG_R3 404 405 q = obj.Appendp(ctxt, q) 406 q.As = ABNE 407 q.From.Type = obj.TYPE_REG 408 q.From.Reg = REG_R2 409 q.Reg = REG_R3 410 q.To.Type = obj.TYPE_BRANCH 411 q.Mark |= BRANCH 412 p2 = q 413 414 q = obj.Appendp(ctxt, q) 415 q.As = add 416 q.From.Type = obj.TYPE_CONST 417 q.From.Offset = ctxt.FixedFrameSize() 418 q.Reg = REGSP 419 q.To.Type = obj.TYPE_REG 420 q.To.Reg = REG_R2 421 422 q = obj.Appendp(ctxt, q) 423 q.As = mov 424 q.From.Type = obj.TYPE_REG 425 q.From.Reg = REG_R2 426 q.To.Type = obj.TYPE_MEM 427 q.To.Reg = REG_R1 428 q.To.Offset = 0 // Panic.argp 429 430 q = obj.Appendp(ctxt, q) 431 432 q.As = obj.ANOP 433 p1.Pcond = q 434 p2.Pcond = q 435 } 436 437 case ARET: 438 if p.From.Type == obj.TYPE_CONST { 439 ctxt.Diag("using BECOME (%v) is not supported!", p) 440 break 441 } 442 443 retSym := p.To.Sym 444 p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction 445 p.To.Sym = nil 446 447 if cursym.Text.Mark&LEAF != 0 { 448 if autosize == 0 { 449 p.As = AJMP 450 p.From = obj.Addr{} 451 if retSym != nil { // retjmp 452 p.To.Type = obj.TYPE_BRANCH 453 p.To.Name = obj.NAME_EXTERN 454 p.To.Sym = retSym 455 } else { 456 p.To.Type = obj.TYPE_MEM 457 p.To.Reg = REGLINK 458 p.To.Offset = 0 459 } 460 p.Mark |= BRANCH 461 break 462 } 463 464 p.As = add 465 p.From.Type = obj.TYPE_CONST 466 p.From.Offset = int64(autosize) 467 p.To.Type = obj.TYPE_REG 468 p.To.Reg = REGSP 469 p.Spadj = -autosize 470 471 q = ctxt.NewProg() 472 q.As = AJMP 473 q.Pos = p.Pos 474 q.To.Type = obj.TYPE_MEM 475 q.To.Offset = 0 476 q.To.Reg = REGLINK 477 q.Mark |= BRANCH 478 q.Spadj = +autosize 479 480 q.Link = p.Link 481 p.Link = q 482 break 483 } 484 485 p.As = mov 486 p.From.Type = obj.TYPE_MEM 487 p.From.Offset = 0 488 p.From.Reg = REGSP 489 p.To.Type = obj.TYPE_REG 490 p.To.Reg = REG_R4 491 if retSym != nil { // retjmp from non-leaf, need to restore LINK register 492 p.To.Reg = REGLINK 493 } 494 495 if autosize != 0 { 496 q = ctxt.NewProg() 497 q.As = add 498 q.Pos = p.Pos 499 q.From.Type = obj.TYPE_CONST 500 q.From.Offset = int64(autosize) 501 q.To.Type = obj.TYPE_REG 502 q.To.Reg = REGSP 503 q.Spadj = -autosize 504 505 q.Link = p.Link 506 p.Link = q 507 } 508 509 q1 = ctxt.NewProg() 510 q1.As = AJMP 511 q1.Pos = p.Pos 512 if retSym != nil { // retjmp 513 q1.To.Type = obj.TYPE_BRANCH 514 q1.To.Name = obj.NAME_EXTERN 515 q1.To.Sym = retSym 516 } else { 517 q1.To.Type = obj.TYPE_MEM 518 q1.To.Offset = 0 519 q1.To.Reg = REG_R4 520 } 521 q1.Mark |= BRANCH 522 q1.Spadj = +autosize 523 524 q1.Link = q.Link 525 q.Link = q1 526 527 case AADD, 528 AADDU, 529 AADDV, 530 AADDVU: 531 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 532 p.Spadj = int32(-p.From.Offset) 533 } 534 } 535 } 536 537 if ctxt.Mode&Mips32 != 0 { 538 // rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access 539 for p = cursym.Text; p != nil; p = p1 { 540 p1 = p.Link 541 542 if p.As != AMOVD { 543 continue 544 } 545 if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM { 546 continue 547 } 548 549 p.As = AMOVF 550 q = ctxt.NewProg() 551 *q = *p 552 q.Link = p.Link 553 p.Link = q 554 p1 = q.Link 555 556 var regOff int16 557 if ctxt.Arch.ByteOrder == binary.BigEndian { 558 regOff = 1 // load odd register first 559 } 560 if p.From.Type == obj.TYPE_MEM { 561 reg := REG_F0 + (p.To.Reg-REG_F0)&^1 562 p.To.Reg = reg + regOff 563 q.To.Reg = reg + 1 - regOff 564 q.From.Offset += 4 565 } else if p.To.Type == obj.TYPE_MEM { 566 reg := REG_F0 + (p.From.Reg-REG_F0)&^1 567 p.From.Reg = reg + regOff 568 q.From.Reg = reg + 1 - regOff 569 q.To.Offset += 4 570 } 571 } 572 } 573 574 if nosched { 575 // if we don't do instruction scheduling, simply add 576 // NOP after each branch instruction. 577 for p = cursym.Text; p != nil; p = p.Link { 578 if p.Mark&BRANCH != 0 { 579 addnop(ctxt, p) 580 } 581 } 582 return 583 } 584 585 // instruction scheduling 586 q = nil // p - 1 587 q1 = cursym.Text // top of block 588 o := 0 // count of instructions 589 for p = cursym.Text; p != nil; p = p1 { 590 p1 = p.Link 591 o++ 592 if p.Mark&NOSCHED != 0 { 593 if q1 != p { 594 sched(ctxt, q1, q) 595 } 596 for ; p != nil; p = p.Link { 597 if p.Mark&NOSCHED == 0 { 598 break 599 } 600 q = p 601 } 602 p1 = p 603 q1 = p 604 o = 0 605 continue 606 } 607 if p.Mark&(LABEL|SYNC) != 0 { 608 if q1 != p { 609 sched(ctxt, q1, q) 610 } 611 q1 = p 612 o = 1 613 } 614 if p.Mark&(BRANCH|SYNC) != 0 { 615 sched(ctxt, q1, p) 616 q1 = p1 617 o = 0 618 } 619 if o >= NSCHED { 620 sched(ctxt, q1, p) 621 q1 = p1 622 o = 0 623 } 624 q = p 625 } 626 } 627 628 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 629 // Leaf function with no frame is effectively NOSPLIT. 630 if framesize == 0 { 631 return p 632 } 633 634 var mov, add, sub obj.As 635 636 if ctxt.Mode&Mips64 != 0 { 637 add = AADDV 638 mov = AMOVV 639 sub = ASUBVU 640 } else { 641 add = AADDU 642 mov = AMOVW 643 sub = ASUBU 644 } 645 646 // MOV g_stackguard(g), R1 647 p = obj.Appendp(ctxt, p) 648 649 p.As = mov 650 p.From.Type = obj.TYPE_MEM 651 p.From.Reg = REGG 652 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 653 if ctxt.Cursym.CFunc() { 654 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 655 } 656 p.To.Type = obj.TYPE_REG 657 p.To.Reg = REG_R1 658 659 var q *obj.Prog 660 if framesize <= obj.StackSmall { 661 // small stack: SP < stackguard 662 // AGTU SP, stackguard, R1 663 p = obj.Appendp(ctxt, p) 664 665 p.As = ASGTU 666 p.From.Type = obj.TYPE_REG 667 p.From.Reg = REGSP 668 p.Reg = REG_R1 669 p.To.Type = obj.TYPE_REG 670 p.To.Reg = REG_R1 671 } else if framesize <= obj.StackBig { 672 // large stack: SP-framesize < stackguard-StackSmall 673 // ADD $-framesize, SP, R2 674 // SGTU R2, stackguard, R1 675 p = obj.Appendp(ctxt, p) 676 677 p.As = add 678 p.From.Type = obj.TYPE_CONST 679 p.From.Offset = int64(-framesize) 680 p.Reg = REGSP 681 p.To.Type = obj.TYPE_REG 682 p.To.Reg = REG_R2 683 684 p = obj.Appendp(ctxt, p) 685 p.As = ASGTU 686 p.From.Type = obj.TYPE_REG 687 p.From.Reg = REG_R2 688 p.Reg = REG_R1 689 p.To.Type = obj.TYPE_REG 690 p.To.Reg = REG_R1 691 } else { 692 // Such a large stack we need to protect against wraparound. 693 // If SP is close to zero: 694 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 695 // The +StackGuard on both sides is required to keep the left side positive: 696 // SP is allowed to be slightly below stackguard. See stack.h. 697 // 698 // Preemption sets stackguard to StackPreempt, a very large value. 699 // That breaks the math above, so we have to check for that explicitly. 700 // // stackguard is R1 701 // MOV $StackPreempt, R2 702 // BEQ R1, R2, label-of-call-to-morestack 703 // ADD $StackGuard, SP, R2 704 // SUB R1, R2 705 // MOV $(framesize+(StackGuard-StackSmall)), R1 706 // SGTU R2, R1, R1 707 p = obj.Appendp(ctxt, p) 708 709 p.As = mov 710 p.From.Type = obj.TYPE_CONST 711 p.From.Offset = obj.StackPreempt 712 p.To.Type = obj.TYPE_REG 713 p.To.Reg = REG_R2 714 715 p = obj.Appendp(ctxt, p) 716 q = p 717 p.As = ABEQ 718 p.From.Type = obj.TYPE_REG 719 p.From.Reg = REG_R1 720 p.Reg = REG_R2 721 p.To.Type = obj.TYPE_BRANCH 722 p.Mark |= BRANCH 723 724 p = obj.Appendp(ctxt, p) 725 p.As = add 726 p.From.Type = obj.TYPE_CONST 727 p.From.Offset = obj.StackGuard 728 p.Reg = REGSP 729 p.To.Type = obj.TYPE_REG 730 p.To.Reg = REG_R2 731 732 p = obj.Appendp(ctxt, p) 733 p.As = sub 734 p.From.Type = obj.TYPE_REG 735 p.From.Reg = REG_R1 736 p.To.Type = obj.TYPE_REG 737 p.To.Reg = REG_R2 738 739 p = obj.Appendp(ctxt, p) 740 p.As = mov 741 p.From.Type = obj.TYPE_CONST 742 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 743 p.To.Type = obj.TYPE_REG 744 p.To.Reg = REG_R1 745 746 p = obj.Appendp(ctxt, p) 747 p.As = ASGTU 748 p.From.Type = obj.TYPE_REG 749 p.From.Reg = REG_R2 750 p.Reg = REG_R1 751 p.To.Type = obj.TYPE_REG 752 p.To.Reg = REG_R1 753 } 754 755 // q1: BNE R1, done 756 p = obj.Appendp(ctxt, p) 757 q1 := p 758 759 p.As = ABNE 760 p.From.Type = obj.TYPE_REG 761 p.From.Reg = REG_R1 762 p.To.Type = obj.TYPE_BRANCH 763 p.Mark |= BRANCH 764 765 // MOV LINK, R3 766 p = obj.Appendp(ctxt, p) 767 768 p.As = mov 769 p.From.Type = obj.TYPE_REG 770 p.From.Reg = REGLINK 771 p.To.Type = obj.TYPE_REG 772 p.To.Reg = REG_R3 773 if q != nil { 774 q.Pcond = p 775 p.Mark |= LABEL 776 } 777 778 // JAL runtime.morestack(SB) 779 p = obj.Appendp(ctxt, p) 780 781 p.As = AJAL 782 p.To.Type = obj.TYPE_BRANCH 783 if ctxt.Cursym.CFunc() { 784 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 785 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 786 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 787 } else { 788 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 789 } 790 p.Mark |= BRANCH 791 792 // JMP start 793 p = obj.Appendp(ctxt, p) 794 795 p.As = AJMP 796 p.To.Type = obj.TYPE_BRANCH 797 p.Pcond = ctxt.Cursym.Text.Link 798 p.Mark |= BRANCH 799 800 // placeholder for q1's jump target 801 p = obj.Appendp(ctxt, p) 802 803 p.As = obj.ANOP // zero-width place holder 804 q1.Pcond = p 805 806 return p 807 } 808 809 func addnop(ctxt *obj.Link, p *obj.Prog) { 810 q := ctxt.NewProg() 811 // we want to use the canonical NOP (SLL $0,R0,R0) here, 812 // however, as the assembler will always replace $0 813 // as R0, we have to resort to manually encode the SLL 814 // instruction as WORD $0. 815 q.As = AWORD 816 q.Pos = p.Pos 817 q.From.Type = obj.TYPE_CONST 818 q.From.Name = obj.NAME_NONE 819 q.From.Offset = 0 820 821 q.Link = p.Link 822 p.Link = q 823 } 824 825 const ( 826 E_HILO = 1 << 0 827 E_FCR = 1 << 1 828 E_MCR = 1 << 2 829 E_MEM = 1 << 3 830 E_MEMSP = 1 << 4 /* uses offset and size */ 831 E_MEMSB = 1 << 5 /* uses offset and size */ 832 ANYMEM = E_MEM | E_MEMSP | E_MEMSB 833 //DELAY = LOAD|BRANCH|FCMP 834 DELAY = BRANCH /* only schedule branch */ 835 ) 836 837 type Dep struct { 838 ireg uint32 839 freg uint32 840 cc uint32 841 } 842 843 type Sch struct { 844 p obj.Prog 845 set Dep 846 used Dep 847 soffset int32 848 size uint8 849 nop uint8 850 comp bool 851 } 852 853 func sched(ctxt *obj.Link, p0, pe *obj.Prog) { 854 var sch [NSCHED]Sch 855 856 /* 857 * build side structure 858 */ 859 s := sch[:] 860 for p := p0; ; p = p.Link { 861 s[0].p = *p 862 markregused(ctxt, &s[0]) 863 if p == pe { 864 break 865 } 866 s = s[1:] 867 } 868 se := s 869 870 for i := cap(sch) - cap(se); i >= 0; i-- { 871 s = sch[i:] 872 if s[0].p.Mark&DELAY == 0 { 873 continue 874 } 875 if -cap(s) < -cap(se) { 876 if !conflict(&s[0], &s[1]) { 877 continue 878 } 879 } 880 881 var t []Sch 882 var j int 883 for j = cap(sch) - cap(s) - 1; j >= 0; j-- { 884 t = sch[j:] 885 if t[0].comp { 886 if s[0].p.Mark&BRANCH != 0 { 887 goto no2 888 } 889 } 890 if t[0].p.Mark&DELAY != 0 { 891 if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) { 892 goto no2 893 } 894 } 895 for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] { 896 if depend(ctxt, &u[0], &t[0]) { 897 goto no2 898 } 899 } 900 goto out2 901 no2: 902 } 903 904 if s[0].p.Mark&BRANCH != 0 { 905 s[0].nop = 1 906 } 907 continue 908 909 out2: 910 // t[0] is the instruction being moved to fill the delay 911 stmp := t[0] 912 copy(t[:i-j], t[1:i-j+1]) 913 s[0] = stmp 914 915 if t[i-j-1].p.Mark&BRANCH != 0 { 916 // t[i-j] is being put into a branch delay slot 917 // combine its Spadj with the branch instruction 918 t[i-j-1].p.Spadj += t[i-j].p.Spadj 919 t[i-j].p.Spadj = 0 920 } 921 922 i-- 923 } 924 925 /* 926 * put it all back 927 */ 928 var p *obj.Prog 929 var q *obj.Prog 930 for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q { 931 q = p.Link 932 if q != s[0].p.Link { 933 *p = s[0].p 934 p.Link = q 935 } 936 for s[0].nop != 0 { 937 s[0].nop-- 938 addnop(ctxt, p) 939 } 940 } 941 } 942 943 func markregused(ctxt *obj.Link, s *Sch) { 944 p := &s.p 945 s.comp = compound(ctxt, p) 946 s.nop = 0 947 if s.comp { 948 s.set.ireg |= 1 << (REGTMP - REG_R0) 949 s.used.ireg |= 1 << (REGTMP - REG_R0) 950 } 951 952 ar := 0 /* dest is really reference */ 953 ad := 0 /* source/dest is really address */ 954 ld := 0 /* opcode is load instruction */ 955 sz := 20 /* size of load/store for overlap computation */ 956 957 /* 958 * flags based on opcode 959 */ 960 switch p.As { 961 case obj.ATEXT: 962 ctxt.Autosize = int32(p.To.Offset + 8) 963 ad = 1 964 965 case AJAL: 966 c := p.Reg 967 if c == 0 { 968 c = REGLINK 969 } 970 s.set.ireg |= 1 << uint(c-REG_R0) 971 ar = 1 972 ad = 1 973 974 case ABGEZAL, 975 ABLTZAL: 976 s.set.ireg |= 1 << (REGLINK - REG_R0) 977 fallthrough 978 case ABEQ, 979 ABGEZ, 980 ABGTZ, 981 ABLEZ, 982 ABLTZ, 983 ABNE: 984 ar = 1 985 ad = 1 986 987 case ABFPT, 988 ABFPF: 989 ad = 1 990 s.used.cc |= E_FCR 991 992 case ACMPEQD, 993 ACMPEQF, 994 ACMPGED, 995 ACMPGEF, 996 ACMPGTD, 997 ACMPGTF: 998 ar = 1 999 s.set.cc |= E_FCR 1000 p.Mark |= FCMP 1001 1002 case AJMP: 1003 ar = 1 1004 ad = 1 1005 1006 case AMOVB, 1007 AMOVBU: 1008 sz = 1 1009 ld = 1 1010 1011 case AMOVH, 1012 AMOVHU: 1013 sz = 2 1014 ld = 1 1015 1016 case AMOVF, 1017 AMOVW, 1018 AMOVWL, 1019 AMOVWR: 1020 sz = 4 1021 ld = 1 1022 1023 case AMOVD, 1024 AMOVV, 1025 AMOVVL, 1026 AMOVVR: 1027 sz = 8 1028 ld = 1 1029 1030 case ADIV, 1031 ADIVU, 1032 AMUL, 1033 AMULU, 1034 AREM, 1035 AREMU, 1036 ADIVV, 1037 ADIVVU, 1038 AMULV, 1039 AMULVU, 1040 AREMV, 1041 AREMVU: 1042 s.set.cc = E_HILO 1043 fallthrough 1044 case AADD, 1045 AADDU, 1046 AADDV, 1047 AADDVU, 1048 AAND, 1049 ANOR, 1050 AOR, 1051 ASGT, 1052 ASGTU, 1053 ASLL, 1054 ASRA, 1055 ASRL, 1056 ASLLV, 1057 ASRAV, 1058 ASRLV, 1059 ASUB, 1060 ASUBU, 1061 ASUBV, 1062 ASUBVU, 1063 AXOR, 1064 1065 AADDD, 1066 AADDF, 1067 AADDW, 1068 ASUBD, 1069 ASUBF, 1070 ASUBW, 1071 AMULF, 1072 AMULD, 1073 AMULW, 1074 ADIVF, 1075 ADIVD, 1076 ADIVW: 1077 if p.Reg == 0 { 1078 if p.To.Type == obj.TYPE_REG { 1079 p.Reg = p.To.Reg 1080 } 1081 //if(p->reg == NREG) 1082 // print("botch %P\n", p); 1083 } 1084 } 1085 1086 /* 1087 * flags based on 'to' field 1088 */ 1089 c := int(p.To.Class) 1090 if c == 0 { 1091 c = aclass(ctxt, &p.To) + 1 1092 p.To.Class = int8(c) 1093 } 1094 c-- 1095 switch c { 1096 default: 1097 fmt.Printf("unknown class %d %v\n", c, p) 1098 1099 case C_ZCON, 1100 C_SCON, 1101 C_ADD0CON, 1102 C_AND0CON, 1103 C_ADDCON, 1104 C_ANDCON, 1105 C_UCON, 1106 C_LCON, 1107 C_NONE, 1108 C_SBRA, 1109 C_LBRA, 1110 C_ADDR, 1111 C_TEXTSIZE: 1112 break 1113 1114 case C_HI, 1115 C_LO: 1116 s.set.cc |= E_HILO 1117 1118 case C_FCREG: 1119 s.set.cc |= E_FCR 1120 1121 case C_MREG: 1122 s.set.cc |= E_MCR 1123 1124 case C_ZOREG, 1125 C_SOREG, 1126 C_LOREG: 1127 c = int(p.To.Reg) 1128 s.used.ireg |= 1 << uint(c-REG_R0) 1129 if ad != 0 { 1130 break 1131 } 1132 s.size = uint8(sz) 1133 s.soffset = regoff(ctxt, &p.To) 1134 1135 m := uint32(ANYMEM) 1136 if c == REGSB { 1137 m = E_MEMSB 1138 } 1139 if c == REGSP { 1140 m = E_MEMSP 1141 } 1142 1143 if ar != 0 { 1144 s.used.cc |= m 1145 } else { 1146 s.set.cc |= m 1147 } 1148 1149 case C_SACON, 1150 C_LACON: 1151 s.used.ireg |= 1 << (REGSP - REG_R0) 1152 1153 case C_SECON, 1154 C_LECON: 1155 s.used.ireg |= 1 << (REGSB - REG_R0) 1156 1157 case C_REG: 1158 if ar != 0 { 1159 s.used.ireg |= 1 << uint(p.To.Reg-REG_R0) 1160 } else { 1161 s.set.ireg |= 1 << uint(p.To.Reg-REG_R0) 1162 } 1163 1164 case C_FREG: 1165 if ar != 0 { 1166 s.used.freg |= 1 << uint(p.To.Reg-REG_F0) 1167 } else { 1168 s.set.freg |= 1 << uint(p.To.Reg-REG_F0) 1169 } 1170 if ld != 0 && p.From.Type == obj.TYPE_REG { 1171 p.Mark |= LOAD 1172 } 1173 1174 case C_SAUTO, 1175 C_LAUTO: 1176 s.used.ireg |= 1 << (REGSP - REG_R0) 1177 if ad != 0 { 1178 break 1179 } 1180 s.size = uint8(sz) 1181 s.soffset = regoff(ctxt, &p.To) 1182 1183 if ar != 0 { 1184 s.used.cc |= E_MEMSP 1185 } else { 1186 s.set.cc |= E_MEMSP 1187 } 1188 1189 case C_SEXT, 1190 C_LEXT: 1191 s.used.ireg |= 1 << (REGSB - REG_R0) 1192 if ad != 0 { 1193 break 1194 } 1195 s.size = uint8(sz) 1196 s.soffset = regoff(ctxt, &p.To) 1197 1198 if ar != 0 { 1199 s.used.cc |= E_MEMSB 1200 } else { 1201 s.set.cc |= E_MEMSB 1202 } 1203 } 1204 1205 /* 1206 * flags based on 'from' field 1207 */ 1208 c = int(p.From.Class) 1209 if c == 0 { 1210 c = aclass(ctxt, &p.From) + 1 1211 p.From.Class = int8(c) 1212 } 1213 c-- 1214 switch c { 1215 default: 1216 fmt.Printf("unknown class %d %v\n", c, p) 1217 1218 case C_ZCON, 1219 C_SCON, 1220 C_ADD0CON, 1221 C_AND0CON, 1222 C_ADDCON, 1223 C_ANDCON, 1224 C_UCON, 1225 C_LCON, 1226 C_NONE, 1227 C_SBRA, 1228 C_LBRA, 1229 C_ADDR, 1230 C_TEXTSIZE: 1231 break 1232 1233 case C_HI, 1234 C_LO: 1235 s.used.cc |= E_HILO 1236 1237 case C_FCREG: 1238 s.used.cc |= E_FCR 1239 1240 case C_MREG: 1241 s.used.cc |= E_MCR 1242 1243 case C_ZOREG, 1244 C_SOREG, 1245 C_LOREG: 1246 c = int(p.From.Reg) 1247 s.used.ireg |= 1 << uint(c-REG_R0) 1248 if ld != 0 { 1249 p.Mark |= LOAD 1250 } 1251 s.size = uint8(sz) 1252 s.soffset = regoff(ctxt, &p.From) 1253 1254 m := uint32(ANYMEM) 1255 if c == REGSB { 1256 m = E_MEMSB 1257 } 1258 if c == REGSP { 1259 m = E_MEMSP 1260 } 1261 1262 s.used.cc |= m 1263 1264 case C_SACON, 1265 C_LACON: 1266 c = int(p.From.Reg) 1267 if c == 0 { 1268 c = REGSP 1269 } 1270 s.used.ireg |= 1 << uint(c-REG_R0) 1271 1272 case C_SECON, 1273 C_LECON: 1274 s.used.ireg |= 1 << (REGSB - REG_R0) 1275 1276 case C_REG: 1277 s.used.ireg |= 1 << uint(p.From.Reg-REG_R0) 1278 1279 case C_FREG: 1280 s.used.freg |= 1 << uint(p.From.Reg-REG_F0) 1281 if ld != 0 && p.To.Type == obj.TYPE_REG { 1282 p.Mark |= LOAD 1283 } 1284 1285 case C_SAUTO, 1286 C_LAUTO: 1287 s.used.ireg |= 1 << (REGSP - REG_R0) 1288 if ld != 0 { 1289 p.Mark |= LOAD 1290 } 1291 if ad != 0 { 1292 break 1293 } 1294 s.size = uint8(sz) 1295 s.soffset = regoff(ctxt, &p.From) 1296 1297 s.used.cc |= E_MEMSP 1298 1299 case C_SEXT: 1300 case C_LEXT: 1301 s.used.ireg |= 1 << (REGSB - REG_R0) 1302 if ld != 0 { 1303 p.Mark |= LOAD 1304 } 1305 if ad != 0 { 1306 break 1307 } 1308 s.size = uint8(sz) 1309 s.soffset = regoff(ctxt, &p.From) 1310 1311 s.used.cc |= E_MEMSB 1312 } 1313 1314 c = int(p.Reg) 1315 if c != 0 { 1316 if REG_F0 <= c && c <= REG_F31 { 1317 s.used.freg |= 1 << uint(c-REG_F0) 1318 } else { 1319 s.used.ireg |= 1 << uint(c-REG_R0) 1320 } 1321 } 1322 s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */ 1323 } 1324 1325 /* 1326 * test to see if two instructions can be 1327 * interchanged without changing semantics 1328 */ 1329 func depend(ctxt *obj.Link, sa, sb *Sch) bool { 1330 if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 { 1331 return true 1332 } 1333 if sb.set.ireg&sa.used.ireg != 0 { 1334 return true 1335 } 1336 1337 if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 { 1338 return true 1339 } 1340 if sb.set.freg&sa.used.freg != 0 { 1341 return true 1342 } 1343 1344 /* 1345 * special case. 1346 * loads from same address cannot pass. 1347 * this is for hardware fifo's and the like 1348 */ 1349 if sa.used.cc&sb.used.cc&E_MEM != 0 { 1350 if sa.p.Reg == sb.p.Reg { 1351 if regoff(ctxt, &sa.p.From) == regoff(ctxt, &sb.p.From) { 1352 return true 1353 } 1354 } 1355 } 1356 1357 x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc) 1358 if x != 0 { 1359 /* 1360 * allow SB and SP to pass each other. 1361 * allow SB to pass SB iff doffsets are ok 1362 * anything else conflicts 1363 */ 1364 if x != E_MEMSP && x != E_MEMSB { 1365 return true 1366 } 1367 x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc 1368 if x&E_MEM != 0 { 1369 return true 1370 } 1371 if offoverlap(sa, sb) { 1372 return true 1373 } 1374 } 1375 1376 return false 1377 } 1378 1379 func offoverlap(sa, sb *Sch) bool { 1380 if sa.soffset < sb.soffset { 1381 if sa.soffset+int32(sa.size) > sb.soffset { 1382 return true 1383 } 1384 return false 1385 } 1386 if sb.soffset+int32(sb.size) > sa.soffset { 1387 return true 1388 } 1389 return false 1390 } 1391 1392 /* 1393 * test 2 adjacent instructions 1394 * and find out if inserted instructions 1395 * are desired to prevent stalls. 1396 */ 1397 func conflict(sa, sb *Sch) bool { 1398 if sa.set.ireg&sb.used.ireg != 0 { 1399 return true 1400 } 1401 if sa.set.freg&sb.used.freg != 0 { 1402 return true 1403 } 1404 if sa.set.cc&sb.used.cc != 0 { 1405 return true 1406 } 1407 return false 1408 } 1409 1410 func compound(ctxt *obj.Link, p *obj.Prog) bool { 1411 o := oplook(ctxt, p) 1412 if o.size != 4 { 1413 return true 1414 } 1415 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB { 1416 return true 1417 } 1418 return false 1419 } 1420 1421 var Linkmips64 = obj.LinkArch{ 1422 Arch: sys.ArchMIPS64, 1423 Preprocess: preprocess, 1424 Assemble: span0, 1425 Progedit: progedit, 1426 } 1427 1428 var Linkmips64le = obj.LinkArch{ 1429 Arch: sys.ArchMIPS64LE, 1430 Preprocess: preprocess, 1431 Assemble: span0, 1432 Progedit: progedit, 1433 } 1434 1435 var Linkmips = obj.LinkArch{ 1436 Arch: sys.ArchMIPS, 1437 Preprocess: preprocess, 1438 Assemble: span0, 1439 Progedit: progedit, 1440 } 1441 1442 var Linkmipsle = obj.LinkArch{ 1443 Arch: sys.ArchMIPSLE, 1444 Preprocess: preprocess, 1445 Assemble: span0, 1446 Progedit: progedit, 1447 }