Annotation of researchv9/cmd/sun/c2/coalesce.c, revision 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.