Annotation of researchv9/jerq/sgs/optim/optim.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.