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