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