github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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.Name = obj.NAME_EXTERN 67 p.From.Offset = 0 68 } 69 70 case AFMOVD: 71 if p.From.Type == obj.TYPE_FCONST { 72 i64 := math.Float64bits(p.From.Val.(float64)) 73 literal := fmt.Sprintf("$f64.%016x", i64) 74 s := obj.Linklookup(ctxt, literal, 0) 75 s.Size = 8 76 p.From.Type = obj.TYPE_MEM 77 p.From.Sym = s 78 p.From.Name = obj.NAME_EXTERN 79 p.From.Offset = 0 80 } 81 82 // Put >32-bit constants in memory and load them 83 case AMOVD: 84 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset { 85 literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset)) 86 s := obj.Linklookup(ctxt, literal, 0) 87 s.Size = 8 88 p.From.Type = obj.TYPE_MEM 89 p.From.Sym = s 90 p.From.Name = obj.NAME_EXTERN 91 p.From.Offset = 0 92 } 93 } 94 95 // Rewrite SUB constants into ADD. 96 switch p.As { 97 case ASUBC: 98 if p.From.Type == obj.TYPE_CONST { 99 p.From.Offset = -p.From.Offset 100 p.As = AADDC 101 } 102 103 case ASUBCCC: 104 if p.From.Type == obj.TYPE_CONST { 105 p.From.Offset = -p.From.Offset 106 p.As = AADDCCC 107 } 108 109 case ASUB: 110 if p.From.Type == obj.TYPE_CONST { 111 p.From.Offset = -p.From.Offset 112 p.As = AADD 113 } 114 } 115 } 116 117 func preprocess(ctxt *obj.Link, cursym *obj.LSym) { 118 // TODO(minux): add morestack short-cuts with small fixed frame-size. 119 ctxt.Cursym = cursym 120 121 if cursym.Text == nil || cursym.Text.Link == nil { 122 return 123 } 124 125 p := cursym.Text 126 textstksiz := p.To.Offset 127 128 cursym.Args = p.To.Val.(int32) 129 cursym.Locals = int32(textstksiz) 130 131 /* 132 * find leaf subroutines 133 * strip NOPs 134 * expand RET 135 * expand BECOME pseudo 136 */ 137 if ctxt.Debugvlog != 0 { 138 fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime()) 139 } 140 ctxt.Bso.Flush() 141 142 var q *obj.Prog 143 var q1 *obj.Prog 144 for p := cursym.Text; p != nil; p = p.Link { 145 switch p.As { 146 /* too hard, just leave alone */ 147 case obj.ATEXT: 148 q = p 149 150 p.Mark |= LABEL | LEAF | SYNC 151 if p.Link != nil { 152 p.Link.Mark |= LABEL 153 } 154 155 case ANOR: 156 q = p 157 if p.To.Type == obj.TYPE_REG { 158 if p.To.Reg == REGZERO { 159 p.Mark |= LABEL | SYNC 160 } 161 } 162 163 case ALWAR, 164 ASTWCCC, 165 AECIWX, 166 AECOWX, 167 AEIEIO, 168 AICBI, 169 AISYNC, 170 ATLBIE, 171 ATLBIEL, 172 ASLBIA, 173 ASLBIE, 174 ASLBMFEE, 175 ASLBMFEV, 176 ASLBMTE, 177 ADCBF, 178 ADCBI, 179 ADCBST, 180 ADCBT, 181 ADCBTST, 182 ADCBZ, 183 ASYNC, 184 ATLBSYNC, 185 APTESYNC, 186 ATW, 187 AWORD, 188 ARFI, 189 ARFCI, 190 ARFID, 191 AHRFID: 192 q = p 193 p.Mark |= LABEL | SYNC 194 continue 195 196 case AMOVW, AMOVWZ, AMOVD: 197 q = p 198 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 199 p.Mark |= LABEL | SYNC 200 } 201 continue 202 203 case AFABS, 204 AFABSCC, 205 AFADD, 206 AFADDCC, 207 AFCTIW, 208 AFCTIWCC, 209 AFCTIWZ, 210 AFCTIWZCC, 211 AFDIV, 212 AFDIVCC, 213 AFMADD, 214 AFMADDCC, 215 AFMOVD, 216 AFMOVDU, 217 /* case AFMOVDS: */ 218 AFMOVS, 219 AFMOVSU, 220 221 /* case AFMOVSD: */ 222 AFMSUB, 223 AFMSUBCC, 224 AFMUL, 225 AFMULCC, 226 AFNABS, 227 AFNABSCC, 228 AFNEG, 229 AFNEGCC, 230 AFNMADD, 231 AFNMADDCC, 232 AFNMSUB, 233 AFNMSUBCC, 234 AFRSP, 235 AFRSPCC, 236 AFSUB, 237 AFSUBCC: 238 q = p 239 240 p.Mark |= FLOAT 241 continue 242 243 case ABL, 244 ABCL, 245 obj.ADUFFZERO, 246 obj.ADUFFCOPY: 247 cursym.Text.Mark &^= LEAF 248 fallthrough 249 250 case ABC, 251 ABEQ, 252 ABGE, 253 ABGT, 254 ABLE, 255 ABLT, 256 ABNE, 257 ABR, 258 ABVC, 259 ABVS: 260 p.Mark |= BRANCH 261 q = p 262 q1 = p.Pcond 263 if q1 != nil { 264 for q1.As == obj.ANOP { 265 q1 = q1.Link 266 p.Pcond = q1 267 } 268 269 if q1.Mark&LEAF == 0 { 270 q1.Mark |= LABEL 271 } 272 } else { 273 p.Mark |= LABEL 274 } 275 q1 = p.Link 276 if q1 != nil { 277 q1.Mark |= LABEL 278 } 279 continue 280 281 case AFCMPO, AFCMPU: 282 q = p 283 p.Mark |= FCMP | FLOAT 284 continue 285 286 case obj.ARET: 287 q = p 288 if p.Link != nil { 289 p.Link.Mark |= LABEL 290 } 291 continue 292 293 case obj.ANOP: 294 q1 = p.Link 295 q.Link = q1 /* q is non-nop */ 296 q1.Mark |= p.Mark 297 continue 298 299 default: 300 q = p 301 continue 302 } 303 } 304 305 autosize := int32(0) 306 var aoffset int 307 var mov int 308 var o int 309 var p1 *obj.Prog 310 var p2 *obj.Prog 311 for p := cursym.Text; p != nil; p = p.Link { 312 o = int(p.As) 313 switch o { 314 case obj.ATEXT: 315 mov = AMOVD 316 aoffset = 0 317 autosize = int32(textstksiz + 8) 318 if (p.Mark&LEAF != 0) && autosize <= 8 { 319 autosize = 0 320 } else if autosize&4 != 0 { 321 autosize += 4 322 } 323 p.To.Offset = int64(autosize) - 8 324 325 if p.From3.Offset&obj.NOSPLIT == 0 { 326 p = stacksplit(ctxt, p, autosize) // emit split check 327 } 328 329 q = p 330 331 if autosize != 0 { 332 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 333 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 334 mov = AMOVDU 335 aoffset = int(-autosize) 336 } else { 337 q = obj.Appendp(ctxt, p) 338 q.As = AADD 339 q.Lineno = p.Lineno 340 q.From.Type = obj.TYPE_CONST 341 q.From.Offset = int64(-autosize) 342 q.To.Type = obj.TYPE_REG 343 q.To.Reg = REGSP 344 q.Spadj = +autosize 345 } 346 } else if cursym.Text.Mark&LEAF == 0 { 347 if ctxt.Debugvlog != 0 { 348 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name) 349 ctxt.Bso.Flush() 350 } 351 352 cursym.Text.Mark |= LEAF 353 } 354 355 if cursym.Text.Mark&LEAF != 0 { 356 cursym.Leaf = 1 357 break 358 } 359 360 q = obj.Appendp(ctxt, q) 361 q.As = AMOVD 362 q.Lineno = p.Lineno 363 q.From.Type = obj.TYPE_REG 364 q.From.Reg = REG_LR 365 q.To.Type = obj.TYPE_REG 366 q.To.Reg = REGTMP 367 368 q = obj.Appendp(ctxt, q) 369 q.As = int16(mov) 370 q.Lineno = p.Lineno 371 q.From.Type = obj.TYPE_REG 372 q.From.Reg = REGTMP 373 q.To.Type = obj.TYPE_MEM 374 q.To.Offset = int64(aoffset) 375 q.To.Reg = REGSP 376 if q.As == AMOVDU { 377 q.Spadj = int32(-aoffset) 378 } 379 380 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 381 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 382 // 383 // MOVD g_panic(g), R3 384 // CMP R0, R3 385 // BEQ end 386 // MOVD panic_argp(R3), R4 387 // ADD $(autosize+8), R1, R5 388 // CMP R4, R5 389 // BNE end 390 // ADD $8, R1, R6 391 // MOVD R6, panic_argp(R3) 392 // end: 393 // NOP 394 // 395 // The NOP is needed to give the jumps somewhere to land. 396 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 397 398 q = obj.Appendp(ctxt, q) 399 400 q.As = AMOVD 401 q.From.Type = obj.TYPE_MEM 402 q.From.Reg = REGG 403 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 404 q.To.Type = obj.TYPE_REG 405 q.To.Reg = REG_R3 406 407 q = obj.Appendp(ctxt, q) 408 q.As = ACMP 409 q.From.Type = obj.TYPE_REG 410 q.From.Reg = REG_R0 411 q.To.Type = obj.TYPE_REG 412 q.To.Reg = REG_R3 413 414 q = obj.Appendp(ctxt, q) 415 q.As = ABEQ 416 q.To.Type = obj.TYPE_BRANCH 417 p1 = q 418 419 q = obj.Appendp(ctxt, q) 420 q.As = AMOVD 421 q.From.Type = obj.TYPE_MEM 422 q.From.Reg = REG_R3 423 q.From.Offset = 0 // Panic.argp 424 q.To.Type = obj.TYPE_REG 425 q.To.Reg = REG_R4 426 427 q = obj.Appendp(ctxt, q) 428 q.As = AADD 429 q.From.Type = obj.TYPE_CONST 430 q.From.Offset = int64(autosize) + 8 431 q.Reg = REGSP 432 q.To.Type = obj.TYPE_REG 433 q.To.Reg = REG_R5 434 435 q = obj.Appendp(ctxt, q) 436 q.As = ACMP 437 q.From.Type = obj.TYPE_REG 438 q.From.Reg = REG_R4 439 q.To.Type = obj.TYPE_REG 440 q.To.Reg = REG_R5 441 442 q = obj.Appendp(ctxt, q) 443 q.As = ABNE 444 q.To.Type = obj.TYPE_BRANCH 445 p2 = q 446 447 q = obj.Appendp(ctxt, q) 448 q.As = AADD 449 q.From.Type = obj.TYPE_CONST 450 q.From.Offset = 8 451 q.Reg = REGSP 452 q.To.Type = obj.TYPE_REG 453 q.To.Reg = REG_R6 454 455 q = obj.Appendp(ctxt, q) 456 q.As = AMOVD 457 q.From.Type = obj.TYPE_REG 458 q.From.Reg = REG_R6 459 q.To.Type = obj.TYPE_MEM 460 q.To.Reg = REG_R3 461 q.To.Offset = 0 // Panic.argp 462 463 q = obj.Appendp(ctxt, q) 464 465 q.As = obj.ANOP 466 p1.Pcond = q 467 p2.Pcond = q 468 } 469 470 case obj.ARET: 471 if p.From.Type == obj.TYPE_CONST { 472 ctxt.Diag("using BECOME (%v) is not supported!", p) 473 break 474 } 475 476 retTarget := p.To.Sym 477 478 if cursym.Text.Mark&LEAF != 0 { 479 if autosize == 0 { 480 p.As = ABR 481 p.From = obj.Addr{} 482 if retTarget == nil { 483 p.To.Type = obj.TYPE_REG 484 p.To.Reg = REG_LR 485 } else { 486 p.To.Type = obj.TYPE_BRANCH 487 p.To.Sym = retTarget 488 } 489 p.Mark |= BRANCH 490 break 491 } 492 493 p.As = AADD 494 p.From.Type = obj.TYPE_CONST 495 p.From.Offset = int64(autosize) 496 p.To.Type = obj.TYPE_REG 497 p.To.Reg = REGSP 498 p.Spadj = -autosize 499 500 q = ctxt.NewProg() 501 q.As = ABR 502 q.Lineno = p.Lineno 503 q.To.Type = obj.TYPE_REG 504 q.To.Reg = REG_LR 505 q.Mark |= BRANCH 506 q.Spadj = +autosize 507 508 q.Link = p.Link 509 p.Link = q 510 break 511 } 512 513 p.As = AMOVD 514 p.From.Type = obj.TYPE_MEM 515 p.From.Offset = 0 516 p.From.Reg = REGSP 517 p.To.Type = obj.TYPE_REG 518 p.To.Reg = REGTMP 519 520 q = ctxt.NewProg() 521 q.As = AMOVD 522 q.Lineno = p.Lineno 523 q.From.Type = obj.TYPE_REG 524 q.From.Reg = REGTMP 525 q.To.Type = obj.TYPE_REG 526 q.To.Reg = REG_LR 527 528 q.Link = p.Link 529 p.Link = q 530 p = q 531 532 if false { 533 // Debug bad returns 534 q = ctxt.NewProg() 535 536 q.As = AMOVD 537 q.Lineno = p.Lineno 538 q.From.Type = obj.TYPE_MEM 539 q.From.Offset = 0 540 q.From.Reg = REGTMP 541 q.To.Type = obj.TYPE_REG 542 q.To.Reg = REGTMP 543 544 q.Link = p.Link 545 p.Link = q 546 p = q 547 } 548 549 if autosize != 0 { 550 q = ctxt.NewProg() 551 q.As = AADD 552 q.Lineno = p.Lineno 553 q.From.Type = obj.TYPE_CONST 554 q.From.Offset = int64(autosize) 555 q.To.Type = obj.TYPE_REG 556 q.To.Reg = REGSP 557 q.Spadj = -autosize 558 559 q.Link = p.Link 560 p.Link = q 561 } 562 563 q1 = ctxt.NewProg() 564 q1.As = ABR 565 q1.Lineno = p.Lineno 566 if retTarget == nil { 567 q1.To.Type = obj.TYPE_REG 568 q1.To.Reg = REG_LR 569 } else { 570 q1.To.Type = obj.TYPE_BRANCH 571 q1.To.Sym = retTarget 572 } 573 q1.Mark |= BRANCH 574 q1.Spadj = +autosize 575 576 q1.Link = q.Link 577 q.Link = q1 578 case AADD: 579 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 580 p.Spadj = int32(-p.From.Offset) 581 } 582 } 583 } 584 } 585 586 /* 587 // instruction scheduling 588 if(debug['Q'] == 0) 589 return; 590 591 curtext = nil; 592 q = nil; // p - 1 593 q1 = firstp; // top of block 594 o = 0; // count of instructions 595 for(p = firstp; p != nil; p = p1) { 596 p1 = p->link; 597 o++; 598 if(p->mark & NOSCHED){ 599 if(q1 != p){ 600 sched(q1, q); 601 } 602 for(; p != nil; p = p->link){ 603 if(!(p->mark & NOSCHED)) 604 break; 605 q = p; 606 } 607 p1 = p; 608 q1 = p; 609 o = 0; 610 continue; 611 } 612 if(p->mark & (LABEL|SYNC)) { 613 if(q1 != p) 614 sched(q1, q); 615 q1 = p; 616 o = 1; 617 } 618 if(p->mark & (BRANCH|SYNC)) { 619 sched(q1, p); 620 q1 = p1; 621 o = 0; 622 } 623 if(o >= NSCHED) { 624 sched(q1, p); 625 q1 = p1; 626 o = 0; 627 } 628 q = p; 629 } 630 */ 631 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 632 // MOVD g_stackguard(g), R3 633 p = obj.Appendp(ctxt, p) 634 635 p.As = AMOVD 636 p.From.Type = obj.TYPE_MEM 637 p.From.Reg = REGG 638 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 639 if ctxt.Cursym.Cfunc != 0 { 640 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 641 } 642 p.To.Type = obj.TYPE_REG 643 p.To.Reg = REG_R3 644 645 var q *obj.Prog 646 if framesize <= obj.StackSmall { 647 // small stack: SP < stackguard 648 // CMP stackguard, SP 649 p = obj.Appendp(ctxt, p) 650 651 p.As = ACMPU 652 p.From.Type = obj.TYPE_REG 653 p.From.Reg = REG_R3 654 p.To.Type = obj.TYPE_REG 655 p.To.Reg = REGSP 656 } else if framesize <= obj.StackBig { 657 // large stack: SP-framesize < stackguard-StackSmall 658 // ADD $-framesize, SP, R4 659 // CMP stackguard, R4 660 p = obj.Appendp(ctxt, p) 661 662 p.As = AADD 663 p.From.Type = obj.TYPE_CONST 664 p.From.Offset = int64(-framesize) 665 p.Reg = REGSP 666 p.To.Type = obj.TYPE_REG 667 p.To.Reg = REG_R4 668 669 p = obj.Appendp(ctxt, p) 670 p.As = ACMPU 671 p.From.Type = obj.TYPE_REG 672 p.From.Reg = REG_R3 673 p.To.Type = obj.TYPE_REG 674 p.To.Reg = REG_R4 675 } else { 676 // Such a large stack we need to protect against wraparound. 677 // If SP is close to zero: 678 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 679 // The +StackGuard on both sides is required to keep the left side positive: 680 // SP is allowed to be slightly below stackguard. See stack.h. 681 // 682 // Preemption sets stackguard to StackPreempt, a very large value. 683 // That breaks the math above, so we have to check for that explicitly. 684 // // stackguard is R3 685 // CMP R3, $StackPreempt 686 // BEQ label-of-call-to-morestack 687 // ADD $StackGuard, SP, R4 688 // SUB R3, R4 689 // MOVD $(framesize+(StackGuard-StackSmall)), R31 690 // CMPU R31, R4 691 p = obj.Appendp(ctxt, p) 692 693 p.As = ACMP 694 p.From.Type = obj.TYPE_REG 695 p.From.Reg = REG_R3 696 p.To.Type = obj.TYPE_CONST 697 p.To.Offset = obj.StackPreempt 698 699 p = obj.Appendp(ctxt, p) 700 q = p 701 p.As = ABEQ 702 p.To.Type = obj.TYPE_BRANCH 703 704 p = obj.Appendp(ctxt, p) 705 p.As = AADD 706 p.From.Type = obj.TYPE_CONST 707 p.From.Offset = obj.StackGuard 708 p.Reg = REGSP 709 p.To.Type = obj.TYPE_REG 710 p.To.Reg = REG_R4 711 712 p = obj.Appendp(ctxt, p) 713 p.As = ASUB 714 p.From.Type = obj.TYPE_REG 715 p.From.Reg = REG_R3 716 p.To.Type = obj.TYPE_REG 717 p.To.Reg = REG_R4 718 719 p = obj.Appendp(ctxt, p) 720 p.As = AMOVD 721 p.From.Type = obj.TYPE_CONST 722 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 723 p.To.Type = obj.TYPE_REG 724 p.To.Reg = REGTMP 725 726 p = obj.Appendp(ctxt, p) 727 p.As = ACMPU 728 p.From.Type = obj.TYPE_REG 729 p.From.Reg = REGTMP 730 p.To.Type = obj.TYPE_REG 731 p.To.Reg = REG_R4 732 } 733 734 // q1: BLT done 735 p = obj.Appendp(ctxt, p) 736 q1 := p 737 738 p.As = ABLT 739 p.To.Type = obj.TYPE_BRANCH 740 741 // MOVD LR, R5 742 p = obj.Appendp(ctxt, p) 743 744 p.As = AMOVD 745 p.From.Type = obj.TYPE_REG 746 p.From.Reg = REG_LR 747 p.To.Type = obj.TYPE_REG 748 p.To.Reg = REG_R5 749 if q != nil { 750 q.Pcond = p 751 } 752 753 // BL runtime.morestack(SB) 754 p = obj.Appendp(ctxt, p) 755 756 p.As = ABL 757 p.To.Type = obj.TYPE_BRANCH 758 if ctxt.Cursym.Cfunc != 0 { 759 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 760 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 761 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 762 } else { 763 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 764 } 765 766 // BR start 767 p = obj.Appendp(ctxt, p) 768 769 p.As = ABR 770 p.To.Type = obj.TYPE_BRANCH 771 p.Pcond = ctxt.Cursym.Text.Link 772 773 // placeholder for q1's jump target 774 p = obj.Appendp(ctxt, p) 775 776 p.As = obj.ANOP // zero-width place holder 777 q1.Pcond = p 778 779 return p 780 } 781 782 func follow(ctxt *obj.Link, s *obj.LSym) { 783 ctxt.Cursym = s 784 785 firstp := ctxt.NewProg() 786 lastp := firstp 787 xfol(ctxt, s.Text, &lastp) 788 lastp.Link = nil 789 s.Text = firstp.Link 790 } 791 792 func relinv(a int) int { 793 switch a { 794 case ABEQ: 795 return ABNE 796 case ABNE: 797 return ABEQ 798 799 case ABGE: 800 return ABLT 801 case ABLT: 802 return ABGE 803 804 case ABGT: 805 return ABLE 806 case ABLE: 807 return ABGT 808 809 case ABVC: 810 return ABVS 811 case ABVS: 812 return ABVC 813 } 814 815 return 0 816 } 817 818 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 819 var q *obj.Prog 820 var r *obj.Prog 821 var a int 822 var b int 823 var i int 824 825 loop: 826 if p == nil { 827 return 828 } 829 a = int(p.As) 830 if a == ABR { 831 q = p.Pcond 832 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 833 p.Mark |= FOLL 834 (*last).Link = p 835 *last = p 836 p = p.Link 837 xfol(ctxt, p, last) 838 p = q 839 if p != nil && p.Mark&FOLL == 0 { 840 goto loop 841 } 842 return 843 } 844 845 if q != nil { 846 p.Mark |= FOLL 847 p = q 848 if p.Mark&FOLL == 0 { 849 goto loop 850 } 851 } 852 } 853 854 if p.Mark&FOLL != 0 { 855 i = 0 856 q = p 857 for ; i < 4; i, q = i+1, q.Link { 858 if q == *last || (q.Mark&NOSCHED != 0) { 859 break 860 } 861 b = 0 /* set */ 862 a = int(q.As) 863 if a == obj.ANOP { 864 i-- 865 continue 866 } 867 868 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 869 goto copy 870 } 871 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 872 continue 873 } 874 b = relinv(a) 875 if b == 0 { 876 continue 877 } 878 879 copy: 880 for { 881 r = ctxt.NewProg() 882 *r = *p 883 if r.Mark&FOLL == 0 { 884 fmt.Printf("cant happen 1\n") 885 } 886 r.Mark |= FOLL 887 if p != q { 888 p = p.Link 889 (*last).Link = r 890 *last = r 891 continue 892 } 893 894 (*last).Link = r 895 *last = r 896 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 897 return 898 } 899 r.As = int16(b) 900 r.Pcond = p.Link 901 r.Link = p.Pcond 902 if r.Link.Mark&FOLL == 0 { 903 xfol(ctxt, r.Link, last) 904 } 905 if r.Pcond.Mark&FOLL == 0 { 906 fmt.Printf("cant happen 2\n") 907 } 908 return 909 } 910 } 911 912 a = ABR 913 q = ctxt.NewProg() 914 q.As = int16(a) 915 q.Lineno = p.Lineno 916 q.To.Type = obj.TYPE_BRANCH 917 q.To.Offset = p.Pc 918 q.Pcond = p 919 p = q 920 } 921 922 p.Mark |= FOLL 923 (*last).Link = p 924 *last = p 925 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 926 if p.Mark&NOSCHED != 0 { 927 p = p.Link 928 goto loop 929 } 930 931 return 932 } 933 934 if p.Pcond != nil { 935 if a != ABL && p.Link != nil { 936 xfol(ctxt, p.Link, last) 937 p = p.Pcond 938 if p == nil || (p.Mark&FOLL != 0) { 939 return 940 } 941 goto loop 942 } 943 } 944 945 p = p.Link 946 goto loop 947 } 948 949 var Linkppc64 = obj.LinkArch{ 950 ByteOrder: binary.BigEndian, 951 Name: "ppc64", 952 Thechar: '9', 953 Preprocess: preprocess, 954 Assemble: span9, 955 Follow: follow, 956 Progedit: progedit, 957 Minlc: 4, 958 Ptrsize: 8, 959 Regsize: 8, 960 } 961 962 var Linkppc64le = obj.LinkArch{ 963 ByteOrder: binary.LittleEndian, 964 Name: "ppc64le", 965 Thechar: '9', 966 Preprocess: preprocess, 967 Assemble: span9, 968 Follow: follow, 969 Progedit: progedit, 970 Minlc: 4, 971 Ptrsize: 8, 972 Regsize: 8, 973 }