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