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