|
|
1.1 ! root 1: /* static char ID[] = "@(#) optim.c: 1.19 3/2/84"; */ ! 2: ! 3: /* machine independent improvement routines */ ! 4: ! 5: #include "optim.h" ! 6: ! 7: /* unit of allocatable space (in char *'s) */ ! 8: #ifndef NSPACE ! 9: #define NSPACE 1024 ! 10: #endif ! 11: ! 12: /* maximum number of labels referenced in a function */ ! 13: #ifndef NUMLBLS ! 14: #define NUMLBLS 513 ! 15: #endif ! 16: #define H_INCR 5 ! 17: #define N_LBLS (NUMLBLS / H_INCR * H_INCR + 1) ! 18: ! 19: /* what to do if no input file specified */ ! 20: #ifndef NOFILE ! 21: #define NOFILE() /* by default, use stdin */ ! 22: #endif ! 23: ! 24: /* what to report if file-opening fails */ ! 25: #ifndef FFILER ! 26: #define FFILER(S) "can't open %s\n" ! 27: #endif ! 28: ! 29: /* block of text */ ! 30: ! 31: typedef struct block { ! 32: struct block *next; /* pointer to textually next block */ ! 33: struct block *nextl; /* pointer to next executed block if no br */ ! 34: struct block *nextr; /* pointer to next executed block if br */ ! 35: struct block *ltest; /* for loop termination tests */ ! 36: NODE *firstn; /* first text node of block */ ! 37: NODE *lastn; /* last text node of block */ ! 38: short index; /* block index for debugging purposes */ ! 39: short length; /* number of instructions in block */ ! 40: short indeg; /* number of text references */ ! 41: short marked; /* marker for various things */ ! 42: } BLOCK; ! 43: ! 44: /* symbol table entry */ ! 45: ! 46: typedef struct { ! 47: char *cp; /* the symbol */ ! 48: BLOCK *bl; /* the block it is defined in */ ! 49: } LBL; ! 50: ! 51: /* data structures */ ! 52: ! 53: NODE n0; /* header for text list */ ! 54: NODE ntail = { NULL, NULL, TAIL }; /* trailer for text list */ ! 55: REF r0; /* header for non-text reference list */ ! 56: REF *lastref; /* pointer to last label reference */ ! 57: static BLOCK b0; /* header for block list */ ! 58: static BLOCK * Lastb = NULL; /* pointer to array of blocks previously ! 59: ** allocated for bldgr() ! 60: */ ! 61: static LBL *Lbltbl; /* pointer to hash table of labels */ ! 62: static int Numlbls; /* count of labels in hash table */ ! 63: static BLOCK *Prevb; /* pointer to previous block during ! 64: traversal of list */ ! 65: int fnum = 0; /* function counter */ ! 66: int npass; /* pass-through-this-function counter */ ! 67: static int idx; /* block index (for debugging) */ ! 68: ! 69: /* space allocation control */ ! 70: ! 71: static struct space_t { /* to manage space allocation */ ! 72: struct space_t *next; ! 73: char *space[NSPACE - 1]; ! 74: } *s0 = NULL, **Space; ! 75: static char *Lasta, *Lastx; /* pointers into allocatable space */ ! 76: static long Maxu = 0, Maxm = 0, Maxa = 0; ! 77: ! 78: /* statistic counters */ ! 79: ! 80: int ndisc = 0; /* instructions discarded */ ! 81: int ninst = 0; /* total instructions */ ! 82: static int nunr = 0; /* unreachable instructions */ ! 83: int nmerge = 0; /* redundant instructions */ ! 84: static int nsave = 0; /* branches saved */ ! 85: static int nrot = 0; /* rotated loops */ ! 86: static int noptim = 0; /* calls to optim */ ! 87: #define PCASES 13 ! 88: static int Pcase[PCASES + 1]; /* block types during reconstruction of text */ ! 89: static struct added { /* to keep statistics on branches added */ ! 90: struct added *next; ! 91: short fnum, ! 92: n_added; ! 93: } a0, *lastadd = &a0; ! 94: ! 95: /* debugging flags */ ! 96: ! 97: static int bflag = 0; /* Blocks after initial construction */ ! 98: int cflag = 0; /* do Conservative Comtail */ ! 99: int dflag = 0; /* print live/Dead information if set */ ! 100: static int eflag = 0; /* Execution trace */ ! 101: int hflag = 0; /* peepHole disable if set */ ! 102: static int lflag = 0; /* Labels deleted */ ! 103: static int mflag = 0; /* Merged suffixes found */ ! 104: static int pflag = 0; /* Path reconstruction trace */ ! 105: int sflag = 0; /* Statistics (on stderr) */ ! 106: static int uflag = 0; /* Unreachable code deleted */ ! 107: static int wflag = 0; /* Window peephole trace */ ! 108: ! 109: /* for readability */ ! 110: ! 111: #ifdef MEMFCN /* replace strncpy when memset is available (5.0 and after) */ ! 112: #define CLEAR(s, n) (void) memset((char *)(s), 0, (int)(n)) ! 113: #else ! 114: #define CLEAR(s, n) (void) strncpy((char *)(s), "", (int)(n)) ! 115: #endif ! 116: #define FATAL(S) fatal((S), (char *)NULL) ! 117: #define FLAG(L, LFLAG) case 'L': LFLAG = -1; continue; ! 118: #define ALLB(b, s) b = (s); b != NULL; b = b->next ! 119: #define PRCASE(N) if (pflag) { prcase(N, b); Pcase[N]++; } ! 120: #define TOPOFBLOCK(p) ((p) == NULL || islabel(p)) ! 121: #define TRACE(F) if (eflag) PRINTF("%cStarting F[%d, %d]\n", \ ! 122: CC, fnum, npass) ! 123: #define MPRINTF if (mflag) PRINTF ! 124: #define PRINDEX(P) (b->P == NULL ? 0 : b->P->index) ! 125: #define PSTAT(S, N) if ((N) > 0) FPRINTF(stderr, (S), (N)) ! 126: #define FINDLBL(l) lblhash((l), (BLOCK *)NULL) ! 127: #define ADDLBL(l, b) (void) lblhash((l), (b)) ! 128: #define ISUNCBL(b) ((b)->length == 1 && isuncbr((b)->lastn)) ! 129: #define ISREMBL(b) (ISUNCBL(b) && !ishb((b)->lastn)) ! 130: #define ISREMBR(p) (isbr(p) && !ishb(p)) ! 131: #define RMBR(p) (ndisc++, nsave++, DELNODE(p)) ! 132: /* TARGET follows branches until a non-branch is reached. However, ! 133: ** there is the danger that we will loop on ourselves if we encounter ! 134: ** an infinite loop. Solve the problem partially by preventing ! 135: ** self-loops. ! 136: */ ! 137: #define TARGET(b) while (b->nextl != NULL && ISUNCBL(b->nextl) &&\ ! 138: b->nextl != b) b = b->nextl ! 139: #define NEWBLK(n, type) ((type *) xalloc((n) * sizeof(type))) ! 140: ! 141: /* function declarations */ ! 142: ! 143: extern char *label_left(); ! 144: extern BLOCK *lblhash(); ! 145: extern void bldgr(), putbr(), rmunrch(), modrefs(), indegree(), mkltbl(); ! 146: #ifdef spflg ! 147: extern char * yysflgs(); ! 148: #endif ! 149: ! 150: /************************************************************************/ ! 151: ! 152: int ! 153: main(argc, argv) /* initialize, process parameters, control processing, etc. */ ! 154: int argc; register char *argv[]; { ! 155: ! 156: extern void mustopen(); ! 157: char usrflag[10]; ! 158: int ufl = 0, i, fileseen = 0; ! 159: ! 160: /* process parameters on command line */ ! 161: ! 162: while (--argc > 0) { ! 163: if (**++argv != '-') { /* alternate file(s) */ ! 164: switch (fileseen) { ! 165: case 0: /* none yet, open input file */ ! 166: mustopen(*argv, "r", stdin); ! 167: fileseen++; ! 168: continue; ! 169: case 1: /* input seen, open output file */ ! 170: mustopen(*argv, "w", stdout); ! 171: fileseen++; ! 172: continue; ! 173: } ! 174: FATAL("too many filenames\n"); ! 175: } ! 176: while ((i = *++*argv) != '\0') { /* debugging flags */ ! 177: switch (tolower(i)) { ! 178: case 'i': /* alternate input file */ ! 179: if (--argc <= 0) ! 180: FATAL("no argument for -I option\n"); ! 181: mustopen(*++argv, "r", stdin); ! 182: break; ! 183: case 'o': /* alternate output file */ ! 184: if (--argc <= 0) ! 185: FATAL("no argument for -O option\n"); ! 186: mustopen(*++argv, "w", stdout); ! 187: break; ! 188: FLAG(b, bflag); ! 189: FLAG(c, cflag); /* kill comtail */ ! 190: FLAG(d, dflag); /* display live/dead info */ ! 191: FLAG(e, eflag); ! 192: FLAG(h, hflag); /* kill peephole optimizations */ ! 193: FLAG(l, lflag); ! 194: FLAG(m, mflag); ! 195: FLAG(n, noptim); /* kill optimization */ ! 196: FLAG(p, pflag); ! 197: FLAG(r, nrot); /* kill loop rotations */ ! 198: FLAG(s, sflag); ! 199: FLAG(u, uflag); ! 200: FLAG(w, wflag); ! 201: default: ! 202: #ifdef spflg ! 203: if(spflg(i)) { ! 204: *argv = yysflgs(*argv); ! 205: } ! 206: else ! 207: #endif ! 208: usrflag[ufl++] = i; ! 209: continue; ! 210: } ! 211: break; ! 212: } ! 213: } ! 214: if (bflag | eflag | lflag | mflag | pflag | uflag | wflag) ! 215: setbuf(stdout, (char *)NULL); /* for easier debugging */ ! 216: NOFILE(); /* if no input file specified */ ! 217: ! 218: /* initialize everything */ ! 219: ! 220: Lbltbl = NEWBLK(N_LBLS, LBL); ! 221: init(); ! 222: usrflag[ufl] = '\0'; ! 223: yyinit(usrflag); ! 224: ! 225: /* transfer to the machine dependent part */ ! 226: ! 227: (void) yylex(); ! 228: wrapup(); ! 229: ! 230: /* print statistics if asked for */ ! 231: ! 232: if (sflag) { ! 233: register struct added *a; ! 234: ! 235: for (a = a0.next; a != NULL; a = a->next) ! 236: FPRINTF(stderr, "%d branch(es) added to function %d\n", ! 237: a->n_added, a->fnum); ! 238: dstats(); /* machine dependent statistics */ ! 239: PSTAT("%d unreachable instruction(s) deleted\n", nunr); ! 240: PSTAT("%d branch(es) saved\n", nsave); ! 241: PSTAT("%d instruction(s) merged\n", nmerge); ! 242: FPRINTF(stderr, "%d of %d total instructions discarded\n", ! 243: ndisc, ninst); ! 244: PSTAT("%d loop(s) rotated\n", nrot); ! 245: FPRINTF(stderr, ! 246: "%ld bytes used, %ld allocated\n%d function(s), %d optim(s)\n", ! 247: Maxm, Maxa, fnum - 1, noptim > 0 ? noptim : 0); ! 248: if (pflag && noptim > 0) ! 249: for (FPRINTF(stderr, "case\tnumber\n"), ! 250: i = 0; i <= PCASES; i++) ! 251: FPRINTF(stderr, "%2d\t%3d\n", i, Pcase[i]); ! 252: } ! 253: return (0); ! 254: } ! 255: ! 256: static void ! 257: mustopen(name, dir, file) char *name, *dir; FILE *file; { ! 258: ! 259: if (freopen(name, dir, file) == NULL) ! 260: fatal(FFILER(name), name); ! 261: } ! 262: ! 263: void ! 264: init() { /* reset pointers, counters, etc for next function */ ! 265: ! 266: register struct space_t *p, *pp; ! 267: long maxa = N_LBLS * sizeof(LBL); ! 268: ! 269: if (Lastb != NULL) /* free bldgr's storage */ ! 270: xfree((char *) Lastb); ! 271: Lastb = NULL; /* no memory now allocated */ ! 272: ! 273: for (p = s0; p != NULL; p = pp) { ! 274: maxa += sizeof(struct space_t); ! 275: pp = p->next; ! 276: xfree((char *) p); ! 277: } ! 278: if ((Maxu += Numlbls * sizeof(LBL)) > Maxm) ! 279: Maxm = Maxu; ! 280: if (maxa > Maxa) ! 281: Maxa = maxa; ! 282: Maxu = 0; ! 283: Space = &s0; ! 284: s0 = NULL; ! 285: Lasta = Lastx = NULL; ! 286: n0.forw = &ntail; ! 287: ntail.back = &n0; ! 288: b0.firstn = b0.lastn = &n0; ! 289: r0.nextref = NULL; ! 290: lastref = &r0; ! 291: fnum++; ! 292: npass = 0; ! 293: } ! 294: ! 295: void ! 296: optim() { /* control improvement sequencing */ ! 297: ! 298: if (noptim < 0) ! 299: return; ! 300: noptim++; ! 301: if (n0.forw != &ntail) { ! 302: ! 303: extern void rmlbls(), mrgbrs(), comtail(), reord(), rmbrs(); ! 304: int onsave = nsave; ! 305: ! 306: rmlbls(); /* remove useless labels */ ! 307: bldgr(true); /* build flow graph and call bboptim */ ! 308: mrgbrs(); /* merge branches to branches */ ! 309: rmunrch(false); /* remove unreachable code, don't preserve ! 310: ** block/node connectivity ! 311: */ ! 312: comtail(); /* remove common tails */ ! 313: reord(); /* reorder code */ ! 314: rmbrs(); /* remove redundant branches */ ! 315: rmlbls(); /* remove useless labels */ ! 316: #ifdef LIVEDEAD ! 317: ldanal(); /* perform live/dead analysis */ ! 318: #endif ! 319: if (sflag && onsave > nsave) { ! 320: register struct added *a = lastadd = lastadd->next = ! 321: NEWBLK(1, struct added); ! 322: ! 323: a->next = NULL; ! 324: a->fnum = fnum; ! 325: a->n_added = onsave - nsave; ! 326: } ! 327: } ! 328: npass++; ! 329: } ! 330: ! 331: static void ! 332: rmlbls() { /* remove unreferenced labels */ ! 333: ! 334: register REF *r; ! 335: register NODE *p; ! 336: register char *s; ! 337: ! 338: TRACE(rmlbls); ! 339: ! 340: clrltbl(); ! 341: ! 342: /* add references from data section */ ! 343: ! 344: for (r = r0.nextref; r != NULL; r = r->nextref) ! 345: ADDLBL(r->lab, &b0); ! 346: ! 347: /* add references from branches in text section */ ! 348: ! 349: for (ALLN(p)) ! 350: if ((isbr(p) || ISLABREF(p)) && (s = getp(p)) != NULL) ! 351: ADDLBL(s, &b0); ! 352: ! 353: /* delete non-hard labels that are not now in the label table */ ! 354: ! 355: for (ALLN(p)) ! 356: if (islabel(p) && !ishl(p) && FINDLBL(p->ops[0]) == NULL) { ! 357: if (lflag) ! 358: PRINTF("%clabel %s removed\n", CC, p->ops[0]); ! 359: DELNODE(p); ! 360: } ! 361: ! 362: } ! 363: ! 364: /* This routine attempts to economize on space be allocating a hunk ! 365: ** of storage big enough for all program blocks. It deallocates that ! 366: ** hunk on the next call in hopes it can be reused. ! 367: */ ! 368: ! 369: static void ! 370: bldgr(opt) boolean opt; { /* build flow graph of procedure */ ! 371: ! 372: register BLOCK *b = &b0; ! 373: register NODE *p; ! 374: ! 375: TRACE(bldgr); ! 376: ! 377: if (Lastb != NULL) /* deallocate old array, if any */ ! 378: xfree((char *)Lastb); ! 379: ! 380: /* Count number of blocks so we can allocate an array */ ! 381: ! 382: idx = 0; /* use this to count blocks */ ! 383: p = n0.forw; /* point at first node */ ! 384: while (p != &ntail) ! 385: { ! 386: idx++; /* count one more block */ ! 387: while (islabel(p)) /* skip leading labels */ ! 388: p = p->forw; ! 389: ! 390: for ( ; p != &ntail && !islabel(p); p = p->forw) { ! 391: if (isbr(p)) { ! 392: p = p->forw; ! 393: break; ! 394: } ! 395: } ! 396: } ! 397: ! 398: /* idx is now the number of blocks. Allocate array. */ ! 399: ! 400: Lastb = (BLOCK *) xalloc(idx * sizeof(BLOCK)); ! 401: ! 402: /* now build the flow graph */ ! 403: ! 404: idx = 0; ! 405: b = b0.next = Lastb; /* point at prospective first block */ ! 406: for (p = n0.forw; p != &ntail; ) { ! 407: ! 408: register NODE *prevn = p->back; ! 409: ! 410: b->next = b + 1; /* "next" will be physically next */ ! 411: b->index = ++idx; ! 412: b->length = b->indeg = 0; ! 413: ! 414: /* a block starts with 0 or more labels */ ! 415: ! 416: while (islabel(p)) ! 417: p = p->forw; ! 418: ! 419: /* followed by 0 or more non-branch instructions ! 420: terminated with a branch or before another label */ ! 421: ! 422: for ( ; p != &ntail && !islabel(p); p = p->forw) { ! 423: b->length++; ! 424: if (isbr(p)) { ! 425: p = p->forw; ! 426: break; ! 427: } ! 428: } ! 429: if (opt) { /* do dependent basic-block optimization */ ! 430: ! 431: int omit = bboptim(prevn->forw, p->back); ! 432: if (omit > b->length) ! 433: omit = b->length; ! 434: b->length -= omit; ! 435: ndisc += omit; ! 436: } ! 437: b->lastn = p->back; ! 438: if ((b->firstn = prevn->forw) != p) /* if non-empty block */ ! 439: b++; /* we will next do next block */ ! 440: } ! 441: b[-1].next = NULL; /* (assumes at least one block) next ! 442: ** pointer of last block we filled in ! 443: ** is NULL ! 444: */ ! 445: ! 446: mkltbl(); /* make label table with only definitions */ ! 447: ! 448: /* set branch pointers */ ! 449: ! 450: for (ALLB(b, b0.next)) { ! 451: char *s; ! 452: ! 453: p = b->lastn; ! 454: b->nextl = b->next; ! 455: b->nextr = isbr(p) && (s = getp(p)) != NULL ? ! 456: FINDLBL(s) : NULL; ! 457: if (isuncbr(p)) { ! 458: b->nextl = b->nextr; ! 459: b->nextr = NULL; ! 460: } ! 461: if (bflag) { ! 462: PRINTF( ! 463: "%c\n%cblock %d (left: %d, right: %d, length: %d)\n%cfirst:\t", ! 464: CC, CC, b->index, PRINDEX(nextl), PRINDEX(nextr), ! 465: b->length, CC); ! 466: prinst(b->firstn); ! 467: PRINTF("%clast:\t", CC); ! 468: prinst(p); ! 469: } ! 470: } ! 471: } ! 472: ! 473: static void ! 474: mrgbrs() { /* merge branches to unconditional branches */ ! 475: ! 476: register BLOCK *b, *bb; ! 477: ! 478: TRACE(mrgbrs); ! 479: ! 480: /* merge unconditional branches to their destinations */ ! 481: ! 482: for (ALLB(b, b0.next)) ! 483: if ((bb = b->nextl) == b->next) { /* fall-through */ ! 484: if ((b = bb) == NULL) ! 485: break; ! 486: } ! 487: else if (bb != NULL && bb != b && ! 488: islabel(b->firstn) && ISREMBL(b)) { ! 489: ndisc++; ! 490: nsave++; ! 491: modrefs(b->lastn->back, b, bb); ! 492: } ! 493: ! 494: /* ! 495: * It is assumed that "ret" is an unconditional branch; ! 496: * that getp on a "ret" returns NULL; that this can be ! 497: * placed on an unconditional branch ("jbr"); ! 498: * that prinst() will convert "jbr NULL" back to "ret"; ! 499: * but that the NULL ! 500: * cannot be placed on a conditional branch ("jne"). ! 501: * (NULL is also returned by a multi-way branch (switch).) ! 502: */ ! 503: ! 504: for (ALLB(b, b0.next)) { ! 505: ! 506: char *t; ! 507: register NODE *p = b->lastn; ! 508: ! 509: if (!isbr(p)) ! 510: continue; ! 511: if (isuncbr(p)) ! 512: while ((bb = b->nextl) != NULL && bb != bb->nextl && ! 513: ISREMBL(bb)) { ! 514: register NODE *pp = bb->lastn; ! 515: ! 516: if ((t = getp(pp)) != NULL) ! 517: putp(p, t); ! 518: else { /* pp is a dead-end */ ! 519: #ifdef MEMFCN ! 520: (void) memcpy((char *)p->ops, ! 521: (char *)pp->ops, ! 522: sizeof(pp->ops)); ! 523: #else ! 524: register char **b_p = p->ops, ! 525: **bb_p = pp->ops; ! 526: register int i = MAXOPS + 1; ! 527: ! 528: while (--i >= 0) ! 529: *b_p++ = *bb_p++; ! 530: #endif ! 531: p->op = pp->op; ! 532: } ! 533: b->nextl = bb->nextl; ! 534: } ! 535: else ! 536: while ((bb = b->nextr) != NULL && bb != bb->nextl && ! 537: ISREMBL(bb) && (t = getp(bb->lastn)) != NULL) { ! 538: putp(p, t); ! 539: b->nextr = bb->nextl; ! 540: } ! 541: } ! 542: } ! 543: ! 544: static void ! 545: comtail() { /* merge common tails from code blocks */ ! 546: ! 547: boolean changed; ! 548: ! 549: TRACE(comtail); ! 550: ! 551: do { ! 552: extern boolean chktail(); ! 553: register BLOCK *bi, *bj, *bi0, *bj0; ! 554: ! 555: changed = false; ! 556: if (cflag) /* for conservative analysis only */ ! 557: indegree(); /* compute indegree (0 from bldgr()) */ ! 558: for (ALLB(bi, b0.next)) { /* compute a key for each block */ ! 559: bi->marked = 0; ! 560: if (bi->length == 1 && isbr(bi->lastn)) ! 561: continue; ! 562: bi0 = bi; ! 563: if (isbr(bi->lastn) && !isuncbr(bi->lastn)) { ! 564: TARGET(bi0); ! 565: bi->marked += bi0->lastn->op; ! 566: } ! 567: bi->marked += bi0->nextl - &b0; ! 568: } ! 569: for (ALLB(bi, b0.next)) { ! 570: int cond_br; ! 571: ! 572: if (!bi->marked) ! 573: continue; ! 574: for (ALLB(bj, bi->next)) { ! 575: if (bi->marked != bj->marked) ! 576: continue; /* quick sieve on key */ ! 577: if (bi->nextr != bj->nextr) ! 578: continue; ! 579: bi0 = bi; bj0 = bj; ! 580: /* if both blocks end in conditional branches, ! 581: * look ahead for left targets */ ! 582: if (cond_br = ! 583: isbr(bj->lastn) && !isuncbr(bj->lastn)) { ! 584: if (bi->lastn->op != bj->lastn->op) ! 585: continue; ! 586: if(bi->nextr == NULL && ! 587: !same(bi->lastn,bj->lastn)) ! 588: continue; ! 589: TARGET(bi0); ! 590: TARGET(bj0); ! 591: } ! 592: /* blocks must fall through to same place */ ! 593: if (bi0->nextl != bj0->nextl) ! 594: continue; ! 595: /* dead-end branches must have same text */ ! 596: if (bi0->nextl == NULL && ! 597: !same(bi0->lastn, bj0->lastn)) ! 598: continue; ! 599: if (chktail(bi, bj, bi0->nextl) == true) ! 600: changed = true; ! 601: } ! 602: } ! 603: } while (changed == true); ! 604: } ! 605: ! 606: static boolean ! 607: chktail(bi, bj, bl) /* merge tails of bi-> and bj-> */ ! 608: register BLOCK *bi, *bj; BLOCK *bl; { ! 609: ! 610: extern void rmtail(); ! 611: register BLOCK *bn; ! 612: NODE *pi = bi->lastn, *pj = bj->lastn, *firstn, *lastn, *pb = NULL; ! 613: int length = 0, isbri = 0, isbrj = 0; ! 614: ! 615: /* pi and pj scan backwards through blocks bi and bj ! 616: until difference or no more code */ ! 617: ! 618: if (isbr(pi)) { /* trailing branches have already been matched */ ! 619: pb = pi; ! 620: pi = pi->back; ! 621: isbri++; ! 622: } ! 623: if (isbr(pj)) { ! 624: pb = pj; ! 625: pj = pj->back; ! 626: isbrj++; ! 627: } ! 628: for (firstn = lastn = pj; !TOPOFBLOCK(pi) && !TOPOFBLOCK(pj) && ! 629: same(pi, pj) == true; length++) { ! 630: firstn = pj; ! 631: pi = (pi == bi->firstn) ? NULL : pi->back; ! 632: pj = (pj == bj->firstn) ? NULL : pj->back; ! 633: } ! 634: if (length == 0) ! 635: return (false); ! 636: ! 637: /* if blocks identical, change references to one to the other */ ! 638: ! 639: if (TOPOFBLOCK(pi) && TOPOFBLOCK(pj)) { ! 640: isbri = 0; ! 641: modrefs(pj, bj, bn = bi); ! 642: MPRINTF("%cblock %d merged into block %d and deleted\n", ! 643: CC, bj->index, bi->index); ! 644: } ! 645: ! 646: /* ! 647: * Conservative common-tail merging avoids adding a branch to ! 648: * achieve a merge. It merges only blocks which join with no other ! 649: * blocks joining &at that point, so that the joining branch is merely ! 650: * raised above the common tail, and no new branch is added. ! 651: */ ! 652: ! 653: else if (cflag && (bl == NULL || bl->indeg > 2)) ! 654: return (false); /* conservative common tails */ ! 655: ! 656: /* if one block is a tail of the other, remove the tail from the ! 657: larger block and make it reference the smaller */ ! 658: ! 659: else if (TOPOFBLOCK(pi)) { ! 660: isbri = 0; ! 661: bj->lastn = pj; ! 662: bj->length -= length + isbrj; ! 663: bj->nextl = bn = bi; ! 664: rmtail(bj); ! 665: } ! 666: else if (TOPOFBLOCK(pj)) { ! 667: isbrj = 0; ! 668: bi->lastn = pi; ! 669: bi->length -= length + isbri; ! 670: bi->nextl = bn = bj; ! 671: rmtail(bi); ! 672: } ! 673: ! 674: /* otherwise make a new block, remove tails from common blocks and ! 675: make them reference the new block */ ! 676: ! 677: else { ! 678: bi->lastn = pi; ! 679: bj->lastn = pj; ! 680: bi->length -= length + isbri; ! 681: bj->length -= length + isbrj; ! 682: bn = GETSTR(BLOCK); ! 683: *bn = *bj; ! 684: bn->firstn = firstn; ! 685: bn->lastn = lastn; ! 686: bn->length = length; ! 687: bn->index = ++idx; ! 688: bn->indeg = 2; ! 689: bi->nextl = bj->nextl = bj->next = bn; ! 690: bi->nextr = bj->nextr = NULL; ! 691: MPRINTF("%ctails of %d and %d merged into new block %d\n", ! 692: CC, bi->index, bj->index, idx); ! 693: } ! 694: if (pb != NULL && !isbr(bn->lastn)) { /* save final branch */ ! 695: ndisc--; ! 696: nsave--; ! 697: bn->length++; ! 698: pb->back = bn->lastn; ! 699: bn->lastn = bn->lastn->forw = pb; ! 700: } ! 701: ! 702: #ifdef IDVAL ! 703: for (pb = bn->firstn; pb != NULL; pb = pb->forw) { ! 704: pb->uniqid = IDVAL; ! 705: if (pb == bn->lastn) ! 706: break; ! 707: } ! 708: #endif ! 709: ! 710: ndisc += length + isbri + isbrj; ! 711: nmerge += length; ! 712: nsave += isbri + isbrj; /* don't blame resequence for added branch */ ! 713: MPRINTF("%c%d instruction(s) common to blocks %d and %d\n", ! 714: CC, length, bi->index, bj->index); ! 715: return (true); ! 716: } ! 717: ! 718: static void ! 719: rmtail(b) register BLOCK *b; { /* remove tail of b */ ! 720: ! 721: b->nextr = NULL; ! 722: MPRINTF("%ctail of block %d deleted\n", CC, b->index); ! 723: } ! 724: ! 725: static void ! 726: modrefs(pi, bi, bj) /* change all refs from bi to bj */ ! 727: register NODE *pi; register BLOCK *bi, *bj; { ! 728: ! 729: register BLOCK *b; ! 730: ! 731: if (pi != NULL) { /* transfer labels, if any, from bi to bj */ ! 732: /* bi->firstn points to the first label to be transferred, ! 733: * pi points to the last. */ ! 734: bj->firstn->back = pi; ! 735: pi->forw = bj->firstn; ! 736: bj->firstn = bi->firstn; ! 737: for ( ; ; pi = pi->back) { /* update the label table */ ! 738: ADDLBL(pi->ops[0], bj); ! 739: if (pi == bi->firstn) ! 740: break; ! 741: } ! 742: } ! 743: for (ALLB(b, &b0)) { /* update the block structure */ ! 744: if (b->next == bi) ! 745: b->next = bi->next; ! 746: if (b->nextl == bi) ! 747: b->nextl = bj; ! 748: if (b->nextr == bi) ! 749: b->nextr = bj; ! 750: } ! 751: } ! 752: ! 753: static void ! 754: reord() { /* reorder code */ ! 755: ! 756: extern BLOCK *reord1(); ! 757: extern void findlt(); ! 758: register BLOCK *b; ! 759: ! 760: TRACE(reord); ! 761: ! 762: for (ALLB(b, b0.next)) { ! 763: b->ltest = NULL; ! 764: b->marked = 0; /* mark all blocks as unprocessed */ ! 765: } ! 766: indegree(); /* compute indegree */ ! 767: ! 768: if (nrot >= 0) ! 769: findlt(); /* find rotatable loops */ ! 770: ! 771: /* tie blocks back together */ ! 772: ! 773: if (pflag) ! 774: PRINTF("%cblock\tleft\tright\tcase\tlabels\n", CC); ! 775: Prevb = &b0; ! 776: for (b = b0.next; b != NULL; ) ! 777: b = reord1(b); ! 778: if (Prevb->nextl != NULL) ! 779: putbr(Prevb); ! 780: Prevb->lastn->forw = &ntail; ! 781: ntail.back = Prevb->lastn; /* tack on tail node to text list */ ! 782: ! 783: mkltbl(); /* make label table with only definitions */ ! 784: rmunrch(true); /* remove unreachable code */ ! 785: } ! 786: ! 787: static void ! 788: indegree() { /* compute indegree */ ! 789: ! 790: register BLOCK *b, *bb; ! 791: ! 792: for (ALLB(b, b0.next)) ! 793: b->indeg = 0; ! 794: for (ALLB(b, b0.next)) { /* compute indegree */ ! 795: if ((bb = b->nextl) != NULL) ! 796: bb->indeg++; ! 797: if ((bb = b->nextr) != NULL) ! 798: bb->indeg++; ! 799: } ! 800: } ! 801: ! 802: static void ! 803: findlt() { /* find rotatable loops */ ! 804: ! 805: /* ! 806: * To identify the top and termination-test of a rotatable loop: ! 807: * Look at the target of an unconditional backward branch. ! 808: * If it has only one reference, then it isn't the start of a loop. ! 809: * Then look at all intermediate blocks in lexical order ! 810: * to find a conditional jump past the backward branch. ! 811: * This is a very simplistic heuristic approach, because the loop ! 812: * test is actually never made. ! 813: * But it seems to give reasonable results rather rapidly. ! 814: * If there is more than one exit from the loop, ! 815: * rotate at the exit nearest to the bottom, ! 816: * in order to keep the elements of a compound test near each ! 817: * other (in case of window optimization) ! 818: * and near the bottom (in case of span-dependent branches). ! 819: */ ! 820: ! 821: register BLOCK *b, *bl, *bb, *br; ! 822: ! 823: if (bflag) ! 824: PRINTF("%cltests are:", CC); ! 825: for (ALLB(b, b0.next)) { ! 826: if (b->nextr != NULL || (bl = b->nextl) == NULL || ! 827: bl->indeg < 2 || bl->index > b->index || bl->ltest != NULL) ! 828: continue; ! 829: for (bb = bl; bb != NULL && bb->index < b->index; bb = bb->next) ! 830: if ((br = bb->nextr) != NULL && br->index > b->index) ! 831: bl->ltest = bb; ! 832: if (bflag && bl->ltest != NULL) ! 833: PRINTF(" %d/%d", bl->index, bl->ltest->index); ! 834: } ! 835: if (bflag) ! 836: PUTCHAR('\n'); ! 837: } ! 838: ! 839: #define B_EXIT 2 ! 840: ! 841: static BLOCK * ! 842: reord1(b) register BLOCK *b; { ! 843: ! 844: extern BLOCK *nextbr(); ! 845: extern void prcase(); ! 846: register BLOCK *bl, *br, *blt; ! 847: ! 848: /* top of rotatable loop */ ! 849: /* don't rotate unless there already must be a branch to the entry */ ! 850: ! 851: if (b->ltest != NULL && b != Prevb->nextl && ! 852: (bl = b->ltest->nextl)->ltest == NULL && !bl->marked) { ! 853: b->ltest = NULL; ! 854: nrot++; ! 855: return (bl); ! 856: } ! 857: ! 858: /* mark block as processed and tie it in */ ! 859: ! 860: b->marked++; ! 861: if (b != Prevb->nextl) ! 862: putbr(Prevb); ! 863: Prevb->lastn->forw = b->firstn; ! 864: b->firstn->back = Prevb->lastn; ! 865: Prevb = b; ! 866: ! 867: /* dead-end block */ ! 868: ! 869: if ((bl = b->nextl) == NULL) { ! 870: PRCASE(0); ! 871: return (nextbr(b)); ! 872: } ! 873: ! 874: bl->indeg--; ! 875: if ((br = b->nextr) != NULL) ! 876: br->indeg--; ! 877: ! 878: /* top of rotatable loop */ ! 879: ! 880: if ((blt = bl->ltest) != NULL && blt->nextl->ltest == NULL && ! 881: !blt->nextl->marked && !blt->nextr->marked && outdeg(bl) <= 1) { ! 882: PRCASE(1); ! 883: b = blt->nextl; ! 884: bl->ltest = NULL; ! 885: nrot++; ! 886: return (b); ! 887: } ! 888: ! 889: if (br == NULL) { /* unconditional branch or conditional to dead-end */ ! 890: ! 891: if (!bl->marked) { /* to unprocessed block */ ! 892: ! 893: if (bl->indeg <= 0) { /* with indeg 1 */ ! 894: PRCASE(2); ! 895: return (bl); ! 896: } ! 897: ! 898: /* branch to block with indeg > 1 ! 899: that originally followed this one */ ! 900: ! 901: if (bl == b->next) { ! 902: PRCASE(3); ! 903: return (bl); ! 904: } ! 905: ! 906: /* branch to dead-end block */ ! 907: ! 908: if (bl->nextl == NULL) { ! 909: PRCASE(4); ! 910: return (bl); ! 911: } ! 912: ! 913: } ! 914: ! 915: /* all other unconditional branches */ ! 916: ! 917: PRCASE(5); ! 918: return (nextbr(b)); ! 919: } ! 920: ! 921: /* conditional branch to processed block */ ! 922: ! 923: if (br->marked && !bl->marked) { ! 924: ! 925: /* fall through to unprocessed block with indeg = 1 */ ! 926: ! 927: if (bl->indeg <= 0) { ! 928: PRCASE(6); ! 929: return (bl); ! 930: } ! 931: ! 932: /* fall through to unprocessed block with indeg > 1 ! 933: that originally followed this one */ ! 934: ! 935: if (bl == b->next) { ! 936: PRCASE(7); ! 937: return (bl); ! 938: } ! 939: } ! 940: ! 941: /* reversible conditional branch to unprocessed block, ! 942: fall through to processed block */ ! 943: ! 944: if (bl->marked && !br->marked && isrev(b->lastn)) { ! 945: revbr(b->lastn); ! 946: putp(b->lastn, label_left(b)); ! 947: b->nextr = b->nextl; ! 948: b->nextl = br; ! 949: PRCASE(8); ! 950: return (br->indeg <= 0 ? br : nextbr(b)); ! 951: } ! 952: ! 953: /* all other conditional branches that have one leg or the ! 954: other going to processed blocks */ ! 955: ! 956: if (bl->marked || br->marked) { ! 957: PRCASE(9); ! 958: return (nextbr(b)); ! 959: } ! 960: ! 961: /* fall through to block with indeg = 1 ! 962: but not if it is an unlabeled unconditional transfer */ ! 963: ! 964: if (bl->indeg <= 0 && !(isuncbr(bl->firstn) && isrev(b->lastn))) { ! 965: PRCASE(10); ! 966: return (bl); ! 967: } ! 968: ! 969: /* reversible branch to block with indeg = 1 */ ! 970: ! 971: if (br->indeg <= 0 && isrev(b->lastn)) { ! 972: revbr(b->lastn); ! 973: putp(b->lastn, label_left(b)); ! 974: b->nextr = b->nextl; ! 975: b->nextl = br; ! 976: PRCASE(11); ! 977: return (br); ! 978: } ! 979: ! 980: /* fall through to block with indeg > 1 that ! 981: originally followed this block */ ! 982: ! 983: if (bl == b->next) { ! 984: PRCASE(12); ! 985: return (bl); ! 986: } ! 987: ! 988: /* everything else */ ! 989: ! 990: PRCASE(13); ! 991: return (nextbr(b)); ! 992: } ! 993: ! 994: /* Routine outdeg works in conjunction with loop rotation. It uses a ! 995: ** heuristic to determine how many of the loop exit target's remaining ! 996: ** incoming arcs are due to exits from the loop that is to be rotated. ! 997: ** Outdeg is called with a pointer to the top-of-loop block. It scans ! 998: ** lexically through the blocks that follow the top (much like findlt()) ! 999: ** until ! 1000: ** 1) there is no next block ! 1001: ** 2) the "left" path points at the loop top, indicating the block ! 1002: ** is the loop end ! 1003: ** 3) the new block's index is at or past the loop target (since ! 1004: ** findlt calls something a loop exit when the block index ! 1005: ** of the "right" path is beyond the loop end) ! 1006: ** ! 1007: ** As we scan through the blocks lexically, we decrement the effective ! 1008: ** indegree of the loop target whenever we find a "right" path that ! 1009: ** goes to the target from an unmarked block. (If the block was marked, ! 1010: ** its contribution to indegree has already been accounted for.) ! 1011: */ ! 1012: ! 1013: static int ! 1014: outdeg(top) ! 1015: BLOCK * top; /* pointer to top of loop */ ! 1016: { ! 1017: BLOCK * target = top->ltest->nextr; /* loop exit target */ ! 1018: BLOCK * bp; /* scanning block pointer */ ! 1019: int indegree = target->indeg; /* in-degree of target block */ ! 1020: ! 1021: /* As a short-circuit, discontinue searching when the new indegree ! 1022: ** is <= 1 ! 1023: */ ! 1024: ! 1025: if (indegree <= 1) ! 1026: return(indegree); ! 1027: ! 1028: for (bp = top; ! 1029: bp != NULL /* have a block */ ! 1030: && bp->nextl != top /* it doesn't close the loop */ ! 1031: && bp->index < target->index ; /* it isn't past the target */ ! 1032: bp = bp->next) ! 1033: { ! 1034: if ( ! 1035: ! bp->marked /* the block is unmarked */ ! 1036: && bp->nextr == target /* it branches cond. to target */ ! 1037: && --indegree <= 1 /* time to quit */ ! 1038: ) ! 1039: break; ! 1040: } ! 1041: ! 1042: return(indegree); /* return effective indegree */ ! 1043: } ! 1044: ! 1045: ! 1046: static void ! 1047: prcase(n, b) int n; register BLOCK *b; { /* print information during reord */ ! 1048: ! 1049: register NODE *p; ! 1050: ! 1051: PRINTF("%c%d\t%d\t%d\t%d", CC, b->index, ! 1052: PRINDEX(nextl), PRINDEX(nextr), n); ! 1053: for (p = b->firstn; islabel(p); p = p->forw) ! 1054: PRINTF("\t%s", p->ops[0]); ! 1055: PRINTF("\n"); ! 1056: } ! 1057: ! 1058: static BLOCK * ! 1059: nextbr(b) register BLOCK *b; { /* select next block to process */ ! 1060: ! 1061: register BLOCK *bb; ! 1062: ! 1063: /* first look for orphan blocks (no more references) from the top */ ! 1064: ! 1065: for (ALLB(bb, b0.next)) ! 1066: if (!bb->marked && bb->indeg <= 0) ! 1067: return (bb); ! 1068: ! 1069: /* now look for unmarked block with live consequent (circularly) */ ! 1070: ! 1071: for (bb = b->next; bb != b; bb = bb->next) ! 1072: if (bb == NULL) /* circular scan for next block */ ! 1073: bb = &b0; ! 1074: else if (!bb->marked && ! 1075: bb->nextl != NULL && !bb->nextl->marked) ! 1076: return (bb); ! 1077: ! 1078: /* now look for any unmarked block (circularly) */ ! 1079: ! 1080: for (bb = b->next; bb != b; bb = bb->next) ! 1081: if (bb == NULL) /* circular scan for next block */ ! 1082: bb = &b0; ! 1083: else if (!bb->marked) ! 1084: return (bb); ! 1085: ! 1086: return (NULL); /* no more blocks to process */ ! 1087: } ! 1088: ! 1089: static void ! 1090: putbr(b) register BLOCK *b; { /* append a branch to b->nextl onto b */ ! 1091: ! 1092: register NODE *p, *pl = b->lastn; ! 1093: char *s; ! 1094: ! 1095: if (b == &b0 || isuncbr(pl)) ! 1096: return; ! 1097: ndisc--; ! 1098: nsave--; ! 1099: b->length++; ! 1100: p = Saveop(0, (char *)NULL, 0, GHOST); /* make node but don't link */ ! 1101: b->lastn = pl->forw = p; /* link at end of this block */ ! 1102: p->back = pl; ! 1103: s = label_left(b); /* get destination label, in 2 steps */ ! 1104: setbr(p, s); /* in case setbr is a macro which double-evaluates */ ! 1105: } ! 1106: ! 1107: static char * ! 1108: label_left(b) register BLOCK *b; { /* get label of b->nextl */ ! 1109: ! 1110: register NODE *pf, *p; ! 1111: register BLOCK *bl; ! 1112: ! 1113: if ((bl = b->nextl) == NULL) ! 1114: FATAL("label of nonexistent block requested\n"); ! 1115: for ( ; ISUNCBL(bl) && bl->nextl != bl; bl = bl->nextl) ! 1116: if (bl->nextl == NULL) { ! 1117: ! 1118: char *s = getp(bl->lastn); ! 1119: ! 1120: if (s == NULL) /* no target */ ! 1121: break; ! 1122: b->nextl = NULL; /* dead-end */ ! 1123: return (s); ! 1124: } ! 1125: b->nextl = bl; /* re-aim b at final target */ ! 1126: pf = bl->firstn; ! 1127: if (islabel(pf) && !ishl(pf)) ! 1128: return (pf->ops[0]); ! 1129: p = Saveop(0, newlab(), 0, GHOST); /* make node but don't link */ ! 1130: p->forw = pf; /* link at beginning of this block */ ! 1131: p->back = pf->back; ! 1132: if (bl->marked) /* this block already processed by reord */ ! 1133: pf->back->forw = p; ! 1134: bl->firstn = pf->back = p; ! 1135: setlab(p); ! 1136: return (p->ops[0]); ! 1137: } ! 1138: ! 1139: static void ! 1140: rmunrch(preserve) boolean preserve; { /* remove unreachable code */ ! 1141: ! 1142: extern void reach(); ! 1143: register REF *r; ! 1144: register BLOCK *b, *prevb; ! 1145: ! 1146: TRACE(rmunrch); ! 1147: ! 1148: if (b0.next == NULL) ! 1149: return; ! 1150: for (ALLB(b, b0.next)) ! 1151: b->marked = 0; ! 1152: reach(b0.next); /* mark all blocks reachable from initial block */ ! 1153: ! 1154: /* mark all blocks reachable from hard-label blocks */ ! 1155: ! 1156: for (ALLB(b, b0.next)) ! 1157: if (!b->marked && ishlp(b->firstn)) ! 1158: reach(b); ! 1159: ! 1160: /* mark all blocks reachable from non-text references */ ! 1161: ! 1162: for (r = r0.nextref; r != NULL; r = r->nextref) ! 1163: if ((b = FINDLBL(r->lab)) != NULL && !b->marked) ! 1164: reach(b); ! 1165: ! 1166: for (ALLB(b, b0.next)) /* remove unmarked blocks */ ! 1167: if (b->marked) ! 1168: prevb = b; ! 1169: else { ! 1170: ndisc += b->length; ! 1171: if (ISUNCBL(b) && islabel(b->firstn)) ! 1172: nsave++; ! 1173: else { ! 1174: if (uflag) ! 1175: PRINTF("%cunreachable block %d removed\n", ! 1176: CC, b->index); ! 1177: nunr += b->length; ! 1178: } ! 1179: if (preserve) { /* node sequence must be preserved */ ! 1180: b->firstn->back->forw = b->lastn->forw; ! 1181: b->lastn->forw->back = b->firstn->back; ! 1182: } ! 1183: prevb->next = b->next; ! 1184: } ! 1185: } ! 1186: ! 1187: static void ! 1188: reach(b) register BLOCK *b; { /* recursively mark reachable blocks */ ! 1189: ! 1190: register BLOCK *bb; ! 1191: ! 1192: b->marked++; ! 1193: ! 1194: /* ! 1195: * Link around the second of successive removable branches with same ! 1196: * op-codes; multi-way branches (switches) must be identical in text. ! 1197: */ ! 1198: ! 1199: while ((bb = b->nextl) != NULL && !bb->marked && bb->length == 1 && ! 1200: bb->lastn->op == b->lastn->op && ISREMBR(bb->lastn)) { ! 1201: if(!(isuncbr(bb->lastn) || ! 1202: bb->nextr != NULL || same(bb->lastn, b->lastn))) ! 1203: break; ! 1204: b->nextl = bb->nextl; ! 1205: } ! 1206: if (bb != NULL && !bb->marked) ! 1207: reach(bb); ! 1208: if ((bb = b->nextr) != NULL && !bb->marked) ! 1209: reach(bb); ! 1210: } ! 1211: ! 1212: static void ! 1213: rmbrs() { /* remove redundant branches */ ! 1214: ! 1215: register BLOCK *b, *bl; ! 1216: register NODE *p; ! 1217: ! 1218: TRACE(rmbrs); ! 1219: ! 1220: for (ALLB(b, b0.next)) ! 1221: if ((bl = b->nextl) != NULL && ! 1222: (p = b->lastn)->forw == bl->firstn && ISREMBR(p)) { ! 1223: ! 1224: /* delete unconditional branch ahead of target */ ! 1225: ! 1226: if (isuncbr(p)) { ! 1227: RMBR(p); ! 1228: continue; ! 1229: } ! 1230: ! 1231: /* delete conditional branch ahead of target ! 1232: or ahead of unconditional branch to same target */ ! 1233: ! 1234: do { ! 1235: if (b->nextr == bl || b->nextr == NULL && ! 1236: bl->nextl == NULL && ISUNCBL(bl) && ! 1237: sameaddr(p, bl->lastn)) { ! 1238: RMBR(p); ! 1239: break; ! 1240: } ! 1241: } while ( ISUNCBL(bl) ! 1242: && bl != bl->nextl /* avoid self-loop */ ! 1243: && (bl = bl->nextl) != NULL); ! 1244: } ! 1245: } ! 1246: /* ldanal -- perform live/dead analysis over flow graph ! 1247: ** ! 1248: ** This routine calculates live/dead register information for the ! 1249: ** entire flow graph in these steps: ! 1250: ** ! 1251: ** 1. Allocate temporary array to hold block-level live/dead info. ! 1252: ** Initialize it. ! 1253: ** 2. On a block-wise basis, determine registers set and used by ! 1254: ** each instruction. Determine registers used and set by the ! 1255: ** block. ! 1256: ** 3. Propagate register use/set information throughout the flow ! 1257: ** graph blocks. ! 1258: ** 4. Propagate final information back through each block to ! 1259: ** reflect correct live/dead information for each instruction. ! 1260: ** ! 1261: ** We use the live/dead algorithm described in the Aho and Ullman ! 1262: ** "dragon book". ! 1263: */ ! 1264: ! 1265: #ifdef LIVEDEAD ! 1266: void ! 1267: ldanal() { /* perform live-dead register analysis */ ! 1268: ! 1269: typedef unsigned int LDREG; ! 1270: register BLOCK * b; /* pointer to current block */ ! 1271: register NODE * p; /* pointer to current inst. node */ ! 1272: struct ldinfo /* temporary block-level structure */ ! 1273: { ! 1274: LDREG buses; /* registers used by block */ ! 1275: LDREG bdef; /* registers defined (set) by block */ ! 1276: LDREG bin; /* registers live coming into block */ ! 1277: LDREG bout; /* registers live exiting block */ ! 1278: }; ! 1279: struct ldinfo * lddata; /* array of data for each block */ ! 1280: register struct ldinfo * ldptr; /* pointer to one of the above */ ! 1281: unsigned i; ! 1282: boolean changed; ! 1283: ! 1284: TRACE(ldanal); ! 1285: ! 1286: bldgr(false); /* update block structure but don't call bboptim */ ! 1287: lddata = NEWBLK(idx + 1, struct ldinfo); ! 1288: ! 1289: /* Initialize: set the recently allocated array to zero. The idea, here, ! 1290: ** is that each entry in the array corresponds to one block in the flow ! 1291: ** graph. We assume that blocks have sequential index numbers and that ! 1292: ** idx is the last index number. ! 1293: */ ! 1294: ! 1295: CLEAR(lddata, (idx + 1) * sizeof(struct ldinfo)); ! 1296: ! 1297: /* Step 2. Calculate uses/def for each node and for the containing block. */ ! 1298: ! 1299: for (ALLB(b,b0.next)) ! 1300: { ! 1301: ldptr = lddata + b->index; ! 1302: for (p = b->lastn; !islabel(p); p = p->back) ! 1303: { ! 1304: p->nlive = uses(p) | LIVEREGS; /* what's used here, + always live */ ! 1305: p->ndead = sets(p) & ~p->nlive; /* what's set, but not used, here */ ! 1306: ldptr->buses = (p->nlive | (ldptr->buses & ~p->ndead)) & REGS; ! 1307: /* current live registers */ ! 1308: ldptr->bdef = (p->ndead | (ldptr->bdef & ~p->nlive)) & REGS; ! 1309: /* current registers killed by block */ ! 1310: ! 1311: if (p == b->firstn) /* stop if reached first node */ ! 1312: break; ! 1313: } ! 1314: ! 1315: } ! 1316: ! 1317: /* Propagate live/dead data throughout the flow graph, using Aho and ! 1318: ** Ullman algorithm. ! 1319: */ ! 1320: ! 1321: do ! 1322: { ! 1323: changed = false; /* will continue until no changes */ ! 1324: ! 1325: for (ALLB(b,b0.next)) ! 1326: { ! 1327: LDREG in, out; ! 1328: ! 1329: if (b->nextr == NULL && (b->nextl == NULL || ! 1330: (isbr(b->lastn) && !isuncbr(b->lastn)))) ! 1331: { ! 1332: /* This case represents a return, or an unconditional indexed ! 1333: ** jump, or a switch. If we had better connectivity in the ! 1334: ** flow graph, we could trace all successors correctly. As ! 1335: ** things are, we have to assume the worst about what registers ! 1336: ** are live going into the next block. For a return, this means ! 1337: ** those registers that can be used to return a value. For ! 1338: ** others, we mark all registers live. ! 1339: */ ! 1340: out = isret(b->lastn) ? RETREG : REGS; ! 1341: } ! 1342: else ! 1343: { ! 1344: /* OUT = union (of successors) IN */ ! 1345: out = 0; /* registers out of current block. */ ! 1346: if (b->nextr != NULL) ! 1347: out |= lddata[b->nextr->index].bin; ! 1348: if (b->nextl != NULL) ! 1349: out |= lddata[b->nextl->index].bin; ! 1350: } ! 1351: ! 1352: ldptr = lddata + b->index; /* point at data for current block */ ! 1353: /* IN = OUT - DEF u USE */ ! 1354: in = (out & ~ldptr->bdef) | ldptr->buses; ! 1355: ! 1356: /* see what changed */ ! 1357: ! 1358: if (in != ldptr->bin || out != ldptr->bout) ! 1359: { ! 1360: changed = true; ! 1361: ldptr->bin = in; /* set changed values */ ! 1362: ldptr->bout = out; ! 1363: } ! 1364: } /* end for */ ! 1365: } while (changed); ! 1366: ! 1367: /* Now set the final live/dead (really, just live) information in ! 1368: ** each node of each block. ! 1369: */ ! 1370: ! 1371: for (ALLB(b,b0.next)) ! 1372: { ! 1373: /* go backward again through each block */ ! 1374: /* initial live is outgoing regs of block */ ! 1375: ! 1376: LDREG live = lddata[b->index].bout; ! 1377: for (p = b->lastn; !islabel(p); p = p->back) ! 1378: { ! 1379: LDREG newlive = (p->nlive | (live & ~p->ndead)) & REGS; ! 1380: p->nlive = live; /* live for this node is what was ! 1381: ** live going into successor ! 1382: */ ! 1383: live = newlive; /* live for next node is whatever ! 1384: ** else we used, but didn't kill ! 1385: */ ! 1386: if (p == b->firstn) ! 1387: break; /* quit if first node in block */ ! 1388: } ! 1389: } ! 1390: ! 1391: xfree((char *) lddata); /* free up temp. storage */ ! 1392: } ! 1393: ! 1394: #endif /* def LIVEDEAD */ ! 1395: ! 1396: #ifdef PEEPHOLE ! 1397: static NODE *pf; /* pointer to first window node */ ! 1398: static NODE *opf; /* pointer to predecessor of first window node */ ! 1399: static int wsize; /* window size for peephole trace */ ! 1400: ! 1401: window(size, func) register int size; boolean (*func)(); { /* peephole scan */ ! 1402: ! 1403: extern NODE *initw(); ! 1404: register NODE *pl; ! 1405: register int i; ! 1406: ! 1407: TRACE(window); ! 1408: ! 1409: /* find first window */ ! 1410: ! 1411: wsize = size; ! 1412: if ((pl = initw(n0.forw)) == NULL) ! 1413: return; ! 1414: ! 1415: /* move window through code */ ! 1416: ! 1417: for (opf = pf->back; ; opf = pf->back) { ! 1418: if ((*func)(pf, pl) == true) { ! 1419: if (wflag) ! 1420: if (opf->forw == pl->forw) ! 1421: PRINTF("%cdeleted\n", CC); ! 1422: else { ! 1423: PRINTF("%cchanged to:\n", CC); ! 1424: prwindow(opf->forw, size); ! 1425: } ! 1426: if (size > 1) { ! 1427: ! 1428: /* move window back in case ! 1429: there is an overlapping improvement */ ! 1430: ! 1431: for (i = 2; i <= size; i++) ! 1432: if ((opf = opf->back) == &n0) { ! 1433: opf = n0.forw; ! 1434: break; ! 1435: } ! 1436: if ((pl = initw(opf)) == NULL) ! 1437: return; ! 1438: continue; ! 1439: } ! 1440: } ! 1441: ! 1442: /* move window ahead */ ! 1443: ! 1444: if ((pl = pl->forw) == &ntail) ! 1445: return; ! 1446: pf = pf->forw; ! 1447: if (islabel(pl) && (pl = initw(pl->forw)) == NULL) ! 1448: return; ! 1449: } ! 1450: } ! 1451: ! 1452: static NODE * ! 1453: initw(p) register NODE *p; { /* find first available window */ ! 1454: ! 1455: register int i; ! 1456: ! 1457: if ((pf = p) == NULL) ! 1458: return (NULL); ! 1459: ! 1460: /* move p down until window is large enough */ ! 1461: ! 1462: for (i = 1; i <= wsize; i++) { ! 1463: if (p == &ntail) /* no more windows */ ! 1464: return (NULL); ! 1465: if (islabel(p)) { /* restart scan */ ! 1466: pf = p->forw; ! 1467: i = 0; ! 1468: } ! 1469: p = p->forw; ! 1470: } ! 1471: return (p->back); ! 1472: } ! 1473: ! 1474: wchange() { /* print window before change */ ! 1475: ! 1476: if (wflag) { ! 1477: PRINTF("%cwindow:\n", CC); ! 1478: prwindow(opf->forw, wsize); ! 1479: } ! 1480: } ! 1481: ! 1482: static ! 1483: prwindow(p, size) /* print "size" instructions starting at p */ ! 1484: register NODE *p; register int size; { ! 1485: ! 1486: for ( ; --size >= 0 && p != &ntail && !islabel(p); p = p->forw) { ! 1487: PUTCHAR(CC); ! 1488: #ifdef LIVEDEAD ! 1489: PRINTF("(live: 0x%X)", p->nlive); ! 1490: #endif ! 1491: prinst(p); ! 1492: } ! 1493: } ! 1494: #endif ! 1495: ! 1496: static void ! 1497: mkltbl() { /* make label table with only definitions */ ! 1498: ! 1499: register BLOCK *b; ! 1500: register NODE *p; ! 1501: ! 1502: clrltbl(); ! 1503: ! 1504: /* add definitions from labels in text section */ ! 1505: ! 1506: for (ALLB(b, b0.next)) ! 1507: for (p = b->firstn; islabel(p); p = p->forw) ! 1508: ADDLBL(p->ops[0], b); ! 1509: } ! 1510: ! 1511: static ! 1512: clrltbl() { /* clear label table */ ! 1513: ! 1514: CLEAR(Lbltbl, N_LBLS * sizeof(LBL)); ! 1515: Numlbls = 0; ! 1516: } ! 1517: ! 1518: static BLOCK * ! 1519: lblhash(l, b) register char *l; BLOCK *b; { /* add or find label in label table */ ! 1520: ! 1521: register LBL *p; ! 1522: register int lh = 0, c; ! 1523: register char *ll = l; ! 1524: ! 1525: while ((c = *ll++) != '\0') ! 1526: lh += c; ! 1527: /* ! 1528: * The precheck on the third character avoids many superfluous ! 1529: * calls to strcmp when the hash table is fairly full. The third ! 1530: * character is chosen because most compilers generate labels ! 1531: * with an invariant two-character prefix. In a later version, ! 1532: * perhaps labels should be converted at the machine-dependent ! 1533: * level into unique integers instead of being stored as strings. ! 1534: */ ! 1535: for (p = Lbltbl + lh % N_LBLS; p->cp != NULL && ! 1536: (l[2] != p->cp[2] && l[1] != '\0' || strcmp(p->cp, l)); ) ! 1537: if ((p -= H_INCR) < Lbltbl) ! 1538: p += N_LBLS; ! 1539: if (b != NULL) { /* enter or overwrite the block entry */ ! 1540: if (p->bl == NULL && ++Numlbls >= N_LBLS) ! 1541: FATAL("too many labels\n"); ! 1542: p->cp = l; ! 1543: p->bl = b; ! 1544: } ! 1545: return (p->bl); ! 1546: } ! 1547: ! 1548: char * ! 1549: getspace(n) register unsigned n; { /* return a pointer to "n" bytes */ ! 1550: ! 1551: register char *p = Lasta; ! 1552: ! 1553: /* round up so pointers are always word-aligned */ ! 1554: /* int conversions are to avoid call to software remaindering */ ! 1555: ! 1556: n += sizeof(char *) - ((int) n % (int) sizeof(char *)); ! 1557: Maxu += n; ! 1558: while ((Lasta += n) >= Lastx) { ! 1559: *Space = NEWBLK(1, struct space_t); ! 1560: p = Lasta = (char *) &(*Space)->space[0]; ! 1561: Lastx = (char *) &(*Space)->space[NSPACE - 1]; ! 1562: (*Space)->next = NULL; ! 1563: Space = &(*Space)->next; ! 1564: } ! 1565: return (p); ! 1566: } ! 1567: /* Branch shortening ! 1568: ** ! 1569: ** This code shortens span-dependent branches with assistance from ! 1570: ** machine dependent routines. The interface is as follows: ! 1571: ** ! 1572: ** bspan(flag) is the entry point available to machine- ! 1573: ** dependent routines; the flag is true to print ! 1574: ** debugging information ! 1575: ** ! 1576: ** BSHORTEN symbol, defined in "defs"; enables all this ! 1577: ** ! 1578: ** int instsize(node) ! 1579: ** routine or macro; returns upper bound on size of ! 1580: ** instruction in node in arbitrary units ! 1581: ** void bshorten(node,dist) ! 1582: ** routine or macro; changes op at node to be ! 1583: ** shortened version of branch, based on (long) ! 1584: ** distance (dist) between branch and target ! 1585: ** ! 1586: ** The algorithm proceeds in two passes over the blocks of the program. ! 1587: ** The first pass calculates the relative PC (program counter) value for ! 1588: ** the beginning of each block. (Remember, labels are always at the ! 1589: ** beginning of a block.) Since branches are always at the end of blocks, ! 1590: ** the assumption is that the machine's program counter register always ! 1591: ** points to the beginning of the block following the branch when the ! 1592: ** branch is executed. (This assumption for the purpose of calculating ! 1593: ** distances.) Branches are assumed to be shortenable both forward and ! 1594: ** backward. ! 1595: ** ! 1596: ** The PC values for the blocks are kept in a dynamically allocated ! 1597: ** array. The array is size idx+2, where idx is the highest block ! 1598: ** number. The +2 accounts for not using array[0] (we index into ! 1599: ** the array by block index numbers which are non-zero) and for one ! 1600: ** additional entry at the end to contain the PC just after the ! 1601: ** last block. ! 1602: ** ! 1603: ** Pass two calculates distances between branches and their targets ! 1604: ** and shortens branches which can be shortened. ! 1605: */ ! 1606: ! 1607: #ifdef BSHORTEN ! 1608: ! 1609: void ! 1610: bspan(flag) /* shorten span-dependent branches */ ! 1611: boolean flag; /* true to print debug info. */ ! 1612: { ! 1613: long * bpc; /* point to array of PC's */ ! 1614: register BLOCK * block; /* block pointer */ ! 1615: register NODE * node; /* pointer for scanning block's nodes */ ! 1616: BLOCK * target; /* branch target block */ ! 1617: char * label; /* branch label string */ ! 1618: long pc; /* current PC */ ! 1619: long pcdiff; /* PC difference, branch to target */ ! 1620: extern int instsize(); /* returns size of instruction */ ! 1621: ! 1622: bldgr(false); /* build flow graph */ ! 1623: /* allocate array for block start PC's */ ! 1624: ! 1625: bpc = (long *) xalloc( sizeof(long) * (idx+2)); ! 1626: pc = 0; /* current PC */ ! 1627: ! 1628: /* make first pass to compute PC at start of each block */ ! 1629: ! 1630: if (flag) ! 1631: PRINTF("%c Block starting PC:\n", CC); ! 1632: ! 1633: for ( ALLB(block, b0.next) ) ! 1634: { ! 1635: if (flag) ! 1636: PRINTF("%c\t%d\t%d\n", CC, block->index, pc); ! 1637: ! 1638: bpc[block->index] = pc; /* current PC is block start PC */ ! 1639: for (node = block->firstn ; ; node = node->forw) ! 1640: { ! 1641: pc += instsize(node); /* increase PC by instruction size */ ! 1642: if (node == block->lastn) ! 1643: break; /* done this block at last inst. */ ! 1644: } ! 1645: } ! 1646: bpc[idx+1] = pc; /* set PC of non-existent next block */ ! 1647: if (flag) ! 1648: PRINTF("%c\t(last)\t%d\n", CC, pc); ! 1649: /* Pass 2. Try to shorten branches. */ ! 1650: ! 1651: for ( ALLB(block, b0.next) ) ! 1652: { ! 1653: if (isbr(block->lastn) && (label = getp(block->lastn)) != NULL) ! 1654: { ! 1655: /* Beware of non-existent target for branch */ ! 1656: ! 1657: if((target = FINDLBL(label)) == NULL) ! 1658: pcdiff = ~((unsigned long) 0) >> 1; /* maximum offset */ ! 1659: else ! 1660: pcdiff = bpc[target->index] /* target PC */ ! 1661: - bpc[block->index + 1]; ! 1662: /* branch PC (PC of next block */ ! 1663: ! 1664: /* shorten branch if branch-to-target distance short enough */ ! 1665: ! 1666: if (flag) ! 1667: { ! 1668: PRINTF("%c Difference: %d -- Shorten:\t", CC, pcdiff); ! 1669: prinst(block->lastn); ! 1670: } ! 1671: bshorten(block->lastn,pcdiff); ! 1672: } ! 1673: } ! 1674: xfree((char *) bpc); /* free up array */ ! 1675: return; ! 1676: } ! 1677: ! 1678: #endif /* def BSHORTEN */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.