Annotation of researchv9/cmd/sun/c2/coalesce.c, revision 1.1.1.1

1.1       root        1: 
                      2: #ifndef lint
                      3: static char sccsid[] = "@(#)coalesce.c 1.1 86/02/03 Copyr 1985 Sun Micro";
                      4: #endif
                      5: 
                      6: /*
                      7:  * Copyright (c) 1985 by Sun Microsystems, Inc.
                      8:  */
                      9: 
                     10: #include "as.h"
                     11: #include "c2.h"
                     12: 
                     13: extern struct oper *newoperand();
                     14: extern struct ins_bkt *moveq;
                     15: 
                     16: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); }
                     17: #define nexti( p ) { do p=p->forw; while( ISDIRECTIVE(p->op) ); }
                     18: 
                     19: #define ispushop(o) ((o)->type_o == T_PREDEC && (o)->value_o == SPREG)
                     20: #define ispopop(o) ((o)->type_o == T_POSTINC && (o)->value_o == SPREG)
                     21: 
                     22: extern int bytesize[];
                     23: #define BYTESIZE( s ) (bytesize[ (int)(s)])
                     24: 
                     25: /*
                     26:  * Can register r1 be replaced by a new register r2?
                     27:  * The answer is yes, provided that:
                     28:  *     1. all uses of r1 in (p) are explicit
                     29:  *     2. r1 and r2 are of the same type (a-reg, d-reg, or fp-reg)
                     30:  * Certain exceptions to rule 2 are permissible if both r1 and r2 are
                     31:  * a-regs or d-regs.
                     32:  */
                     33: int
                     34: can_replace(p, r1, r2)
                     35:     register NODE *p;
                     36:     register r1,r2;
                     37: {
                     38:     register struct oper *o;
                     39:     register i;
                     40:     int r1_found;
                     41: 
                     42:     /* search for explicit uses of r1 */
                     43:     r1_found = 0;
                     44:     for (i = 0; i < p->nref; i++) {
                     45:        o = p->ref[i];
                     46:        switch(o->type_o) {
                     47:        case T_REG:
                     48:            if (o->value_o == r1) {
                     49:                r1_found++;
                     50:                if ((p->op == OP_MOVE || p->op == OP_ADD || p->op == OP_SUB)
                     51:                  && p->subop == SUBOP_L
                     52:                  && !inmask(CCREG, p->forw->rlive)
                     53:                  && !inmask(FPCCREG, p->forw->rlive)) {
                     54:                    int ok;
                     55:                    o->value_o = r2;
                     56:                    ok = operand_ok(p->instr, p->ref[0], p->ref[1], 0);
                     57:                    o->value_o = r1;
                     58:                    if (ok) continue;
                     59:                }
                     60:                if (reg_access[r1] == reg_access[r2]) {
                     61:                    continue;
                     62:                }
                     63:                return 0;
                     64:            }
                     65:            continue;
                     66:        case T_DEFER:
                     67:        case T_POSTINC:
                     68:        case T_PREDEC:
                     69:            if (o->value_o == r1) {
                     70:                return 0;
                     71:            }
                     72:            continue;
                     73:        case T_DISPL:
                     74:            if (o->reg_o == r1) {
                     75:                return 0;
                     76:            }
                     77:            continue;
                     78:        case T_INDEX:
                     79:            if (o->reg_o == r1) {
                     80:                return 0;
                     81:            }
                     82:            if (o->value_o == r1) {
                     83:                /* a-regs and d-regs can be used interchangeably here */
                     84:                r1_found++;
                     85:            }
                     86:            continue;
                     87:        case T_REGPAIR:
                     88:            if (o->reg_o == r1 || o->value_o == r1) {
                     89:                return 0;
                     90:            }
                     91:            continue;
                     92:        }
                     93:        if (o->flags_o&O_BFLD) {
                     94:            if (o->flags_o&O_BFOREG && o->bfoffset_o == r1) {
                     95:                return 0;
                     96:            }
                     97:            if (o->flags_o&O_BFWREG && o->bfwidth_o == r1) {
                     98:                return 0;
                     99:            }
                    100:        }
                    101:     }
                    102:     /*
                    103:      * we know that r1 is used or set by p,
                    104:      * but if r1_found == 0, we haven't found an
                    105:      * explicit use.  In this case we should bail out.
                    106:      */
                    107:     return(r1_found);
                    108: }
                    109: 
                    110: void
                    111: replace(p, r1, r2)
                    112:     register NODE *p;
                    113:     register r1, r2;
                    114: {
                    115:     register struct oper *o;
                    116:     register i;
                    117: 
                    118:     /* search for explicit uses of r1 */
                    119:     for (i = 0; i < p->nref; i++) {
                    120:        o = p->ref[i];
                    121:        switch(o->type_o) {
                    122:        case T_REG:
                    123:        case T_DEFER:
                    124:        case T_POSTINC:
                    125:        case T_PREDEC:
                    126:            if (o->value_o == r1) {
                    127:                o->value_o = r2;
                    128:            }
                    129:            continue;
                    130:        case T_DISPL:
                    131:            if (o->reg_o == r1) {
                    132:                o->reg_o = r2;
                    133:            }
                    134:            continue;
                    135:        case T_INDEX:
                    136:        case T_REGPAIR:
                    137:            if (o->reg_o == r1) {
                    138:                o->reg_o = r2;
                    139:            }
                    140:            if (o->value_o == r1) {
                    141:                o->value_o = r2;
                    142:            }
                    143:            continue;
                    144:        }
                    145:        if (o->flags_o&O_BFLD) {
                    146:            if (o->flags_o&O_BFOREG && o->bfoffset_o == r1) {
                    147:                o->bfoffset_o = r2;
                    148:            }
                    149:            if (o->flags_o&O_BFWREG && o->bfwidth_o == r1) {
                    150:                o->bfwidth_o = r2;
                    151:            }
                    152:            continue;
                    153:        } /* if */
                    154:     } /* for */
                    155:     installinstruct(p, p->instr);
                    156: } /* replace */
                    157: 
                    158: int
                    159: next_member(regtype, regset)
                    160:     int regtype;
                    161:     regmask regset;
                    162: {
                    163:     register regno;
                    164: 
                    165:     switch(regtype) {
                    166:     case AM_DREG:
                    167:        /* try for d-reg first */
                    168:        for(regno = D0REG; regno <= D7REG; regno++) {
                    169:            if (inmask(regno,regset))
                    170:                return(regno);
                    171:        }
                    172:        for(regno = A0REG; regno < A6REG; regno++) {
                    173:            if (inmask(regno,regset))
                    174:                return(regno);
                    175:        }
                    176:        break;
                    177:     case AM_AREG:
                    178:        /* try for a-reg first */
                    179:        for(regno = A0REG; regno < A6REG; regno++) {
                    180:            if (inmask(regno,regset))
                    181:                return(regno);
                    182:        }
                    183:        for(regno = D0REG; regno <= D7REG; regno++) {
                    184:            if (inmask(regno,regset))
                    185:                return(regno);
                    186:        }
                    187:        break;
                    188:     case AM_FREG:
                    189:        /* only another fp-reg will do */
                    190:        for(regno = FP0REG; regno <= FP7REG; regno++) {
                    191:            if (inmask(regno,regset))
                    192:                return(regno);
                    193:        }
                    194:        break;
                    195:     }
                    196:     return(-1);
                    197: }
                    198: 
                    199: /*
                    200:  * look for a register that is not live anywhere in (b)..(n).
                    201:  * regtype is the type of register preferred (or required,
                    202:  * in the case of a floating point register). Returns -1 if
                    203:  * no suitable register is found.
                    204:  */
                    205: int
                    206: find_freereg(b, n, regtype)
                    207:     register NODE *b, *n;
                    208:     int regtype;
                    209: {
                    210:     register NODE *p,*bb;
                    211:     regmask liveset;
                    212:     register regno;
                    213: 
                    214:     bb = b->back;
                    215:     liveset = n->rlive;
                    216:     for (p = n; p != bb; p = p->back) {
                    217:        liveset = addmask(liveset, p->rlive);
                    218:     }
                    219:     liveset = addmask(liveset, p->rlive);
                    220:     return(next_member(regtype, notmask(liveset)));
                    221: }
                    222: 
                    223: /*
                    224:  * try to replace register r1 with register r2 in the
                    225:  * set of nodes (b)..(n) (assumed to be a basic block).
                    226:  * r2 is assumed to be available in (b)..(n).
                    227:  * Returns 1 if the new assignment succeeds.
                    228:  * Otherwise returns 0 and leaves (b)..(n) unchanged.
                    229:  */
                    230: int
                    231: can_reassign_reg(b,n,r1,r2)
                    232:     register NODE *b,*n;
                    233:     register r1;
                    234:     register r2;
                    235: {
                    236:     register NODE *p,*bb;
                    237:     regmask l;
                    238: 
                    239:     if (!inmask(r1, b->rlive) && !inmask(r1, n->forw->rlive)) {
                    240:        /* r1 and r2 must have the same type or must both be a/d regs */
                    241:        if (reg_access[r1] != reg_access[r2]
                    242:          && (!dareg(r1) || !dareg(r2))) {
                    243:            return(0);
                    244:        }
                    245:        /* (b)..(n) contains the lifetime of r1 */
                    246:        bb = b->back;
                    247:        for (p = n; p != bb; p = p->back) {
                    248:            if (ISINSTRUC(p->op)) {
                    249:                if ((inmask(r1, p->ruse) || inmask(r1, p->rset))
                    250:                  && !can_replace(p, r1, r2)) {
                    251:                    return(0);
                    252:                }
                    253:            }
                    254:        }
                    255:        return(1);
                    256:     }
                    257:     return(0);
                    258: } /* can_reassign_reg */
                    259: 
                    260: void
                    261: reassign_reg(b,n,r1,r2)
                    262:     register NODE *b,*n;
                    263:     register r1;
                    264:     register r2;
                    265: {
                    266:     register NODE *p,*bb;
                    267:     regmask l;
                    268: 
                    269:     l = n->forw->rlive;
                    270:     bb = b->back;
                    271:     for (p = n; p != bb; p = p->back) {
                    272:        if (ISINSTRUC(p->op)
                    273:          && (inmask(r1, p->ruse) || inmask(r1, p->rset)))
                    274:            replace(p, r1, r2);
                    275:        l = p->rlive = compute_normal(p, l);
                    276:     }
                    277: }
                    278: 
                    279: 
                    280: static struct ins_bkt *
                    281: move_inst(b,n,x,y)
                    282:     register NODE *b, *n;
                    283:     register struct oper *x, *y;
                    284: {
                    285:     if (operand_ok(b->instr, x, y, 0)) {
                    286:        return(b->instr);
                    287:     } else if (operand_ok(n->instr, x, y, 0)) {
                    288:        return(n->instr);
                    289:     } else {
                    290:        /* try special cases involving floating point */
                    291:        int Xisfp, Yisfp;
                    292:        Xisfp = Yisfp = 0;
                    293:        if (x->type_o==T_REG && freg(x->value_o))
                    294:            Xisfp = 1;
                    295:        if (y->type_o==T_REG && freg(y->value_o))
                    296:            Yisfp = 1;
                    297:        if (!Xisfp && !Yisfp
                    298:          && !inmask(FPCCREG, n->forw->rlive)) {
                    299:            /* rewrite as (b) mov{b,w,l} X,Y */
                    300:            switch(b->subop) {
                    301:            case SUBOP_B:
                    302:                return(sopcode("movb"));
                    303:            case SUBOP_W:
                    304:                return(sopcode("movw"));
                    305:            case SUBOP_L:
                    306:            case SUBOP_S:
                    307:                return(sopcode("movl"));
                    308:            default:
                    309:                /* if larger than a word, forget it */
                    310:                return(NULL);
                    311:            }
                    312:        } else if (Xisfp && Yisfp) {
                    313:            /* floating point reg-reg move */
                    314:            return(sopcode("fmovex"));
                    315:        }
                    316:     }
                    317:     return(NULL);
                    318: }
                    319: 
                    320: /*
                    321:  * Is this instruction a reg-reg operation ?
                    322:  * To be safe, we require the instruction to use all of
                    323:  * both registers, with no data conversions.
                    324:  */
                    325: static int
                    326: reg_reg_op(p)
                    327:     register NODE *p;
                    328: {
                    329:     register struct oper *rm, *rn;
                    330: 
                    331:     if (p->nref == 2) {
                    332:        rm = p->ref[0]; rn = p->ref[1];
                    333:        if(rm != NULL && rm->type_o == T_REG && datareg(rm->value_o)
                    334:          && rn != NULL && rn->type_o == T_REG && datareg(rn->value_o)) {
                    335:            switch (p->subop) {
                    336:            case SUBOP_L:
                    337:                return(dareg(rm->value_o) && dareg(rn->value_o));
                    338:            case SUBOP_X:
                    339:                return(freg(rm->value_o) && freg(rn->value_o));
                    340:            }
                    341:        }
                    342:     }
                    343:     return(0);
                    344: }
                    345: 
                    346: static int
                    347: iscommuteop(p)
                    348:     NODE *p;
                    349: {
                    350:     char *s;
                    351: 
                    352:     switch(p->op){
                    353:     case OP_ADD:
                    354:     case OP_AND:
                    355:     case OP_OR:
                    356:     case OP_EOR:
                    357:        return(reg_reg_op(p));
                    358:     case OP_OTHER:
                    359:        /*
                    360:         * careful: multiplication isn't really commutative
                    361:         * unless it is also known to be reg-reg
                    362:         */
                    363:        s = p->instr->text_i;
                    364:        if (!strcmp(s,"mulsl") || !strcmp(s,"mulul")
                    365:          || !strcmp(s,"fmulx") || !strcmp(s, "faddx"))
                    366:            return(reg_reg_op(p));
                    367:     }
                    368:     return(0);
                    369: }
                    370: 
                    371: /*
                    372:  * returns 1 if an instruction does implied data conversion
                    373:  * to match its destination operand (assumed to be the last operand).
                    374:  * In the 68xxx processors this occurs in cases involving address
                    375:  * registers or floating point registers.
                    376:  */
                    377: int
                    378: implied_conversion(p)
                    379:     register NODE *p;
                    380: {
                    381:     struct oper *o;
                    382: 
                    383:     if (p->nref > 0) {
                    384:        o = p->ref[p->nref-1];
                    385:        if (datareg_addr(o)) {
                    386:            if (areg(o->value_o)) return (p->subop != SUBOP_L);
                    387:            if (freg(o->value_o)) return (p->subop != SUBOP_X);
                    388:        }
                    389:     }
                    390:     return 0;
                    391: }
                    392: 
                    393: /*
                    394:  * coalesce register usage over subranges of a basic block,
                    395:  * eliminating unnecessary reg-reg moves.
                    396:  */
                    397: int
                    398: coalesce()
                    399: {
                    400:     register NODE *n;
                    401:     register NODE *p,*b;
                    402:     register struct oper *o;
                    403:     register struct ins_bkt *ip;
                    404:     struct oper *rm, *rn;
                    405:     NODE *q;
                    406:     register int regno;
                    407:     extern NODE *deletenode();
                    408:     int changes;
                    409:     regmask l;
                    410: 
                    411:     changes = 0;
                    412:     for (n=first.forw; n != &first; n=n->forw) {
                    413: 
                    414:        /*
                    415:         * Pattern #1: given
                    416:         *      (b) move X,rn
                    417:         *          ....
                    418:         *      (n) move rn,Y
                    419:         *
                    420:         * rewrite #1: if possible, rewrite as:
                    421:         *      (b) move X,Y
                    422:         *          ....
                    423:         *      (n) (deleted)
                    424:         *
                    425:         * rewrite #2: if possible, rewrite as:
                    426:         *      (b) (deleted)
                    427:         *          ....
                    428:         *      (n) move X,Y
                    429:         *
                    430:         * requirements:
                    431:         *      -- (b) and (n) must be moves of the same type
                    432:         *      -- (n) must not do sign-extension or other data conversion
                    433:         *      -- X must not be an immediate operand.
                    434:         *      -- Y must be a legal replacement for rn in (b).
                    435:         *      -- neither X nor Y can be a control register or i/o device
                    436:         *      -- rn must not be live at (n).
                    437:         *      -- rn must be neither used nor set in the interim.
                    438:         *      -- side effects of X and Y must not be used in the interim.
                    439:         *      -- condition codes should not be live at either (b) or (n).
                    440:         *
                    441:         * for #1:
                    442:         *      -- Y must not be used or modified in the interim.
                    443:         *
                    444:         * for #2:
                    445:         *      -- X must not be modified in the interim.
                    446:         */
                    447:        o = n->ref[0];
                    448:        if (n->op == OP_MOVE && o->type_o == T_REG && datareg(o->value_o)
                    449:          && !implied_conversion(n)
                    450:          && !inmask(o->value_o, n->forw->rlive)) {
                    451:            struct oper *x, *y;
                    452:            x = y = NULL;
                    453:            regno = o->value_o;
                    454:            b = n;
                    455:            do {
                    456:                previ(b);
                    457:                if (b->op == OP_FIRST || b->op == OP_LABEL
                    458:                  || ISBRANCH(b->op)) {
                    459:                    /* flow of control to reach this point is unknown */
                    460:                    break;
                    461:                }
                    462:                if (b->op == OP_MOVE && b->subop == n->subop
                    463:                  && b->ref[1]->type_o == T_REG
                    464:                  && b->ref[1]->value_o == o->value_o) {
                    465:                    /* have move x,rn;...;move rn,y */
                    466:                    x = b->ref[0];
                    467:                    y = n->ref[1];
                    468:                    /* do checks on x,y */
                    469:                    if (x->type_o == T_IMMED 
                    470:                      || x->type_o == T_REG && !datareg(x->value_o)
                    471:                      || y->type_o == T_REG && !datareg(y->value_o)
                    472:                      || inmask(CCREG, b->forw->rlive)
                    473:                      || inmask(CCREG, n->forw->rlive)
                    474:                      || inmask(FPCCREG, b->forw->rlive)
                    475:                      || inmask(FPCCREG, n->forw->rlive)) {
                    476:                        /* can't optimize */
                    477:                        x = y = NULL;
                    478:                    }
                    479:                    break;
                    480:                }
                    481:                if (inmask(regno,b->rset) || inmask(regno,b->ruse)) {
                    482:                    /* unknown use/modification of regno */
                    483:                    break;
                    484:                }
                    485:            } while (1);
                    486:            /*
                    487:             * if the preceding search yielded a suitable operand
                    488:             * pair, try to delete either node (b) or node (n).
                    489:             */
                    490:            if (y != NULL) {
                    491:                int can_move_x = (x->type_o == T_REG || cancache(x));
                    492:                int can_move_y = (y->type_o == T_REG || cancache(y));
                    493:                /* determine side effects of (n) other than defining Y */
                    494:                if (y->type_o == T_REG) {
                    495:                    l = submask(n->rset, MAKEWMASK(y->value_o, BW|WW|LW));
                    496:                } else {
                    497:                    l = n->rset;
                    498:                }
                    499:                if (emptymask(andmask(l, n->forw->rlive))) {
                    500:                    /*
                    501:                     * search for defs/uses of Y and defs affecting access to Y;
                    502:                     * if none are found, move def of Y back to node (b).
                    503:                     */
                    504:                    p = n;
                    505:                    previ(p);
                    506:                    while (p != b) {
                    507:                        if (may_touch(p, y, n->subop, RMASK|WMASK)) {
                    508:                            can_move_y = 0;
                    509:                            break;
                    510:                        }
                    511:                        if (!emptymask(andmask(n->ruse, p->rset))) {
                    512:                            /* try salvaging by reassigning registers */
                    513:                            int r1, r2;
                    514:                            if (p->op != OP_MOVE
                    515:                              || p->ref[1]->type_o != T_REG ) {
                    516:                                /* def is implicit; give up */
                    517:                                can_move_y = 0;
                    518:                                break;
                    519:                            }
                    520:                            r1 = p->ref[1]->value_o;
                    521:                            r2 = find_freereg(p, n, reg_access[r1]);
                    522:                            if (r2 == -1 || !can_reassign_reg(p, n, r1, r2)) {
                    523:                                can_move_y = 0;
                    524:                                break;
                    525:                            }
                    526:                            reassign_reg(p, n, r1, r2);
                    527:                        }
                    528:                        previ(p);
                    529:                    }
                    530:                    if (can_move_y && (ip = move_inst(b, n, x, y)) != NULL) {
                    531:                        /* rewrite */
                    532:                        freeoperand(b->ref[1]);
                    533:                        b->ref[1] = newoperand(y);
                    534:                        installinstruct(b, ip);
                    535:                        n = deletenode(n);
                    536:                        changes++;
                    537:                        meter.redunm++;
                    538:                        if (ispopop(x) && ispushop(y)) {
                    539:                            b = deletenode(b);
                    540:                            changes++;
                    541:                            meter.redunm++;
                    542:                        }
                    543:                        l = n->forw->rlive;
                    544:                        for (p = n; p != b; p = p->back) {
                    545:                            l = p->rlive = compute_normal(p, l);
                    546:                        }
                    547:                        continue;
                    548:                    } /* if can_move_y */
                    549:                } /* if */
                    550:                /*
                    551:                 * search for defs of X and defs affecting access to X;
                    552:                 * if none are found, move use of X forward to node (n).
                    553:                 */
                    554:                p = n;
                    555:                previ(p);
                    556:                while (p != b) {
                    557:                    if (may_touch(p, x, n->subop, WMASK)) {
                    558:                        can_move_x = 0;
                    559:                        break;
                    560:                    }
                    561:                    if (!emptymask(andmask(b->ruse, p->rset))) {
                    562:                        /* try salvaging by reassigning registers */
                    563:                        int r1, r2;
                    564:                        if (p->op != OP_MOVE
                    565:                          || p->ref[1]->type_o != T_REG ) {
                    566:                            /* def is implicit; give up */
                    567:                            can_move_x = 0;
                    568:                            break;
                    569:                        }
                    570:                        r1 = p->ref[1]->value_o;
                    571:                        r2 = find_freereg(p, n, reg_access[r1]);
                    572:                        if (r2 == -1 || !can_reassign_reg(p, n, r1, r2)) {
                    573:                            can_move_x = 0;
                    574:                            break;
                    575:                        }
                    576:                        reassign_reg(p, n, r1, r2);
                    577:                    }
                    578:                    previ(p);
                    579:                }
                    580:                if (can_move_x && (ip = move_inst(b, n, x, y)) != NULL) {
                    581:                    /* rewrite */
                    582:                    freeoperand(n->ref[0]);
                    583:                    n->ref[0] = newoperand(x);
                    584:                    installinstruct(n, ip);
                    585:                    b = deletenode(b);
                    586:                    changes++;
                    587:                    meter.redunm++;
                    588:                    if (ispopop(x) && ispushop(y)) {
                    589:                        n = deletenode(n);
                    590:                        changes++;
                    591:                        meter.redunm++;
                    592:                    }
                    593:                    l = n->forw->rlive;
                    594:                    for (p = n; p != b; p = p->back) {
                    595:                        l = p->rlive = compute_normal(p, l);
                    596:                    }
                    597:                    continue;
                    598:                } /* if can_move_x */
                    599:            } /* y != NULL */
                    600:        } /* if */
                    601: 
                    602:        /*
                    603:         * Pattern #2: given
                    604:         *      (b) move X,rn
                    605:         *          ....
                    606:         *          (computations involving rn)
                    607:         *          ....
                    608:         *      (n) move rn,rm
                    609:         *
                    610:         * if possible, rewrite as:
                    611:         *      (b) move X,rm
                    612:         *          ....
                    613:         *          (all defs/uses of rn changed to def/use rm)
                    614:         *          ....
                    615:         *      (n) (deleted)
                    616:         *
                    617:         * requirements:
                    618:         *      -- rn must not be live at (n).
                    619:         *      -- condition codes should not be live at (n).
                    620:         *      -- rm must neither be used nor set in the interim.
                    621:         *      -- all defs/uses of rn in (b)..(n) must be replaceable with rm.
                    622:         */
                    623:        o = n->ref[0];
                    624:        if (n->op == OP_MOVE && reg_reg_op(n)
                    625:          && !inmask(CCREG, n->forw->rlive)
                    626:          && !inmask(FPCCREG, n->forw->rlive)
                    627:          && !inmask(o->value_o, n->forw->rlive)) {
                    628:            regno = n->ref[1]->value_o;
                    629:            b = n;
                    630:            do {
                    631:                previ(b);
                    632:                if (b->op == OP_FIRST || b->op == OP_LABEL
                    633:                  || ISBRANCH(b->op)) {
                    634:                    /* flow of control to reach this point is unknown */
                    635:                    break;
                    636:                }
                    637:                if (b->op == OP_MOVE && b->subop == n->subop
                    638:                  && sameops(o, b->ref[1])
                    639:                  && !inmask(regno, b->forw->rlive)) {
                    640:                    /* have move x,rn;...;move rn,rm */
                    641:                    if (can_reassign_reg(b, n, o->value_o, regno)) {
                    642:                        reassign_reg(b, n, o->value_o, regno);
                    643:                        b->ref[1]->value_o = regno;
                    644:                        n = deletenode(n);
                    645:                        changes++;
                    646:                        meter.redunm++;
                    647:                        l = n->forw->rlive;
                    648:                        for (p = n; p != b; p = p->back) {
                    649:                            l = p->rlive = compute_normal(p, l);
                    650:                        }
                    651:                    }
                    652:                    break;
                    653:                }
                    654:                if (inmask(regno,b->rset) || inmask(regno,b->ruse)) {
                    655:                    /* unknown use/modification of regno */
                    656:                    break;
                    657:                }
                    658:            } while (1);
                    659:        } /* if */
                    660: 
                    661:        /*
                    662:         * Pattern #3: (forward copy propagation)
                    663:         *      (n) move rm,rn  (rm is dead after (n))
                    664:         *          ....
                    665:         *          (computations involving rn)
                    666:         *          ....
                    667:         *      (p) lastuse(rn) (rn is dead after (p))
                    668:         *
                    669:         * if possible, rewrite as:
                    670:         *      (n) (deleted)
                    671:         *          ....
                    672:         *          (all defs/uses of rn changed to def/use rm)
                    673:         *          ....
                    674:         *      (p) lastuse(rm)
                    675:         *
                    676:         * requirements:
                    677:         *      -- the move at (n) must not involve data conversions.
                    678:         *      -- rm must not be live after (n).
                    679:         *      -- rn must not be live after (p).
                    680:         *      -- rm must neither be used nor set in the interim.
                    681:         *      -- condition codes must not be live after (n).
                    682:         *      -- if condition codes are live at (p), rm and rn must be
                    683:         *         of the same type.
                    684:         *      -- all defs/uses of rn in (n)..(p) must be replaceable with rm.
                    685:         */
                    686:        if (n->op == OP_MOVE && reg_reg_op(n)
                    687:          && !inmask(CCREG, n->forw->rlive)
                    688:          && !inmask(FPCCREG, n->forw->rlive)
                    689:          && !inmask(n->ref[0]->value_o, n->forw->rlive)) {
                    690:            rm = n->ref[0];
                    691:            rn = n->ref[1];
                    692:            regno = rn->value_o;
                    693:            p = n;
                    694:            do {
                    695:                /* scan forward for last use of value in rn */
                    696:                nexti(p);
                    697:                if (p->op == OP_FIRST || p->op == OP_LABEL
                    698:                  || ISBRANCH(p->op)) {
                    699:                    /* flow of control to reach this point is unknown */
                    700:                    break;
                    701:                }
                    702:                if (!inmask(regno, p->forw->rlive)) {
                    703:                    if (can_reassign_reg(n, p, regno, rm->value_o)) {
                    704:                        reassign_reg(n, p, regno, rm->value_o);
                    705:                        n = deletenode(n);
                    706:                        changes++;
                    707:                        meter.redunm++;
                    708:                        n->rlive = compute_normal(n, n->forw->rlive);
                    709:                    }
                    710:                    break;
                    711:                }
                    712:                if (inmask(rm->value_o,p->rset)||inmask(rm->value_o,p->ruse)) {
                    713:                    /* unknown use/modification of rm */
                    714:                    break;
                    715:                }
                    716:            } while(1);
                    717:        } /* if */
                    718: 
                    719:        /*
                    720:         * Pattern #4: (similar to #3, but exploits commutativity)
                    721:         *      (n) move rm,rn
                    722:         *      (q) <op> ro,rn  (ro is dead after (q))
                    723:         *          ....
                    724:         *          (computations involving rn)
                    725:         *          ....
                    726:         *      (p) lastuse(rn) (rn is dead after (p))
                    727:         *
                    728:         * if possible, rewrite as:
                    729:         *      (n) (deleted)
                    730:         *      (q) <op> rm,ro
                    731:         *          ....
                    732:         *          (all defs/uses of rn changed to def/use ro)
                    733:         *          ....
                    734:         *      (p) lastuse(ro)
                    735:         *
                    736:         * requirements:
                    737:         *      -- the move at (n) must not involve data conversions.
                    738:         *      -- <op> must be commutative
                    739:         *      -- ro must not be live after (q).
                    740:         *      -- condition codes must not be live after (q).
                    741:         *      -- if condition codes are live after (p), rn and ro
                    742:         *         must be registers of the same type.
                    743:         *      -- rn must not be live after (p).
                    744:         *      -- ro must neither be used nor set in the interim.
                    745:         *      -- all defs/uses of rn in (q)..(p) must be replaceable with ro.
                    746:         */
                    747:        if (n->op == OP_MOVE && reg_reg_op(n)) {
                    748:            rm = n->ref[0];
                    749:            rn = n->ref[1];
                    750:            q = n;
                    751:            nexti(q);
                    752:            if (iscommuteop(q)
                    753:              && sameops(rn, q->ref[1])
                    754:              && operand_ok(q->instr, rm, (o = q->ref[0]), 0)
                    755:              && !inmask(o->value_o, q->forw->rlive)
                    756:              && !inmask(CCREG, q->forw->rlive)
                    757:              && !inmask(FPCCREG, q->forw->rlive) ) {
                    758:                /*
                    759:                 * ro is dead, and its last use is in
                    760:                 * a commutative operator with rn.  Scan for
                    761:                 * the last use of the value in rn.
                    762:                 */
                    763:                regno = rn->value_o;
                    764:                p = q;
                    765:                do {
                    766:                    nexti(p);
                    767:                    if (p->op == OP_FIRST || p->op == OP_LABEL
                    768:                      || ISBRANCH(p->op)) {
                    769:                        /* flow of control to reach this point is unknown */
                    770:                        break;
                    771:                    }
                    772:                    if (!inmask(regno, p->forw->rlive)) {
                    773:                        if (can_reassign_reg(n, p, regno, o->value_o)) {
                    774:                            /*
                    775:                             * use rm as the first operand of q,
                    776:                             * propagate ro through the lifetime of rn,
                    777:                             * and delete the move from rm to rn.
                    778:                             */
                    779:                            q->ref[0] = newoperand(rm);
                    780:                            reassign_reg(n, p, regno, o->value_o);
                    781:                            freeoperand(o);
                    782:                            n = deletenode(n);
                    783:                            changes++;
                    784:                            meter.redunm++;
                    785:                            n->rlive = compute_normal(n, n->forw->rlive);
                    786:                        }
                    787:                        break;
                    788:                    } /* if */
                    789:                    if(inmask(o->value_o,p->ruse)||inmask(o->value_o,p->rset)) {
                    790:                        /* unknown use/def of ro */
                    791:                        break;
                    792:                    }
                    793:                } while (1);
                    794:            } /* if */
                    795:        } /* if */
                    796: 
                    797:     } /* for */
                    798:     return(changes);
                    799: }

unix.superglobalmegacorp.com

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