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