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