1 #include "l.h" 2 3 static struct { 4 ulong start; 5 ulong size; 6 } pool; 7 8 void checkpool(Prog*); 9 void flushpool(Prog*, int); 10 11 void 12 span(void) 13 { 14 Prog *p; 15 Sym *setext, *s; 16 Optab *o; 17 int m, bflag, i; 18 long c, otxt, v; 19 20 if(debug['v']) 21 Bprint(&bso, "%5.2f span\n", cputime()); 22 Bflush(&bso); 23 24 bflag = 0; 25 c = INITTEXT; 26 otxt = c; 27 for(p = firstp; p != P; p = p->link) { 28 p->pc = c; 29 o = oplook(p); 30 m = o->size; 31 if(m == 0) { 32 if(p->as == ATEXT) { 33 curtext = p; 34 autosize = p->to.offset + 4; 35 if(p->from.sym != S) 36 p->from.sym->value = c; 37 /* need passes to resolve branches */ 38 if(c-otxt >= 1L<<17) 39 bflag = 1; 40 otxt = c; 41 continue; 42 } 43 diag("zero-width instruction\n%P\n", p); 44 continue; 45 } 46 switch(o->flag & (LFROM|LTO|LPOOL)) { 47 case LFROM: 48 addpool(p, &p->from); 49 break; 50 case LTO: 51 addpool(p, &p->to); 52 break; 53 case LPOOL: 54 if ((p->scond&C_SCOND) == 14) 55 flushpool(p, 0); 56 break; 57 } 58 if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) 59 flushpool(p, 0); 60 c += m; 61 if(blitrl) 62 checkpool(p); 63 } 64 65 /* 66 * if any procedure is large enough to 67 * generate a large SBRA branch, then 68 * generate extra passes putting branches 69 * around jmps to fix. this is rare. 70 */ 71 while(bflag) { 72 if(debug['v']) 73 Bprint(&bso, "%5.2f span1\n", cputime()); 74 bflag = 0; 75 c = INITTEXT; 76 for(p = firstp; p != P; p = p->link) { 77 p->pc = c; 78 o = oplook(p); 79 /* very larg branches 80 if(o->type == 6 && p->cond) { 81 otxt = p->cond->pc - c; 82 if(otxt < 0) 83 otxt = -otxt; 84 if(otxt >= (1L<<17) - 10) { 85 q = prg(); 86 q->link = p->link; 87 p->link = q; 88 q->as = AB; 89 q->to.type = D_BRANCH; 90 q->cond = p->cond; 91 p->cond = q; 92 q = prg(); 93 q->link = p->link; 94 p->link = q; 95 q->as = AB; 96 q->to.type = D_BRANCH; 97 q->cond = q->link->link; 98 bflag = 1; 99 } 100 } 101 */ 102 m = o->size; 103 if(m == 0) { 104 if(p->as == ATEXT) { 105 curtext = p; 106 autosize = p->to.offset + 4; 107 if(p->from.sym != S) 108 p->from.sym->value = c; 109 continue; 110 } 111 diag("zero-width instruction\n%P\n", p); 112 continue; 113 } 114 c += m; 115 } 116 } 117 118 if(debug['t']) { 119 /* 120 * add strings to text segment 121 */ 122 c = rnd(c, 8); 123 for(i=0; i<NHASH; i++) 124 for(s = hash[i]; s != S; s = s->link) { 125 if(s->type != SSTRING) 126 continue; 127 v = s->value; 128 while(v & 3) 129 v++; 130 s->value = c; 131 c += v; 132 } 133 } 134 135 c = rnd(c, 8); 136 137 setext = lookup("etext", 0); 138 if(setext != S) { 139 setext->value = c; 140 textsize = c - INITTEXT; 141 } 142 if(INITRND) 143 INITDAT = rnd(c, INITRND); 144 if(debug['v']) 145 Bprint(&bso, "tsize = %lux\n", textsize); 146 Bflush(&bso); 147 } 148 149 /* 150 * when the first reference to the literal pool threatens 151 * to go out of range of a 12-bit PC-relative offset, 152 * drop the pool now, and branch round it. 153 * this happens only in extended basic blocks that exceed 4k. 154 */ 155 void 156 checkpool(Prog *p) 157 { 158 if(pool.size >= 0xffc || immaddr((p->pc+4)+4+pool.size - pool.start+8) == 0) 159 flushpool(p, 1); 160 else if(p->link == P) 161 flushpool(p, 2); 162 } 163 164 void 165 flushpool(Prog *p, int skip) 166 { 167 Prog *q; 168 169 if(blitrl) { 170 if(skip){ 171 if(debug['v'] && skip == 1) 172 print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start); 173 q = prg(); 174 q->as = AB; 175 q->to.type = D_BRANCH; 176 q->cond = p->link; 177 q->link = blitrl; 178 blitrl = q; 179 } 180 else if(p->pc+pool.size-pool.start < 2048) 181 return; 182 elitrl->link = p->link; 183 p->link = blitrl; 184 blitrl = 0; /* BUG: should refer back to values until out-of-range */ 185 elitrl = 0; 186 pool.size = 0; 187 pool.start = 0; 188 } 189 } 190 191 void 192 addpool(Prog *p, Adr *a) 193 { 194 Prog *q, t; 195 int c; 196 197 c = aclass(a); 198 199 t = zprg; 200 t.as = AWORD; 201 202 switch(c) { 203 default: 204 t.to = *a; 205 break; 206 207 case C_SROREG: 208 case C_LOREG: 209 case C_ROREG: 210 case C_FOREG: 211 case C_SOREG: 212 case C_FAUTO: 213 case C_SAUTO: 214 case C_LAUTO: 215 case C_LACON: 216 t.to.type = D_CONST; 217 t.to.offset = instoffset; 218 break; 219 } 220 221 for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */ 222 if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { 223 p->cond = q; 224 return; 225 } 226 227 q = prg(); 228 *q = t; 229 q->pc = pool.size; 230 231 if(blitrl == P) { 232 blitrl = q; 233 pool.start = p->pc; 234 } else 235 elitrl->link = q; 236 elitrl = q; 237 pool.size += 4; 238 239 p->cond = q; 240 } 241 242 void 243 xdefine(char *p, int t, long v) 244 { 245 Sym *s; 246 247 s = lookup(p, 0); 248 if(s->type == 0 || s->type == SXREF) { 249 s->type = t; 250 s->value = v; 251 } 252 } 253 254 long 255 regoff(Adr *a) 256 { 257 258 instoffset = 0; 259 aclass(a); 260 return instoffset; 261 } 262 263 long 264 immrot(ulong v) 265 { 266 int i; 267 268 for(i=0; i<16; i++) { 269 if((v & ~0xff) == 0) 270 return (i<<8) | v | (1<<25); 271 v = (v<<2) | (v>>30); 272 } 273 return 0; 274 } 275 276 long 277 immaddr(long v) 278 { 279 if(v >= 0 && v <= 0xfff) 280 return (v & 0xfff) | 281 (1<<24) | /* pre indexing */ 282 (1<<23); /* pre indexing, up */ 283 if(v >= -0xfff && v < 0) 284 return (-v & 0xfff) | 285 (1<<24); /* pre indexing */ 286 return 0; 287 } 288 289 int 290 immfloat(long v) 291 { 292 return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ 293 } 294 295 int 296 immhalf(long v) 297 { 298 if(v >= 0 && v <= 0xff) 299 return v| 300 (1<<24)| /* pre indexing */ 301 (1<<23); /* pre indexing, up */ 302 if(v >= -0xff && v < 0) 303 return (-v & 0xff)| 304 (1<<24); /* pre indexing */ 305 return 0; 306 } 307 308 int 309 aclass(Adr *a) 310 { 311 Sym *s; 312 int t; 313 314 switch(a->type) { 315 case D_NONE: 316 return C_NONE; 317 318 case D_REG: 319 return C_REG; 320 321 case D_REGREG: 322 return C_REGREG; 323 324 case D_SHIFT: 325 return C_SHIFT; 326 327 case D_FREG: 328 return C_FREG; 329 330 case D_FPCR: 331 return C_FCR; 332 333 case D_OREG: 334 switch(a->name) { 335 case D_EXTERN: 336 case D_STATIC: 337 if(a->sym == 0 || a->sym->name == 0) { 338 print("null sym external\n"); 339 print("%D\n", a); 340 return C_GOK; 341 } 342 s = a->sym; 343 t = s->type; 344 if(t == 0 || t == SXREF) { 345 diag("undefined external: %s in %s\n", 346 s->name, TNAME); 347 s->type = SDATA; 348 } 349 if(reloc) { 350 switch(t) { 351 default: 352 instoffset = s->value + a->offset + INITDAT; 353 break; 354 case STEXT: 355 if(s->value == -1) 356 undefsym(s); 357 case SCONST: 358 case SLEAF: 359 case SSTRING: 360 instoffset = s->value + a->offset; 361 break; 362 } 363 return C_ADDR; 364 } 365 instoffset = s->value + a->offset - BIG; 366 t = immaddr(instoffset); 367 if(t) { 368 if(immhalf(instoffset)) 369 return immfloat(t) ? C_HFEXT : C_HEXT; 370 if(immfloat(t)) 371 return C_FEXT; 372 return C_SEXT; 373 } 374 return C_LEXT; 375 case D_AUTO: 376 instoffset = autosize + a->offset; 377 t = immaddr(instoffset); 378 if(t){ 379 if(immhalf(instoffset)) 380 return immfloat(t) ? C_HFAUTO : C_HAUTO; 381 if(immfloat(t)) 382 return C_FAUTO; 383 return C_SAUTO; 384 } 385 return C_LAUTO; 386 387 case D_PARAM: 388 instoffset = autosize + a->offset + 4L; 389 t = immaddr(instoffset); 390 if(t){ 391 if(immhalf(instoffset)) 392 return immfloat(t) ? C_HFAUTO : C_HAUTO; 393 if(immfloat(t)) 394 return C_FAUTO; 395 return C_SAUTO; 396 } 397 return C_LAUTO; 398 case D_NONE: 399 instoffset = a->offset; 400 t = immaddr(instoffset); 401 if(t) { 402 if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */ 403 return immfloat(t) ? C_HFOREG : C_HOREG; 404 if(immfloat(t)) 405 return C_FOREG; /* n.b. that it will also satisfy immrot */ 406 t = immrot(instoffset); 407 if(t) 408 return C_SROREG; 409 if(immhalf(instoffset)) 410 return C_HOREG; 411 return C_SOREG; 412 } 413 t = immrot(instoffset); 414 if(t) 415 return C_ROREG; 416 return C_LOREG; 417 } 418 return C_GOK; 419 420 case D_PSR: 421 return C_PSR; 422 423 case D_OCONST: 424 switch(a->name) { 425 case D_EXTERN: 426 case D_STATIC: 427 s = a->sym; 428 t = s->type; 429 if(t == 0 || t == SXREF) { 430 diag("undefined external: %s in %s\n", 431 s->name, TNAME); 432 s->type = SDATA; 433 } 434 instoffset = s->value + a->offset + INITDAT; 435 if(s->type == STEXT || s->type == SLEAF) { 436 if(s->value == -1) 437 undefsym(s); 438 instoffset = s->value + a->offset; 439 } 440 return C_LCON; 441 } 442 return C_GOK; 443 444 case D_FCONST: 445 return C_FCON; 446 447 case D_CONST: 448 switch(a->name) { 449 450 case D_NONE: 451 instoffset = a->offset; 452 if(a->reg != NREG) 453 goto aconsize; 454 455 t = immrot(instoffset); 456 if(t) 457 return C_RCON; 458 t = immrot(~instoffset); 459 if(t) 460 return C_NCON; 461 return C_LCON; 462 463 case D_EXTERN: 464 case D_STATIC: 465 s = a->sym; 466 if(s == S) 467 break; 468 t = s->type; 469 switch(t) { 470 case 0: 471 case SXREF: 472 diag("undefined external: %s in %s\n", 473 s->name, TNAME); 474 s->type = SDATA; 475 break; 476 case STEXT: 477 if(s->value == -1) 478 undefsym(s); 479 case SSTRING: 480 case SCONST: 481 case SLEAF: 482 instoffset = s->value + a->offset; 483 return C_LCON; 484 } 485 if(!reloc) { 486 instoffset = s->value + a->offset - BIG; 487 t = immrot(instoffset); 488 if(t && instoffset != 0) 489 return C_RECON; 490 } 491 instoffset = s->value + a->offset + INITDAT; 492 return C_LCON; 493 494 case D_AUTO: 495 instoffset = autosize + a->offset; 496 goto aconsize; 497 498 case D_PARAM: 499 instoffset = autosize + a->offset + 4L; 500 aconsize: 501 t = immrot(instoffset); 502 if(t) 503 return C_RACON; 504 return C_LACON; 505 } 506 return C_GOK; 507 508 case D_BRANCH: 509 return C_SBRA; 510 } 511 return C_GOK; 512 } 513 514 Optab* 515 oplook(Prog *p) 516 { 517 int a1, a2, a3, r; 518 char *c1, *c3; 519 Optab *o, *e; 520 521 a1 = p->optab; 522 if(a1) 523 return optab+(a1-1); 524 a1 = p->from.class; 525 if(a1 == 0) { 526 a1 = aclass(&p->from) + 1; 527 p->from.class = a1; 528 } 529 a1--; 530 a3 = p->to.class; 531 if(a3 == 0) { 532 a3 = aclass(&p->to) + 1; 533 p->to.class = a3; 534 } 535 a3--; 536 a2 = C_NONE; 537 if(p->reg != NREG) 538 a2 = C_REG; 539 r = p->as; 540 o = oprange[r].start; 541 if(o == 0) { 542 a1 = opcross[repop[r]][a1][a2][a3]; 543 if(a1) { 544 p->optab = a1+1; 545 return optab+a1; 546 } 547 o = oprange[r].stop; /* just generate an error */ 548 } 549 if(0) { 550 print("oplook %A %d %d %d\n", 551 (int)p->as, a1, a2, a3); 552 print(" %d %d\n", p->from.type, p->to.type); 553 } 554 e = oprange[r].stop; 555 c1 = xcmp[a1]; 556 c3 = xcmp[a3]; 557 for(; o<e; o++) 558 if(o->a2 == a2) 559 if(c1[o->a1]) 560 if(c3[o->a3]) { 561 p->optab = (o-optab)+1; 562 return o; 563 } 564 diag("illegal combination %A %d %d %d\n", 565 p->as, a1, a2, a3); 566 prasm(p); 567 if(o == 0) 568 o = optab; 569 return o; 570 } 571 572 int 573 cmp(int a, int b) 574 { 575 576 if(a == b) 577 return 1; 578 switch(a) { 579 case C_LCON: 580 if(b == C_RCON || b == C_NCON) 581 return 1; 582 break; 583 case C_LACON: 584 if(b == C_RACON) 585 return 1; 586 break; 587 case C_LECON: 588 if(b == C_RECON) 589 return 1; 590 break; 591 592 case C_HFEXT: 593 return b == C_HEXT || b == C_FEXT; 594 case C_FEXT: 595 case C_HEXT: 596 return b == C_HFEXT; 597 case C_SEXT: 598 return cmp(C_HFEXT, b); 599 case C_LEXT: 600 return cmp(C_SEXT, b); 601 602 case C_HFAUTO: 603 return b == C_HAUTO || b == C_FAUTO; 604 case C_FAUTO: 605 case C_HAUTO: 606 return b == C_HFAUTO; 607 case C_SAUTO: 608 return cmp(C_HFAUTO, b); 609 case C_LAUTO: 610 return cmp(C_SAUTO, b); 611 612 case C_HFOREG: 613 return b == C_HOREG || b == C_FOREG; 614 case C_FOREG: 615 case C_HOREG: 616 return b == C_HFOREG; 617 case C_SROREG: 618 return cmp(C_SOREG, b) || cmp(C_ROREG, b); 619 case C_SOREG: 620 case C_ROREG: 621 return b == C_SROREG || cmp(C_HFOREG, b); 622 case C_LOREG: 623 return cmp(C_SROREG, b); 624 625 case C_LBRA: 626 if(b == C_SBRA) 627 return 1; 628 break; 629 } 630 return 0; 631 } 632 633 int 634 ocmp(const void *a1, const void *a2) 635 { 636 Optab *p1, *p2; 637 int n; 638 639 p1 = (Optab*)a1; 640 p2 = (Optab*)a2; 641 n = p1->as - p2->as; 642 if(n) 643 return n; 644 n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */ 645 if(n) 646 return n; 647 n = p1->a1 - p2->a1; 648 if(n) 649 return n; 650 n = p1->a2 - p2->a2; 651 if(n) 652 return n; 653 n = p1->a3 - p2->a3; 654 if(n) 655 return n; 656 return 0; 657 } 658 659 void 660 buildop(void) 661 { 662 int i, n, r; 663 664 armv4 = !debug['h']; 665 for(i=0; i<C_GOK; i++) 666 for(n=0; n<C_GOK; n++) 667 xcmp[i][n] = cmp(n, i); 668 for(n=0; optab[n].as != AXXX; n++) 669 if((optab[n].flag & V4) && !armv4) { 670 optab[n].as = AXXX; 671 break; 672 } 673 qsort(optab, n, sizeof(optab[0]), ocmp); 674 for(i=0; i<n; i++) { 675 r = optab[i].as; 676 oprange[r].start = optab+i; 677 while(optab[i].as == r) 678 i++; 679 oprange[r].stop = optab+i; 680 i--; 681 682 switch(r) 683 { 684 default: 685 diag("unknown op in build: %A\n", r); 686 errorexit(); 687 case AADD: 688 oprange[AAND] = oprange[r]; 689 oprange[AEOR] = oprange[r]; 690 oprange[ASUB] = oprange[r]; 691 oprange[ARSB] = oprange[r]; 692 oprange[AADC] = oprange[r]; 693 oprange[ASBC] = oprange[r]; 694 oprange[ARSC] = oprange[r]; 695 oprange[AORR] = oprange[r]; 696 oprange[ABIC] = oprange[r]; 697 break; 698 case ACMP: 699 oprange[ATST] = oprange[r]; 700 oprange[ATEQ] = oprange[r]; 701 oprange[ACMN] = oprange[r]; 702 break; 703 case AMVN: 704 break; 705 case ABEQ: 706 oprange[ABNE] = oprange[r]; 707 oprange[ABCS] = oprange[r]; 708 oprange[ABHS] = oprange[r]; 709 oprange[ABCC] = oprange[r]; 710 oprange[ABLO] = oprange[r]; 711 oprange[ABMI] = oprange[r]; 712 oprange[ABPL] = oprange[r]; 713 oprange[ABVS] = oprange[r]; 714 oprange[ABVC] = oprange[r]; 715 oprange[ABHI] = oprange[r]; 716 oprange[ABLS] = oprange[r]; 717 oprange[ABGE] = oprange[r]; 718 oprange[ABLT] = oprange[r]; 719 oprange[ABGT] = oprange[r]; 720 oprange[ABLE] = oprange[r]; 721 break; 722 case ASLL: 723 oprange[ASRL] = oprange[r]; 724 oprange[ASRA] = oprange[r]; 725 break; 726 case AMUL: 727 oprange[AMULU] = oprange[r]; 728 break; 729 case ADIV: 730 oprange[AMOD] = oprange[r]; 731 oprange[AMODU] = oprange[r]; 732 oprange[ADIVU] = oprange[r]; 733 break; 734 case AMOVW: 735 case AMOVB: 736 case AMOVBU: 737 case AMOVH: 738 case AMOVHU: 739 break; 740 case ASWPW: 741 oprange[ASWPBU] = oprange[r]; 742 break; 743 case AB: 744 case ABL: 745 case ASWI: 746 case AWORD: 747 case AMOVM: 748 case ARFE: 749 case ATEXT: 750 case ACASE: 751 case ABCASE: 752 break; 753 case AADDF: 754 oprange[AADDD] = oprange[r]; 755 oprange[ASUBF] = oprange[r]; 756 oprange[ASUBD] = oprange[r]; 757 oprange[AMULF] = oprange[r]; 758 oprange[AMULD] = oprange[r]; 759 oprange[ADIVF] = oprange[r]; 760 oprange[ADIVD] = oprange[r]; 761 oprange[AMOVFD] = oprange[r]; 762 oprange[AMOVDF] = oprange[r]; 763 break; 764 765 case ACMPF: 766 oprange[ACMPD] = oprange[r]; 767 break; 768 769 case AMOVF: 770 oprange[AMOVD] = oprange[r]; 771 break; 772 773 case AMOVFW: 774 oprange[AMOVWF] = oprange[r]; 775 oprange[AMOVWD] = oprange[r]; 776 oprange[AMOVDW] = oprange[r]; 777 break; 778 779 case AMULL: 780 oprange[AMULA] = oprange[r]; 781 oprange[AMULAL] = oprange[r]; 782 oprange[AMULLU] = oprange[r]; 783 oprange[AMULALU] = oprange[r]; 784 break; 785 } 786 } 787 } 788 789 /* 790 void 791 buildrep(int x, int as) 792 { 793 Opcross *p; 794 Optab *e, *s, *o; 795 int a1, a2, a3, n; 796 797 if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) { 798 diag("assumptions fail in buildrep"); 799 errorexit(); 800 } 801 repop[as] = x; 802 p = (opcross + x); 803 s = oprange[as].start; 804 e = oprange[as].stop; 805 for(o=e-1; o>=s; o--) { 806 n = o-optab; 807 for(a2=0; a2<2; a2++) { 808 if(a2) { 809 if(o->a2 == C_NONE) 810 continue; 811 } else 812 if(o->a2 != C_NONE) 813 continue; 814 for(a1=0; a1<32; a1++) { 815 if(!xcmp[a1][o->a1]) 816 continue; 817 for(a3=0; a3<32; a3++) 818 if(xcmp[a3][o->a3]) 819 (*p)[a1][a2][a3] = n; 820 } 821 } 822 } 823 oprange[as].start = 0; 824 } 825 */ 826