Annotation of researchv9/cmd/sun/c2/instruction.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char sccsid[] = "@(#)instruction.c 1.1 86/02/03 Copyr 1985 Sun Micro";
        !             3: #endif
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 1985 by Sun Microsystems, Inc.
        !             7:  */
        !             8: 
        !             9: #include "as.h"
        !            10: #include "c2.h"
        !            11: 
        !            12: extern char *malloc();
        !            13: struct oper *newoperand();
        !            14: struct oper  operands[OPERANDS_MAX];
        !            15: int numops;
        !            16: void new_csect(), save_stabs();
        !            17: 
        !            18: NODE first = { OP_FIRST, SUBOP_Z, &first, &first };
        !            19: 
        !            20: #define nexti( p ) { do p=p->forw; while( ISDIRECTIVE(p->op) ); }
        !            21: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); }
        !            22: 
        !            23: extern int bytesize[];
        !            24: #define BYTESIZE( s ) (bytesize[ (int)(s)])
        !            25: 
        !            26: /* does this branch read the c or v bit of the condition code? */
        !            27: char read_cc_cv[]={ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 };
        !            28: static struct ins_bkt * moveq = NULL;
        !            29: static err_code operand_error = E_NOERROR;
        !            30: 
        !            31: extern struct ins_bkt *tstw, *tstl;
        !            32: extern int ext_instruction_set;
        !            33: 
        !            34: static int
        !            35: numeric_immediate( op )
        !            36:     struct oper *op;
        !            37: {
        !            38:     if (op->type_o != T_IMMED || op->sym_o != NULL )
        !            39:        return 0;
        !            40:     return 1;
        !            41: }
        !            42: 
        !            43: static int
        !            44: immediate_value( op, value )
        !            45:     struct oper *op;
        !            46:     int value;
        !            47: {
        !            48:     if (op->type_o != T_IMMED || op->sym_o != NULL || op->flags_o&O_FLOAT || op->value_o != value)
        !            49:        return 0;
        !            50:     return 1;
        !            51: }
        !            52: 
        !            53: instruction( ip )
        !            54:     struct ins_bkt *ip;
        !            55: {
        !            56:     register NODE *np;
        !            57:     register i;
        !            58: 
        !            59:     if (ip->noper_i != numops && ip->noper_i <= OPERANDS_MAX){
        !            60:        /* shifts are a special case...*/
        !            61:        if ((ip->touchop_i&TOUCHMASK) == SPEC(2) || numops==1 || ip->subop_i==SUBOP_W)
        !            62:            i = 0;
        !            63:        else if ( (ip->touchop_i&TOUCH1(TOUCHMASK)) == TOUCH1(SPEC(7)) && numops==0 )
        !            64:            /* so is rts */
        !            65:            i = 0;
        !            66:        else
        !            67:            prog_error(E_NUMOPS);
        !            68:     }
        !            69:     if ( ISINSTRUC(ip->op_i) ){
        !            70:        if (cur_csect_name != C_TEXT){
        !            71:            /* non-text is not delt with -- echo it out directly */
        !            72:            putinstr( ip );
        !            73:            /* instruction in data space -- punt addressing      */
        !            74:            bc = 0x80000000; /* magic, negative number */
        !            75:            return;
        !            76:        }
        !            77:        switch (numops){
        !            78:        case 0: i = 1; break;
        !            79:        case 1: i = operand_ok( ip, &operands[0], (struct oper *)NULL, (struct oper *)NULL  ); break;
        !            80:        case 2: i = operand_ok( ip, &operands[0], &operands[1], (struct oper *)NULL  );break; 
        !            81:        case 3: i = operand_ok( ip, &operands[0], &operands[1], &operands[2]  );break; 
        !            82:        }
        !            83:        if (!i)
        !            84:            prog_warning(operand_error);
        !            85:     } else {
        !            86:        switch ( ip->op_i ){ 
        !            87:        case OP_TEXT:  cur_csect_name = C_TEXT;  new_csect(); return;
        !            88:        case OP_DATA:  cur_csect_name = C_DATA;  new_csect(); break;
        !            89:        case OP_DATA1: cur_csect_name = C_DATA1; new_csect(); break;
        !            90:        case OP_DATA2: cur_csect_name = C_DATA2; new_csect(); break;
        !            91:        case OP_BSS:   cur_csect_name = C_BSS;   new_csect(); break;
        !            92:        case OP_ASCII:
        !            93:        case OP_ASCIZ: bc += ascii(cur_csect_name)+(ip->op_i==OP_ASCIZ); break;
        !            94:        case OP_STABS: save_stabs(cur_csect_name); break;
        !            95:        default:       bc += pseudo_size( ip ); break;
        !            96:        }
        !            97:        if (cur_csect_name != C_TEXT){
        !            98:            /* non-text is not delt with -- echo it out directly */
        !            99:            putinstr( ip );
        !           100:            return;
        !           101:        }
        !           102:     }
        !           103:     np = new();
        !           104:     np->nref = numops;
        !           105:     for (i=0; i<numops; i++){
        !           106:        np->ref[i] = newoperand( &operands[i] );
        !           107:     }
        !           108:     installinstruct( np, ip );
        !           109:     addnode( np );
        !           110: }
        !           111: 
        !           112: unsigned short
        !           113: make_touchop( np, to )
        !           114:     NODE *np;
        !           115:     unsigned short to;
        !           116: {
        !           117:     /* ripped off from installinstruct, but not yet used by it */
        !           118:     int i;
        !           119:     unsigned short tfield, tretval;
        !           120:     struct oper *o;
        !           121: 
        !           122:     tretval = 0;
        !           123:     for (i=np->nref-1; i >= 0; i--){
        !           124:        o = np->ref[i];
        !           125:        switch(tfield = (to>>(TOUCHWIDTH*i))&TOUCHMASK){
        !           126:        case SPEC(0): /* bset, bclr, bcng */
        !           127:                if (o->type_o==T_REG){
        !           128:                    tfield = touchselect(np->ref[0], BR+BW, WR+WW, LR+LW);
        !           129:                } else{
        !           130:                    tfield = (BR+BW);
        !           131:                }
        !           132:                break;
        !           133:        case SPEC(1): /* btst */
        !           134:                if (o->type_o==T_REG){
        !           135:                    tfield = touchselect(np->ref[0], BR, WR, LR);
        !           136:                } else {
        !           137:                    tfield = (BR);
        !           138:                }
        !           139:                break;
        !           140:        case SPEC(2): /* shifts */
        !           141:                if (np->nref==1)
        !           142:                    tfield = (WR+WW);
        !           143:                else
        !           144:                    tfield = (WR);
        !           145:                break;
        !           146:        case SPEC(3): /* pea, link, unlk    */
        !           147:                tfield = 0;
        !           148:                break;
        !           149:        case SPEC(4): /* bfset  bfins */
        !           150:                tfield = (LW);
        !           151:                break;
        !           152:        case SPEC(5): /* bfext? bftst */
        !           153:                tfield = (LR);
        !           154:                break;
        !           155:        case SPEC(6): /* mulsl, divsll */
        !           156:                tfield = (LR+LW);
        !           157:                break;
        !           158:        }
        !           159:        tretval <<= TOUCHWIDTH;
        !           160:        tretval |= tfield;
        !           161:     }
        !           162:     return tretval;
        !           163: }
        !           164: 
        !           165: static int
        !           166: touchselect( operand, b, w, l )
        !           167:     struct oper *operand;
        !           168: {
        !           169:     register v;
        !           170:     if (!numeric_immediate( operand ))  return l;
        !           171:     v = operand->value_o;
        !           172:     if ( v >=0 && v < 16 )
        !           173:        if (v < 8 ) return b;
        !           174:        else return w;
        !           175:     else return l;
        !           176: }
        !           177: 
        !           178: static subop_t
        !           179: subopselect( touchword )
        !           180: {
        !           181:     switch (touchword&TOUCHMASK) {
        !           182:     case BR:
        !           183:     case BW:
        !           184:     case BR+BW:
        !           185:        return SUBOP_B;
        !           186:     case WR:
        !           187:     case WW:
        !           188:     case WR+WW:
        !           189:        return SUBOP_W;
        !           190:     }
        !           191:     return SUBOP_L;
        !           192: }
        !           193: 
        !           194: void
        !           195: cannibalize( np, sp )
        !           196:     NODE *np;
        !           197:     char *sp;
        !           198: {
        !           199:     installinstruct( np, sopcode(sp) );
        !           200: }
        !           201: 
        !           202: installinstruct( np, ip )
        !           203:     register NODE *np;
        !           204:     register struct ins_bkt *ip;
        !           205: {
        !           206:     register struct oper *o;
        !           207:     register unsigned short touchop;
        !           208:     regmask smask, umask;
        !           209:     register i;
        !           210:     static int regnames[] = {
        !           211:        D0REG, D0REG+1,
        !           212:        A0REG, A0REG+1,
        !           213:        FP0REG, FP0REG+1
        !           214:     };
        !           215: 
        !           216:     np->instr = ip;
        !           217:     np->op = ip->op_i;
        !           218:     np->subop = ip->subop_i;
        !           219:     umask = MAKERMASK( CCREG, (ip->cc_i&CCR)?BR:0);
        !           220:     smask = MAKEWMASK( CCREG, (ip->cc_i&CCX)?BW:0);
        !           221:     if (ip->cc_i&FCCR) umask = addmask( umask, MAKERMASK( FPCCREG, BR));
        !           222:     if (ip->cc_i&FCC) smask = addmask( smask, MAKEWMASK( FPCCREG, BW));
        !           223:     switch (np->op){
        !           224:     case OP_CALL: /* writes d0,d1,a0,a1 except with exceptions */
        !           225:        o = np->ref[0];
        !           226:        if ( o->type_o == T_NORMAL && o->value_o==0 ){
        !           227:            struct sym_bkt *s;
        !           228:            s = o->sym_o;
        !           229:            if (s->attr_s & S_CRT){
        !           230:                /*
        !           231:                 * c- runtime support routine -- some of these may touch
        !           232:                 * the floating point registers, but as of 3.0 they are
        !           233:                 * not called by programs that use them.
        !           234:                 */
        !           235:                for (i=0; i<4; i++ ){
        !           236:                    umask = addmask( umask, MAKERMASK( regnames[i], s->builtin_s[i] ));
        !           237:                    smask = addmask( smask, MAKEWMASK( regnames[i], s->builtin_s[i] ));
        !           238:                }
        !           239:                break;
        !           240:            }
        !           241:        }
        !           242:        /* normal routine -- write d0,d1,a0,a1,fp0,fp1 */
        !           243:        for (i=0; i<6; i++){
        !           244:            smask = addmask(smask,MAKEWMASK( regnames[i], LW ));
        !           245:        }
        !           246:        break;
        !           247:     case OP_EXIT: /* reads some registers, writes all */
        !           248:        umask  = addmask(exitmask, regmask_nontemp);
        !           249:        smask = regmask_all;
        !           250:        break;
        !           251:     }
        !           252:     touchop = ip->touchop_i;
        !           253:     for (i=0; i<np->nref; i++, touchop >>= TOUCHWIDTH ){
        !           254:        o = np->ref[i];
        !           255:        switch(touchop&TOUCHMASK){
        !           256:        case SPEC(0): /* bset, bclr, bcng */
        !           257:                if (o->type_o==T_REG){
        !           258:                    touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR+BW, WR+WW, LR+LW);
        !           259:                } else{
        !           260:                    touchop = (touchop&~TOUCHMASK)|(BR+BW);
        !           261:                }
        !           262:                np->subop = subopselect( touchop );
        !           263:                break;
        !           264:        case SPEC(1): /* btst */
        !           265:                if (o->type_o==T_REG){
        !           266:                    touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR, WR, LR);
        !           267:                } else {
        !           268:                    touchop = (touchop&~TOUCHMASK)|(BR);
        !           269:                }
        !           270:                np->subop = subopselect( touchop );
        !           271:                break;
        !           272:        case SPEC(2): /* shifts */
        !           273:                if (np->nref==1)
        !           274:                    touchop = (touchop&~TOUCHMASK)|(WR+WW);
        !           275:                else
        !           276:                    touchop = (touchop&~TOUCHMASK)|(WR);
        !           277:                break;
        !           278:        case SPEC(3): /* pea, link, unlk    */
        !           279:                smask = MAKEWMASK( SPREG, LW );
        !           280:                /* umask = MAKERMASK( SPREG, LR ); */
        !           281:                /* the unlk instruction does not read sp before setting it */
        !           282:                umask = (ip->op_i == OP_UNLK) ? regmask0 : smask;
        !           283:                touchop = LR+LW; /* link and unlk use this */
        !           284:                break;
        !           285:        case SPEC(4): /* bfset  bfins */
        !           286:                touchop = (touchop&~TOUCHMASK)|(LW);
        !           287:                break;
        !           288:        case SPEC(5): /* bfext? bftst */
        !           289:                touchop = (touchop&~TOUCHMASK)|(LR);
        !           290:                break;
        !           291:        case SPEC(6): /* mulsl, divsll */
        !           292:                if (o->type_o != T_REGPAIR){
        !           293:                    touchop = (touchop&~TOUCHMASK)|(LR+LW);
        !           294:                    break;
        !           295:                } else {
        !           296:                    /* 1st register of pair written only */
        !           297:                    smask = addmask( smask, MAKEWMASK( o->value_o, LW ));
        !           298:                    /* 2nd register of pair read+written */
        !           299:                    umask = addmask( umask, MAKERMASK( o->reg_o,   LR ));
        !           300:                    smask = addmask( smask, MAKEWMASK( o->reg_o,   LW ));
        !           301:                    continue;
        !           302:                }
        !           303:        }
        !           304:        switch (o->type_o ){
        !           305:        case T_REGPAIR:
        !           306:            umask = addmask( umask, MAKERMASK( o->reg_o,   touchop ));
        !           307:            smask = addmask( smask, MAKEWMASK( o->reg_o,   touchop ));
        !           308:            /* FALL THROUGH */
        !           309:        case T_REG:
        !           310:            if (dareg( o->value_o ) || srreg( o->value_o) || freg( o->value_o)){
        !           311:                umask = addmask( umask, MAKERMASK( o->value_o, touchop ));
        !           312:                smask = addmask( smask, MAKEWMASK( o->value_o, touchop ));
        !           313:            }
        !           314:            break;
        !           315:        case T_POSTINC:
        !           316:        case T_PREDEC:
        !           317:            smask = addmask( smask, MAKEWMASK( o->value_o, LW ));
        !           318:            /* FALL THROUGH */
        !           319:        case T_DEFER:
        !           320:            umask = addmask( umask, MAKERMASK( o->value_o, LR ));
        !           321:            break;
        !           322:        case T_DISPL:
        !           323:            umask = addmask( umask, MAKERMASK( o->reg_o, LR ));
        !           324:            break;
        !           325:        case T_INDEX:
        !           326:            if (! (o->flags_o & O_BSUPRESS))
        !           327:                umask = addmask( umask, MAKERMASK( o->reg_o, LR ));
        !           328:            if ( o->flags_o & (O_PREINDEX|O_POSTINDEX)) 
        !           329:                umask = addmask( umask, MAKERMASK( o->value_o, 
        !           330:                    o->flags_o&O_LINDEX ? LR : WR ));
        !           331:            break;
        !           332:        }
        !           333:        if (o->flags_o & O_BFLD){
        !           334:            if (o->flags_o & O_BFOREG)
        !           335:                umask = addmask( umask, MAKERMASK( o->bfoffset_o, BR ));
        !           336:            if (o->flags_o & O_BFWREG)
        !           337:                umask = addmask( umask, MAKERMASK( o->bfwidth_o, BR ));
        !           338:        }
        !           339:     }
        !           340:     np->ruse = umask;
        !           341:     np->rset = smask;
        !           342: }
        !           343: 
        !           344: static unsigned
        !           345: op_to_bits( op )
        !           346:     register struct oper *op;
        !           347: {
        !           348:     /* return the address-mode bits for operand *op */
        !           349:     register unsigned s; 
        !           350:     static unsigned bits[] = {
        !           351:        0,
        !           352:        AM_REG, AM_DEFER, AM_POSTINC, AM_PREDEC, AM_DISPL,
        !           353:        AM_INDEX, AM_ABSS, AM_ABSL, AM_IMMED, AM_NORMAL, 
        !           354:        AM_REGPAIR, -1, -1
        !           355:     };
        !           356:     switch ( s = bits[(int)op->type_o]){
        !           357:     case AM_REG:
        !           358:        s = reg_access[op->value_o]; break;
        !           359:     case AM_DISPL:
        !           360:        if (op->reg_o == PCREG) s = AM_PCDISPL; break;
        !           361:     case AM_INDEX:
        !           362:        if (op->reg_o == PCREG) s = AM_PCINDEX; break;
        !           363:     }
        !           364:     return s;
        !           365: }
        !           366: 
        !           367: int
        !           368: operand_ok( ip, op1, op2, op3 )
        !           369:     struct ins_bkt *ip;
        !           370:     struct oper    *op1, *op2, *op3;
        !           371: {
        !           372:     /*
        !           373:      * this routine answers the eternal question:
        !           374:      *  are operands *op1 and *op2 ok to use as the operands of instruction *ip?
        !           375:      * it does it by looking at the optype_i bit fields in the instruction
        !           376:      * description.
        !           377:      */
        !           378:     register i;
        !           379:     register unsigned opbits1, opbits2, opbits3;
        !           380:     register noperands = ip->noper_i;
        !           381: 
        !           382:     opbits1 = op_to_bits( op1 );
        !           383:     if (op2)
        !           384:        opbits2 = op_to_bits( op2 );
        !           385:     else
        !           386:        opbits2 = 0;
        !           387:     if (op3)
        !           388:        opbits3 = op_to_bits( op3 );
        !           389:     else
        !           390:        opbits3 = 0;
        !           391:     switch (ip->touchop_i&TOUCH2(TOUCHMASK)){
        !           392:     case TOUCH2(SPEC(0)):
        !           393:     case TOUCH2(SPEC(1)):
        !           394:        /* special hackery for bit ops */
        !           395:        if (opbits1 == AM_IMMED){
        !           396:            i = op1->value_o;
        !           397:            if (op1->sym_o) { operand_error =  E_CONSTANT; return 0;}
        !           398:            if (opbits2 == AM_DREG){
        !           399:                if (i < 0 || i > 31 ) { operand_error =  E_CONSTANT; return 0;}
        !           400:            } else 
        !           401:                if (i < 0 || i > 7 ) { operand_error =  E_CONSTANT; return 0;}
        !           402:        }
        !           403:        break;
        !           404:     }
        !           405:     switch (ip->touchop_i&TOUCH1(TOUCHMASK)){
        !           406:     case TOUCH1(SPEC(2)):
        !           407:        /* special hackery for shifts */
        !           408:        if (opbits1 == AM_IMMED && ((i=op1->value_o)<1 || i>8 || op1->sym_o)){
        !           409:            operand_error = E_CONSTANT;
        !           410:            return 0;
        !           411:        }
        !           412:        break;
        !           413:     }
        !           414:     switch (noperands){
        !           415:     case 0: return 1;
        !           416:     case 1:
        !           417:        if ((ip == tstw || ip == tstl) && areg_addr(op1)
        !           418:          && !ext_instruction_set)
        !           419:            break;
        !           420:        for (i=0; i<N_OPTYPES; i+=1)
        !           421:            if ((opbits1&ip->optype_i[i])==opbits1) return 1;
        !           422:        break;
        !           423:     case 2:
        !           424:        for (i=0; i<N_OPTYPES; i+=2)
        !           425:            if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) ) return 1;
        !           426:        break;
        !           427:     case 3:
        !           428:        for (i=0; i<N_OPTYPES; i+=3)
        !           429:            if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) && ((opbits3&ip->optype_i[i+2])==opbits3) ) return 1;
        !           430:        break;
        !           431:     }
        !           432:     operand_error =  E_OPERAND;
        !           433:     return 0;
        !           434: }
        !           435: onceonly()
        !           436: {
        !           437:     /*
        !           438:      * A collection of context-free, compiler specific hacks 
        !           439:      * we need only do once, as circumstances will not change
        !           440:      * during the course of our work. These include:
        !           441:      *  - moveml's: deleting those that do nothing, replacing the degenerate
        !           442:      *             cases with movl's.
        !           443:      *  - link a6,#0 ... addl #X,sp: combine if X in range of the link.
        !           444:      *  - pea 0 : becomes clrl sp@-
        !           445:      *  - cmpX #0,Y : becomes tstX Y, for Y not an address register.
        !           446:      *  - movX #0,Y : becomes clrX Y, for Y not a  register, or
        !           447:      *                        moveq #0,Y, for type long data register, or
        !           448:      *                        subl Y,Y for Y an address register.
        !           449:      */
        !           450:     
        !           451:     register NODE * n;
        !           452:     register NODE *f;
        !           453:     register i, v;
        !           454:     register struct oper *o;
        !           455:     int regno;
        !           456:     extern NODE *deletenode();
        !           457: 
        !           458:     for (n=first.forw; n != &first; n=n->forw){
        !           459:        switch( n->op){
        !           460:        case OP_MOVEM:
        !           461:            if (n->subop==SUBOP_L || n->subop==SUBOP_X) {
        !           462:                /* i get the index of the immediate operand */
        !           463:                i = (n->ref[1]->type_o==T_IMMED); 
        !           464:                /* o get the pointer to the immediate operand */
        !           465:                o = n->ref[i];
        !           466:                if (o->sym_o || o->type_o!=T_IMMED) continue;
        !           467:                /* v gets the register mask -- how many bits set here? */
        !           468:                switch( cntbits( v=o->value_o ) ){
        !           469:                case 0: 
        !           470:                    if (deladdr(n->ref[1-i])){
        !           471:                        n = deletenode( n ); 
        !           472:                        meter.nrmtfr++;
        !           473:                    }
        !           474:                    break;
        !           475:                case 1: /* replace with a moveml, same "other" operand */
        !           476:                    v = ffs(v); /* find first bit set -- "1" on littleend */
        !           477:                    /* if mode of "other" operand is predecrement, bits work backwards */
        !           478:                    o->type_o=T_REG;
        !           479:                    if (n->subop==SUBOP_L){
        !           480:                        if (n->ref[1-i]->type_o==T_PREDEC)
        !           481:                            v = 16 - v;
        !           482:                        o->value_o = v-1;
        !           483:                        cannibalize( n, "movl" );
        !           484:                    }else{
        !           485:                        o->value_o = FP0REG + 8 - v;
        !           486:                        cannibalize( n, "fmovex" );
        !           487:                    }
        !           488:                    meter.nmmtmo++;
        !           489:                    break;
        !           490:                }
        !           491:            }
        !           492:            continue;
        !           493:        case OP_LINK:
        !           494:            /* make sure we understand this instruction */
        !           495:            o = n->ref[1];
        !           496:            if (!numeric_immediate(o)) continue;
        !           497:            v = o->value_o;
        !           498:            /* see if next instruction is of form: addl #nnn,sp */
        !           499:            f = n;
        !           500:            nexti(f);
        !           501:            if (f->op!=OP_ADD) continue;
        !           502:            o = f->ref[0];
        !           503:            if (!numeric_immediate(o)) continue;
        !           504:            v += o->value_o;
        !           505:            o = f->ref[1];
        !           506:            if (!(o->type_o==T_REG && o->value_o==SPREG)) continue; 
        !           507:            /* make sure sum of immediates is in range */
        !           508:            if (v <-32768 || v > 32767) continue;
        !           509:            /* got it! */
        !           510:            n->ref[1]->value_o = v;
        !           511:            n = deletenode( f );
        !           512:            meter.namwl++;
        !           513:            continue;
        !           514:        case OP_PEA:
        !           515:            /* if operand is a "normal" 0, change the opcode */
        !           516:            o = n->ref[0];
        !           517:            if (o->type_o==T_NORMAL && o->sym_o==NULL && o->value_o==0){
        !           518:                o->type_o = T_PREDEC;
        !           519:                o->value_o = SPREG;
        !           520:                cannibalize( n, "clrl" );
        !           521:                meter.nmtoc++;
        !           522:            }
        !           523:            continue;
        !           524:        case OP_CMP:
        !           525:            /* compares to zero are degenerate */
        !           526:            o = n->ref[0];
        !           527:            if (immediate_value( o, 0)){
        !           528:                if (areg_addr(n->ref[1])){
        !           529:                    /* "A" register
        !           530:                     * may be able to do something about this later on,
        !           531:                     * after we gain some context.
        !           532:                     */
        !           533:                    continue;
        !           534:                } else {
        !           535:                    n->ref[0] = n->ref[1];
        !           536:                    n->nref--;
        !           537:                    freeoperand( o );
        !           538:                    cannibalize( n,  (n->subop==SUBOP_L)?"tstl"
        !           539:                                    :(n->subop==SUBOP_W)?"tstw"
        !           540:                                    :              "tstb");
        !           541:                    meter.nctot++;
        !           542:                }
        !           543:            }
        !           544:            continue;
        !           545:        case OP_MOVE:
        !           546:            /* moves of zero can often be simplified */
        !           547:            o = n->ref[0];
        !           548:            if (immediate_value(o, 0)){
        !           549:                switch (n->ref[1]->type_o){
        !           550:                case T_REG:
        !           551:                    v = n->ref[1]->value_o;
        !           552:                    if (dreg(v) ){
        !           553:                        if (n->subop != SUBOP_L) goto mkclr;
        !           554:                        /* use moveq */
        !           555:                        cannibalize( n, "moveq" );
        !           556:                        meter.nwmov++;
        !           557:                    } else if (areg(v)){
        !           558:                        /* subtract from self */
        !           559:                        o->type_o = T_REG;
        !           560:                        o->value_o = v;
        !           561:                        cannibalize( n , "subl" );
        !           562:                        meter.nmtos++;
        !           563:                    }
        !           564:                    break;
        !           565:                default:
        !           566:                mkclr:
        !           567:                    /* use the clear instruction */
        !           568:                    n->ref[0] = n->ref[1];
        !           569:                    n->nref--;
        !           570:                    freeoperand( o );
        !           571:                    cannibalize( n,  (n->subop==SUBOP_L)?"clrl"
        !           572:                                    :(n->subop==SUBOP_W)?"clrw"
        !           573:                                    :              "clrb");
        !           574:                    meter.nmtoc++;
        !           575:                    break;
        !           576:                }
        !           577:            }
        !           578:            continue;
        !           579:        case OP_AND:
        !           580:            /*
        !           581:             * if this looks like a mask of the lower bits,
        !           582:             * then it kill the rest of the register without
        !           583:             * reading it: i.e.
        !           584:             *  andl    #255,d0
        !           585:             * only uses the low-order 8bits anyway, so we can
        !           586:             * change our usage mask.
        !           587:             */
        !           588:            if (numeric_immediate(o=n->ref[0])){
        !           589:                v = o->value_o;
        !           590:                if ((o=n->ref[1])->type_o==T_REG){
        !           591:                    regno = o->value_o;
        !           592:                    if ( v>= 0 && v <= 0xffff && dreg(regno) ){
        !           593:                        n->ruse = submask( n->ruse, MAKERMASK( regno, LR ));
        !           594:                        n->ruse = addmask( n->ruse, MAKERMASK( regno, v<=0xff ? BR : WR ));
        !           595:                        n->rlive = compute_normal( n, n->forw->rlive);
        !           596:                    }
        !           597:                }
        !           598:            }
        !           599:            continue;
        !           600:        }
        !           601:     }
        !           602: }
        !           603: 
        !           604: int
        !           605: addr_delt( old, new )
        !           606:     subop_t old, new;
        !           607: {
        !           608: #define NO_WAY -32768
        !           609:     /*
        !           610:      * if an operand was addressed using subop "old", and will be
        !           611:      * addressed by "new", what is the address increment?
        !           612:      */
        !           613:     static char deltsize[7][7] = {
        !           614:     /* new is ... B    W    L    S    D    X     P       */
        !           615:     /* old is ... */
        !           616:     /* B */ {     0,  -1,  -3,  -3,  -7,  -11,   -11    },
        !           617:     /* W */ {     1,   0,  -2,  -2,  -6,  -10,   -10    },
        !           618:     /* L */ {     3,   2,   0,   0,  -4,   -8,    -8    },
        !           619:     /* S */ {     3,   2,   0,   0,  -4,   -8,    -8    },
        !           620:     /* D */ {     7,   6,   4,   4,   0,   -4,    -4    },
        !           621:     /* X */ {    11,  10,   8,   8,   4,    0,     0    }, 
        !           622:     /* P */ {    11,  10,   8,   8,   4,    0,     0    }, 
        !           623:     };
        !           624: 
        !           625:     switch ( old ){
        !           626:     case SUBOP_B:
        !           627:     case SUBOP_W:
        !           628:     case SUBOP_L:
        !           629:        break;
        !           630:     default: return NO_WAY;
        !           631:     }
        !           632:     switch ( new ){
        !           633:     case SUBOP_B:
        !           634:     case SUBOP_W:
        !           635:     case SUBOP_L:
        !           636:        break;
        !           637:     default: return NO_WAY;
        !           638:     }
        !           639:     return deltsize[(int)old - (int)SUBOP_B][(int)new - (int)SUBOP_B];
        !           640: #undef NO_WAY
        !           641: }
        !           642: 
        !           643: int
        !           644: long_immediate( opcode )
        !           645:     opcode_t opcode;
        !           646: {
        !           647:     /*
        !           648:      * list some of the opcodes in which immediate operands are long (addl),
        !           649:      * as opposed to those in which this is not the case (asrl).
        !           650:      */
        !           651:     switch ( opcode ){
        !           652:     case OP_ADD:
        !           653:     case OP_AND:
        !           654:     case OP_SUB:
        !           655:     case OP_MOVE:
        !           656:     case OP_CMP:
        !           657:     case OP_OR:
        !           658:        return 1;
        !           659:     }
        !           660:     return 0;
        !           661: }
        !           662: 
        !           663: static int
        !           664: exception( p, pnext )
        !           665:     NODE *p, *pnext;
        !           666: {      
        !           667:     if (p->instr==moveq && long_immediate(pnext->op )) 
        !           668:        return 1; /* don't elide moveq's */
        !           669:     if (pnext->op == OP_BOP){
        !           670:        if (!numeric_immediate(pnext->ref[0])) return 1; /* be careful here */
        !           671:        if (p->subop!=SUBOP_B)
        !           672:            if (p->ref[0]->type_o != T_REG && !cancache(p->ref[0]))
        !           673:                return 1; /* don't mess up memory references */
        !           674:     }
        !           675:     return 0;
        !           676: }
        !           677: 
        !           678: /*
        !           679:  * have the pattern 
        !           680:  *   movX   Y,d0
        !           681:  *   opZ    d0,...
        !           682:  * where the second instruction only reads the operand, and we could 
        !           683:  * have done
        !           684:  *   opZ    Y',...
        !           685:  * instead.
        !           686:  */
        !           687: static NODE *
        !           688: elide_move( p, pnext, opset )
        !           689:     register NODE *p;
        !           690:     register NODE *pnext;
        !           691:     int opset;
        !           692: {
        !           693:     register i;
        !           694: 
        !           695:     for ( i=0 ; i<pnext->nref; i++)
        !           696:        if (opset & (1<<i)) 
        !           697:            *pnext->ref[i] = *p->ref[0];
        !           698:     installinstruct( pnext, pnext->instr );
        !           699:     pnext->rlive = compute_normal(pnext,pnext->forw->rlive);
        !           700:     meter.redunm++;
        !           701:     return( deletenode( p ));
        !           702: }
        !           703: 
        !           704: /*
        !           705:  * look for dbra-equivalent sequence. The compiler
        !           706:  * already makes some assumptions about 16-bit reachability
        !           707:  * (word offsets in case-jumps), so we don't worry about that
        !           708:  * here. We're going to be rather strict about what we recognize,
        !           709:  * because we don't have the information to determine whether,
        !           710:  * for instance, an index begins positive, in which case we
        !           711:  * could recognize the condition " > 0 " as being equivalent
        !           712:  * to " != -1". Someday, perhaps.
        !           713:  * We will also be just a little adventuresome and try to
        !           714:  * handle the "long dbra" case, too. (Long is the data type,
        !           715:  * not the jump offset!)
        !           716:  */
        !           717: static NODE *
        !           718: make_dbra( p, didchange )
        !           719:     register NODE *p;
        !           720:     int *didchange;
        !           721: {
        !           722:     register NODE *pnext;
        !           723:     NODE *p3;
        !           724:     register struct oper *o;
        !           725:     subop_t length;
        !           726:     static struct oper immed = { T_IMMED, 0,0,0, NULL, NULL, NULL, 0 };
        !           727: 
        !           728:     /* recognize subqZ #1,dX */
        !           729:     length = p->subop;
        !           730:     if (length == SUBOP_B) return p;
        !           731:     if ( !immediate_value((o=p->ref[0]), 1))
        !           732:        return p;
        !           733:     o=p->ref[1];
        !           734:     if (!dreg_addr(o)) return p;
        !           735:     pnext = p->forw;
        !           736:     switch (pnext->op){
        !           737:     case OP_CMP:
        !           738:        /* recognize cmpZ #-1,dX */
        !           739:        if (pnext->subop != length ||
        !           740:            !immediate_value( pnext->ref[0], -1) ||
        !           741:            !sameops( o, pnext->ref[1]))
        !           742:                return p;
        !           743:        /* recognize jne Y */
        !           744:        pnext = pnext->forw;
        !           745:        if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p;
        !           746:        if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p;
        !           747:        /*
        !           748:         * found the pattern:
        !           749:         *    subqX   #1,dY    <== p
        !           750:         *    cmpX    #-1,dY
        !           751:         *    jne     Z        <== pnext
        !           752:         */
        !           753:        /* save one copy of the operand register, delete much */
        !           754:        p->nref --;
        !           755:        p = deletenode( p)->forw;
        !           756:        p = deletenode( p)->forw;
        !           757:        /* p == pnext */
        !           758:        break;
        !           759:     case OP_TST:
        !           760:        /* try a different pattern */
        !           761:        p3 = p->back;
        !           762:        if (p3->op != OP_MOVE || p3->subop != length ||
        !           763:            !sameops( p3->ref[0], o) || !dreg_addr( p3->ref[1]))
        !           764:            return p;
        !           765:        if (pnext->subop != length || !sameops( p3->ref[1], pnext->ref[0]))
        !           766:            return p;
        !           767:        /* recognize jne Y */
        !           768:        pnext = pnext->forw;
        !           769:        if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p;
        !           770:        if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p;
        !           771:        if (inmask( p3->ref[1]->value_o, pnext->rlive )) return p;
        !           772:        /*
        !           773:         * found the pattern:
        !           774:         *    movX      dY,dW   <== p3
        !           775:         *        subqX #1,dY   <== p
        !           776:         *    tstX      dW
        !           777:         *    jne   Y       <== pnext
        !           778:         */
        !           779:        /* save one copy of the operand register, delete much */
        !           780:        (void) deletenode( p3 );
        !           781:        p->nref --;
        !           782:        p = deletenode( p)->forw;
        !           783:        p = deletenode( p)->forw;
        !           784:        /* p == pnext */
        !           785:        break;
        !           786:     default:
        !           787:        return p;
        !           788:     }
        !           789:     /* 
        !           790:      * now: two cases here: simple and long:
        !           791:      *
        !           792:      * simple case: move operand o to the jump instruction; 
        !           793:      * cannibalize it as a dbra;
        !           794:      *
        !           795:      * long case: as simple case, then add the long-dbra
        !           796:      * tail: clrw , cmpl, jcc.
        !           797:      */
        !           798:     pnext->ref[0] = o;
        !           799:     pnext->nref++;
        !           800:     cannibalize( pnext, "dbra" );
        !           801:     pnext->op = OP_DJMP;
        !           802:     if (length == SUBOP_L){
        !           803:        /* add clrw dX instruction after that */
        !           804:        pnext = new();
        !           805:        pnext->nref = 1;
        !           806:        pnext->ref[0] = newoperand( o );
        !           807:        insert( pnext, p);
        !           808:        cannibalize( pnext, "clrw" );
        !           809:        /* add subql #1 instruction next */
        !           810:        p3 = pnext;
        !           811:        pnext = new();
        !           812:        pnext->nref = 2;
        !           813:        immed.value_o = 1;
        !           814:        pnext->ref[0] = newoperand( &immed );
        !           815:        pnext->ref[1] = newoperand( o );
        !           816:        insert( pnext, p3);
        !           817:        cannibalize( pnext, "subql" );
        !           818:        /* finally, add jcc Y instruction */
        !           819:        p3 = pnext;
        !           820:        pnext = new();
        !           821:        insert( pnext, p3);
        !           822:        newreference( p->luse, pnext );
        !           823:        cannibalize( pnext, "jcc" );
        !           824:        pnext->op = OP_JUMP;
        !           825:     }
        !           826:     meter.ndbra++;
        !           827:     (*didchange)++;
        !           828:     return p;
        !           829: }
        !           830: 
        !           831: /*
        !           832:  * find out if operand *o uses the register r 
        !           833:  */
        !           834: int
        !           835: operand_uses( o, r )
        !           836:     struct oper *o;
        !           837:     int r;
        !           838: {
        !           839:     int t;
        !           840:     switch (o->type_o){
        !           841:     case T_REG:
        !           842:     case T_DEFER:
        !           843:     case T_POSTINC:
        !           844:     case T_PREDEC:
        !           845:        return (o->value_o == r);
        !           846:     case T_DISPL:
        !           847:        return (o->reg_o == r);
        !           848:     case T_INDEX:
        !           849:        t  = (o->flags_o & O_BSUPRESS)?0 : (o->reg_o == r);
        !           850:        t |= (o->flags_o & (O_PREINDEX|O_POSTINDEX))? (o->value_o == r) : 0;
        !           851:        return t;
        !           852:     case T_REGPAIR:
        !           853:        return (o->value_o == r || o->reg_o == r);
        !           854:     }
        !           855:     return 0; /* others don't use registers */
        !           856: }
        !           857: 
        !           858: /*
        !           859:  * Look for arithmetic on an A register. Look for nearby uses of
        !           860:  * the same register using deferred addressing. See if we can combine
        !           861:  * them into postincrement or predecrement mode addressing.
        !           862:  */
        !           863: NODE *
        !           864: plus_minus( p, didchange )
        !           865:     register NODE *p;
        !           866:     int *didchange;
        !           867: {
        !           868:     int incrval;
        !           869:     register int reg;
        !           870:     register NODE *q;
        !           871:     int found;
        !           872:     int i;
        !           873:     operand_t substitute;
        !           874:     register struct oper *o;
        !           875: 
        !           876:     if ( numeric_immediate( p->ref[0] ) && areg_addr( p->ref[1] ) ){
        !           877:        incrval = p->ref[0]->value_o;
        !           878:        reg = p->ref[1]->value_o;
        !           879:        q = p;
        !           880:        found = 0;
        !           881:        if ( p->op == OP_ADD ){
        !           882:            /* search backwards */
        !           883:            substitute = T_POSTINC;
        !           884:            while ( (q=q->back)->op != OP_FIRST && q->op != OP_LABEL
        !           885:            && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){
        !           886:                if (inmask( reg, q->ruse)){ 
        !           887:                    found = 1; 
        !           888:                    break;
        !           889:                }
        !           890:            }
        !           891:        } else {
        !           892:            /* search forwards */
        !           893:            substitute = T_PREDEC;
        !           894:            while ( (q=q->forw)->op != OP_FIRST && q->op != OP_LABEL
        !           895:            && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){
        !           896:                if (inmask( reg, q->ruse)){ 
        !           897:                    found = 1; 
        !           898:                    break;
        !           899:                }
        !           900:            }
        !           901:        }
        !           902:        if (found){
        !           903:            /*
        !           904:             * we've found a nearby node that reads our register.
        !           905:             * it must now meet these criteria:
        !           906:             *  -- the size of the access must agree with the size of the
        !           907:             *     increment/decrement operation
        !           908:             *  -- must not change the register (already checked)
        !           909:             *  -- must use the register exactly once
        !           910:             *  -- must use the register in a type T_DEFER operand
        !           911:             *  -- must be able to take the substituted operand type
        !           912:             */
        !           913:            switch (q->subop){
        !           914:            case SUBOP_B:  found = incrval==1; break;
        !           915:            case SUBOP_W:  found = incrval==2; break;
        !           916:            case SUBOP_L:  found = incrval==4; break;
        !           917:            case SUBOP_S:  found = incrval==4; break;
        !           918:            case SUBOP_D:  found = incrval==8; break;
        !           919:            case SUBOP_X:  found = incrval==12; break;
        !           920:            default:       found = 0; break;
        !           921:            }
        !           922:            if (found){
        !           923:                found = 0;
        !           924:                for (i=0; i < q->nref; i++)
        !           925:                    if (operand_uses( q->ref[i], reg)){
        !           926:                        found++;
        !           927:                        o = q->ref[i];
        !           928:                    }
        !           929:                if (found == 1 && o->type_o == T_DEFER){
        !           930:                    o->type_o = substitute;
        !           931:                    if (operand_ok(q->instr, q->ref[0], q->ref[1], q->ref[2] )){
        !           932:                        /* got it */
        !           933:                        p = deletenode( p );
        !           934:                        q->rset = addmask( q->rset, MAKEWMASK( reg, LW ) );
        !           935:                        *didchange++;
        !           936:                        meter.nplusminus++;
        !           937:                    } else {
        !           938:                        /* blew it */
        !           939:                        o->type_o = T_DEFER; /* restore operand, go home */
        !           940:                    }
        !           941:                }
        !           942:            }
        !           943:        }
        !           944:     }
        !           945:     return p;
        !           946: }
        !           947: 
        !           948: int
        !           949: shorten()
        !           950: {
        !           951:     int nchanged = 0;
        !           952:     register NODE *p, *pnext;
        !           953:     NODE *pprev, *p3;
        !           954:     register struct oper *o;
        !           955:     register regno, t;
        !           956:     int didchange;
        !           957:     char *newname;
        !           958:     int i, newcc, opset;
        !           959:     int otherreg;
        !           960:     regmask m;
        !           961:     struct oper *trialops[OPERANDS_MAX];
        !           962: 
        !           963:     /*
        !           964:      * delete instructions that do useless things:
        !           965:      * moves to registers or parts of registers that are dead;
        !           966:      *  extends to parts of registers that are dead;
        !           967:      *  reset the condition codes to its current value.
        !           968:      * also, anything that depends on context which might
        !           969:      *  be changed by rearranging branchs:
        !           970:      *  resetting condition codes, multiple shifts in a row,
        !           971:      *  changing a "cmpl #0,A0" into a "movl A0,Di", where Di is dead.
        !           972:      *  and the transformation
        !           973:      *  - subqw #1,dX; cmpw #-1,dX; jne Y: becomes dbra dX,Y
        !           974:      *                      (most often requested hack).
        !           975:      */ 
        !           976:     if (moveq==NULL) moveq = sopcode( "moveq" ); 
        !           977:     didchange = 1; 
        !           978:     while(didchange){ 
        !           979:        didchange = 0;
        !           980:        for (p=first.forw; p != &first; p=p->forw){
        !           981:            if (!ISINSTRUC(p->op)) continue;
        !           982:            if (!emptymask( submask(p->rset , addmask( p->forw->rlive, MAKERMASK( CCREG, LR)))) ){
        !           983:                switch (p->op){
        !           984:                case OP_CALL:
        !           985:                case OP_DBRA:
        !           986:                case OP_DJMP:
        !           987:                case OP_BRANCH:
        !           988:                case OP_JUMP:
        !           989:                    break;
        !           990:                case OP_EXT:
        !           991:                    /* ext's also set condition codes */
        !           992:                    if (!inmask( CCREG, p->forw->rlive)){
        !           993:                        /* useless extend -- simply delete it */
        !           994:                        p = deletenode( p );
        !           995:                        didchange++;
        !           996:                        meter.nredext++;
        !           997:                    }
        !           998:                    break;
        !           999:                case OP_MOVE:
        !          1000:                    /* be careful here -- useless set must be to a register */
        !          1001:                    /* for instance: movl #0,a0@+ sets a0, but we cannot change it */
        !          1002:                    o = p->ref[1]; /* object of move */
        !          1003:                    if (o->type_o != T_REG) break;
        !          1004:                    if (!datareg(regno = o->value_o)) break;
        !          1005:                    /* TEST FOR CC USAGE */
        !          1006:                    if ( dreg(regno) && inmask( CCREG, p->forw->rlive)) break;
        !          1007:                    if ( freg(regno) && inmask( FPCCREG, p->forw->rlive)) break;
        !          1008:                    switch (inmask(regno,  p->forw->rlive)) {
        !          1009:                    case 0:
        !          1010:                        if (!deladdr( p->ref[0])) continue; /* side effects? */
        !          1011:                        /* totally useless -- fugg it */
        !          1012:                        p = deletenode( p );
        !          1013:                        didchange++;
        !          1014:                        meter.redunm++;
        !          1015:                        continue;
        !          1016:                    case 1: /* BYTE ONLY */
        !          1017:                        newname = "movb";
        !          1018:                        t = (p->subop ==SUBOP_L )?3 : 1; /* could have been movw */
        !          1019:                        break;
        !          1020:                    case 2:
        !          1021:                    case 3: /* WORD ONLY */
        !          1022:                        newname = "movw";
        !          1023:                        t = 2;
        !          1024:                        break;
        !          1025:                    default: continue;
        !          1026:                    } 
        !          1027:                    if ( freg(regno) ) break; /* don't rewrite fp moves */
        !          1028:                    if (incraddr( p->ref[0], t)) break;/* not ok */
        !          1029:                    if (p->instr == moveq) break; /* already moveq */
        !          1030:                    cannibalize( p, newname );
        !          1031:                    p->rlive = compute_normal( p, p->forw->rlive );
        !          1032:                    didchange++;
        !          1033:                    meter.nwmov++;
        !          1034:                    continue;
        !          1035:                case OP_AND:
        !          1036:                    /*
        !          1037:                     * if we're doing an AND to a dead register, it must be
        !          1038:                     * for condition-code only (don't even bother to check).
        !          1039:                     * if its only a single bit, change this to a btst.
        !          1040:                     */
        !          1041:                    if ((o=p->ref[1])->type_o!=T_REG || !dreg(regno=o->value_o))
        !          1042:                        break;
        !          1043:                    if (inmask(regno, p->forw->rlive)!=0)
        !          1044:                        break;
        !          1045:                    if (!numeric_immediate(o=p->ref[0]))
        !          1046:                        break;
        !          1047:                    if (cntbits( t = o->value_o ) == 1){
        !          1048:                        o->value_o = ffs(t)-1;
        !          1049:                        cannibalize( p, "btst" );
        !          1050:                        p->rlive = compute_normal( p, p->forw->rlive );
        !          1051:                        didchange++;
        !          1052:                        meter.nwop++;
        !          1053:                    }
        !          1054:                    break;
        !          1055:                }
        !          1056:            }
        !          1057:            switch (p->op){
        !          1058:            case OP_MOVE:
        !          1059:                /*
        !          1060:                 * If this is a move to a register which is only read once
        !          1061:                 * by a following instruction, see if we can elide a move.
        !          1062:                 * If this is a move to a register which is changed once
        !          1063:                 * in the next instruction, then written back whence it
        !          1064:                 * came, try doing the modify directly to the source 
        !          1065:                 * of it all.
        !          1066:                 * If this is a move of a register to itself, and condition
        !          1067:                 * codes are dead, elide the move.
        !          1068:                 * SPECIAL HACK: the sequence
        !          1069:                 *      moveq   #n, d0
        !          1070:                 *      movl    d0, XXX
        !          1071:                 * is FASTER and shorter than the instruction
        !          1072:                 *      movl    #n, XXX
        !          1073:                 * DO NOT UNDO THIS OPTIMIZATION!
        !          1074:                 */
        !          1075:                if ((o=p->ref[1])->type_o != T_REG) break;
        !          1076:                regno = o->value_o;
        !          1077:                if ( p->ref[0]->type_o ==T_REG && p->ref[0]->value_o == regno){
        !          1078:                    /* either:
        !          1079:                     * its a Dreg or Freg, and the condition code is useless,
        !          1080:                     * or its an Areg, and we're not doing some funny
        !          1081:                     * sign extension.
        !          1082:                     */
        !          1083:                    if ( ((dreg(regno)||freg(regno))  && !inmask( CCREG, p->forw->rlive))
        !          1084:                    || (areg(regno) && p->subop == SUBOP_L)){
        !          1085:                        p = deletenode( p );
        !          1086:                        didchange++;
        !          1087:                        meter.redunm++;
        !          1088:                        break;
        !          1089:                    }
        !          1090:                }
        !          1091:                newcc = 0;
        !          1092:                p3 = p;
        !          1093:                nexti(p3);
        !          1094:                for (pnext=p3; ISINSTRUC(pnext->op)||ISDIRECTIVE(pnext->op); pnext=pnext->forw){
        !          1095:                    if (ISDIRECTIVE(pnext->op)) continue;
        !          1096:                    newcc = inmask( CCREG, pnext->rset );
        !          1097:                    if (inmask( regno, pnext->ruse)) break;
        !          1098:                    if ((!newcc && inmask(CCREG, pnext->ruse )) || inmask( regno,  pnext->rset))
        !          1099:                        goto no_cookie;
        !          1100:                    if (!emptymask( andmask( pnext->rset,p->ruse)) || !emptymask( andmask( p->rset,pnext->ruse)) )
        !          1101:                        goto no_cookie;
        !          1102:                    switch (pnext->op){
        !          1103:                    case OP_BRANCH:
        !          1104:                    case OP_DBRA:
        !          1105:                    case OP_JUMP:
        !          1106:                    case OP_DJMP:
        !          1107:                        goto no_cookie;
        !          1108:                    }
        !          1109:                }
        !          1110:                if (!ISINSTRUC(pnext->op)) break;
        !          1111:                /* see if operands the same */
        !          1112:                /* for each operand #i that is the same, opset gets bit 1<<i set */
        !          1113:                opset = 0;
        !          1114:                for ( i=0 ; i<pnext->nref; i++)
        !          1115:                    if (sameops( o, pnext->ref[i])) opset |= 1<<i;
        !          1116:                if (!opset) break;
        !          1117:                /*
        !          1118:                 * We have only two cases we are smart enough to understand.
        !          1119:                 * Either the two instructions are ajacent, in which case
        !          1120:                 * there can have been no side effects in the intervening
        !          1121:                 * (null) instructions, OR we're looking at this pattern:
        !          1122:                 *      movX Y,d0; ... ; opX d0,dZ
        !          1123:                 * where dZ is not used between the moves. The reason for
        !          1124:                 * this restriction is that it's too easy to break subtile
        !          1125:                 * C constructs like post-incrementing, and too hard to detect
        !          1126:                 * the general case.
        !          1127:                 */
        !          1128:                if (pnext==p3){
        !          1129:                    /*
        !          1130:                     * see if register used after that instruction
        !          1131:                     * make sure its a read-only access, and same size
        !          1132:                     */
        !          1133:                    if (!inmask(regno, pnext->forw->rlive) && !inmask( regno, pnext->rset ) ){
        !          1134:                        t = addr_delt(p->subop, pnext->subop);
        !          1135:                        for ( i=0 ; i<pnext->nref; i++)
        !          1136:                            trialops[i] = (opset & (1<<i) ) ? p->ref[0] : pnext->ref[i];
        !          1137:                        for ( i ; i<OPERANDS_MAX; i++)
        !          1138:                                trialops[i]  = NULL;
        !          1139:                        if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2])){
        !          1140:                            int ok = 0;
        !          1141:                            if (t==0) {
        !          1142:                                /* both instructions use same size data */
        !          1143:                                ok = 1;
        !          1144:                            } else if (t>0 && !areg(regno)) {
        !          1145:                                /*
        !          1146:                                 * second inst uses smaller data, and
        !          1147:                                 * doesn't depend on sign-extension. The
        !          1148:                                 * check on regno prevents us from changing
        !          1149:                                 *      movl a6@(8),a0; cmpw #0,a0 | RIGHT
        !          1150:                                 * into
        !          1151:                                 *      cmpw #0,a6@(10)            | WRONG
        !          1152:                                 */
        !          1153:                                ok = !incraddr(p->ref[0],t);
        !          1154:                            }
        !          1155:                            if (ok && !exception( p, pnext)){
        !          1156:                                p = elide_move(p, pnext, opset);
        !          1157:                                didchange++;
        !          1158:                                break;
        !          1159:                            }
        !          1160:                        } else if (pnext->op == OP_BOP && 
        !          1161:                        numeric_immediate( pnext->ref[0] )){
        !          1162:                            /*
        !          1163:                             * btst  #t,d0
        !          1164:                             * take t modulo 8
        !          1165:                             */
        !          1166:                            t = pnext->ref[0]->value_o;
        !          1167:                            pnext->ref[0]->value_o = t%8;
        !          1168:                            if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2]) &&
        !          1169:                            !incraddr( p->ref[0], BYTESIZE(p->subop)-1-t/8 )){
        !          1170:                                /* it worked */
        !          1171:                                p = elide_move(p, pnext, opset);
        !          1172:                                didchange++;
        !          1173:                                break;
        !          1174:                            } else {
        !          1175:                                /* didn't work; put it back */
        !          1176:                                pnext->ref[0]->value_o = t;
        !          1177:                            }
        !          1178:                                
        !          1179:                        }
        !          1180:                    }
        !          1181:                }else{
        !          1182:                    if (pnext->nref!=2 || !dareg_addr(pnext->ref[1])) break;
        !          1183:                    otherreg =  pnext->ref[1]->value_o;
        !          1184:                    for (p3=p->forw; p3!=pnext; p3=p3->forw){
        !          1185:                        if (inmask( otherreg, addmask(p3->ruse,p3->rset) )) break;
        !          1186:                    }
        !          1187:                    if (p3!=pnext ) break;
        !          1188:                    if (!inmask( regno, pnext->forw->rlive ) && !inmask( CCREG, pnext->forw->rlive)
        !          1189:                    && ! (inmask( regno, pnext->rset) || p->subop != pnext->subop )){
        !          1190:                        if ( operand_ok(pnext->instr,p->ref[0],pnext->ref[1], 0 )){
        !          1191:                            freeoperand( p->ref[1] );
        !          1192:                            p->ref[1] = pnext->ref[1];
        !          1193:                            installinstruct( p, pnext->instr );
        !          1194:                            pnext->nref=1;
        !          1195:                            m = pnext->forw->rlive;
        !          1196:                            for (p3=pnext->back; p3!=p; p3=p3->back)
        !          1197:                                p3->rlive = m = compute_normal( p3, m);
        !          1198:                            p->rlive = compute_normal(p, m );
        !          1199:                            (void) deletenode(pnext);
        !          1200:                            didchange++;
        !          1201:                            meter.redunm++;
        !          1202:                        }
        !          1203:                    }
        !          1204:                    break;
        !          1205:                }
        !          1206: 
        !          1207:                /* see if the operand is written in the next instruction,
        !          1208:                 * then moved back in the following, and dead thereafter 
        !          1209:                 */
        !          1210:     no_cookie:
        !          1211:                if (inmask( regno, pnext->rset ) && (p3=pnext->forw)->op==OP_MOVE 
        !          1212:                && sameops( o, p3->ref[0] ) 
        !          1213:                && (pnext->nref== 1 || !sameops( o, pnext->ref[0] ) )
        !          1214:                && sameops( p->ref[0], p3->ref[1] ) && !inmask(regno , p3->forw->rlive)
        !          1215:                && p->subop==pnext->subop && pnext->subop==p3->subop )
        !          1216:                {
        !          1217:                    if (pnext->nref==1 && operand_ok( pnext->instr, p->ref[0], NULL, 0 )){
        !          1218:                        /* looks like a negX d0 or notX d0 */
        !          1219:                        /* move p's operand to pnext */
        !          1220:                        freeoperand( pnext->ref[0] );
        !          1221:                        pnext->ref[0] = p->ref[0];
        !          1222:                        p->ref[0] = NULL;
        !          1223:                        /* delete p and p3 */
        !          1224:                        p = deletenode( p ); 
        !          1225:                        (void )deletenode( p3 );
        !          1226:                        /* recompute register info */
        !          1227:                        installinstruct( pnext, pnext->instr );
        !          1228:                        pnext->rlive = compute_normal(pnext, pnext->forw->rlive );
        !          1229:                        didchange++;
        !          1230:                        meter.redunm += 2;
        !          1231:                        break;
        !          1232:                    } else if (pnext->nref==2 && operand_ok( pnext->instr, pnext->ref[0], p->ref[0], 0 )){
        !          1233:                        /* looks like a addX #Y,d0 */
        !          1234:                        /* move p's operand to pnext */
        !          1235:                        freeoperand( pnext->ref[1] );
        !          1236:                        pnext->ref[1] = p->ref[0];
        !          1237:                        p->ref[0] = NULL;
        !          1238:                        /* delete p and p3 */
        !          1239:                        p = deletenode( p ); 
        !          1240:                        (void )deletenode( p3 );
        !          1241:                        /* recompute register info */
        !          1242:                        installinstruct( pnext, pnext->instr );
        !          1243:                        pnext->rlive = compute_normal(pnext, pnext->forw->rlive );
        !          1244:                        didchange++;
        !          1245:                        meter.redunm += 2;
        !          1246:                        break;
        !          1247:                    } else if (pnext->nref==2 && !inmask(regno , p3->forw->rlive) 
        !          1248:                    && operand_ok( pnext->instr, o, p->ref[0], 0 )){
        !          1249:                        /* 
        !          1250:                         * change:
        !          1251:                         *      movX    A,d0    <== p
        !          1252:                         *      opX     B,d0    <== pnext
        !          1253:                         *      movX    d0,A    <== p3
        !          1254:                         * into:
        !          1255:                         *      movX    B,d0    <== p
        !          1256:                         *      opX     d0,A    <== pnext
        !          1257:                         */
        !          1258:                        p->ref[0] = pnext->ref[0];
        !          1259:                        installinstruct( p, p->instr );
        !          1260:                        pnext->ref[0] = pnext->ref[1];
        !          1261:                        pnext->ref[1] = p3->ref[1];
        !          1262:                        p3->nref=1;
        !          1263:                        (void)deletenode( p3 );
        !          1264:                        installinstruct( pnext, pnext->instr );
        !          1265:                        pnext->rlive = m = compute_normal( pnext, pnext->forw->rlive);
        !          1266:                        p->rlive = compute_normal( p, m );
        !          1267:                        didchange++;
        !          1268:                        meter.redunm ++;
        !          1269:                        break;
        !          1270:                    }
        !          1271:                }
        !          1272:                break;
        !          1273:                    
        !          1274:            case OP_TST:
        !          1275:                /*
        !          1276:                 * if a previous instruction touched this as an operand
        !          1277:                 * AND set cc on it in a way we appreciate, then delete this
        !          1278:                 * EXTRA HACKERY:
        !          1279:                 *    some instructions (e.g.: lsrl) set the condition codes
        !          1280:                 *    in a way that we can use MOST of the time. others
        !          1281:                 *    (esp moves) set the cond codes in a way that is ok
        !          1282:                 *    all of the time. If the previous instruction is not
        !          1283:                 *    a move, we will try to find the instruction checking
        !          1284:                 *    the cc, and decide if this is an extraordinary case.
        !          1285:                 */
        !          1286:                pprev = p;
        !          1287:                do{
        !          1288:                    previ( pprev );
        !          1289:                } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) && 
        !          1290:                    !inmask(CCREG, p->rset));
        !          1291:                if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break;
        !          1292:                /* integer cc is very funny -- floating cc very regular */
        !          1293:                if (pprev->op!=OP_MOVE){
        !          1294:                    for( p3 = p->forw;  p3->op != OP_FIRST; ){
        !          1295:                        switch (p3->op){
        !          1296:                        case OP_LABEL:
        !          1297:                            nexti(p3);
        !          1298:                            continue;
        !          1299:                        case OP_JUMP:
        !          1300:                        case OP_BRANCH:
        !          1301:                        case OP_DBRA:
        !          1302:                        case OP_DJMP:
        !          1303:                            break;
        !          1304:                        default:
        !          1305:                            if (inmask( CCREG, p3->ruse))
        !          1306:                                break;
        !          1307:                            nexti(p3);
        !          1308:                            continue;
        !          1309:                        }
        !          1310:                        break;
        !          1311:                    }
        !          1312:                    if (!inmask( CCREG, p3->ruse)) break;/* cannot find user */
        !          1313:                    if (p3->op == OP_BRANCH || p3->op == OP_DBRA) 
        !          1314:                        break;  /* too hard */
        !          1315:                    if (p3->op == OP_JUMP || p3->op == OP_DJMP){
        !          1316:                        if (inmask( CCREG, p3->luse->rlive)) break; /* double use */
        !          1317:                        if (p3->subop != JALL)
        !          1318:                            if (inmask( CCREG, p3->forw->rlive)) break; /* double use */
        !          1319:                    }
        !          1320:                    if (read_cc_cv[(int)p3->subop - (int)JEQ]) break; /* untrustworthy */
        !          1321:                }
        !          1322:                o = p->ref[0];
        !          1323:                if (!deladdr( o )) break; /* not ok to remove this reference */
        !          1324:                /*
        !          1325:                 * if we set condition codes on this, AND its not an
        !          1326:                 * Areg (on which condition codes are never set, then
        !          1327:                 * its ok to delete the test
        !          1328:                 */
        !          1329:                if (pprev->nref>=1 && sameops( pprev->ref[0], o)){
        !          1330:                    if (((pprev->instr->cc_i&CCX) == CC1) || 
        !          1331:                    ( pprev->op == OP_MOVE  && !areg_addr( pprev->ref[1])) ){
        !          1332:                        p = deletenode( p );
        !          1333:                        didchange++;
        !          1334:                        meter.nrtst++;
        !          1335:                    }
        !          1336:                } else if (pprev->nref==2 && sameops( pprev->ref[1], o)){
        !          1337:                    if (((pprev->instr->cc_i&CCX) == CC2) && !areg_addr(o) ){
        !          1338:                        p = deletenode( p );
        !          1339:                        didchange++;
        !          1340:                        meter.nrtst++;
        !          1341:                    }
        !          1342:                }
        !          1343:                break;
        !          1344:            case OP_FTST:
        !          1345:                /*
        !          1346:                 * Floating-point instructions always set their condition codes
        !          1347:                 * on the result. The exception is that a move from the 
        !          1348:                 * coprocessor does not set the condition codes at all.
        !          1349:                 */
        !          1350:                /* see if we can find an instruction that sets fpcc */
        !          1351:                pprev = p;
        !          1352:                do{
        !          1353:                    previ( pprev );
        !          1354:                } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) && 
        !          1355:                    !inmask(FPCCREG, p->rset));
        !          1356:                if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break;
        !          1357:                o = p->ref[0];
        !          1358:                if ((pprev->op ==OP_MOVE && sameops( o, pprev->ref[0] ))||
        !          1359:                    (pprev->op !=OP_MOVE && sameops( o, pprev->ref[pprev->nref-1] ))){
        !          1360:                    p = deletenode( p );
        !          1361:                    didchange++;
        !          1362:                    meter.nrtst++;
        !          1363:                }
        !          1364:                break;
        !          1365:            case OP_OR:
        !          1366:                /*
        !          1367:                 * if what we're or-ing will fit into a byte or word, then
        !          1368:                 * there's no excuse for using a longer immediate.
        !          1369:                 * unless condition codes are live.
        !          1370:                 */
        !          1371:                if ( inmask( CCREG, p->forw->rlive)) break;
        !          1372:                if (numeric_immediate(o=p->ref[0])){
        !          1373:                    t = o->value_o;
        !          1374:                    if (t==0 && deladdr(p->ref[1] )){
        !          1375:                        p = deletenode(p);
        !          1376:                        didchange++;
        !          1377:                        break;
        !          1378:                    }
        !          1379:                    if (t>0 && t<0xffff){
        !          1380:                        i = (p->subop==SUBOP_L)?2:0;
        !          1381:                        newname = "orw";
        !          1382:                        if (t<0xff){
        !          1383:                            i = (p->subop==SUBOP_L)?3:(p->subop==SUBOP_W)?1:0;
        !          1384:                            newname = "orb";
        !          1385:                        }
        !          1386:                        if (i && !incraddr( p->ref[1], i)){
        !          1387:                            cannibalize( p, newname);
        !          1388:                            meter.nwop++;
        !          1389:                            didchange++;
        !          1390:                        }
        !          1391:                    }
        !          1392:                        
        !          1393:                }
        !          1394:                break;
        !          1395:            case OP_ASL:
        !          1396:                /* look for multiple shifts in a row */
        !          1397:                if (!numeric_immediate(o=p->ref[0])) continue;
        !          1398:                t = o->value_o;
        !          1399:                o = p->ref[1];
        !          1400:                while ((pnext=p->forw)->op==OP_ASL){
        !          1401:                    register struct oper *iop;
        !          1402:                    if (!numeric_immediate(iop=pnext->ref[0])
        !          1403:                    || !sameops( pnext->ref[1], o))
        !          1404:                        break;
        !          1405:                    if ( t + iop->value_o > 8){
        !          1406:                        p->ref[0]->value_o = t;
        !          1407:                        t = iop->value_o;
        !          1408:                        p = pnext;
        !          1409:                        o = p->ref[1];
        !          1410:                        continue;
        !          1411:                    }
        !          1412:                    t += iop->value_o;
        !          1413:                    (void)deletenode( pnext );
        !          1414:                    meter.nredshf++;
        !          1415:                    didchange++;
        !          1416:                }
        !          1417:                p->ref[0]->value_o = t;
        !          1418:                break;
        !          1419:            case OP_CMP:
        !          1420:                /* compares to zero are degenerate */
        !          1421:                o = p->ref[0];
        !          1422:                if (immediate_value(o, 0) && areg_addr(p->ref[1])){
        !          1423:                    /* "A" register */
        !          1424:                    /* look for a dead D register. Make this a movl */
        !          1425:                    if ((i=dead_dreg(p)) >= 0){
        !          1426:                        /* change cmpx #0,ay => movl ay,di */
        !          1427:                        /* reuse the #0 operand as the di operand */
        !          1428:                        p->ref[0] = p->ref[1];
        !          1429:                        o->type_o = T_REG;
        !          1430:                        o->value_o = i;
        !          1431:                        p->ref[1] = o;
        !          1432:                        cannibalize( p, "movl" );
        !          1433:                        p->rlive = compute_normal( p, p->forw->rlive );
        !          1434:                        meter.nttomo++;
        !          1435:                        didchange++;
        !          1436:                    }
        !          1437:                }
        !          1438:                break;
        !          1439:            case OP_LEA:
        !          1440:                /*
        !          1441:                 * this form seems to occur rather often:
        !          1442:                 *      lea     XXX,a0
        !          1443:                 *      movl    a0,aN
        !          1444:                 * with a0 dead beyond this point. Change this into
        !          1445:                 *      lea     XXX,aN
        !          1446:                 * then, look for the case
        !          1447:                 *      lea     aN@(0,dM:Z),aN
        !          1448:                 * and simplify it into
        !          1449:                 *      addZ    dM,aN
        !          1450:                 */
        !          1451:                if ((pnext=p->forw)->op == OP_MOVE
        !          1452:                  && pnext->subop == SUBOP_L 
        !          1453:                  && sameops( p->ref[1], pnext->ref[0])
        !          1454:                  && emptymask( andmask(p->rset,pnext->forw->rlive))) {
        !          1455:                    /* if the move is to an A register, we're set */
        !          1456:                    o=pnext->ref[1];
        !          1457:                    if (areg_addr(o)){
        !          1458:                        pnext->ref[1] = p->ref[1]; /* give away our 2nd operand */
        !          1459:                        p->ref[1] = o; /* gain a new operand */
        !          1460:                        (void) deletenode( pnext ); /* get rid of next, with operands */
        !          1461:                        p->rset = MAKEWMASK( o->value_o, LW );
        !          1462:                        p->rlive = compute_normal( p, p->forw->rlive);
        !          1463:                        didchange++;
        !          1464:                        meter.redunm++;
        !          1465:                    }
        !          1466:                }
        !          1467:                if ((o=p->ref[0])->type_o == T_INDEX
        !          1468:                  && o->reg_o == p->ref[1]->value_o
        !          1469:                  && o->scale_o == 1
        !          1470:                  && !(o->flags_o&(O_BSUPRESS|O_INDIRECT|O_POSTINDEX))
        !          1471:                  && o->disp_o == 0){
        !          1472:                    o->type_o = T_REG;
        !          1473:                    newname = (o->flags_o&O_WINDEX) ? "addw" : "addl";
        !          1474:                    o->flags_o &= ~(O_WINDEX|O_LINDEX);
        !          1475:                    cannibalize( p, newname );
        !          1476:                    meter.nsaddr++;
        !          1477:                    didchange++;
        !          1478:                }
        !          1479:                break;
        !          1480: 
        !          1481:            case OP_SUB:
        !          1482:                p = make_dbra( p, &didchange );
        !          1483:                if (p->op != OP_SUB) break;
        !          1484:                /* FALL THROUGH */
        !          1485:            case OP_ADD:
        !          1486:                p = plus_minus( p, &didchange );
        !          1487:                break;
        !          1488:            }
        !          1489:        }
        !          1490:        nchanged += didchange;
        !          1491:     }
        !          1492:     return nchanged;
        !          1493: }

unix.superglobalmegacorp.com

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