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 (a] 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 (a] 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 if p.To.Sym != nil { // retjmp 477 p.As = ABR 478 p.To.Type = obj.TYPE_BRANCH 479 break 480 } 481 482 if cursym.Text.Mark&LEAF != 0 { 483 if autosize == 0 { 484 p.As = ABR 485 p.From = obj.Addr{} 486 p.To.Type = obj.TYPE_REG 487 p.To.Reg = REG_LR 488 p.Mark |= BRANCH 489 break 490 } 491 492 p.As = AADD 493 p.From.Type = obj.TYPE_CONST 494 p.From.Offset = int64(autosize) 495 p.To.Type = obj.TYPE_REG 496 p.To.Reg = REGSP 497 p.Spadj = -autosize 498 499 q = ctxt.NewProg() 500 q.As = ABR 501 q.Lineno = p.Lineno 502 q.To.Type = obj.TYPE_REG 503 q.To.Reg = REG_LR 504 q.Mark |= BRANCH 505 q.Spadj = +autosize 506 507 q.Link = p.Link 508 p.Link = q 509 break 510 } 511 512 p.As = AMOVD 513 p.From.Type = obj.TYPE_MEM 514 p.From.Offset = 0 515 p.From.Reg = REGSP 516 p.To.Type = obj.TYPE_REG 517 p.To.Reg = REGTMP 518 519 q = ctxt.NewProg() 520 q.As = AMOVD 521 q.Lineno = p.Lineno 522 q.From.Type = obj.TYPE_REG 523 q.From.Reg = REGTMP 524 q.To.Type = obj.TYPE_REG 525 q.To.Reg = REG_LR 526 527 q.Link = p.Link 528 p.Link = q 529 p = q 530 531 if false { 532 // Debug bad returns 533 q = ctxt.NewProg() 534 535 q.As = AMOVD 536 q.Lineno = p.Lineno 537 q.From.Type = obj.TYPE_MEM 538 q.From.Offset = 0 539 q.From.Reg = REGTMP 540 q.To.Type = obj.TYPE_REG 541 q.To.Reg = REGTMP 542 543 q.Link = p.Link 544 p.Link = q 545 p = q 546 } 547 548 if autosize != 0 { 549 q = ctxt.NewProg() 550 q.As = AADD 551 q.Lineno = p.Lineno 552 q.From.Type = obj.TYPE_CONST 553 q.From.Offset = int64(autosize) 554 q.To.Type = obj.TYPE_REG 555 q.To.Reg = REGSP 556 q.Spadj = -autosize 557 558 q.Link = p.Link 559 p.Link = q 560 } 561 562 q1 = ctxt.NewProg() 563 q1.As = ABR 564 q1.Lineno = p.Lineno 565 q1.To.Type = obj.TYPE_REG 566 q1.To.Reg = REG_LR 567 q1.Mark |= BRANCH 568 q1.Spadj = +autosize 569 570 q1.Link = q.Link 571 q.Link = q1 572 573 case AADD: 574 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 575 p.Spadj = int32(-p.From.Offset) 576 } 577 } 578 } 579 } 580 581 /* 582 // instruction scheduling 583 if(debug['Q'] == 0) 584 return; 585 586 curtext = nil; 587 q = nil; // p - 1 588 q1 = firstp; // top of block 589 o = 0; // count of instructions 590 for(p = firstp; p != nil; p = p1) { 591 p1 = p->link; 592 o++; 593 if(p->mark & NOSCHED){ 594 if(q1 != p){ 595 sched(q1, q); 596 } 597 for(; p != nil; p = p->link){ 598 if(!(p->mark & NOSCHED)) 599 break; 600 q = p; 601 } 602 p1 = p; 603 q1 = p; 604 o = 0; 605 continue; 606 } 607 if(p->mark & (LABEL|SYNC)) { 608 if(q1 != p) 609 sched(q1, q); 610 q1 = p; 611 o = 1; 612 } 613 if(p->mark & (BRANCH|SYNC)) { 614 sched(q1, p); 615 q1 = p1; 616 o = 0; 617 } 618 if(o >= NSCHED) { 619 sched(q1, p); 620 q1 = p1; 621 o = 0; 622 } 623 q = p; 624 } 625 */ 626 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog { 627 // MOVD g_stackguard(g), R3 628 p = obj.Appendp(ctxt, p) 629 630 p.As = AMOVD 631 p.From.Type = obj.TYPE_MEM 632 p.From.Reg = REGG 633 p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 634 if ctxt.Cursym.Cfunc != 0 { 635 p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 636 } 637 p.To.Type = obj.TYPE_REG 638 p.To.Reg = REG_R3 639 640 var q *obj.Prog 641 if framesize <= obj.StackSmall { 642 // small stack: SP < stackguard 643 // CMP stackguard, SP 644 p = obj.Appendp(ctxt, p) 645 646 p.As = ACMPU 647 p.From.Type = obj.TYPE_REG 648 p.From.Reg = REG_R3 649 p.To.Type = obj.TYPE_REG 650 p.To.Reg = REGSP 651 } else if framesize <= obj.StackBig { 652 // large stack: SP-framesize < stackguard-StackSmall 653 // ADD $-framesize, SP, R4 654 // CMP stackguard, R4 655 p = obj.Appendp(ctxt, p) 656 657 p.As = AADD 658 p.From.Type = obj.TYPE_CONST 659 p.From.Offset = int64(-framesize) 660 p.Reg = REGSP 661 p.To.Type = obj.TYPE_REG 662 p.To.Reg = REG_R4 663 664 p = obj.Appendp(ctxt, p) 665 p.As = ACMPU 666 p.From.Type = obj.TYPE_REG 667 p.From.Reg = REG_R3 668 p.To.Type = obj.TYPE_REG 669 p.To.Reg = REG_R4 670 } else { 671 // Such a large stack we need to protect against wraparound. 672 // If SP is close to zero: 673 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 674 // The +StackGuard on both sides is required to keep the left side positive: 675 // SP is allowed to be slightly below stackguard. See stack.h. 676 // 677 // Preemption sets stackguard to StackPreempt, a very large value. 678 // That breaks the math above, so we have to check for that explicitly. 679 // // stackguard is R3 680 // CMP R3, $StackPreempt 681 // BEQ label-of-call-to-morestack 682 // ADD $StackGuard, SP, R4 683 // SUB R3, R4 684 // MOVD $(framesize+(StackGuard-StackSmall)), R31 685 // CMPU R31, R4 686 p = obj.Appendp(ctxt, p) 687 688 p.As = ACMP 689 p.From.Type = obj.TYPE_REG 690 p.From.Reg = REG_R3 691 p.To.Type = obj.TYPE_CONST 692 p.To.Offset = obj.StackPreempt 693 694 p = obj.Appendp(ctxt, p) 695 q = p 696 p.As = ABEQ 697 p.To.Type = obj.TYPE_BRANCH 698 699 p = obj.Appendp(ctxt, p) 700 p.As = AADD 701 p.From.Type = obj.TYPE_CONST 702 p.From.Offset = obj.StackGuard 703 p.Reg = REGSP 704 p.To.Type = obj.TYPE_REG 705 p.To.Reg = REG_R4 706 707 p = obj.Appendp(ctxt, p) 708 p.As = ASUB 709 p.From.Type = obj.TYPE_REG 710 p.From.Reg = REG_R3 711 p.To.Type = obj.TYPE_REG 712 p.To.Reg = REG_R4 713 714 p = obj.Appendp(ctxt, p) 715 p.As = AMOVD 716 p.From.Type = obj.TYPE_CONST 717 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 718 p.To.Type = obj.TYPE_REG 719 p.To.Reg = REGTMP 720 721 p = obj.Appendp(ctxt, p) 722 p.As = ACMPU 723 p.From.Type = obj.TYPE_REG 724 p.From.Reg = REGTMP 725 p.To.Type = obj.TYPE_REG 726 p.To.Reg = REG_R4 727 } 728 729 // q1: BLT done 730 p = obj.Appendp(ctxt, p) 731 q1 := p 732 733 p.As = ABLT 734 p.To.Type = obj.TYPE_BRANCH 735 736 // MOVD LR, R5 737 p = obj.Appendp(ctxt, p) 738 739 p.As = AMOVD 740 p.From.Type = obj.TYPE_REG 741 p.From.Reg = REG_LR 742 p.To.Type = obj.TYPE_REG 743 p.To.Reg = REG_R5 744 if q != nil { 745 q.Pcond = p 746 } 747 748 // BL runtime.morestack(SB) 749 p = obj.Appendp(ctxt, p) 750 751 p.As = ABL 752 p.To.Type = obj.TYPE_BRANCH 753 if ctxt.Cursym.Cfunc != 0 { 754 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) 755 } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 { 756 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 757 } else { 758 p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0) 759 } 760 761 // BR start 762 p = obj.Appendp(ctxt, p) 763 764 p.As = ABR 765 p.To.Type = obj.TYPE_BRANCH 766 p.Pcond = ctxt.Cursym.Text.Link 767 768 // placeholder for q1's jump target 769 p = obj.Appendp(ctxt, p) 770 771 p.As = obj.ANOP // zero-width place holder 772 q1.Pcond = p 773 774 return p 775 } 776 777 func follow(ctxt *obj.Link, s *obj.LSym) { 778 ctxt.Cursym = s 779 780 firstp := ctxt.NewProg() 781 lastp := firstp 782 xfol(ctxt, s.Text, &lastp) 783 lastp.Link = nil 784 s.Text = firstp.Link 785 } 786 787 func relinv(a int) int { 788 switch a { 789 case ABEQ: 790 return ABNE 791 case ABNE: 792 return ABEQ 793 794 case ABGE: 795 return ABLT 796 case ABLT: 797 return ABGE 798 799 case ABGT: 800 return ABLE 801 case ABLE: 802 return ABGT 803 804 case ABVC: 805 return ABVS 806 case ABVS: 807 return ABVC 808 } 809 810 return 0 811 } 812 813 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 814 var q *obj.Prog 815 var r *obj.Prog 816 var a int 817 var b int 818 var i int 819 820 loop: 821 if p == nil { 822 return 823 } 824 a = int(p.As) 825 if a == ABR { 826 q = p.Pcond 827 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 828 p.Mark |= FOLL 829 (*last).Link = p 830 *last = p 831 p = p.Link 832 xfol(ctxt, p, last) 833 p = q 834 if p != nil && p.Mark&FOLL == 0 { 835 goto loop 836 } 837 return 838 } 839 840 if q != nil { 841 p.Mark |= FOLL 842 p = q 843 if p.Mark&FOLL == 0 { 844 goto loop 845 } 846 } 847 } 848 849 if p.Mark&FOLL != 0 { 850 i = 0 851 q = p 852 for ; i < 4; i, q = i+1, q.Link { 853 if q == *last || (q.Mark&NOSCHED != 0) { 854 break 855 } 856 b = 0 /* set */ 857 a = int(q.As) 858 if a == obj.ANOP { 859 i-- 860 continue 861 } 862 863 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 864 goto copy 865 } 866 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 867 continue 868 } 869 b = relinv(a) 870 if b == 0 { 871 continue 872 } 873 874 copy: 875 for { 876 r = ctxt.NewProg() 877 *r = *p 878 if r.Mark&FOLL == 0 { 879 fmt.Printf("cant happen 1\n") 880 } 881 r.Mark |= FOLL 882 if p != q { 883 p = p.Link 884 (*last).Link = r 885 *last = r 886 continue 887 } 888 889 (*last).Link = r 890 *last = r 891 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 892 return 893 } 894 r.As = int16(b) 895 r.Pcond = p.Link 896 r.Link = p.Pcond 897 if r.Link.Mark&FOLL == 0 { 898 xfol(ctxt, r.Link, last) 899 } 900 if r.Pcond.Mark&FOLL == 0 { 901 fmt.Printf("cant happen 2\n") 902 } 903 return 904 } 905 } 906 907 a = ABR 908 q = ctxt.NewProg() 909 q.As = int16(a) 910 q.Lineno = p.Lineno 911 q.To.Type = obj.TYPE_BRANCH 912 q.To.Offset = p.Pc 913 q.Pcond = p 914 p = q 915 } 916 917 p.Mark |= FOLL 918 (*last).Link = p 919 *last = p 920 if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 921 if p.Mark&NOSCHED != 0 { 922 p = p.Link 923 goto loop 924 } 925 926 return 927 } 928 929 if p.Pcond != nil { 930 if a != ABL && p.Link != nil { 931 xfol(ctxt, p.Link, last) 932 p = p.Pcond 933 if p == nil || (p.Mark&FOLL != 0) { 934 return 935 } 936 goto loop 937 } 938 } 939 940 p = p.Link 941 goto loop 942 } 943 944 var Linkppc64 = obj.LinkArch{ 945 ByteOrder: binary.BigEndian, 946 Name: "ppc64", 947 Thechar: '9', 948 Preprocess: preprocess, 949 Assemble: span9, 950 Follow: follow, 951 Progedit: progedit, 952 Minlc: 4, 953 Ptrsize: 8, 954 Regsize: 8, 955 } 956 957 var Linkppc64le = obj.LinkArch{ 958 ByteOrder: binary.LittleEndian, 959 Name: "ppc64le", 960 Thechar: '9', 961 Preprocess: preprocess, 962 Assemble: span9, 963 Follow: follow, 964 Progedit: progedit, 965 Minlc: 4, 966 Ptrsize: 8, 967 Regsize: 8, 968 } 969