github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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" { 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. 486 // 487 // These are AWORDS because there is no (afaict) way to 488 // generate the addis instruction except as part of the 489 // load of a large constant, and in that case there is no 490 // way to use r12 as the source. 491 q = obj.Appendp(ctxt, q) 492 q.As = AWORD 493 q.Lineno = p.Lineno 494 q.From.Type = obj.TYPE_CONST 495 q.From.Offset = 0x3c4c0000 496 q = obj.Appendp(ctxt, q) 497 q.As = AWORD 498 q.Lineno = p.Lineno 499 q.From.Type = obj.TYPE_CONST 500 q.From.Offset = 0x38420000 501 rel := obj.Addrel(ctxt.Cursym) 502 rel.Off = 0 503 rel.Siz = 8 504 rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0) 505 rel.Type = obj.R_ADDRPOWER_PCREL 506 } 507 508 if cursym.Text.From3.Offset&obj.NOSPLIT == 0 { 509 q = stacksplit(ctxt, q, autosize) // emit split check 510 } 511 512 if autosize != 0 { 513 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 514 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 515 mov = AMOVDU 516 aoffset = int(-autosize) 517 } else { 518 q = obj.Appendp(ctxt, q) 519 q.As = AADD 520 q.Lineno = p.Lineno 521 q.From.Type = obj.TYPE_CONST 522 q.From.Offset = int64(-autosize) 523 q.To.Type = obj.TYPE_REG 524 q.To.Reg = REGSP 525 q.Spadj = +autosize 526 } 527 } else if cursym.Text.Mark&LEAF == 0 { 528 // A very few functions that do not return to their caller 529 // (e.g. gogo) are not identified as leaves but still have 530 // no frame. 531 cursym.Text.Mark |= LEAF 532 } 533 534 if cursym.Text.Mark&LEAF != 0 { 535 cursym.Leaf = 1 536 break 537 } 538 539 q = obj.Appendp(ctxt, q) 540 q.As = AMOVD 541 q.Lineno = p.Lineno 542 q.From.Type = obj.TYPE_REG 543 q.From.Reg = REG_LR 544 q.To.Type = obj.TYPE_REG 545 q.To.Reg = REGTMP 546 547 q = obj.Appendp(ctxt, q) 548 q.As = int16(mov) 549 q.Lineno = p.Lineno 550 q.From.Type = obj.TYPE_REG 551 q.From.Reg = REGTMP 552 q.To.Type = obj.TYPE_MEM 553 q.To.Offset = int64(aoffset) 554 q.To.Reg = REGSP 555 if q.As == AMOVDU { 556 q.Spadj = int32(-aoffset) 557 } 558 559 if ctxt.Flag_shared != 0 { 560 q = obj.Appendp(ctxt, q) 561 q.As = AMOVD 562 q.Lineno = p.Lineno 563 q.From.Type = obj.TYPE_REG 564 q.From.Reg = REG_R2 565 q.To.Type = obj.TYPE_MEM 566 q.To.Reg = REGSP 567 q.To.Offset = 24 568 } 569 570 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 571 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 572 // 573 // MOVD g_panic(g), R3 574 // CMP R0, R3 575 // BEQ end 576 // MOVD panic_argp(R3), R4 577 // ADD $(autosize+8), R1, R5 578 // CMP R4, R5 579 // BNE end 580 // ADD $8, R1, R6 581 // MOVD R6, panic_argp(R3) 582 // end: 583 // NOP 584 // 585 // The NOP is needed to give the jumps somewhere to land. 586 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 587 588 q = obj.Appendp(ctxt, q) 589 590 q.As = AMOVD 591 q.From.Type = obj.TYPE_MEM 592 q.From.Reg = REGG 593 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 594 q.To.Type = obj.TYPE_REG 595 q.To.Reg = REG_R3 596 597 q = obj.Appendp(ctxt, q) 598 q.As = ACMP 599 q.From.Type = obj.TYPE_REG 600 q.From.Reg = REG_R0 601 q.To.Type = obj.TYPE_REG 602 q.To.Reg = REG_R3 603 604 q = obj.Appendp(ctxt, q) 605 q.As = ABEQ 606 q.To.Type = obj.TYPE_BRANCH 607 p1 = q 608 609 q = obj.Appendp(ctxt, q) 610 q.As = AMOVD 611 q.From.Type = obj.TYPE_MEM 612 q.From.Reg = REG_R3 613 q.From.Offset = 0 // Panic.argp 614 q.To.Type = obj.TYPE_REG 615 q.To.Reg = REG_R4 616 617 q = obj.Appendp(ctxt, q) 618 q.As = AADD 619 q.From.Type = obj.TYPE_CONST 620 q.From.Offset = int64(autosize) + ctxt.FixedFrameSize() 621 q.Reg = REGSP 622 q.To.Type = obj.TYPE_REG 623 q.To.Reg = REG_R5 624 625 q = obj.Appendp(ctxt, q) 626 q.As = ACMP 627 q.From.Type = obj.TYPE_REG 628 q.From.Reg = REG_R4 629 q.To.Type = obj.TYPE_REG 630 q.To.Reg = REG_R5 631 632 q = obj.Appendp(ctxt, q) 633 q.As = ABNE 634 q.To.Type = obj.TYPE_BRANCH 635 p2 = q 636 637 q = obj.Appendp(ctxt, q) 638 q.As = AADD 639 q.From.Type = obj.TYPE_CONST 640 q.From.Offset = ctxt.FixedFrameSize() 641 q.Reg = REGSP 642 q.To.Type = obj.TYPE_REG 643 q.To.Reg = REG_R6 644 645 q = obj.Appendp(ctxt, q) 646 q.As = AMOVD 647 q.From.Type = obj.TYPE_REG 648 q.From.Reg = REG_R6 649 q.To.Type = obj.TYPE_MEM 650 q.To.Reg = REG_R3 651 q.To.Offset = 0 // Panic.argp 652 653 q = obj.Appendp(ctxt, q) 654 655 q.As = obj.ANOP 656 p1.Pcond = q 657 p2.Pcond = q 658 } 659 660 case obj.ARET: 661 if p.From.Type == obj.TYPE_CONST { 662 ctxt.Diag("using BECOME (%v) is not supported!", p) 663 break 664 } 665 666 retTarget := p.To.Sym 667 668 if cursym.Text.Mark&LEAF != 0 { 669 if autosize == 0 { 670 p.As = ABR 671 p.From = obj.Addr{} 672 if retTarget == nil { 673 p.To.Type = obj.TYPE_REG 674 p.To.Reg = REG_LR 675 } else { 676 p.To.Type = obj.TYPE_BRANCH 677 p.To.Sym = retTarget 678 } 679 p.Mark |= BRANCH 680 break 681 } 682 683 p.As = AADD 684 p.From.Type = obj.TYPE_CONST 685 p.From.Offset = int64(autosize) 686 p.To.Type = obj.TYPE_REG 687 p.To.Reg = REGSP 688 p.Spadj = -autosize 689 690 q = ctxt.NewProg() 691 q.As = ABR 692 q.Lineno = p.Lineno 693 q.To.Type = obj.TYPE_REG 694 q.To.Reg = REG_LR 695 q.Mark |= BRANCH 696 q.Spadj = +autosize 697 698 q.Link = p.Link 699 p.Link = q 700 break 701 } 702 703 p.As = AMOVD 704 p.From.Type = obj.TYPE_MEM 705 p.From.Offset = 0 706 p.From.Reg = REGSP 707 p.To.Type = obj.TYPE_REG 708 p.To.Reg = REGTMP 709 710 q = ctxt.NewProg() 711 q.As = AMOVD 712 q.Lineno = p.Lineno 713 q.From.Type = obj.TYPE_REG 714 q.From.Reg = REGTMP 715 q.To.Type = obj.TYPE_REG 716 q.To.Reg = REG_LR 717 718 q.Link = p.Link 719 p.Link = q 720 p = q 721 722 if false { 723 // Debug bad returns 724 q = ctxt.NewProg() 725 726 q.As = AMOVD 727 q.Lineno = p.Lineno 728 q.From.Type = obj.TYPE_MEM 729 q.From.Offset = 0 730 q.From.Reg = REGTMP 731 q.To.Type = obj.TYPE_REG 732 q.To.Reg = REGTMP 733 734 q.Link = p.Link 735 p.Link = q 736 p = q 737 } 738 739 if autosize != 0 { 740 q = ctxt.NewProg() 741 q.As = AADD 742 q.Lineno = p.Lineno 743 q.From.Type = obj.TYPE_CONST 744 q.From.Offset = int64(autosize) 745 q.To.Type = obj.TYPE_REG 746 q.To.Reg = REGSP 747 q.Spadj = -autosize 748 749 q.Link = p.Link 750 p.Link = q 751 } 752 753 q1 = ctxt.NewProg() 754 q1.As = ABR 755 q1.Lineno = p.Lineno 756 if retTarget == nil { 757 q1.To.Type = obj.TYPE_REG 758 q1.To.Reg = REG_LR 759 } else { 760 q1.To.Type = obj.TYPE_BRANCH 761 q1.To.Sym = retTarget 762 } 763 q1.Mark |= BRANCH 764 q1.Spadj = +autosize 765 766 q1.Link = q.Link 767 q.Link = q1 768 case AADD: 769 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 770 p.Spadj = int32(-p.From.Offset) 771 } 772 } 773 } 774 } 775 776 /* 777 // instruction scheduling 778 if(debug['Q'] == 0) 779 return; 780 781 curtext = nil; 782 q = nil; // p - 1 783 q1 = firstp; // top of block 784 o = 0; // count of instructions 785 for(p = firstp; p != nil; p = p1) { 786 p1 = p->link; 787 o++; 788 if(p->mark & NOSCHED){ 789 if(q1 != p){ 790 sched(q1, q); 791 } 792 for(; p != nil; p = p->link){ 793 if(!(p->mark & NOSCHED)) 794 break; 795 q = p; 796 } 797 p1 = p; 798 q1 = p; 799 o = 0; 800 continue; 801 } 802 if(p->mark & (LABEL|SYNC)) { 803 if(q1 != p) 804 sched(q1, q); 805 q1 = p; 806 o = 1; 807 } 808 if(p->mark & (BRANCH|SYNC)) { 809 sched(q1, p); 810 q1 = p1; 811 o = 0; 812 } 813 if(o >= NSCHED) { 814 sched(q1, p); 815 q1 = p1; 816 o = 0; 817 } 818 q = p; 819 } 820 */ 821 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 822 // MOVD g_stackguard(g), R3 823 p = obj.Appendp(ctxt, p) 824 825 p.As = AMOVD 826 p.From.Type = obj.TYPE_MEM 827 p.From.Reg = REGG 828 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 829 if ctxt.Cursym.Cfunc != 0 { 830 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 831 } 832 p.To.Type = obj.TYPE_REG 833 p.To.Reg = REG_R3 834 835 var q *obj.Prog 836 if framesize <= obj.StackSmall { 837 // small stack: SP < stackguard 838 // CMP stackguard, SP 839 p = obj.Appendp(ctxt, p) 840 841 p.As = ACMPU 842 p.From.Type = obj.TYPE_REG 843 p.From.Reg = REG_R3 844 p.To.Type = obj.TYPE_REG 845 p.To.Reg = REGSP 846 } else if framesize <= obj.StackBig { 847 // large stack: SP-framesize < stackguard-StackSmall 848 // ADD $-framesize, SP, R4 849 // CMP stackguard, R4 850 p = obj.Appendp(ctxt, p) 851 852 p.As = AADD 853 p.From.Type = obj.TYPE_CONST 854 p.From.Offset = int64(-framesize) 855 p.Reg = REGSP 856 p.To.Type = obj.TYPE_REG 857 p.To.Reg = REG_R4 858 859 p = obj.Appendp(ctxt, p) 860 p.As = ACMPU 861 p.From.Type = obj.TYPE_REG 862 p.From.Reg = REG_R3 863 p.To.Type = obj.TYPE_REG 864 p.To.Reg = REG_R4 865 } else { 866 // Such a large stack we need to protect against wraparound. 867 // If SP is close to zero: 868 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 869 // The +StackGuard on both sides is required to keep the left side positive: 870 // SP is allowed to be slightly below stackguard. See stack.h. 871 // 872 // Preemption sets stackguard to StackPreempt, a very large value. 873 // That breaks the math above, so we have to check for that explicitly. 874 // // stackguard is R3 875 // CMP R3, $StackPreempt 876 // BEQ label-of-call-to-morestack 877 // ADD $StackGuard, SP, R4 878 // SUB R3, R4 879 // MOVD $(framesize+(StackGuard-StackSmall)), R31 880 // CMPU R31, R4 881 p = obj.Appendp(ctxt, p) 882 883 p.As = ACMP 884 p.From.Type = obj.TYPE_REG 885 p.From.Reg = REG_R3 886 p.To.Type = obj.TYPE_CONST 887 p.To.Offset = obj.StackPreempt 888 889 p = obj.Appendp(ctxt, p) 890 q = p 891 p.As = ABEQ 892 p.To.Type = obj.TYPE_BRANCH 893 894 p = obj.Appendp(ctxt, p) 895 p.As = AADD 896 p.From.Type = obj.TYPE_CONST 897 p.From.Offset = obj.StackGuard 898 p.Reg = REGSP 899 p.To.Type = obj.TYPE_REG 900 p.To.Reg = REG_R4 901 902 p = obj.Appendp(ctxt, p) 903 p.As = ASUB 904 p.From.Type = obj.TYPE_REG 905 p.From.Reg = REG_R3 906 p.To.Type = obj.TYPE_REG 907 p.To.Reg = REG_R4 908 909 p = obj.Appendp(ctxt, p) 910 p.As = AMOVD 911 p.From.Type = obj.TYPE_CONST 912 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 913 p.To.Type = obj.TYPE_REG 914 p.To.Reg = REGTMP 915 916 p = obj.Appendp(ctxt, p) 917 p.As = ACMPU 918 p.From.Type = obj.TYPE_REG 919 p.From.Reg = REGTMP 920 p.To.Type = obj.TYPE_REG 921 p.To.Reg = REG_R4 922 } 923 924 // q1: BLT done 925 p = obj.Appendp(ctxt, p) 926 q1 := p 927 928 p.As = ABLT 929 p.To.Type = obj.TYPE_BRANCH 930 931 // MOVD LR, R5 932 p = obj.Appendp(ctxt, p) 933 934 p.As = AMOVD 935 p.From.Type = obj.TYPE_REG 936 p.From.Reg = REG_LR 937 p.To.Type = obj.TYPE_REG 938 p.To.Reg = REG_R5 939 if q != nil { 940 q.Pcond = p 941 } 942 943 var morestacksym *obj.LSym 944 if ctxt.Cursym.Cfunc != 0 { 945 morestacksym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 946 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 947 morestacksym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 948 } else { 949 morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0) 950 } 951 952 if ctxt.Flag_dynlink { 953 // Avoid calling morestack via a PLT when dynamically linking. The 954 // PLT stubs generated by the system linker on ppc64le when "std r2, 955 // 24(r1)" to save the TOC pointer in their callers stack 956 // frame. Unfortunately (and necessarily) morestack is called before 957 // the function that calls it sets up its frame and so the PLT ends 958 // up smashing the saved TOC pointer for its caller's caller. 959 // 960 // According to the ABI documentation there is a mechanism to avoid 961 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE 962 // relocation on the nop after the call to morestack) but at the time 963 // of writing it is not supported at all by gold and my attempt to 964 // use it with ld.bfd caused an internal linker error. So this hack 965 // seems preferable. 966 967 // MOVD $runtime.morestack(SB), R12 968 p = obj.Appendp(ctxt, p) 969 p.As = AMOVD 970 p.From.Type = obj.TYPE_MEM 971 p.From.Sym = morestacksym 972 p.From.Name = obj.NAME_GOTREF 973 p.To.Type = obj.TYPE_REG 974 p.To.Reg = REG_R12 975 976 // MOVD R12, CTR 977 p = obj.Appendp(ctxt, p) 978 p.As = AMOVD 979 p.From.Type = obj.TYPE_REG 980 p.From.Reg = REG_R12 981 p.To.Type = obj.TYPE_REG 982 p.To.Reg = REG_CTR 983 984 // BL CTR 985 p = obj.Appendp(ctxt, p) 986 p.As = obj.ACALL 987 p.From.Type = obj.TYPE_REG 988 p.From.Reg = REG_R12 989 p.To.Type = obj.TYPE_REG 990 p.To.Reg = REG_CTR 991 } else { 992 // BL runtime.morestack(SB) 993 p = obj.Appendp(ctxt, p) 994 995 p.As = ABL 996 p.To.Type = obj.TYPE_BRANCH 997 p.To.Sym = morestacksym 998 } 999 // BR start 1000 p = obj.Appendp(ctxt, p) 1001 1002 p.As = ABR 1003 p.To.Type = obj.TYPE_BRANCH 1004 p.Pcond = ctxt.Cursym.Text.Link 1005 1006 // placeholder for q1's jump target 1007 p = obj.Appendp(ctxt, p) 1008 1009 p.As = obj.ANOP // zero-width place holder 1010 q1.Pcond = p 1011 1012 return p 1013 } 1014 1015 func follow(ctxt *obj.Link, s *obj.LSym) { 1016 ctxt.Cursym = s 1017 1018 firstp := ctxt.NewProg() 1019 lastp := firstp 1020 xfol(ctxt, s.Text, &lastp) 1021 lastp.Link = nil 1022 s.Text = firstp.Link 1023 } 1024 1025 func relinv(a int) int { 1026 switch a { 1027 case ABEQ: 1028 return ABNE 1029 case ABNE: 1030 return ABEQ 1031 1032 case ABGE: 1033 return ABLT 1034 case ABLT: 1035 return ABGE 1036 1037 case ABGT: 1038 return ABLE 1039 case ABLE: 1040 return ABGT 1041 1042 case ABVC: 1043 return ABVS 1044 case ABVS: 1045 return ABVC 1046 } 1047 1048 return 0 1049 } 1050 1051 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 1052 var q *obj.Prog 1053 var r *obj.Prog 1054 var a int 1055 var b int 1056 var i int 1057 1058 loop: 1059 if p == nil { 1060 return 1061 } 1062 a = int(p.As) 1063 if a == ABR { 1064 q = p.Pcond 1065 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 1066 p.Mark |= FOLL 1067 (*last).Link = p 1068 *last = p 1069 p = p.Link 1070 xfol(ctxt, p, last) 1071 p = q 1072 if p != nil && p.Mark&FOLL == 0 { 1073 goto loop 1074 } 1075 return 1076 } 1077 1078 if q != nil { 1079 p.Mark |= FOLL 1080 p = q 1081 if p.Mark&FOLL == 0 { 1082 goto loop 1083 } 1084 } 1085 } 1086 1087 if p.Mark&FOLL != 0 { 1088 i = 0 1089 q = p 1090 for ; i < 4; i, q = i+1, q.Link { 1091 if q == *last || (q.Mark&NOSCHED != 0) { 1092 break 1093 } 1094 b = 0 /* set */ 1095 a = int(q.As) 1096 if a == obj.ANOP { 1097 i-- 1098 continue 1099 } 1100 1101 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1102 goto copy 1103 } 1104 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 1105 continue 1106 } 1107 b = relinv(a) 1108 if b == 0 { 1109 continue 1110 } 1111 1112 copy: 1113 for { 1114 r = ctxt.NewProg() 1115 *r = *p 1116 if r.Mark&FOLL == 0 { 1117 fmt.Printf("cant happen 1\n") 1118 } 1119 r.Mark |= FOLL 1120 if p != q { 1121 p = p.Link 1122 (*last).Link = r 1123 *last = r 1124 continue 1125 } 1126 1127 (*last).Link = r 1128 *last = r 1129 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1130 return 1131 } 1132 r.As = int16(b) 1133 r.Pcond = p.Link 1134 r.Link = p.Pcond 1135 if r.Link.Mark&FOLL == 0 { 1136 xfol(ctxt, r.Link, last) 1137 } 1138 if r.Pcond.Mark&FOLL == 0 { 1139 fmt.Printf("cant happen 2\n") 1140 } 1141 return 1142 } 1143 } 1144 1145 a = ABR 1146 q = ctxt.NewProg() 1147 q.As = int16(a) 1148 q.Lineno = p.Lineno 1149 q.To.Type = obj.TYPE_BRANCH 1150 q.To.Offset = p.Pc 1151 q.Pcond = p 1152 p = q 1153 } 1154 1155 p.Mark |= FOLL 1156 (*last).Link = p 1157 *last = p 1158 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 1159 if p.Mark&NOSCHED != 0 { 1160 p = p.Link 1161 goto loop 1162 } 1163 1164 return 1165 } 1166 1167 if p.Pcond != nil { 1168 if a != ABL && p.Link != nil { 1169 xfol(ctxt, p.Link, last) 1170 p = p.Pcond 1171 if p == nil || (p.Mark&FOLL != 0) { 1172 return 1173 } 1174 goto loop 1175 } 1176 } 1177 1178 p = p.Link 1179 goto loop 1180 } 1181 1182 var Linkppc64 = obj.LinkArch{ 1183 ByteOrder: binary.BigEndian, 1184 Name: "ppc64", 1185 Thechar: '9', 1186 Preprocess: preprocess, 1187 Assemble: span9, 1188 Follow: follow, 1189 Progedit: progedit, 1190 Minlc: 4, 1191 Ptrsize: 8, 1192 Regsize: 8, 1193 } 1194 1195 var Linkppc64le = obj.LinkArch{ 1196 ByteOrder: binary.LittleEndian, 1197 Name: "ppc64le", 1198 Thechar: '9', 1199 Preprocess: preprocess, 1200 Assemble: span9, 1201 Follow: follow, 1202 Progedit: progedit, 1203 Minlc: 4, 1204 Ptrsize: 8, 1205 Regsize: 8, 1206 }