github.com/aloncn/graphics-go@v0.0.1/src/cmd/internal/obj/ppc64/obj9.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 ppc64 31 32 import ( 33 "cmd/internal/obj" 34 "encoding/binary" 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 BR/BL to symbol as TYPE_BRANCH. 44 switch p.As { 45 case ABR, 46 ABL, 47 obj.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 AFMOVS: 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.Sym.Local = true 67 p.From.Name = obj.NAME_EXTERN 68 p.From.Offset = 0 69 } 70 71 case AFMOVD: 72 if p.From.Type == obj.TYPE_FCONST { 73 i64 := math.Float64bits(p.From.Val.(float64)) 74 literal := fmt.Sprintf("$f64.%016x", i64) 75 s := obj.Linklookup(ctxt, literal, 0) 76 s.Size = 8 77 p.From.Type = obj.TYPE_MEM 78 p.From.Sym = s 79 p.From.Sym.Local = true 80 p.From.Name = obj.NAME_EXTERN 81 p.From.Offset = 0 82 } 83 84 // Put >32-bit constants in memory and load them 85 case AMOVD: 86 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 { 87 literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset)) 88 s := obj.Linklookup(ctxt, literal, 0) 89 s.Size = 8 90 p.From.Type = obj.TYPE_MEM 91 p.From.Sym = s 92 p.From.Sym.Local = true 93 p.From.Name = obj.NAME_EXTERN 94 p.From.Offset = 0 95 } 96 } 97 98 // Rewrite SUB constants into ADD. 99 switch p.As { 100 case ASUBC: 101 if p.From.Type == obj.TYPE_CONST { 102 p.From.Offset = -p.From.Offset 103 p.As = AADDC 104 } 105 106 case ASUBCCC: 107 if p.From.Type == obj.TYPE_CONST { 108 p.From.Offset = -p.From.Offset 109 p.As = AADDCCC 110 } 111 112 case ASUB: 113 if p.From.Type == obj.TYPE_CONST { 114 p.From.Offset = -p.From.Offset 115 p.As = AADD 116 } 117 } 118 if ctxt.Flag_dynlink { 119 rewriteToUseGot(ctxt, p) 120 } 121 } 122 123 // Rewrite p, if necessary, to access global data via the global offset table. 124 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { 125 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { 126 // ADUFFxxx $offset 127 // becomes 128 // MOVD runtime.duffxxx@GOT, R12 129 // ADD $offset, R12 130 // MOVD R12, CTR 131 // BL (CTR) 132 var sym *obj.LSym 133 if p.As == obj.ADUFFZERO { 134 sym = obj.Linklookup(ctxt, "runtime.duffzero", 0) 135 } else { 136 sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0) 137 } 138 offset := p.To.Offset 139 p.As = AMOVD 140 p.From.Type = obj.TYPE_MEM 141 p.From.Name = obj.NAME_GOTREF 142 p.From.Sym = sym 143 p.To.Type = obj.TYPE_REG 144 p.To.Reg = REG_R12 145 p.To.Name = obj.NAME_NONE 146 p.To.Offset = 0 147 p.To.Sym = nil 148 p1 := obj.Appendp(ctxt, p) 149 p1.As = AADD 150 p1.From.Type = obj.TYPE_CONST 151 p1.From.Offset = offset 152 p1.To.Type = obj.TYPE_REG 153 p1.To.Reg = REG_R12 154 p2 := obj.Appendp(ctxt, p1) 155 p2.As = AMOVD 156 p2.From.Type = obj.TYPE_REG 157 p2.From.Reg = REG_R12 158 p2.To.Type = obj.TYPE_REG 159 p2.To.Reg = REG_CTR 160 p3 := obj.Appendp(ctxt, p2) 161 p3.As = obj.ACALL 162 p3.From.Type = obj.TYPE_REG 163 p3.From.Reg = REG_R12 164 p3.To.Type = obj.TYPE_REG 165 p3.To.Reg = REG_CTR 166 } 167 168 // We only care about global data: NAME_EXTERN means a global 169 // symbol in the Go sense, and p.Sym.Local is true for a few 170 // internally defined symbols. 171 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 172 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 173 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 174 if p.As != AMOVD { 175 ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) 176 } 177 if p.To.Type != obj.TYPE_REG { 178 ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) 179 } 180 p.From.Type = obj.TYPE_MEM 181 p.From.Name = obj.NAME_GOTREF 182 if p.From.Offset != 0 { 183 q := obj.Appendp(ctxt, p) 184 q.As = AADD 185 q.From.Type = obj.TYPE_CONST 186 q.From.Offset = p.From.Offset 187 q.To = p.To 188 p.From.Offset = 0 189 } 190 } 191 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 192 ctxt.Diag("don't know how to handle %v with -dynlink", p) 193 } 194 var source *obj.Addr 195 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry 196 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP) 197 // An addition may be inserted between the two MOVs if there is an offset. 198 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { 199 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 200 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 201 } 202 source = &p.From 203 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { 204 source = &p.To 205 } else { 206 return 207 } 208 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 209 return 210 } 211 if source.Sym.Type == obj.STLSBSS { 212 return 213 } 214 if source.Type != obj.TYPE_MEM { 215 ctxt.Diag("don't know how to handle %v with -dynlink", p) 216 } 217 p1 := obj.Appendp(ctxt, p) 218 p2 := obj.Appendp(ctxt, p1) 219 220 p1.As = AMOVD 221 p1.From.Type = obj.TYPE_MEM 222 p1.From.Sym = source.Sym 223 p1.From.Name = obj.NAME_GOTREF 224 p1.To.Type = obj.TYPE_REG 225 p1.To.Reg = REGTMP 226 227 p2.As = p.As 228 p2.From = p.From 229 p2.To = p.To 230 if p.From.Name == obj.NAME_EXTERN { 231 p2.From.Reg = REGTMP 232 p2.From.Name = obj.NAME_NONE 233 p2.From.Sym = nil 234 } else if p.To.Name == obj.NAME_EXTERN { 235 p2.To.Reg = REGTMP 236 p2.To.Name = obj.NAME_NONE 237 p2.To.Sym = nil 238 } else { 239 return 240 } 241 obj.Nopout(p) 242 } 243 244 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 245 // TODO(minux): add morestack short-cuts with small fixed frame-size. 246 ctxt.Cursym = cursym 247 248 if cursym.Text == nil || cursym.Text.Link == nil { 249 return 250 } 251 252 p := cursym.Text 253 textstksiz := p.To.Offset 254 if textstksiz == -8 { 255 // Compatibility hack. 256 p.From3.Offset |= obj.NOFRAME 257 textstksiz = 0 258 } 259 if textstksiz%8 != 0 { 260 ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 261 } 262 if p.From3.Offset&obj.NOFRAME != 0 { 263 if textstksiz != 0 { 264 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 265 } 266 } 267 268 cursym.Args = p.To.Val.(int32) 269 cursym.Locals = int32(textstksiz) 270 271 /* 272 * find leaf subroutines 273 * strip NOPs 274 * expand RET 275 * expand BECOME pseudo 276 */ 277 if ctxt.Debugvlog != 0 { 278 fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime()) 279 } 280 ctxt.Bso.Flush() 281 282 var q *obj.Prog 283 var q1 *obj.Prog 284 for p := cursym.Text; p != nil; p = p.Link { 285 switch p.As { 286 /* too hard, just leave alone */ 287 case obj.ATEXT: 288 q = p 289 290 p.Mark |= LABEL | LEAF | SYNC 291 if p.Link != nil { 292 p.Link.Mark |= LABEL 293 } 294 295 case ANOR: 296 q = p 297 if p.To.Type == obj.TYPE_REG { 298 if p.To.Reg == REGZERO { 299 p.Mark |= LABEL | SYNC 300 } 301 } 302 303 case ALWAR, 304 ASTWCCC, 305 AECIWX, 306 AECOWX, 307 AEIEIO, 308 AICBI, 309 AISYNC, 310 ATLBIE, 311 ATLBIEL, 312 ASLBIA, 313 ASLBIE, 314 ASLBMFEE, 315 ASLBMFEV, 316 ASLBMTE, 317 ADCBF, 318 ADCBI, 319 ADCBST, 320 ADCBT, 321 ADCBTST, 322 ADCBZ, 323 ASYNC, 324 ATLBSYNC, 325 APTESYNC, 326 ATW, 327 AWORD, 328 ARFI, 329 ARFCI, 330 ARFID, 331 AHRFID: 332 q = p 333 p.Mark |= LABEL | SYNC 334 continue 335 336 case AMOVW, AMOVWZ, AMOVD: 337 q = p 338 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 339 p.Mark |= LABEL | SYNC 340 } 341 continue 342 343 case AFABS, 344 AFABSCC, 345 AFADD, 346 AFADDCC, 347 AFCTIW, 348 AFCTIWCC, 349 AFCTIWZ, 350 AFCTIWZCC, 351 AFDIV, 352 AFDIVCC, 353 AFMADD, 354 AFMADDCC, 355 AFMOVD, 356 AFMOVDU, 357 /* case AFMOVDS: */ 358 AFMOVS, 359 AFMOVSU, 360 361 /* case AFMOVSD: */ 362 AFMSUB, 363 AFMSUBCC, 364 AFMUL, 365 AFMULCC, 366 AFNABS, 367 AFNABSCC, 368 AFNEG, 369 AFNEGCC, 370 AFNMADD, 371 AFNMADDCC, 372 AFNMSUB, 373 AFNMSUBCC, 374 AFRSP, 375 AFRSPCC, 376 AFSUB, 377 AFSUBCC: 378 q = p 379 380 p.Mark |= FLOAT 381 continue 382 383 case ABL, 384 ABCL, 385 obj.ADUFFZERO, 386 obj.ADUFFCOPY: 387 cursym.Text.Mark &^= LEAF 388 fallthrough 389 390 case ABC, 391 ABEQ, 392 ABGE, 393 ABGT, 394 ABLE, 395 ABLT, 396 ABNE, 397 ABR, 398 ABVC, 399 ABVS: 400 p.Mark |= BRANCH 401 q = p 402 q1 = p.Pcond 403 if q1 != nil { 404 for q1.As == obj.ANOP { 405 q1 = q1.Link 406 p.Pcond = q1 407 } 408 409 if q1.Mark&LEAF == 0 { 410 q1.Mark |= LABEL 411 } 412 } else { 413 p.Mark |= LABEL 414 } 415 q1 = p.Link 416 if q1 != nil { 417 q1.Mark |= LABEL 418 } 419 continue 420 421 case AFCMPO, AFCMPU: 422 q = p 423 p.Mark |= FCMP | FLOAT 424 continue 425 426 case obj.ARET: 427 q = p 428 if p.Link != nil { 429 p.Link.Mark |= LABEL 430 } 431 continue 432 433 case obj.ANOP: 434 q1 = p.Link 435 q.Link = q1 /* q is non-nop */ 436 q1.Mark |= p.Mark 437 continue 438 439 default: 440 q = p 441 continue 442 } 443 } 444 445 autosize := int32(0) 446 var aoffset int 447 var mov int 448 var o int 449 var p1 *obj.Prog 450 var p2 *obj.Prog 451 for p := cursym.Text; p != nil; p = p.Link { 452 o = int(p.As) 453 switch o { 454 case obj.ATEXT: 455 mov = AMOVD 456 aoffset = 0 457 autosize = int32(textstksiz) 458 459 if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 { 460 // A leaf function with no locals has no frame. 461 p.From3.Offset |= obj.NOFRAME 462 } 463 464 if p.From3.Offset&obj.NOFRAME == 0 { 465 // If there is a stack frame at all, it includes 466 // space to save the LR. 467 autosize += int32(ctxt.FixedFrameSize()) 468 } 469 470 p.To.Offset = int64(autosize) 471 472 q = p 473 474 if ctxt.Flag_shared != 0 && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" { 475 // When compiling Go into PIC, all functions must start 476 // with instructions to load the TOC pointer into r2: 477 // 478 // addis r2, r12, .TOC.-func@ha 479 // addi r2, r2, .TOC.-func@l+4 480 // 481 // We could probably skip this prologue in some situations 482 // but it's a bit subtle. However, it is both safe and 483 // necessary to leave the prologue off duffzero and 484 // duffcopy as we rely on being able to jump to a specific 485 // instruction offset for them, and stackBarrier is only 486 // ever called from an overwritten LR-save slot on the 487 // stack (when r12 will not be remotely the right thing) 488 // but fortunately does not access global data. 489 // 490 // These are AWORDS because there is no (afaict) way to 491 // generate the addis instruction except as part of the 492 // load of a large constant, and in that case there is no 493 // way to use r12 as the source. 494 q = obj.Appendp(ctxt, q) 495 q.As = AWORD 496 q.Lineno = p.Lineno 497 q.From.Type = obj.TYPE_CONST 498 q.From.Offset = 0x3c4c0000 499 q = obj.Appendp(ctxt, q) 500 q.As = AWORD 501 q.Lineno = p.Lineno 502 q.From.Type = obj.TYPE_CONST 503 q.From.Offset = 0x38420000 504 rel := obj.Addrel(ctxt.Cursym) 505 rel.Off = 0 506 rel.Siz = 8 507 rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0) 508 rel.Type = obj.R_ADDRPOWER_PCREL 509 } 510 511 if cursym.Text.From3.Offset&obj.NOSPLIT == 0 { 512 q = stacksplit(ctxt, q, autosize) // emit split check 513 } 514 515 if autosize != 0 { 516 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 517 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 518 mov = AMOVDU 519 aoffset = int(-autosize) 520 } else { 521 q = obj.Appendp(ctxt, q) 522 q.As = AADD 523 q.Lineno = p.Lineno 524 q.From.Type = obj.TYPE_CONST 525 q.From.Offset = int64(-autosize) 526 q.To.Type = obj.TYPE_REG 527 q.To.Reg = REGSP 528 q.Spadj = +autosize 529 } 530 } else if cursym.Text.Mark&LEAF == 0 { 531 // A very few functions that do not return to their caller 532 // (e.g. gogo) are not identified as leaves but still have 533 // no frame. 534 cursym.Text.Mark |= LEAF 535 } 536 537 if cursym.Text.Mark&LEAF != 0 { 538 cursym.Leaf = 1 539 break 540 } 541 542 q = obj.Appendp(ctxt, q) 543 q.As = AMOVD 544 q.Lineno = p.Lineno 545 q.From.Type = obj.TYPE_REG 546 q.From.Reg = REG_LR 547 q.To.Type = obj.TYPE_REG 548 q.To.Reg = REGTMP 549 550 q = obj.Appendp(ctxt, q) 551 q.As = int16(mov) 552 q.Lineno = p.Lineno 553 q.From.Type = obj.TYPE_REG 554 q.From.Reg = REGTMP 555 q.To.Type = obj.TYPE_MEM 556 q.To.Offset = int64(aoffset) 557 q.To.Reg = REGSP 558 if q.As == AMOVDU { 559 q.Spadj = int32(-aoffset) 560 } 561 562 if ctxt.Flag_shared != 0 { 563 q = obj.Appendp(ctxt, q) 564 q.As = AMOVD 565 q.Lineno = p.Lineno 566 q.From.Type = obj.TYPE_REG 567 q.From.Reg = REG_R2 568 q.To.Type = obj.TYPE_MEM 569 q.To.Reg = REGSP 570 q.To.Offset = 24 571 } 572 573 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 574 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 575 // 576 // MOVD g_panic(g), R3 577 // CMP R0, R3 578 // BEQ end 579 // MOVD panic_argp(R3), R4 580 // ADD $(autosize+8), R1, R5 581 // CMP R4, R5 582 // BNE end 583 // ADD $8, R1, R6 584 // MOVD R6, panic_argp(R3) 585 // end: 586 // NOP 587 // 588 // The NOP is needed to give the jumps somewhere to land. 589 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 590 591 q = obj.Appendp(ctxt, q) 592 593 q.As = AMOVD 594 q.From.Type = obj.TYPE_MEM 595 q.From.Reg = REGG 596 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 597 q.To.Type = obj.TYPE_REG 598 q.To.Reg = REG_R3 599 600 q = obj.Appendp(ctxt, q) 601 q.As = ACMP 602 q.From.Type = obj.TYPE_REG 603 q.From.Reg = REG_R0 604 q.To.Type = obj.TYPE_REG 605 q.To.Reg = REG_R3 606 607 q = obj.Appendp(ctxt, q) 608 q.As = ABEQ 609 q.To.Type = obj.TYPE_BRANCH 610 p1 = q 611 612 q = obj.Appendp(ctxt, q) 613 q.As = AMOVD 614 q.From.Type = obj.TYPE_MEM 615 q.From.Reg = REG_R3 616 q.From.Offset = 0 // Panic.argp 617 q.To.Type = obj.TYPE_REG 618 q.To.Reg = REG_R4 619 620 q = obj.Appendp(ctxt, q) 621 q.As = AADD 622 q.From.Type = obj.TYPE_CONST 623 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 624 q.Reg = REGSP 625 q.To.Type = obj.TYPE_REG 626 q.To.Reg = REG_R5 627 628 q = obj.Appendp(ctxt, q) 629 q.As = ACMP 630 q.From.Type = obj.TYPE_REG 631 q.From.Reg = REG_R4 632 q.To.Type = obj.TYPE_REG 633 q.To.Reg = REG_R5 634 635 q = obj.Appendp(ctxt, q) 636 q.As = ABNE 637 q.To.Type = obj.TYPE_BRANCH 638 p2 = q 639 640 q = obj.Appendp(ctxt, q) 641 q.As = AADD 642 q.From.Type = obj.TYPE_CONST 643 q.From.Offset = ctxt.FixedFrameSize() 644 q.Reg = REGSP 645 q.To.Type = obj.TYPE_REG 646 q.To.Reg = REG_R6 647 648 q = obj.Appendp(ctxt, q) 649 q.As = AMOVD 650 q.From.Type = obj.TYPE_REG 651 q.From.Reg = REG_R6 652 q.To.Type = obj.TYPE_MEM 653 q.To.Reg = REG_R3 654 q.To.Offset = 0 // Panic.argp 655 656 q = obj.Appendp(ctxt, q) 657 658 q.As = obj.ANOP 659 p1.Pcond = q 660 p2.Pcond = q 661 } 662 663 case obj.ARET: 664 if p.From.Type == obj.TYPE_CONST { 665 ctxt.Diag("using BECOME (%v) is not supported!", p) 666 break 667 } 668 669 retTarget := p.To.Sym 670 671 if cursym.Text.Mark&LEAF != 0 { 672 if autosize == 0 { 673 p.As = ABR 674 p.From = obj.Addr{} 675 if retTarget == nil { 676 p.To.Type = obj.TYPE_REG 677 p.To.Reg = REG_LR 678 } else { 679 p.To.Type = obj.TYPE_BRANCH 680 p.To.Sym = retTarget 681 } 682 p.Mark |= BRANCH 683 break 684 } 685 686 p.As = AADD 687 p.From.Type = obj.TYPE_CONST 688 p.From.Offset = int64(autosize) 689 p.To.Type = obj.TYPE_REG 690 p.To.Reg = REGSP 691 p.Spadj = -autosize 692 693 q = ctxt.NewProg() 694 q.As = ABR 695 q.Lineno = p.Lineno 696 q.To.Type = obj.TYPE_REG 697 q.To.Reg = REG_LR 698 q.Mark |= BRANCH 699 q.Spadj = +autosize 700 701 q.Link = p.Link 702 p.Link = q 703 break 704 } 705 706 p.As = AMOVD 707 p.From.Type = obj.TYPE_MEM 708 p.From.Offset = 0 709 p.From.Reg = REGSP 710 p.To.Type = obj.TYPE_REG 711 p.To.Reg = REGTMP 712 713 q = ctxt.NewProg() 714 q.As = AMOVD 715 q.Lineno = p.Lineno 716 q.From.Type = obj.TYPE_REG 717 q.From.Reg = REGTMP 718 q.To.Type = obj.TYPE_REG 719 q.To.Reg = REG_LR 720 721 q.Link = p.Link 722 p.Link = q 723 p = q 724 725 if false { 726 // Debug bad returns 727 q = ctxt.NewProg() 728 729 q.As = AMOVD 730 q.Lineno = p.Lineno 731 q.From.Type = obj.TYPE_MEM 732 q.From.Offset = 0 733 q.From.Reg = REGTMP 734 q.To.Type = obj.TYPE_REG 735 q.To.Reg = REGTMP 736 737 q.Link = p.Link 738 p.Link = q 739 p = q 740 } 741 742 if autosize != 0 { 743 q = ctxt.NewProg() 744 q.As = AADD 745 q.Lineno = p.Lineno 746 q.From.Type = obj.TYPE_CONST 747 q.From.Offset = int64(autosize) 748 q.To.Type = obj.TYPE_REG 749 q.To.Reg = REGSP 750 q.Spadj = -autosize 751 752 q.Link = p.Link 753 p.Link = q 754 } 755 756 q1 = ctxt.NewProg() 757 q1.As = ABR 758 q1.Lineno = p.Lineno 759 if retTarget == nil { 760 q1.To.Type = obj.TYPE_REG 761 q1.To.Reg = REG_LR 762 } else { 763 q1.To.Type = obj.TYPE_BRANCH 764 q1.To.Sym = retTarget 765 } 766 q1.Mark |= BRANCH 767 q1.Spadj = +autosize 768 769 q1.Link = q.Link 770 q.Link = q1 771 case AADD: 772 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 773 p.Spadj = int32(-p.From.Offset) 774 } 775 } 776 } 777 } 778 779 /* 780 // instruction scheduling 781 if(debug['Q'] == 0) 782 return; 783 784 curtext = nil; 785 q = nil; // p - 1 786 q1 = firstp; // top of block 787 o = 0; // count of instructions 788 for(p = firstp; p != nil; p = p1) { 789 p1 = p->link; 790 o++; 791 if(p->mark & NOSCHED){ 792 if(q1 != p){ 793 sched(q1, q); 794 } 795 for(; p != nil; p = p->link){ 796 if(!(p->mark & NOSCHED)) 797 break; 798 q = p; 799 } 800 p1 = p; 801 q1 = p; 802 o = 0; 803 continue; 804 } 805 if(p->mark & (LABEL|SYNC)) { 806 if(q1 != p) 807 sched(q1, q); 808 q1 = p; 809 o = 1; 810 } 811 if(p->mark & (BRANCH|SYNC)) { 812 sched(q1, p); 813 q1 = p1; 814 o = 0; 815 } 816 if(o >= NSCHED) { 817 sched(q1, p); 818 q1 = p1; 819 o = 0; 820 } 821 q = p; 822 } 823 */ 824 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 825 // MOVD g_stackguard(g), R3 826 p = obj.Appendp(ctxt, p) 827 828 p.As = AMOVD 829 p.From.Type = obj.TYPE_MEM 830 p.From.Reg = REGG 831 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 832 if ctxt.Cursym.Cfunc != 0 { 833 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 834 } 835 p.To.Type = obj.TYPE_REG 836 p.To.Reg = REG_R3 837 838 var q *obj.Prog 839 if framesize <= obj.StackSmall { 840 // small stack: SP < stackguard 841 // CMP stackguard, SP 842 p = obj.Appendp(ctxt, p) 843 844 p.As = ACMPU 845 p.From.Type = obj.TYPE_REG 846 p.From.Reg = REG_R3 847 p.To.Type = obj.TYPE_REG 848 p.To.Reg = REGSP 849 } else if framesize <= obj.StackBig { 850 // large stack: SP-framesize < stackguard-StackSmall 851 // ADD $-framesize, SP, R4 852 // CMP stackguard, R4 853 p = obj.Appendp(ctxt, p) 854 855 p.As = AADD 856 p.From.Type = obj.TYPE_CONST 857 p.From.Offset = int64(-framesize) 858 p.Reg = REGSP 859 p.To.Type = obj.TYPE_REG 860 p.To.Reg = REG_R4 861 862 p = obj.Appendp(ctxt, p) 863 p.As = ACMPU 864 p.From.Type = obj.TYPE_REG 865 p.From.Reg = REG_R3 866 p.To.Type = obj.TYPE_REG 867 p.To.Reg = REG_R4 868 } else { 869 // Such a large stack we need to protect against wraparound. 870 // If SP is close to zero: 871 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 872 // The +StackGuard on both sides is required to keep the left side positive: 873 // SP is allowed to be slightly below stackguard. See stack.h. 874 // 875 // Preemption sets stackguard to StackPreempt, a very large value. 876 // That breaks the math above, so we have to check for that explicitly. 877 // // stackguard is R3 878 // CMP R3, $StackPreempt 879 // BEQ label-of-call-to-morestack 880 // ADD $StackGuard, SP, R4 881 // SUB R3, R4 882 // MOVD $(framesize+(StackGuard-StackSmall)), R31 883 // CMPU R31, R4 884 p = obj.Appendp(ctxt, p) 885 886 p.As = ACMP 887 p.From.Type = obj.TYPE_REG 888 p.From.Reg = REG_R3 889 p.To.Type = obj.TYPE_CONST 890 p.To.Offset = obj.StackPreempt 891 892 p = obj.Appendp(ctxt, p) 893 q = p 894 p.As = ABEQ 895 p.To.Type = obj.TYPE_BRANCH 896 897 p = obj.Appendp(ctxt, p) 898 p.As = AADD 899 p.From.Type = obj.TYPE_CONST 900 p.From.Offset = obj.StackGuard 901 p.Reg = REGSP 902 p.To.Type = obj.TYPE_REG 903 p.To.Reg = REG_R4 904 905 p = obj.Appendp(ctxt, p) 906 p.As = ASUB 907 p.From.Type = obj.TYPE_REG 908 p.From.Reg = REG_R3 909 p.To.Type = obj.TYPE_REG 910 p.To.Reg = REG_R4 911 912 p = obj.Appendp(ctxt, p) 913 p.As = AMOVD 914 p.From.Type = obj.TYPE_CONST 915 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 916 p.To.Type = obj.TYPE_REG 917 p.To.Reg = REGTMP 918 919 p = obj.Appendp(ctxt, p) 920 p.As = ACMPU 921 p.From.Type = obj.TYPE_REG 922 p.From.Reg = REGTMP 923 p.To.Type = obj.TYPE_REG 924 p.To.Reg = REG_R4 925 } 926 927 // q1: BLT done 928 p = obj.Appendp(ctxt, p) 929 q1 := p 930 931 p.As = ABLT 932 p.To.Type = obj.TYPE_BRANCH 933 934 // MOVD LR, R5 935 p = obj.Appendp(ctxt, p) 936 937 p.As = AMOVD 938 p.From.Type = obj.TYPE_REG 939 p.From.Reg = REG_LR 940 p.To.Type = obj.TYPE_REG 941 p.To.Reg = REG_R5 942 if q != nil { 943 q.Pcond = p 944 } 945 946 var morestacksym *obj.LSym 947 if ctxt.Cursym.Cfunc != 0 { 948 morestacksym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 949 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 950 morestacksym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 951 } else { 952 morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0) 953 } 954 955 if ctxt.Flag_dynlink { 956 // Avoid calling morestack via a PLT when dynamically linking. The 957 // PLT stubs generated by the system linker on ppc64le when "std r2, 958 // 24(r1)" to save the TOC pointer in their callers stack 959 // frame. Unfortunately (and necessarily) morestack is called before 960 // the function that calls it sets up its frame and so the PLT ends 961 // up smashing the saved TOC pointer for its caller's caller. 962 // 963 // According to the ABI documentation there is a mechanism to avoid 964 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 965 // relocation on the nop after the call to morestack) but at the time 966 // of writing it is not supported at all by gold and my attempt to 967 // use it with ld.bfd caused an internal linker error. So this hack 968 // seems preferable. 969 970 // MOVD $runtime.morestack(SB), R12 971 p = obj.Appendp(ctxt, p) 972 p.As = AMOVD 973 p.From.Type = obj.TYPE_MEM 974 p.From.Sym = morestacksym 975 p.From.Name = obj.NAME_GOTREF 976 p.To.Type = obj.TYPE_REG 977 p.To.Reg = REG_R12 978 979 // MOVD R12, CTR 980 p = obj.Appendp(ctxt, p) 981 p.As = AMOVD 982 p.From.Type = obj.TYPE_REG 983 p.From.Reg = REG_R12 984 p.To.Type = obj.TYPE_REG 985 p.To.Reg = REG_CTR 986 987 // BL CTR 988 p = obj.Appendp(ctxt, p) 989 p.As = obj.ACALL 990 p.From.Type = obj.TYPE_REG 991 p.From.Reg = REG_R12 992 p.To.Type = obj.TYPE_REG 993 p.To.Reg = REG_CTR 994 } else { 995 // BL runtime.morestack(SB) 996 p = obj.Appendp(ctxt, p) 997 998 p.As = ABL 999 p.To.Type = obj.TYPE_BRANCH 1000 p.To.Sym = morestacksym 1001 } 1002 // BR start 1003 p = obj.Appendp(ctxt, p) 1004 1005 p.As = ABR 1006 p.To.Type = obj.TYPE_BRANCH 1007 p.Pcond = ctxt.Cursym.Text.Link 1008 1009 // placeholder for q1's jump target 1010 p = obj.Appendp(ctxt, p) 1011 1012 p.As = obj.ANOP // zero-width place holder 1013 q1.Pcond = p 1014 1015 return p 1016 } 1017 1018 func follow(ctxt *obj.Link, s *obj.LSym) { 1019 ctxt.Cursym = s 1020 1021 firstp := ctxt.NewProg() 1022 lastp := firstp 1023 xfol(ctxt, s.Text, &lastp) 1024 lastp.Link = nil 1025 s.Text = firstp.Link 1026 } 1027 1028 func relinv(a int) int { 1029 switch a { 1030 case ABEQ: 1031 return ABNE 1032 case ABNE: 1033 return ABEQ 1034 1035 case ABGE: 1036 return ABLT 1037 case ABLT: 1038 return ABGE 1039 1040 case ABGT: 1041 return ABLE 1042 case ABLE: 1043 return ABGT 1044 1045 case ABVC: 1046 return ABVS 1047 case ABVS: 1048 return ABVC 1049 } 1050 1051 return 0 1052 } 1053 1054 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 1055 var q *obj.Prog 1056 var r *obj.Prog 1057 var a int 1058 var b int 1059 var i int 1060 1061 loop: 1062 if p == nil { 1063 return 1064 } 1065 a = int(p.As) 1066 if a == ABR { 1067 q = p.Pcond 1068 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 1069 p.Mark |= FOLL 1070 (*last).Link = p 1071 *last = p 1072 p = p.Link 1073 xfol(ctxt, p, last) 1074 p = q 1075 if p != nil && p.Mark&FOLL == 0 { 1076 goto loop 1077 } 1078 return 1079 } 1080 1081 if q != nil { 1082 p.Mark |= FOLL 1083 p = q 1084 if p.Mark&FOLL == 0 { 1085 goto loop 1086 } 1087 } 1088 } 1089 1090 if p.Mark&FOLL != 0 { 1091 i = 0 1092 q = p 1093 for ; i < 4; i, q = i+1, q.Link { 1094 if q == *last || (q.Mark&NOSCHED != 0) { 1095 break 1096 } 1097 b = 0 /* set */ 1098 a = int(q.As) 1099 if a == obj.ANOP { 1100 i-- 1101 continue 1102 } 1103 1104 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1105 goto copy 1106 } 1107 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 1108 continue 1109 } 1110 b = relinv(a) 1111 if b == 0 { 1112 continue 1113 } 1114 1115 copy: 1116 for { 1117 r = ctxt.NewProg() 1118 *r = *p 1119 if r.Mark&FOLL == 0 { 1120 fmt.Printf("cant happen 1\n") 1121 } 1122 r.Mark |= FOLL 1123 if p != q { 1124 p = p.Link 1125 (*last).Link = r 1126 *last = r 1127 continue 1128 } 1129 1130 (*last).Link = r 1131 *last = r 1132 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1133 return 1134 } 1135 r.As = int16(b) 1136 r.Pcond = p.Link 1137 r.Link = p.Pcond 1138 if r.Link.Mark&FOLL == 0 { 1139 xfol(ctxt, r.Link, last) 1140 } 1141 if r.Pcond.Mark&FOLL == 0 { 1142 fmt.Printf("cant happen 2\n") 1143 } 1144 return 1145 } 1146 } 1147 1148 a = ABR 1149 q = ctxt.NewProg() 1150 q.As = int16(a) 1151 q.Lineno = p.Lineno 1152 q.To.Type = obj.TYPE_BRANCH 1153 q.To.Offset = p.Pc 1154 q.Pcond = p 1155 p = q 1156 } 1157 1158 p.Mark |= FOLL 1159 (*last).Link = p 1160 *last = p 1161 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1162 if p.Mark&NOSCHED != 0 { 1163 p = p.Link 1164 goto loop 1165 } 1166 1167 return 1168 } 1169 1170 if p.Pcond != nil { 1171 if a != ABL && p.Link != nil { 1172 xfol(ctxt, p.Link, last) 1173 p = p.Pcond 1174 if p == nil || (p.Mark&FOLL != 0) { 1175 return 1176 } 1177 goto loop 1178 } 1179 } 1180 1181 p = p.Link 1182 goto loop 1183 } 1184 1185 var Linkppc64 = obj.LinkArch{ 1186 ByteOrder: binary.BigEndian, 1187 Name: "ppc64", 1188 Thechar: '9', 1189 Preprocess: preprocess, 1190 Assemble: span9, 1191 Follow: follow, 1192 Progedit: progedit, 1193 Minlc: 4, 1194 Ptrsize: 8, 1195 Regsize: 8, 1196 } 1197 1198 var Linkppc64le = obj.LinkArch{ 1199 ByteOrder: binary.LittleEndian, 1200 Name: "ppc64le", 1201 Thechar: '9', 1202 Preprocess: preprocess, 1203 Assemble: span9, 1204 Follow: follow, 1205 Progedit: progedit, 1206 Minlc: 4, 1207 Ptrsize: 8, 1208 Regsize: 8, 1209 }