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