github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 addrOff int64 535 if c.ctxt.Arch.ByteOrder == binary.BigEndian { 536 addrOff = 4 // swap load/save order 537 } 538 if p.From.Type == obj.TYPE_MEM { 539 reg := REG_F0 + (p.To.Reg-REG_F0)&^1 540 p.To.Reg = reg 541 q.To.Reg = reg + 1 542 p.From.Offset += addrOff 543 q.From.Offset += 4 - addrOff 544 } else if p.To.Type == obj.TYPE_MEM { 545 reg := REG_F0 + (p.From.Reg-REG_F0)&^1 546 p.From.Reg = reg 547 q.From.Reg = reg + 1 548 p.To.Offset += addrOff 549 q.To.Offset += 4 - addrOff 550 } 551 } 552 } 553 554 if nosched { 555 // if we don't do instruction scheduling, simply add 556 // NOP after each branch instruction. 557 for p = c.cursym.Func.Text; p != nil; p = p.Link { 558 if p.Mark&BRANCH != 0 { 559 c.addnop(p) 560 } 561 } 562 return 563 } 564 565 // instruction scheduling 566 q = nil // p - 1 567 q1 = c.cursym.Func.Text // top of block 568 o := 0 // count of instructions 569 for p = c.cursym.Func.Text; p != nil; p = p1 { 570 p1 = p.Link 571 o++ 572 if p.Mark&NOSCHED != 0 { 573 if q1 != p { 574 c.sched(q1, q) 575 } 576 for ; p != nil; p = p.Link { 577 if p.Mark&NOSCHED == 0 { 578 break 579 } 580 q = p 581 } 582 p1 = p 583 q1 = p 584 o = 0 585 continue 586 } 587 if p.Mark&(LABEL|SYNC) != 0 { 588 if q1 != p { 589 c.sched(q1, q) 590 } 591 q1 = p 592 o = 1 593 } 594 if p.Mark&(BRANCH|SYNC) != 0 { 595 c.sched(q1, p) 596 q1 = p1 597 o = 0 598 } 599 if o >= NSCHED { 600 c.sched(q1, p) 601 q1 = p1 602 o = 0 603 } 604 q = p 605 } 606 } 607 608 func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { 609 // Leaf function with no frame is effectively NOSPLIT. 610 if framesize == 0 { 611 return p 612 } 613 614 var mov, add, sub obj.As 615 616 if c.ctxt.Arch.Family == sys.MIPS64 { 617 add = AADDV 618 mov = AMOVV 619 sub = ASUBVU 620 } else { 621 add = AADDU 622 mov = AMOVW 623 sub = ASUBU 624 } 625 626 // MOV g_stackguard(g), R1 627 p = obj.Appendp(p, c.newprog) 628 629 p.As = mov 630 p.From.Type = obj.TYPE_MEM 631 p.From.Reg = REGG 632 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 633 if c.cursym.CFunc() { 634 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 635 } 636 p.To.Type = obj.TYPE_REG 637 p.To.Reg = REG_R1 638 639 var q *obj.Prog 640 if framesize <= objabi.StackSmall { 641 // small stack: SP < stackguard 642 // AGTU SP, stackguard, R1 643 p = obj.Appendp(p, c.newprog) 644 645 p.As = ASGTU 646 p.From.Type = obj.TYPE_REG 647 p.From.Reg = REGSP 648 p.Reg = REG_R1 649 p.To.Type = obj.TYPE_REG 650 p.To.Reg = REG_R1 651 } else if framesize <= objabi.StackBig { 652 // large stack: SP-framesize < stackguard-StackSmall 653 // ADD $-(framesize-StackSmall), SP, R2 654 // SGTU R2, stackguard, R1 655 p = obj.Appendp(p, c.newprog) 656 657 p.As = add 658 p.From.Type = obj.TYPE_CONST 659 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 660 p.Reg = REGSP 661 p.To.Type = obj.TYPE_REG 662 p.To.Reg = REG_R2 663 664 p = obj.Appendp(p, c.newprog) 665 p.As = ASGTU 666 p.From.Type = obj.TYPE_REG 667 p.From.Reg = REG_R2 668 p.Reg = REG_R1 669 p.To.Type = obj.TYPE_REG 670 p.To.Reg = REG_R1 671 } else { 672 // Such a large stack we need to protect against wraparound. 673 // If SP is close to zero: 674 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 675 // The +StackGuard on both sides is required to keep the left side positive: 676 // SP is allowed to be slightly below stackguard. See stack.h. 677 // 678 // Preemption sets stackguard to StackPreempt, a very large value. 679 // That breaks the math above, so we have to check for that explicitly. 680 // // stackguard is R1 681 // MOV $StackPreempt, R2 682 // BEQ R1, R2, label-of-call-to-morestack 683 // ADD $StackGuard, SP, R2 684 // SUB R1, R2 685 // MOV $(framesize+(StackGuard-StackSmall)), R1 686 // SGTU R2, R1, R1 687 p = obj.Appendp(p, c.newprog) 688 689 p.As = mov 690 p.From.Type = obj.TYPE_CONST 691 p.From.Offset = objabi.StackPreempt 692 p.To.Type = obj.TYPE_REG 693 p.To.Reg = REG_R2 694 695 p = obj.Appendp(p, c.newprog) 696 q = p 697 p.As = ABEQ 698 p.From.Type = obj.TYPE_REG 699 p.From.Reg = REG_R1 700 p.Reg = REG_R2 701 p.To.Type = obj.TYPE_BRANCH 702 p.Mark |= BRANCH 703 704 p = obj.Appendp(p, c.newprog) 705 p.As = add 706 p.From.Type = obj.TYPE_CONST 707 p.From.Offset = objabi.StackGuard 708 p.Reg = REGSP 709 p.To.Type = obj.TYPE_REG 710 p.To.Reg = REG_R2 711 712 p = obj.Appendp(p, c.newprog) 713 p.As = sub 714 p.From.Type = obj.TYPE_REG 715 p.From.Reg = REG_R1 716 p.To.Type = obj.TYPE_REG 717 p.To.Reg = REG_R2 718 719 p = obj.Appendp(p, c.newprog) 720 p.As = mov 721 p.From.Type = obj.TYPE_CONST 722 p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall 723 p.To.Type = obj.TYPE_REG 724 p.To.Reg = REG_R1 725 726 p = obj.Appendp(p, c.newprog) 727 p.As = ASGTU 728 p.From.Type = obj.TYPE_REG 729 p.From.Reg = REG_R2 730 p.Reg = REG_R1 731 p.To.Type = obj.TYPE_REG 732 p.To.Reg = REG_R1 733 } 734 735 // q1: BNE R1, done 736 p = obj.Appendp(p, c.newprog) 737 q1 := p 738 739 p.As = ABNE 740 p.From.Type = obj.TYPE_REG 741 p.From.Reg = REG_R1 742 p.To.Type = obj.TYPE_BRANCH 743 p.Mark |= BRANCH 744 745 // MOV LINK, R3 746 p = obj.Appendp(p, c.newprog) 747 748 p.As = mov 749 p.From.Type = obj.TYPE_REG 750 p.From.Reg = REGLINK 751 p.To.Type = obj.TYPE_REG 752 p.To.Reg = REG_R3 753 if q != nil { 754 q.Pcond = p 755 p.Mark |= LABEL 756 } 757 758 // JAL runtime.morestack(SB) 759 p = obj.Appendp(p, c.newprog) 760 761 p.As = AJAL 762 p.To.Type = obj.TYPE_BRANCH 763 if c.cursym.CFunc() { 764 p.To.Sym = c.ctxt.Lookup("runtime.morestackc") 765 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 766 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt") 767 } else { 768 p.To.Sym = c.ctxt.Lookup("runtime.morestack") 769 } 770 p.Mark |= BRANCH 771 772 // JMP start 773 p = obj.Appendp(p, c.newprog) 774 775 p.As = AJMP 776 p.To.Type = obj.TYPE_BRANCH 777 p.Pcond = c.cursym.Func.Text.Link 778 p.Mark |= BRANCH 779 780 // placeholder for q1's jump target 781 p = obj.Appendp(p, c.newprog) 782 783 p.As = obj.ANOP // zero-width place holder 784 q1.Pcond = p 785 786 return p 787 } 788 789 func (c *ctxt0) addnop(p *obj.Prog) { 790 q := c.newprog() 791 q.As = ANOOP 792 q.Pos = p.Pos 793 q.Link = p.Link 794 p.Link = q 795 } 796 797 const ( 798 E_HILO = 1 << 0 799 E_FCR = 1 << 1 800 E_MCR = 1 << 2 801 E_MEM = 1 << 3 802 E_MEMSP = 1 << 4 /* uses offset and size */ 803 E_MEMSB = 1 << 5 /* uses offset and size */ 804 ANYMEM = E_MEM | E_MEMSP | E_MEMSB 805 //DELAY = LOAD|BRANCH|FCMP 806 DELAY = BRANCH /* only schedule branch */ 807 ) 808 809 type Dep struct { 810 ireg uint32 811 freg uint32 812 cc uint32 813 } 814 815 type Sch struct { 816 p obj.Prog 817 set Dep 818 used Dep 819 soffset int32 820 size uint8 821 nop uint8 822 comp bool 823 } 824 825 func (c *ctxt0) sched(p0, pe *obj.Prog) { 826 var sch [NSCHED]Sch 827 828 /* 829 * build side structure 830 */ 831 s := sch[:] 832 for p := p0; ; p = p.Link { 833 s[0].p = *p 834 c.markregused(&s[0]) 835 if p == pe { 836 break 837 } 838 s = s[1:] 839 } 840 se := s 841 842 for i := cap(sch) - cap(se); i >= 0; i-- { 843 s = sch[i:] 844 if s[0].p.Mark&DELAY == 0 { 845 continue 846 } 847 if -cap(s) < -cap(se) { 848 if !conflict(&s[0], &s[1]) { 849 continue 850 } 851 } 852 853 var t []Sch 854 var j int 855 for j = cap(sch) - cap(s) - 1; j >= 0; j-- { 856 t = sch[j:] 857 if t[0].comp { 858 if s[0].p.Mark&BRANCH != 0 { 859 goto no2 860 } 861 } 862 if t[0].p.Mark&DELAY != 0 { 863 if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) { 864 goto no2 865 } 866 } 867 for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] { 868 if c.depend(&u[0], &t[0]) { 869 goto no2 870 } 871 } 872 goto out2 873 no2: 874 } 875 876 if s[0].p.Mark&BRANCH != 0 { 877 s[0].nop = 1 878 } 879 continue 880 881 out2: 882 // t[0] is the instruction being moved to fill the delay 883 stmp := t[0] 884 copy(t[:i-j], t[1:i-j+1]) 885 s[0] = stmp 886 887 if t[i-j-1].p.Mark&BRANCH != 0 { 888 // t[i-j] is being put into a branch delay slot 889 // combine its Spadj with the branch instruction 890 t[i-j-1].p.Spadj += t[i-j].p.Spadj 891 t[i-j].p.Spadj = 0 892 } 893 894 i-- 895 } 896 897 /* 898 * put it all back 899 */ 900 var p *obj.Prog 901 var q *obj.Prog 902 for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q { 903 q = p.Link 904 if q != s[0].p.Link { 905 *p = s[0].p 906 p.Link = q 907 } 908 for s[0].nop != 0 { 909 s[0].nop-- 910 c.addnop(p) 911 } 912 } 913 } 914 915 func (c *ctxt0) markregused(s *Sch) { 916 p := &s.p 917 s.comp = c.compound(p) 918 s.nop = 0 919 if s.comp { 920 s.set.ireg |= 1 << (REGTMP - REG_R0) 921 s.used.ireg |= 1 << (REGTMP - REG_R0) 922 } 923 924 ar := 0 /* dest is really reference */ 925 ad := 0 /* source/dest is really address */ 926 ld := 0 /* opcode is load instruction */ 927 sz := 20 /* size of load/store for overlap computation */ 928 929 /* 930 * flags based on opcode 931 */ 932 switch p.As { 933 case obj.ATEXT: 934 c.autosize = int32(p.To.Offset + 8) 935 ad = 1 936 937 case AJAL: 938 r := p.Reg 939 if r == 0 { 940 r = REGLINK 941 } 942 s.set.ireg |= 1 << uint(r-REG_R0) 943 ar = 1 944 ad = 1 945 946 case ABGEZAL, 947 ABLTZAL: 948 s.set.ireg |= 1 << (REGLINK - REG_R0) 949 fallthrough 950 case ABEQ, 951 ABGEZ, 952 ABGTZ, 953 ABLEZ, 954 ABLTZ, 955 ABNE: 956 ar = 1 957 ad = 1 958 959 case ABFPT, 960 ABFPF: 961 ad = 1 962 s.used.cc |= E_FCR 963 964 case ACMPEQD, 965 ACMPEQF, 966 ACMPGED, 967 ACMPGEF, 968 ACMPGTD, 969 ACMPGTF: 970 ar = 1 971 s.set.cc |= E_FCR 972 p.Mark |= FCMP 973 974 case AJMP: 975 ar = 1 976 ad = 1 977 978 case AMOVB, 979 AMOVBU: 980 sz = 1 981 ld = 1 982 983 case AMOVH, 984 AMOVHU: 985 sz = 2 986 ld = 1 987 988 case AMOVF, 989 AMOVW, 990 AMOVWL, 991 AMOVWR: 992 sz = 4 993 ld = 1 994 995 case AMOVD, 996 AMOVV, 997 AMOVVL, 998 AMOVVR: 999 sz = 8 1000 ld = 1 1001 1002 case ADIV, 1003 ADIVU, 1004 AMUL, 1005 AMULU, 1006 AREM, 1007 AREMU, 1008 ADIVV, 1009 ADIVVU, 1010 AMULV, 1011 AMULVU, 1012 AREMV, 1013 AREMVU: 1014 s.set.cc = E_HILO 1015 fallthrough 1016 case AADD, 1017 AADDU, 1018 AADDV, 1019 AADDVU, 1020 AAND, 1021 ANOR, 1022 AOR, 1023 ASGT, 1024 ASGTU, 1025 ASLL, 1026 ASRA, 1027 ASRL, 1028 ASLLV, 1029 ASRAV, 1030 ASRLV, 1031 ASUB, 1032 ASUBU, 1033 ASUBV, 1034 ASUBVU, 1035 AXOR, 1036 1037 AADDD, 1038 AADDF, 1039 AADDW, 1040 ASUBD, 1041 ASUBF, 1042 ASUBW, 1043 AMULF, 1044 AMULD, 1045 AMULW, 1046 ADIVF, 1047 ADIVD, 1048 ADIVW: 1049 if p.Reg == 0 { 1050 if p.To.Type == obj.TYPE_REG { 1051 p.Reg = p.To.Reg 1052 } 1053 //if(p->reg == NREG) 1054 // print("botch %P\n", p); 1055 } 1056 } 1057 1058 /* 1059 * flags based on 'to' field 1060 */ 1061 cls := int(p.To.Class) 1062 if cls == 0 { 1063 cls = c.aclass(&p.To) + 1 1064 p.To.Class = int8(cls) 1065 } 1066 cls-- 1067 switch cls { 1068 default: 1069 fmt.Printf("unknown class %d %v\n", cls, p) 1070 1071 case C_ZCON, 1072 C_SCON, 1073 C_ADD0CON, 1074 C_AND0CON, 1075 C_ADDCON, 1076 C_ANDCON, 1077 C_UCON, 1078 C_LCON, 1079 C_NONE, 1080 C_SBRA, 1081 C_LBRA, 1082 C_ADDR, 1083 C_TEXTSIZE: 1084 break 1085 1086 case C_HI, 1087 C_LO: 1088 s.set.cc |= E_HILO 1089 1090 case C_FCREG: 1091 s.set.cc |= E_FCR 1092 1093 case C_MREG: 1094 s.set.cc |= E_MCR 1095 1096 case C_ZOREG, 1097 C_SOREG, 1098 C_LOREG: 1099 cls = int(p.To.Reg) 1100 s.used.ireg |= 1 << uint(cls-REG_R0) 1101 if ad != 0 { 1102 break 1103 } 1104 s.size = uint8(sz) 1105 s.soffset = c.regoff(&p.To) 1106 1107 m := uint32(ANYMEM) 1108 if cls == REGSB { 1109 m = E_MEMSB 1110 } 1111 if cls == REGSP { 1112 m = E_MEMSP 1113 } 1114 1115 if ar != 0 { 1116 s.used.cc |= m 1117 } else { 1118 s.set.cc |= m 1119 } 1120 1121 case C_SACON, 1122 C_LACON: 1123 s.used.ireg |= 1 << (REGSP - REG_R0) 1124 1125 case C_SECON, 1126 C_LECON: 1127 s.used.ireg |= 1 << (REGSB - REG_R0) 1128 1129 case C_REG: 1130 if ar != 0 { 1131 s.used.ireg |= 1 << uint(p.To.Reg-REG_R0) 1132 } else { 1133 s.set.ireg |= 1 << uint(p.To.Reg-REG_R0) 1134 } 1135 1136 case C_FREG: 1137 if ar != 0 { 1138 s.used.freg |= 1 << uint(p.To.Reg-REG_F0) 1139 } else { 1140 s.set.freg |= 1 << uint(p.To.Reg-REG_F0) 1141 } 1142 if ld != 0 && p.From.Type == obj.TYPE_REG { 1143 p.Mark |= LOAD 1144 } 1145 1146 case C_SAUTO, 1147 C_LAUTO: 1148 s.used.ireg |= 1 << (REGSP - REG_R0) 1149 if ad != 0 { 1150 break 1151 } 1152 s.size = uint8(sz) 1153 s.soffset = c.regoff(&p.To) 1154 1155 if ar != 0 { 1156 s.used.cc |= E_MEMSP 1157 } else { 1158 s.set.cc |= E_MEMSP 1159 } 1160 1161 case C_SEXT, 1162 C_LEXT: 1163 s.used.ireg |= 1 << (REGSB - REG_R0) 1164 if ad != 0 { 1165 break 1166 } 1167 s.size = uint8(sz) 1168 s.soffset = c.regoff(&p.To) 1169 1170 if ar != 0 { 1171 s.used.cc |= E_MEMSB 1172 } else { 1173 s.set.cc |= E_MEMSB 1174 } 1175 } 1176 1177 /* 1178 * flags based on 'from' field 1179 */ 1180 cls = int(p.From.Class) 1181 if cls == 0 { 1182 cls = c.aclass(&p.From) + 1 1183 p.From.Class = int8(cls) 1184 } 1185 cls-- 1186 switch cls { 1187 default: 1188 fmt.Printf("unknown class %d %v\n", cls, p) 1189 1190 case C_ZCON, 1191 C_SCON, 1192 C_ADD0CON, 1193 C_AND0CON, 1194 C_ADDCON, 1195 C_ANDCON, 1196 C_UCON, 1197 C_LCON, 1198 C_NONE, 1199 C_SBRA, 1200 C_LBRA, 1201 C_ADDR, 1202 C_TEXTSIZE: 1203 break 1204 1205 case C_HI, 1206 C_LO: 1207 s.used.cc |= E_HILO 1208 1209 case C_FCREG: 1210 s.used.cc |= E_FCR 1211 1212 case C_MREG: 1213 s.used.cc |= E_MCR 1214 1215 case C_ZOREG, 1216 C_SOREG, 1217 C_LOREG: 1218 cls = int(p.From.Reg) 1219 s.used.ireg |= 1 << uint(cls-REG_R0) 1220 if ld != 0 { 1221 p.Mark |= LOAD 1222 } 1223 s.size = uint8(sz) 1224 s.soffset = c.regoff(&p.From) 1225 1226 m := uint32(ANYMEM) 1227 if cls == REGSB { 1228 m = E_MEMSB 1229 } 1230 if cls == REGSP { 1231 m = E_MEMSP 1232 } 1233 1234 s.used.cc |= m 1235 1236 case C_SACON, 1237 C_LACON: 1238 cls = int(p.From.Reg) 1239 if cls == 0 { 1240 cls = REGSP 1241 } 1242 s.used.ireg |= 1 << uint(cls-REG_R0) 1243 1244 case C_SECON, 1245 C_LECON: 1246 s.used.ireg |= 1 << (REGSB - REG_R0) 1247 1248 case C_REG: 1249 s.used.ireg |= 1 << uint(p.From.Reg-REG_R0) 1250 1251 case C_FREG: 1252 s.used.freg |= 1 << uint(p.From.Reg-REG_F0) 1253 if ld != 0 && p.To.Type == obj.TYPE_REG { 1254 p.Mark |= LOAD 1255 } 1256 1257 case C_SAUTO, 1258 C_LAUTO: 1259 s.used.ireg |= 1 << (REGSP - REG_R0) 1260 if ld != 0 { 1261 p.Mark |= LOAD 1262 } 1263 if ad != 0 { 1264 break 1265 } 1266 s.size = uint8(sz) 1267 s.soffset = c.regoff(&p.From) 1268 1269 s.used.cc |= E_MEMSP 1270 1271 case C_SEXT: 1272 case C_LEXT: 1273 s.used.ireg |= 1 << (REGSB - REG_R0) 1274 if ld != 0 { 1275 p.Mark |= LOAD 1276 } 1277 if ad != 0 { 1278 break 1279 } 1280 s.size = uint8(sz) 1281 s.soffset = c.regoff(&p.From) 1282 1283 s.used.cc |= E_MEMSB 1284 } 1285 1286 cls = int(p.Reg) 1287 if cls != 0 { 1288 if REG_F0 <= cls && cls <= REG_F31 { 1289 s.used.freg |= 1 << uint(cls-REG_F0) 1290 } else { 1291 s.used.ireg |= 1 << uint(cls-REG_R0) 1292 } 1293 } 1294 s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */ 1295 } 1296 1297 /* 1298 * test to see if two instructions can be 1299 * interchanged without changing semantics 1300 */ 1301 func (c *ctxt0) depend(sa, sb *Sch) bool { 1302 if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 { 1303 return true 1304 } 1305 if sb.set.ireg&sa.used.ireg != 0 { 1306 return true 1307 } 1308 1309 if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 { 1310 return true 1311 } 1312 if sb.set.freg&sa.used.freg != 0 { 1313 return true 1314 } 1315 1316 /* 1317 * special case. 1318 * loads from same address cannot pass. 1319 * this is for hardware fifo's and the like 1320 */ 1321 if sa.used.cc&sb.used.cc&E_MEM != 0 { 1322 if sa.p.Reg == sb.p.Reg { 1323 if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) { 1324 return true 1325 } 1326 } 1327 } 1328 1329 x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc) 1330 if x != 0 { 1331 /* 1332 * allow SB and SP to pass each other. 1333 * allow SB to pass SB iff doffsets are ok 1334 * anything else conflicts 1335 */ 1336 if x != E_MEMSP && x != E_MEMSB { 1337 return true 1338 } 1339 x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc 1340 if x&E_MEM != 0 { 1341 return true 1342 } 1343 if offoverlap(sa, sb) { 1344 return true 1345 } 1346 } 1347 1348 return false 1349 } 1350 1351 func offoverlap(sa, sb *Sch) bool { 1352 if sa.soffset < sb.soffset { 1353 if sa.soffset+int32(sa.size) > sb.soffset { 1354 return true 1355 } 1356 return false 1357 } 1358 if sb.soffset+int32(sb.size) > sa.soffset { 1359 return true 1360 } 1361 return false 1362 } 1363 1364 /* 1365 * test 2 adjacent instructions 1366 * and find out if inserted instructions 1367 * are desired to prevent stalls. 1368 */ 1369 func conflict(sa, sb *Sch) bool { 1370 if sa.set.ireg&sb.used.ireg != 0 { 1371 return true 1372 } 1373 if sa.set.freg&sb.used.freg != 0 { 1374 return true 1375 } 1376 if sa.set.cc&sb.used.cc != 0 { 1377 return true 1378 } 1379 return false 1380 } 1381 1382 func (c *ctxt0) compound(p *obj.Prog) bool { 1383 o := c.oplook(p) 1384 if o.size != 4 { 1385 return true 1386 } 1387 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB { 1388 return true 1389 } 1390 return false 1391 } 1392 1393 var Linkmips64 = obj.LinkArch{ 1394 Arch: sys.ArchMIPS64, 1395 Init: buildop, 1396 Preprocess: preprocess, 1397 Assemble: span0, 1398 Progedit: progedit, 1399 } 1400 1401 var Linkmips64le = obj.LinkArch{ 1402 Arch: sys.ArchMIPS64LE, 1403 Init: buildop, 1404 Preprocess: preprocess, 1405 Assemble: span0, 1406 Progedit: progedit, 1407 } 1408 1409 var Linkmips = obj.LinkArch{ 1410 Arch: sys.ArchMIPS, 1411 Init: buildop, 1412 Preprocess: preprocess, 1413 Assemble: span0, 1414 Progedit: progedit, 1415 } 1416 1417 var Linkmipsle = obj.LinkArch{ 1418 Arch: sys.ArchMIPSLE, 1419 Init: buildop, 1420 Preprocess: preprocess, 1421 Assemble: span0, 1422 Progedit: progedit, 1423 }