rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 ARETURN, 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 if ctxt.Symmorestack[0] == nil { 119 ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0) 120 ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) 121 } 122 123 // TODO(minux): add morestack short-cuts with small fixed frame-size. 124 ctxt.Cursym = cursym 125 126 if cursym.Text == nil || cursym.Text.Link == nil { 127 return 128 } 129 130 p := cursym.Text 131 textstksiz := p.To.Offset 132 133 cursym.Args = p.To.Val.(int32) 134 cursym.Locals = int32(textstksiz) 135 136 /* 137 * find leaf subroutines 138 * strip NOPs 139 * expand RET 140 * expand BECOME pseudo 141 */ 142 if ctxt.Debugvlog != 0 { 143 fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime()) 144 } 145 obj.Bflush(ctxt.Bso) 146 147 var q *obj.Prog 148 var q1 *obj.Prog 149 for p := cursym.Text; p != nil; p = p.Link { 150 switch p.As { 151 /* too hard, just leave alone */ 152 case obj.ATEXT: 153 q = p 154 155 p.Mark |= LABEL | LEAF | SYNC 156 if p.Link != nil { 157 p.Link.Mark |= LABEL 158 } 159 160 case ANOR: 161 q = p 162 if p.To.Type == obj.TYPE_REG { 163 if p.To.Reg == REGZERO { 164 p.Mark |= LABEL | SYNC 165 } 166 } 167 168 case ALWAR, 169 ASTWCCC, 170 AECIWX, 171 AECOWX, 172 AEIEIO, 173 AICBI, 174 AISYNC, 175 ATLBIE, 176 ATLBIEL, 177 ASLBIA, 178 ASLBIE, 179 ASLBMFEE, 180 ASLBMFEV, 181 ASLBMTE, 182 ADCBF, 183 ADCBI, 184 ADCBST, 185 ADCBT, 186 ADCBTST, 187 ADCBZ, 188 ASYNC, 189 ATLBSYNC, 190 APTESYNC, 191 ATW, 192 AWORD, 193 ARFI, 194 ARFCI, 195 ARFID, 196 AHRFID: 197 q = p 198 p.Mark |= LABEL | SYNC 199 continue 200 201 case AMOVW, AMOVWZ, AMOVD: 202 q = p 203 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL { 204 p.Mark |= LABEL | SYNC 205 } 206 continue 207 208 case AFABS, 209 AFABSCC, 210 AFADD, 211 AFADDCC, 212 AFCTIW, 213 AFCTIWCC, 214 AFCTIWZ, 215 AFCTIWZCC, 216 AFDIV, 217 AFDIVCC, 218 AFMADD, 219 AFMADDCC, 220 AFMOVD, 221 AFMOVDU, 222 /* case AFMOVDS: */ 223 AFMOVS, 224 AFMOVSU, 225 226 /* case AFMOVSD: */ 227 AFMSUB, 228 AFMSUBCC, 229 AFMUL, 230 AFMULCC, 231 AFNABS, 232 AFNABSCC, 233 AFNEG, 234 AFNEGCC, 235 AFNMADD, 236 AFNMADDCC, 237 AFNMSUB, 238 AFNMSUBCC, 239 AFRSP, 240 AFRSPCC, 241 AFSUB, 242 AFSUBCC: 243 q = p 244 245 p.Mark |= FLOAT 246 continue 247 248 case ABL, 249 ABCL, 250 obj.ADUFFZERO, 251 obj.ADUFFCOPY: 252 cursym.Text.Mark &^= LEAF 253 fallthrough 254 255 case ABC, 256 ABEQ, 257 ABGE, 258 ABGT, 259 ABLE, 260 ABLT, 261 ABNE, 262 ABR, 263 ABVC, 264 ABVS: 265 p.Mark |= BRANCH 266 q = p 267 q1 = p.Pcond 268 if q1 != nil { 269 for q1.As == obj.ANOP { 270 q1 = q1.Link 271 p.Pcond = q1 272 } 273 274 if q1.Mark&LEAF == 0 { 275 q1.Mark |= LABEL 276 } 277 } else { 278 p.Mark |= LABEL 279 } 280 q1 = p.Link 281 if q1 != nil { 282 q1.Mark |= LABEL 283 } 284 continue 285 286 case AFCMPO, AFCMPU: 287 q = p 288 p.Mark |= FCMP | FLOAT 289 continue 290 291 case ARETURN: 292 q = p 293 if p.Link != nil { 294 p.Link.Mark |= LABEL 295 } 296 continue 297 298 case obj.ANOP: 299 q1 = p.Link 300 q.Link = q1 /* q is non-nop */ 301 q1.Mark |= p.Mark 302 continue 303 304 default: 305 q = p 306 continue 307 } 308 } 309 310 autosize := int32(0) 311 var aoffset int 312 var mov int 313 var o int 314 var p1 *obj.Prog 315 var p2 *obj.Prog 316 for p := cursym.Text; p != nil; p = p.Link { 317 o = int(p.As) 318 switch o { 319 case obj.ATEXT: 320 mov = AMOVD 321 aoffset = 0 322 autosize = int32(textstksiz + 8) 323 if (p.Mark&LEAF != 0) && autosize <= 8 { 324 autosize = 0 325 } else if autosize&4 != 0 { 326 autosize += 4 327 } 328 p.To.Offset = int64(autosize) - 8 329 330 if p.From3.Offset&obj.NOSPLIT == 0 { 331 p = stacksplit(ctxt, p, autosize, cursym.Text.From3.Offset&obj.NEEDCTXT == 0) // emit split check 332 } 333 334 q = p 335 336 if autosize != 0 { 337 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 338 if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG { 339 mov = AMOVDU 340 aoffset = int(-autosize) 341 } else { 342 q = obj.Appendp(ctxt, p) 343 q.As = AADD 344 q.Lineno = p.Lineno 345 q.From.Type = obj.TYPE_CONST 346 q.From.Offset = int64(-autosize) 347 q.To.Type = obj.TYPE_REG 348 q.To.Reg = REGSP 349 q.Spadj = +autosize 350 } 351 } else if cursym.Text.Mark&LEAF == 0 { 352 if ctxt.Debugvlog != 0 { 353 fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name) 354 obj.Bflush(ctxt.Bso) 355 } 356 357 cursym.Text.Mark |= LEAF 358 } 359 360 if cursym.Text.Mark&LEAF != 0 { 361 cursym.Leaf = 1 362 break 363 } 364 365 q = obj.Appendp(ctxt, q) 366 q.As = AMOVD 367 q.Lineno = p.Lineno 368 q.From.Type = obj.TYPE_REG 369 q.From.Reg = REG_LR 370 q.To.Type = obj.TYPE_REG 371 q.To.Reg = REGTMP 372 373 q = obj.Appendp(ctxt, q) 374 q.As = int16(mov) 375 q.Lineno = p.Lineno 376 q.From.Type = obj.TYPE_REG 377 q.From.Reg = REGTMP 378 q.To.Type = obj.TYPE_MEM 379 q.To.Offset = int64(aoffset) 380 q.To.Reg = REGSP 381 if q.As == AMOVDU { 382 q.Spadj = int32(-aoffset) 383 } 384 385 if cursym.Text.From3.Offset&obj.WRAPPER != 0 { 386 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 387 // 388 // MOVD g_panic(g), R3 389 // CMP R0, R3 390 // BEQ end 391 // MOVD panic_argp(R3), R4 392 // ADD $(autosize+8), R1, R5 393 // CMP R4, R5 394 // BNE end 395 // ADD $8, R1, R6 396 // MOVD R6, panic_argp(R3) 397 // end: 398 // NOP 399 // 400 // The NOP is needed to give the jumps somewhere to land. 401 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 402 403 q = obj.Appendp(ctxt, q) 404 405 q.As = AMOVD 406 q.From.Type = obj.TYPE_MEM 407 q.From.Reg = REGG 408 q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic 409 q.To.Type = obj.TYPE_REG 410 q.To.Reg = REG_R3 411 412 q = obj.Appendp(ctxt, q) 413 q.As = ACMP 414 q.From.Type = obj.TYPE_REG 415 q.From.Reg = REG_R0 416 q.To.Type = obj.TYPE_REG 417 q.To.Reg = REG_R3 418 419 q = obj.Appendp(ctxt, q) 420 q.As = ABEQ 421 q.To.Type = obj.TYPE_BRANCH 422 p1 = q 423 424 q = obj.Appendp(ctxt, q) 425 q.As = AMOVD 426 q.From.Type = obj.TYPE_MEM 427 q.From.Reg = REG_R3 428 q.From.Offset = 0 // Panic.argp 429 q.To.Type = obj.TYPE_REG 430 q.To.Reg = REG_R4 431 432 q = obj.Appendp(ctxt, q) 433 q.As = AADD 434 q.From.Type = obj.TYPE_CONST 435 q.From.Offset = int64(autosize) + 8 436 q.Reg = REGSP 437 q.To.Type = obj.TYPE_REG 438 q.To.Reg = REG_R5 439 440 q = obj.Appendp(ctxt, q) 441 q.As = ACMP 442 q.From.Type = obj.TYPE_REG 443 q.From.Reg = REG_R4 444 q.To.Type = obj.TYPE_REG 445 q.To.Reg = REG_R5 446 447 q = obj.Appendp(ctxt, q) 448 q.As = ABNE 449 q.To.Type = obj.TYPE_BRANCH 450 p2 = q 451 452 q = obj.Appendp(ctxt, q) 453 q.As = AADD 454 q.From.Type = obj.TYPE_CONST 455 q.From.Offset = 8 456 q.Reg = REGSP 457 q.To.Type = obj.TYPE_REG 458 q.To.Reg = REG_R6 459 460 q = obj.Appendp(ctxt, q) 461 q.As = AMOVD 462 q.From.Type = obj.TYPE_REG 463 q.From.Reg = REG_R6 464 q.To.Type = obj.TYPE_MEM 465 q.To.Reg = REG_R3 466 q.To.Offset = 0 // Panic.argp 467 468 q = obj.Appendp(ctxt, q) 469 470 q.As = obj.ANOP 471 p1.Pcond = q 472 p2.Pcond = q 473 } 474 475 case ARETURN: 476 if p.From.Type == obj.TYPE_CONST { 477 ctxt.Diag("using BECOME (%v) is not supported!", p) 478 break 479 } 480 481 if p.To.Sym != nil { // retjmp 482 p.As = ABR 483 p.To.Type = obj.TYPE_BRANCH 484 break 485 } 486 487 if cursym.Text.Mark&LEAF != 0 { 488 if autosize == 0 { 489 p.As = ABR 490 p.From = obj.Addr{} 491 p.To.Type = obj.TYPE_REG 492 p.To.Reg = REG_LR 493 p.Mark |= BRANCH 494 break 495 } 496 497 p.As = AADD 498 p.From.Type = obj.TYPE_CONST 499 p.From.Offset = int64(autosize) 500 p.To.Type = obj.TYPE_REG 501 p.To.Reg = REGSP 502 p.Spadj = -autosize 503 504 q = ctxt.NewProg() 505 q.As = ABR 506 q.Lineno = p.Lineno 507 q.To.Type = obj.TYPE_REG 508 q.To.Reg = REG_LR 509 q.Mark |= BRANCH 510 q.Spadj = +autosize 511 512 q.Link = p.Link 513 p.Link = q 514 break 515 } 516 517 p.As = AMOVD 518 p.From.Type = obj.TYPE_MEM 519 p.From.Offset = 0 520 p.From.Reg = REGSP 521 p.To.Type = obj.TYPE_REG 522 p.To.Reg = REGTMP 523 524 q = ctxt.NewProg() 525 q.As = AMOVD 526 q.Lineno = p.Lineno 527 q.From.Type = obj.TYPE_REG 528 q.From.Reg = REGTMP 529 q.To.Type = obj.TYPE_REG 530 q.To.Reg = REG_LR 531 532 q.Link = p.Link 533 p.Link = q 534 p = q 535 536 if false { 537 // Debug bad returns 538 q = ctxt.NewProg() 539 540 q.As = AMOVD 541 q.Lineno = p.Lineno 542 q.From.Type = obj.TYPE_MEM 543 q.From.Offset = 0 544 q.From.Reg = REGTMP 545 q.To.Type = obj.TYPE_REG 546 q.To.Reg = REGTMP 547 548 q.Link = p.Link 549 p.Link = q 550 p = q 551 } 552 553 if autosize != 0 { 554 q = ctxt.NewProg() 555 q.As = AADD 556 q.Lineno = p.Lineno 557 q.From.Type = obj.TYPE_CONST 558 q.From.Offset = int64(autosize) 559 q.To.Type = obj.TYPE_REG 560 q.To.Reg = REGSP 561 q.Spadj = -autosize 562 563 q.Link = p.Link 564 p.Link = q 565 } 566 567 q1 = ctxt.NewProg() 568 q1.As = ABR 569 q1.Lineno = p.Lineno 570 q1.To.Type = obj.TYPE_REG 571 q1.To.Reg = REG_LR 572 q1.Mark |= BRANCH 573 q1.Spadj = +autosize 574 575 q1.Link = q.Link 576 q.Link = q1 577 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, noctxt bool) *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 { 761 p.To.Sym = ctxt.Symmorestack[bool2int(noctxt)] 762 } 763 764 // BR start 765 p = obj.Appendp(ctxt, p) 766 767 p.As = ABR 768 p.To.Type = obj.TYPE_BRANCH 769 p.Pcond = ctxt.Cursym.Text.Link 770 771 // placeholder for q1's jump target 772 p = obj.Appendp(ctxt, p) 773 774 p.As = obj.ANOP // zero-width place holder 775 q1.Pcond = p 776 777 return p 778 } 779 780 func follow(ctxt *obj.Link, s *obj.LSym) { 781 ctxt.Cursym = s 782 783 firstp := ctxt.NewProg() 784 lastp := firstp 785 xfol(ctxt, s.Text, &lastp) 786 lastp.Link = nil 787 s.Text = firstp.Link 788 } 789 790 func relinv(a int) int { 791 switch a { 792 case ABEQ: 793 return ABNE 794 case ABNE: 795 return ABEQ 796 797 case ABGE: 798 return ABLT 799 case ABLT: 800 return ABGE 801 802 case ABGT: 803 return ABLE 804 case ABLE: 805 return ABGT 806 807 case ABVC: 808 return ABVS 809 case ABVS: 810 return ABVC 811 } 812 813 return 0 814 } 815 816 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { 817 var q *obj.Prog 818 var r *obj.Prog 819 var a int 820 var b int 821 var i int 822 823 loop: 824 if p == nil { 825 return 826 } 827 a = int(p.As) 828 if a == ABR { 829 q = p.Pcond 830 if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) { 831 p.Mark |= FOLL 832 (*last).Link = p 833 *last = p 834 p = p.Link 835 xfol(ctxt, p, last) 836 p = q 837 if p != nil && p.Mark&FOLL == 0 { 838 goto loop 839 } 840 return 841 } 842 843 if q != nil { 844 p.Mark |= FOLL 845 p = q 846 if p.Mark&FOLL == 0 { 847 goto loop 848 } 849 } 850 } 851 852 if p.Mark&FOLL != 0 { 853 i = 0 854 q = p 855 for ; i < 4; i, q = i+1, q.Link { 856 if q == *last || (q.Mark&NOSCHED != 0) { 857 break 858 } 859 b = 0 /* set */ 860 a = int(q.As) 861 if a == obj.ANOP { 862 i-- 863 continue 864 } 865 866 if a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 867 goto copy 868 } 869 if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { 870 continue 871 } 872 b = relinv(a) 873 if b == 0 { 874 continue 875 } 876 877 copy: 878 for { 879 r = ctxt.NewProg() 880 *r = *p 881 if r.Mark&FOLL == 0 { 882 fmt.Printf("cant happen 1\n") 883 } 884 r.Mark |= FOLL 885 if p != q { 886 p = p.Link 887 (*last).Link = r 888 *last = r 889 continue 890 } 891 892 (*last).Link = r 893 *last = r 894 if a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 895 return 896 } 897 r.As = int16(b) 898 r.Pcond = p.Link 899 r.Link = p.Pcond 900 if r.Link.Mark&FOLL == 0 { 901 xfol(ctxt, r.Link, last) 902 } 903 if r.Pcond.Mark&FOLL == 0 { 904 fmt.Printf("cant happen 2\n") 905 } 906 return 907 } 908 } 909 910 a = ABR 911 q = ctxt.NewProg() 912 q.As = int16(a) 913 q.Lineno = p.Lineno 914 q.To.Type = obj.TYPE_BRANCH 915 q.To.Offset = p.Pc 916 q.Pcond = p 917 p = q 918 } 919 920 p.Mark |= FOLL 921 (*last).Link = p 922 *last = p 923 if a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID { 924 if p.Mark&NOSCHED != 0 { 925 p = p.Link 926 goto loop 927 } 928 929 return 930 } 931 932 if p.Pcond != nil { 933 if a != ABL && p.Link != nil { 934 xfol(ctxt, p.Link, last) 935 p = p.Pcond 936 if p == nil || (p.Mark&FOLL != 0) { 937 return 938 } 939 goto loop 940 } 941 } 942 943 p = p.Link 944 goto loop 945 } 946 947 var Linkppc64 = obj.LinkArch{ 948 ByteOrder: binary.BigEndian, 949 Name: "ppc64", 950 Thechar: '9', 951 Preprocess: preprocess, 952 Assemble: span9, 953 Follow: follow, 954 Progedit: progedit, 955 Minlc: 4, 956 Ptrsize: 8, 957 Regsize: 8, 958 } 959 960 var Linkppc64le = obj.LinkArch{ 961 ByteOrder: binary.LittleEndian, 962 Name: "ppc64le", 963 Thechar: '9', 964 Preprocess: preprocess, 965 Assemble: span9, 966 Follow: follow, 967 Progedit: progedit, 968 Minlc: 4, 969 Ptrsize: 8, 970 Regsize: 8, 971 }