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