github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/liblink/obj9.c (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 #include <u.h> 31 #include <libc.h> 32 #include <bio.h> 33 #include <link.h> 34 #include "../cmd/9l/9.out.h" 35 #include "../runtime/stack.h" 36 #include "../runtime/funcdata.h" 37 38 static Prog zprg = { 39 .as = AGOK, 40 .reg = NREG, 41 .from = { 42 .name = D_NONE, 43 .type = D_NONE, 44 .reg = NREG, 45 }, 46 .from3 = { 47 .name = D_NONE, 48 .type = D_NONE, 49 .reg = NREG, 50 }, 51 .to = { 52 .name = D_NONE, 53 .type = D_NONE, 54 .reg = NREG, 55 }, 56 }; 57 58 static int 59 symtype(Addr *a) 60 { 61 return a->name; 62 } 63 64 static int 65 isdata(Prog *p) 66 { 67 return p->as == ADATA || p->as == AGLOBL; 68 } 69 70 static int 71 iscall(Prog *p) 72 { 73 return p->as == ABL; 74 } 75 76 static int 77 datasize(Prog *p) 78 { 79 return p->reg; 80 } 81 82 static int 83 textflag(Prog *p) 84 { 85 return p->reg; 86 } 87 88 static void 89 settextflag(Prog *p, int f) 90 { 91 p->reg = f; 92 } 93 94 static void 95 progedit(Link *ctxt, Prog *p) 96 { 97 char literal[64]; 98 LSym *s; 99 100 USED(ctxt); 101 102 p->from.class = 0; 103 p->to.class = 0; 104 105 // Rewrite BR/BL to symbol as D_BRANCH. 106 switch(p->as) { 107 case ABR: 108 case ABL: 109 case ARETURN: 110 case ADUFFZERO: 111 case ADUFFCOPY: 112 if(p->to.sym != nil) 113 p->to.type = D_BRANCH; 114 break; 115 } 116 117 // Rewrite float constants to values stored in memory. 118 switch(p->as) { 119 case AFMOVS: 120 if(p->from.type == D_FCONST) { 121 int32 i32; 122 float32 f32; 123 f32 = p->from.u.dval; 124 memmove(&i32, &f32, 4); 125 sprint(literal, "$f32.%08ux", (uint32)i32); 126 s = linklookup(ctxt, literal, 0); 127 s->size = 4; 128 p->from.type = D_OREG; 129 p->from.sym = s; 130 p->from.name = D_EXTERN; 131 p->from.offset = 0; 132 } 133 break; 134 case AFMOVD: 135 if(p->from.type == D_FCONST) { 136 int64 i64; 137 memmove(&i64, &p->from.u.dval, 8); 138 sprint(literal, "$f64.%016llux", (uvlong)i64); 139 s = linklookup(ctxt, literal, 0); 140 s->size = 8; 141 p->from.type = D_OREG; 142 p->from.sym = s; 143 p->from.name = D_EXTERN; 144 p->from.offset = 0; 145 } 146 break; 147 case AMOVD: 148 if(p->from.type == D_CONST && p->from.name == D_NONE && (int64)(uint32)p->from.offset != p->from.offset) { 149 sprint(literal, "$i64.%016llux", (uvlong)p->from.offset); 150 s = linklookup(ctxt, literal, 0); 151 s->size = 8; 152 p->from.type = D_OREG; 153 p->from.sym = s; 154 p->from.name = D_EXTERN; 155 p->from.offset = 0; 156 } 157 } 158 159 // Rewrite SUB constants into ADD. 160 switch(p->as) { 161 case ASUBC: 162 if(p->from.type == D_CONST) { 163 p->from.offset = -p->from.offset; 164 p->as = AADDC; 165 } 166 break; 167 168 case ASUBCCC: 169 if(p->from.type == D_CONST) { 170 p->from.offset = -p->from.offset; 171 p->as = AADDCCC; 172 } 173 break; 174 175 case ASUB: 176 if(p->from.type == D_CONST) { 177 p->from.offset = -p->from.offset; 178 p->as = AADD; 179 } 180 break; 181 } 182 } 183 184 static Prog* stacksplit(Link*, Prog*, int32, int); 185 186 static void 187 parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg) 188 { 189 *textstksiz = arg & 0xffffffffLL; 190 if(*textstksiz & 0x80000000LL) 191 *textstksiz = -(-*textstksiz & 0xffffffffLL); 192 193 *textarg = (arg >> 32) & 0xffffffffLL; 194 if(*textarg & 0x80000000LL) 195 *textarg = 0; 196 *textarg = (*textarg+7) & ~7LL; 197 } 198 199 static void 200 addstacksplit(Link *ctxt, LSym *cursym) 201 { 202 Prog *p, *q, *p1, *p2, *q1; 203 int o, mov, aoffset; 204 vlong textstksiz, textarg; 205 int32 autosize; 206 207 if(ctxt->symmorestack[0] == nil) { 208 ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); 209 ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0); 210 // TODO(minux): add morestack short-cuts with small fixed frame-size. 211 } 212 213 ctxt->cursym = cursym; 214 215 if(cursym->text == nil || cursym->text->link == nil) 216 return; 217 218 p = cursym->text; 219 parsetextconst(p->to.offset, &textstksiz, &textarg); 220 221 cursym->args = p->to.offset>>32; 222 cursym->locals = textstksiz; 223 224 /* 225 * find leaf subroutines 226 * strip NOPs 227 * expand RET 228 * expand BECOME pseudo 229 */ 230 231 if(ctxt->debugvlog) 232 Bprint(ctxt->bso, "%5.2f noops\n", cputime()); 233 Bflush(ctxt->bso); 234 235 q = nil; 236 for(p = cursym->text; p != nil; p = p->link) { 237 switch(p->as) { 238 /* too hard, just leave alone */ 239 case ATEXT: 240 q = p; 241 p->mark |= LABEL|LEAF|SYNC; 242 if(p->link) 243 p->link->mark |= LABEL; 244 break; 245 246 case ANOR: 247 q = p; 248 if(p->to.type == D_REG) 249 if(p->to.reg == REGZERO) 250 p->mark |= LABEL|SYNC; 251 break; 252 253 case ALWAR: 254 case ASTWCCC: 255 case AECIWX: 256 case AECOWX: 257 case AEIEIO: 258 case AICBI: 259 case AISYNC: 260 case ATLBIE: 261 case ATLBIEL: 262 case ASLBIA: 263 case ASLBIE: 264 case ASLBMFEE: 265 case ASLBMFEV: 266 case ASLBMTE: 267 case ADCBF: 268 case ADCBI: 269 case ADCBST: 270 case ADCBT: 271 case ADCBTST: 272 case ADCBZ: 273 case ASYNC: 274 case ATLBSYNC: 275 case APTESYNC: 276 case ATW: 277 case AWORD: 278 case ARFI: 279 case ARFCI: 280 case ARFID: 281 case AHRFID: 282 q = p; 283 p->mark |= LABEL|SYNC; 284 continue; 285 286 case AMOVW: 287 case AMOVWZ: 288 case AMOVD: 289 q = p; 290 switch(p->from.type) { 291 case D_MSR: 292 case D_SPR: 293 case D_FPSCR: 294 case D_CREG: 295 case D_DCR: 296 p->mark |= LABEL|SYNC; 297 } 298 switch(p->to.type) { 299 case D_MSR: 300 case D_SPR: 301 case D_FPSCR: 302 case D_CREG: 303 case D_DCR: 304 p->mark |= LABEL|SYNC; 305 } 306 continue; 307 308 case AFABS: 309 case AFABSCC: 310 case AFADD: 311 case AFADDCC: 312 case AFCTIW: 313 case AFCTIWCC: 314 case AFCTIWZ: 315 case AFCTIWZCC: 316 case AFDIV: 317 case AFDIVCC: 318 case AFMADD: 319 case AFMADDCC: 320 case AFMOVD: 321 case AFMOVDU: 322 /* case AFMOVDS: */ 323 case AFMOVS: 324 case AFMOVSU: 325 /* case AFMOVSD: */ 326 case AFMSUB: 327 case AFMSUBCC: 328 case AFMUL: 329 case AFMULCC: 330 case AFNABS: 331 case AFNABSCC: 332 case AFNEG: 333 case AFNEGCC: 334 case AFNMADD: 335 case AFNMADDCC: 336 case AFNMSUB: 337 case AFNMSUBCC: 338 case AFRSP: 339 case AFRSPCC: 340 case AFSUB: 341 case AFSUBCC: 342 q = p; 343 p->mark |= FLOAT; 344 continue; 345 346 case ABL: 347 case ABCL: 348 case ADUFFZERO: 349 case ADUFFCOPY: 350 cursym->text->mark &= ~LEAF; 351 352 case ABC: 353 case ABEQ: 354 case ABGE: 355 case ABGT: 356 case ABLE: 357 case ABLT: 358 case ABNE: 359 case ABR: 360 case ABVC: 361 case ABVS: 362 p->mark |= BRANCH; 363 q = p; 364 q1 = p->pcond; 365 if(q1 != nil) { 366 while(q1->as == ANOP) { 367 q1 = q1->link; 368 p->pcond = q1; 369 } 370 if(!(q1->mark & LEAF)) 371 q1->mark |= LABEL; 372 } else 373 p->mark |= LABEL; 374 q1 = p->link; 375 if(q1 != nil) 376 q1->mark |= LABEL; 377 continue; 378 379 case AFCMPO: 380 case AFCMPU: 381 q = p; 382 p->mark |= FCMP|FLOAT; 383 continue; 384 385 case ARETURN: 386 q = p; 387 if(p->link != nil) 388 p->link->mark |= LABEL; 389 continue; 390 391 case ANOP: 392 q1 = p->link; 393 q->link = q1; /* q is non-nop */ 394 q1->mark |= p->mark; 395 continue; 396 397 default: 398 q = p; 399 continue; 400 } 401 } 402 403 autosize = 0; 404 for(p = cursym->text; p != nil; p = p->link) { 405 o = p->as; 406 switch(o) { 407 case ATEXT: 408 mov = AMOVD; 409 aoffset = 0; 410 autosize = textstksiz + 8; 411 if((p->mark & LEAF) && autosize <= 8) 412 autosize = 0; 413 else 414 if(autosize & 4) 415 autosize += 4; 416 p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8); 417 418 if(!(p->reg & NOSPLIT)) 419 p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check 420 421 q = p; 422 if(autosize) { 423 /* use MOVDU to adjust R1 when saving R31, if autosize is small */ 424 if(!(cursym->text->mark & LEAF) && autosize >= -BIG && autosize <= BIG) { 425 mov = AMOVDU; 426 aoffset = -autosize; 427 } else { 428 q = appendp(ctxt, p); 429 q->as = AADD; 430 q->lineno = p->lineno; 431 q->from.type = D_CONST; 432 q->from.offset = -autosize; 433 q->to.type = D_REG; 434 q->to.reg = REGSP; 435 q->spadj = +autosize; 436 } 437 } else 438 if(!(cursym->text->mark & LEAF)) { 439 if(ctxt->debugvlog) { 440 Bprint(ctxt->bso, "save suppressed in: %s\n", 441 cursym->name); 442 Bflush(ctxt->bso); 443 } 444 cursym->text->mark |= LEAF; 445 } 446 447 if(cursym->text->mark & LEAF) { 448 cursym->leaf = 1; 449 break; 450 } 451 452 q = appendp(ctxt, q); 453 q->as = AMOVD; 454 q->lineno = p->lineno; 455 q->from.type = D_SPR; 456 q->from.offset = D_LR; 457 q->to.type = D_REG; 458 q->to.reg = REGTMP; 459 460 q = appendp(ctxt, q); 461 q->as = mov; 462 q->lineno = p->lineno; 463 q->from.type = D_REG; 464 q->from.reg = REGTMP; 465 q->to.type = D_OREG; 466 q->to.offset = aoffset; 467 q->to.reg = REGSP; 468 if(q->as == AMOVDU) 469 q->spadj = -aoffset; 470 471 if(cursym->text->reg & WRAPPER) { 472 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 473 // 474 // MOVD g_panic(g), R3 475 // CMP R0, R3 476 // BEQ end 477 // MOVD panic_argp(R3), R4 478 // ADD $(autosize+8), R1, R5 479 // CMP R4, R5 480 // BNE end 481 // ADD $8, R1, R6 482 // MOVD R6, panic_argp(R3) 483 // end: 484 // NOP 485 // 486 // The NOP is needed to give the jumps somewhere to land. 487 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes. 488 489 490 q = appendp(ctxt, q); 491 q->as = AMOVD; 492 q->from.type = D_OREG; 493 q->from.reg = REGG; 494 q->from.offset = 4*ctxt->arch->ptrsize; // G.panic 495 q->to.type = D_REG; 496 q->to.reg = 3; 497 498 q = appendp(ctxt, q); 499 q->as = ACMP; 500 q->from.type = D_REG; 501 q->from.reg = 0; 502 q->to.type = D_REG; 503 q->to.reg = 3; 504 505 q = appendp(ctxt, q); 506 q->as = ABEQ; 507 q->to.type = D_BRANCH; 508 p1 = q; 509 510 q = appendp(ctxt, q); 511 q->as = AMOVD; 512 q->from.type = D_OREG; 513 q->from.reg = 3; 514 q->from.offset = 0; // Panic.argp 515 q->to.type = D_REG; 516 q->to.reg = 4; 517 518 q = appendp(ctxt, q); 519 q->as = AADD; 520 q->from.type = D_CONST; 521 q->from.offset = autosize+8; 522 q->reg = REGSP; 523 q->to.type = D_REG; 524 q->to.reg = 5; 525 526 q = appendp(ctxt, q); 527 q->as = ACMP; 528 q->from.type = D_REG; 529 q->from.reg = 4; 530 q->to.type = D_REG; 531 q->to.reg = 5; 532 533 q = appendp(ctxt, q); 534 q->as = ABNE; 535 q->to.type = D_BRANCH; 536 p2 = q; 537 538 q = appendp(ctxt, q); 539 q->as = AADD; 540 q->from.type = D_CONST; 541 q->from.offset = 8; 542 q->reg = REGSP; 543 q->to.type = D_REG; 544 q->to.reg = 6; 545 546 q = appendp(ctxt, q); 547 q->as = AMOVD; 548 q->from.type = D_REG; 549 q->from.reg = 6; 550 q->to.type = D_OREG; 551 q->to.reg = 3; 552 q->to.offset = 0; // Panic.argp 553 554 q = appendp(ctxt, q); 555 q->as = ANOP; 556 p1->pcond = q; 557 p2->pcond = q; 558 } 559 560 break; 561 562 case ARETURN: 563 if(p->from.type == D_CONST) { 564 ctxt->diag("using BECOME (%P) is not supported!", p); 565 break; 566 } 567 if(p->to.sym) { // retjmp 568 p->as = ABR; 569 p->to.type = D_BRANCH; 570 break; 571 } 572 if(cursym->text->mark & LEAF) { 573 if(!autosize) { 574 p->as = ABR; 575 p->from = zprg.from; 576 p->to.type = D_SPR; 577 p->to.offset = D_LR; 578 p->mark |= BRANCH; 579 break; 580 } 581 582 p->as = AADD; 583 p->from.type = D_CONST; 584 p->from.offset = autosize; 585 p->to.type = D_REG; 586 p->to.reg = REGSP; 587 p->spadj = -autosize; 588 589 q = ctxt->arch->prg(); 590 q->as = ABR; 591 q->lineno = p->lineno; 592 q->to.type = D_SPR; 593 q->to.offset = D_LR; 594 q->mark |= BRANCH; 595 q->spadj = +autosize; 596 597 q->link = p->link; 598 p->link = q; 599 break; 600 } 601 602 p->as = AMOVD; 603 p->from.type = D_OREG; 604 p->from.offset = 0; 605 p->from.reg = REGSP; 606 p->to.type = D_REG; 607 p->to.reg = REGTMP; 608 609 q = ctxt->arch->prg(); 610 q->as = AMOVD; 611 q->lineno = p->lineno; 612 q->from.type = D_REG; 613 q->from.reg = REGTMP; 614 q->to.type = D_SPR; 615 q->to.offset = D_LR; 616 617 q->link = p->link; 618 p->link = q; 619 p = q; 620 621 if(autosize) { 622 q = ctxt->arch->prg(); 623 q->as = AADD; 624 q->lineno = p->lineno; 625 q->from.type = D_CONST; 626 q->from.offset = autosize; 627 q->to.type = D_REG; 628 q->to.reg = REGSP; 629 q->spadj = -autosize; 630 631 q->link = p->link; 632 p->link = q; 633 } 634 635 q1 = ctxt->arch->prg(); 636 q1->as = ABR; 637 q1->lineno = p->lineno; 638 q1->to.type = D_SPR; 639 q1->to.offset = D_LR; 640 q1->mark |= BRANCH; 641 q1->spadj = +autosize; 642 643 q1->link = q->link; 644 q->link = q1; 645 break; 646 647 case AADD: 648 if(p->to.type == D_REG && p->to.reg == REGSP && p->from.type == D_CONST) 649 p->spadj = -p->from.offset; 650 break; 651 } 652 } 653 654 #if 0 // instruction scheduling 655 if(debug['Q'] == 0) 656 return; 657 658 curtext = nil; 659 q = nil; /* p - 1 */ 660 q1 = firstp; /* top of block */ 661 o = 0; /* count of instructions */ 662 for(p = firstp; p != nil; p = p1) { 663 p1 = p->link; 664 o++; 665 if(p->mark & NOSCHED){ 666 if(q1 != p){ 667 sched(q1, q); 668 } 669 for(; p != nil; p = p->link){ 670 if(!(p->mark & NOSCHED)) 671 break; 672 q = p; 673 } 674 p1 = p; 675 q1 = p; 676 o = 0; 677 continue; 678 } 679 if(p->mark & (LABEL|SYNC)) { 680 if(q1 != p) 681 sched(q1, q); 682 q1 = p; 683 o = 1; 684 } 685 if(p->mark & (BRANCH|SYNC)) { 686 sched(q1, p); 687 q1 = p1; 688 o = 0; 689 } 690 if(o >= NSCHED) { 691 sched(q1, p); 692 q1 = p1; 693 o = 0; 694 } 695 q = p; 696 } 697 #endif 698 } 699 700 static Prog* 701 stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) 702 { 703 Prog *q, *q1; 704 705 // MOVD g_stackguard(g), R3 706 p = appendp(ctxt, p); 707 p->as = AMOVD; 708 p->from.type = D_OREG; 709 p->from.reg = REGG; 710 p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 711 if(ctxt->cursym->cfunc) 712 p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 713 p->to.type = D_REG; 714 p->to.reg = 3; 715 716 q = nil; 717 if(framesize <= StackSmall) { 718 // small stack: SP < stackguard 719 // CMP stackguard, SP 720 p = appendp(ctxt, p); 721 p->as = ACMPU; 722 p->from.type = D_REG; 723 p->from.reg = 3; 724 p->to.type = D_REG; 725 p->to.reg = REGSP; 726 } else if(framesize <= StackBig) { 727 // large stack: SP-framesize < stackguard-StackSmall 728 // ADD $-framesize, SP, R4 729 // CMP stackguard, R4 730 p = appendp(ctxt, p); 731 p->as = AADD; 732 p->from.type = D_CONST; 733 p->from.offset = -framesize; 734 p->reg = REGSP; 735 p->to.type = D_REG; 736 p->to.reg = 4; 737 738 p = appendp(ctxt, p); 739 p->as = ACMPU; 740 p->from.type = D_REG; 741 p->from.reg = 3; 742 p->to.type = D_REG; 743 p->to.reg = 4; 744 } else { 745 // Such a large stack we need to protect against wraparound. 746 // If SP is close to zero: 747 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 748 // The +StackGuard on both sides is required to keep the left side positive: 749 // SP is allowed to be slightly below stackguard. See stack.h. 750 // 751 // Preemption sets stackguard to StackPreempt, a very large value. 752 // That breaks the math above, so we have to check for that explicitly. 753 // // stackguard is R3 754 // CMP R3, $StackPreempt 755 // BEQ label-of-call-to-morestack 756 // ADD $StackGuard, SP, R4 757 // SUB R3, R4 758 // MOVD $(framesize+(StackGuard-StackSmall)), R31 759 // CMPU R31, R4 760 p = appendp(ctxt, p); 761 p->as = ACMP; 762 p->from.type = D_REG; 763 p->from.reg = 3; 764 p->to.type = D_CONST; 765 p->to.offset = StackPreempt; 766 767 q = p = appendp(ctxt, p); 768 p->as = ABEQ; 769 p->to.type = D_BRANCH; 770 771 p = appendp(ctxt, p); 772 p->as = AADD; 773 p->from.type = D_CONST; 774 p->from.offset = StackGuard; 775 p->reg = REGSP; 776 p->to.type = D_REG; 777 p->to.reg = 4; 778 779 p = appendp(ctxt, p); 780 p->as = ASUB; 781 p->from.type = D_REG; 782 p->from.reg = 3; 783 p->to.type = D_REG; 784 p->to.reg = 4; 785 786 p = appendp(ctxt, p); 787 p->as = AMOVD; 788 p->from.type = D_CONST; 789 p->from.offset = framesize + StackGuard - StackSmall; 790 p->to.type = D_REG; 791 p->to.reg = REGTMP; 792 793 p = appendp(ctxt, p); 794 p->as = ACMPU; 795 p->from.type = D_REG; 796 p->from.reg = REGTMP; 797 p->to.type = D_REG; 798 p->to.reg = 4; 799 } 800 801 // q1: BLT done 802 q1 = p = appendp(ctxt, p); 803 p->as = ABLT; 804 p->to.type = D_BRANCH; 805 806 // MOVD LR, R5 807 p = appendp(ctxt, p); 808 p->as = AMOVD; 809 p->from.type = D_SPR; 810 p->from.offset = D_LR; 811 p->to.type = D_REG; 812 p->to.reg = 5; 813 if(q) 814 q->pcond = p; 815 816 // BL runtime.morestack(SB) 817 p = appendp(ctxt, p); 818 p->as = ABL; 819 p->to.type = D_BRANCH; 820 if(ctxt->cursym->cfunc) 821 p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); 822 else 823 p->to.sym = ctxt->symmorestack[noctxt]; 824 825 // BR start 826 p = appendp(ctxt, p); 827 p->as = ABR; 828 p->to.type = D_BRANCH; 829 p->pcond = ctxt->cursym->text->link; 830 831 // placeholder for q1's jump target 832 p = appendp(ctxt, p); 833 p->as = ANOP; // zero-width place holder 834 q1->pcond = p; 835 836 return p; 837 } 838 839 static void xfol(Link*, Prog*, Prog**); 840 841 static void 842 follow(Link *ctxt, LSym *s) 843 { 844 Prog *firstp, *lastp; 845 846 ctxt->cursym = s; 847 848 firstp = ctxt->arch->prg(); 849 lastp = firstp; 850 xfol(ctxt, s->text, &lastp); 851 lastp->link = nil; 852 s->text = firstp->link; 853 } 854 855 static int 856 relinv(int a) 857 { 858 859 switch(a) { 860 case ABEQ: return ABNE; 861 case ABNE: return ABEQ; 862 863 case ABGE: return ABLT; 864 case ABLT: return ABGE; 865 866 case ABGT: return ABLE; 867 case ABLE: return ABGT; 868 869 case ABVC: return ABVS; 870 case ABVS: return ABVC; 871 } 872 return 0; 873 } 874 875 static void 876 xfol(Link *ctxt, Prog *p, Prog **last) 877 { 878 Prog *q, *r; 879 int a, b, i; 880 881 loop: 882 if(p == nil) 883 return; 884 a = p->as; 885 if(a == ABR) { 886 q = p->pcond; 887 if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){ 888 p->mark |= FOLL; 889 (*last)->link = p; 890 *last = p; 891 p = p->link; 892 xfol(ctxt, p, last); 893 p = q; 894 if(p && !(p->mark & FOLL)) 895 goto loop; 896 return; 897 } 898 if(q != nil) { 899 p->mark |= FOLL; 900 p = q; 901 if(!(p->mark & FOLL)) 902 goto loop; 903 } 904 } 905 if(p->mark & FOLL) { 906 for(i=0,q=p; i<4; i++,q=q->link) { 907 if(q == *last || (q->mark&NOSCHED)) 908 break; 909 b = 0; /* set */ 910 a = q->as; 911 if(a == ANOP) { 912 i--; 913 continue; 914 } 915 if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID) 916 goto copy; 917 if(!q->pcond || (q->pcond->mark&FOLL)) 918 continue; 919 b = relinv(a); 920 if(!b) 921 continue; 922 copy: 923 for(;;) { 924 r = ctxt->arch->prg(); 925 *r = *p; 926 if(!(r->mark&FOLL)) 927 print("cant happen 1\n"); 928 r->mark |= FOLL; 929 if(p != q) { 930 p = p->link; 931 (*last)->link = r; 932 *last = r; 933 continue; 934 } 935 (*last)->link = r; 936 *last = r; 937 if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID) 938 return; 939 r->as = b; 940 r->pcond = p->link; 941 r->link = p->pcond; 942 if(!(r->link->mark&FOLL)) 943 xfol(ctxt, r->link, last); 944 if(!(r->pcond->mark&FOLL)) 945 print("cant happen 2\n"); 946 return; 947 } 948 } 949 950 a = ABR; 951 q = ctxt->arch->prg(); 952 q->as = a; 953 q->lineno = p->lineno; 954 q->to.type = D_BRANCH; 955 q->to.offset = p->pc; 956 q->pcond = p; 957 p = q; 958 } 959 p->mark |= FOLL; 960 (*last)->link = p; 961 *last = p; 962 if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID){ 963 if(p->mark & NOSCHED){ 964 p = p->link; 965 goto loop; 966 } 967 return; 968 } 969 if(p->pcond != nil) 970 if(a != ABL && p->link != nil) { 971 xfol(ctxt, p->link, last); 972 p = p->pcond; 973 if(p == nil || (p->mark&FOLL)) 974 return; 975 goto loop; 976 } 977 p = p->link; 978 goto loop; 979 } 980 981 static Prog* 982 prg(void) 983 { 984 Prog *p; 985 986 p = emallocz(sizeof(*p)); 987 *p = zprg; 988 return p; 989 } 990 991 LinkArch linkppc64 = { 992 .name = "ppc64", 993 .thechar = '9', 994 .endian = BigEndian, 995 996 .addstacksplit = addstacksplit, 997 .assemble = span9, 998 .datasize = datasize, 999 .follow = follow, 1000 .iscall = iscall, 1001 .isdata = isdata, 1002 .prg = prg, 1003 .progedit = progedit, 1004 .settextflag = settextflag, 1005 .symtype = symtype, 1006 .textflag = textflag, 1007 1008 .minlc = 4, 1009 .ptrsize = 8, 1010 .regsize = 8, 1011 1012 .D_ADDR = D_ADDR, 1013 .D_AUTO = D_AUTO, 1014 .D_BRANCH = D_BRANCH, 1015 .D_CONST = D_CONST, 1016 .D_EXTERN = D_EXTERN, 1017 .D_FCONST = D_FCONST, 1018 .D_NONE = D_NONE, 1019 .D_PARAM = D_PARAM, 1020 .D_SCONST = D_SCONST, 1021 .D_STATIC = D_STATIC, 1022 .D_OREG = D_OREG, 1023 1024 .ACALL = ABL, 1025 .ADATA = ADATA, 1026 .AEND = AEND, 1027 .AFUNCDATA = AFUNCDATA, 1028 .AGLOBL = AGLOBL, 1029 .AJMP = ABR, 1030 .ANOP = ANOP, 1031 .APCDATA = APCDATA, 1032 .ARET = ARETURN, 1033 .ATEXT = ATEXT, 1034 .ATYPE = ATYPE, 1035 .AUSEFIELD = AUSEFIELD, 1036 }; 1037 1038 LinkArch linkppc64le = { 1039 .name = "ppc64le", 1040 .thechar = '9', 1041 .endian = LittleEndian, 1042 1043 .addstacksplit = addstacksplit, 1044 .assemble = span9, 1045 .datasize = datasize, 1046 .follow = follow, 1047 .iscall = iscall, 1048 .isdata = isdata, 1049 .prg = prg, 1050 .progedit = progedit, 1051 .settextflag = settextflag, 1052 .symtype = symtype, 1053 .textflag = textflag, 1054 1055 .minlc = 4, 1056 .ptrsize = 8, 1057 .regsize = 8, 1058 1059 .D_ADDR = D_ADDR, 1060 .D_AUTO = D_AUTO, 1061 .D_BRANCH = D_BRANCH, 1062 .D_CONST = D_CONST, 1063 .D_EXTERN = D_EXTERN, 1064 .D_FCONST = D_FCONST, 1065 .D_NONE = D_NONE, 1066 .D_PARAM = D_PARAM, 1067 .D_SCONST = D_SCONST, 1068 .D_STATIC = D_STATIC, 1069 .D_OREG = D_OREG, 1070 1071 .ACALL = ABL, 1072 .ADATA = ADATA, 1073 .AEND = AEND, 1074 .AFUNCDATA = AFUNCDATA, 1075 .AGLOBL = AGLOBL, 1076 .AJMP = ABR, 1077 .ANOP = ANOP, 1078 .APCDATA = APCDATA, 1079 .ARET = ARETURN, 1080 .ATEXT = ATEXT, 1081 .ATYPE = ATYPE, 1082 .AUSEFIELD = AUSEFIELD, 1083 };