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