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

1.1       root        1: /* @(#) w1opt.c: 1.4 3/27/84                           */
                      2: /* w1opt.c
                      3: **
                      4: **     3B20S optimizer:  for one-instruction window
                      5: **
                      6: **
                      7: */
                      8: 
                      9: /* #include "defs" -- optim.h takes care of this */
                     10: #include "optim.h"
                     11: #include "optutil.h"
                     12: 
                     13: 
                     14: /*     D A N G E R
                     15: **
                     16: ** This definition selects the highest numbered register that we
                     17: ** can arbitrarily choose as a temporary in the multiply strength
                     18: ** reduction that is performed below.  It should equal the highest
                     19: ** numbered temporary register used by the compiler (1 less than
                     20: ** lowest numbered register used for register variables.
                     21: */
                     22: 
                     23: #define        TEMPREG         3               /* highest temp. reg. to use */
                     24: /* w1opt -- one-instruction optimizer
                     25: **
                     26: ** This routine handles the single-instruction optimization window.
                     27: ** See individual comments below about what's going on.
                     28: ** In some cases (which are noted), the optimizations are ordered.
                     29: */
                     30: 
                     31: boolean                                        /* true if we make any changes */
                     32: w1opt(pf,pl)
                     33: register NODE * pf;                    /* pointer to first instruction in
                     34:                                        ** window (and last)
                     35:                                        */
                     36: NODE * pl;                             /* pointer to last instruction in
                     37:                                        ** window (= pf)
                     38:                                        */
                     39: {
                     40: 
                     41:     register int cop = pf->op;         /* single instruction's op code # */
                     42:     int opn;                           /* temporary op code number */
                     43:     char * opst;                       /* temporary op code string */
                     44:     boolean retval = false;            /* return value:  in some cases
                     45:                                        ** we fall through after completing
                     46:                                        ** an optimization because it could
                     47:                                        ** lead into others.  This variable
                     48:                                        ** contains the return state for the
                     49:                                        ** end.
                     50:                                        */
                     51:     char * dest;                       /* destination string, used below */
                     52:     long mult;                         /* multiplier, used below */
                     53:     boolean f;                         /* random boolean flag, used below */
                     54:     long templ;                                /* general long temporary */
                     55: /* eliminate dead code:
                     56: **
                     57: **     op2 O1,R        or      op3 O1,O2,R
                     58: **             where R is dead
                     59: */
                     60: 
                     61:     if (
                     62:            isdead(dst(pf),pf)          /* we don't really care what the op
                     63:                                        ** is
                     64:                                        */
                     65:        &&  ! isbr(pf)                  /* but some branches set variables
                     66:                                        ** and jump:  keep them
                     67:                                        */
                     68:        &&  isdeadcc( pf )              /* this inst. may have side effects
                     69:                                        ** relied upon by cond. branch
                     70:                                        */
                     71:        &&  isiros( pf->op1 )
                     72:        &&  isiros( pf->op2 )           /* are operands safe for mmio */
                     73:        )
                     74:     {
                     75:        wchange();                      /* Note we're changing the window */
                     76:        ldelin2(pf);                    /* preserve line number info */
                     77:        mvlivecc(pf);                   /* preserve condition codes line info */
                     78:        DELNODE(pf);                    /* discard instruction */
                     79:        return(true);                   /* announce success */
                     80:     }
                     81: 
                     82: /*
                     83: **     cmpw R,&0       ->      movw R,R
                     84: **
                     85: ** This wins on the 3B20S, but might not on other 3B processors.
                     86: */
                     87: 
                     88: /* Although this improvement is a small win, it messes up other
                     89: ** transformations and generally confuses things.  It's probably
                     90: ** better to leave it turned off.
                     91: */
                     92: 
                     93: #ifdef CMPWTOMOVW
                     94: 
                     95:     if (
                     96:            cop == CMPW
                     97:        &&  isreg(pf->op1)
                     98:        &&  strcmp(pf->op2,"&0") == 0
                     99:        )
                    100: 
                    101:     {
                    102:        wchange();                      /* note change */
                    103:        chgop(pf,MOVW,"movw");          /* change the op code */
                    104:        pf->op2 = pf->op1;              /* both operands point at R */
                    105:        makelive(pf->op2,pf);           /* make register appear to be live
                    106:                                        ** hereafter so "compare" isn't thrown
                    107:                                        ** away.  (Otherwise R might be dead
                    108:                                        ** and we would eliminate the inst.)
                    109:                                        */
                    110:        return(true);                   /* made a change */
                    111:     }
                    112: 
                    113: #endif /* def CMPWTOMOV */
                    114: /* get rid of useless arithmetic
                    115: **
                    116: **     addw2   &0,O            ->      deleted  or  cmpw O,&0
                    117: **     subw2   &0,O            ->      deleted  or  cmpw O,&0
                    118: **     orw2    &0,O            ->      deleted  or  cmpw O,&0
                    119: **     xorw2   &0,O            ->      deleted  or  cmpw O,&0
                    120: **     alsw2   &0,O            ->      deleted  or  cmpw O,&0
                    121: **     arsw2   &0,O            ->      deleted  or  cmpw O,&0
                    122: **     llsw2   &0,O            ->      deleted  or  cmpw O,&0
                    123: **     lrsw2   &0,O            ->      deleted  or  cmpw O,&0
                    124: **     mulw2   &1,O            ->      deleted  or  cmpw O,&0
                    125: **     umulw2  &1,O            ->      deleted  or  cmpw O,&0
                    126: **     divw2   &1,O            ->      deleted  or  cmpw O,&0
                    127: **     udivw2  &1,O            ->      deleted  or  cmpw O,&0
                    128: **     andw2   &-1,O           ->      deleted  or  cmpw O,&0
                    129: 
                    130: **     addw3   &0,O1,O2        ->      movw O1,O2
                    131: **     subw3   &0,O1,O2        ->      movw O1,O2
                    132: **     orw3    &0,O1,O2        ->      movw O1,O2
                    133: **     xorw3   &0,O1,O2        ->      movw O1,O2
                    134: **     alsw3   &0,O1,O2        ->      movw O1,O2
                    135: **     arsw3   &0,O1,O2        ->      movw O1,O2
                    136: **     llsw3   &0,O1,O2        ->      movw O1,O2
                    137: **     lrsw3   &0,O1,O2        ->      movw O1,O2
                    138: **     mulw3   &1,O1,O2        ->      movw O1,O2
                    139: **     umulw3  &1,O1,O2        ->      movw O1,O2
                    140: **     divw3   &1,O1,O2        ->      movw O1,O2
                    141: **     udivw3  &1,O1,O2        ->      movw O1,O2
                    142: **     andw3   &-1,O1,O2       ->      movw O1,O2
                    143: **
                    144: **     mulw2   &0,O            ->      movw &0,O
                    145: **     umulw2  &0,O            ->      movw &0,O
                    146: **     andw2   &0,O            ->      movw &0,O
                    147: **     mulw3   &0,O1,O2        ->      movw &0,O2
                    148: **     umulw3  &0,O1,O2        ->      movw &0,O2
                    149: **     andw3   &0,O1,O2        ->      movw &0,O2
                    150: **
                    151: **     xorw2   &-1,O           ->      mcomw O,O
                    152: **     xorw3   &-1,O1,O2       ->      mcomw O1,O2
                    153: **
                    154: **     mulw2   &-1,O           ->      mnegw O,O
                    155: **     divw2   &-1,O           ->      mnegw O,O
                    156: **     mulw3   &-1,O1,O2       ->      mnegw O1,O2
                    157: **     divw3   &-1,O1,O2       ->      mnegw O1,O2
                    158: **
                    159: ** Note that since we've already gotten rid of dead code, we won't
                    160: ** check whether O (O2) is live.  However, we must be careful to
                    161: ** preserve the sense of result indicators if a conditional branch
                    162: ** follows some of these changes.
                    163: */
                    164: 
                    165: /* Define types of changes we will make.... */
                    166: 
                    167: #define        UA_NOP  1                       /* no change */
                    168: #define UA_DEL 2                       /* delete instruction */
                    169: #define UA_MOV 3                       /* change to move */
                    170: #define UA_MOVZ        4                       /* change to move zero to ... */
                    171: #define UA_MCOM        5                       /* change to move complemented */
                    172: #define UA_MNEG        6                       /* change to move negated */
                    173: /* We must have a literal as the first operand, and its value must fit
                    174: ** in an integer.  We check the latter condition by comparing the converted
                    175: ** value from atol to the same value cast as an int:  they must agree.
                    176: ** (This is a particular problem for DMERT when they run the optimizer
                    177: ** on a PDP-11/70 to optimize 3B20 code.)
                    178: */
                    179:     if (    isnumlit(pf->op1)
                    180:        &&  (templ = atol(pf->op1+1)) == (long)((int) templ)
                    181:        )
                    182:     {
                    183:        int ultype = UA_NOP;            /* initial type of change = none */
                    184: 
                    185:        switch((int) templ)             /* branch on literal */
                    186:        {
                    187:        case 0:                         /* handle all instructions with &0
                    188:                                        ** as first operand
                    189:                                        */
                    190:            switch (cop)
                    191:            {
                    192:            case ADDW2:
                    193:            case SUBW2:
                    194:            case ORW2:
                    195:            case XORW2:
                    196:            case ALSW2:
                    197:            case ARSW2:
                    198:            case LLSW2:
                    199:            case LRSW2:
                    200:                if( !isiros( pf->op2 ) ) break;
                    201:                ultype = UA_DEL;
                    202:                break;
                    203:                                        /* if safe from mmio,
                    204:                                        ** delete all of these */
                    205:            
                    206:            case ADDW3:
                    207:            case SUBW3:
                    208:            case ORW3:
                    209:            case XORW3:
                    210:            case ALSW3:
                    211:            case ARSW3:
                    212:            case LLSW3:
                    213:            case LRSW3:
                    214:                ultype = UA_MOV;        /* convert to simple moves */
                    215:                break;
                    216: 
                    217:            case MULW2:
                    218:            case UMULW2:
                    219:            case ANDW2:
                    220:                ultype = UA_MOVZ;       /* convert to move zero */
                    221:                break;
                    222: 
                    223:            case MULW3:
                    224:            case UMULW3:
                    225:            case ANDW3:
                    226:                if( !isiros( pf->op2 ) ) break;
                    227:                ultype = UA_MOVZ;       
                    228:                break;
                    229:                                        /* if safe from mmio,
                    230:                                        ** convert to move zero */
                    231:            }
                    232:            break;                      /* done &0 case */
                    233: 
                    234:        case 1:                         /* &1 case */
                    235:            switch( cop )               /* branch on op code */
                    236:            {
                    237:            case DIVW2:
                    238:            case UDIVW2:
                    239:            case MULW2:
                    240:            case UMULW2:
                    241:                if( !isiros( pf->op2 ) ) break;
                    242:                ultype = UA_DEL;        
                    243:                break;
                    244:                                        /* if safe from mmio, 
                    245:                                        ** delete these */
                    246:            
                    247:            case DIVW3:
                    248:            case UDIVW3:
                    249:            case MULW3:
                    250:            case UMULW3:
                    251:                ultype = UA_MOV;        /* convert these to moves */
                    252:                break;
                    253:            }
                    254:            break;                      /* done &1 case */
                    255:        
                    256:        case -1:                        /* &-1 case */
                    257:            switch ( cop )              /* branch on op code */
                    258:            {
                    259:            case ANDW2:
                    260:                if( !isiros( pf->op2 ) ) break;
                    261:                ultype = UA_DEL;        
                    262:                break;
                    263:                                        /* if safe from mmio,
                    264:                                        ** delete this */
                    265:            
                    266:            case ANDW3:
                    267:                ultype = UA_MOV;        /* change to move */
                    268:                break;
                    269:            
                    270:            case XORW2:
                    271:                if( !isiros( pf->op2 ) ) break;
                    272:                ultype = UA_MCOM;
                    273:                break;
                    274:                                        /* if safe from mmio,
                    275:                                        ** change to move complemented */
                    276: 
                    277:            case XORW3:
                    278:                ultype = UA_MCOM;       /* change to move complemented */
                    279:                break;
                    280:            
                    281:            case MULW2:
                    282:            case DIVW2:
                    283:                if( !isiros( pf->op2 ) ) break;
                    284:                ultype = UA_MNEG;
                    285:                break;
                    286:                                        /* if safe from mmio,
                    287:                                        ** change to move complemented */
                    288:            case MULW3:
                    289:            case DIVW3:
                    290:                ultype = UA_MNEG;       /* change to move negated */
                    291:                break;
                    292:            }
                    293:            break;                      /* end &-1 case */
                    294:        } /* end switch on immediate value */
                    295: /* Now do something, based on selections made above */
                    296: 
                    297:        switch ( ultype )
                    298:        {
                    299:        case UA_MOV:                    /* change instruction to move */
                    300:            wchange();                  /* changing window */
                    301:            pf->op1 = pf->op2;          /* shift operands */
                    302:            pf->op2 = dst(pf);
                    303:            pf->op3 = NULL;             /* in case we removed it */
                    304:            chgop(pf,MOVW,"movw");      /* change op code */
                    305:            retval = true;              /* made a change */
                    306:            break;
                    307:        
                    308:        case UA_MOVZ:                   /* change to move zero to operand */
                    309:            wchange();
                    310:            pf->op1 = "&0";             /* first operand is zero */
                    311:            pf->op2 = dst(pf);          /* second is ultimate destination */
                    312:            pf->op3 = NULL;             /* clean out if there was one */
                    313:            chgop(pf,MOVW,"movw");      /* change op code */
                    314:            retval = true;              /* made a change */
                    315:            break;
                    316:        
                    317:        case UA_MCOM:                   /* change to move complemented */
                    318:            wchange();
                    319:            pf->op1 = pf->op2;          /* shift operands */
                    320:            pf->op2 = dst(pf);
                    321:            pf->op3 = NULL;
                    322:            chgop(pf,MCOMW,"mcomw");    /* change op code */
                    323:            retval = true;              /* made a change */
                    324:            break;
                    325:        
                    326:        case UA_MNEG:                   /* change to move negated */
                    327:            wchange();
                    328:            pf->op1 = pf->op2;          /* shift operands */
                    329:            pf->op2 = dst(pf);
                    330:            pf->op3 = NULL;
                    331:            chgop(pf,MNEGW,"mnegw");    /* change op code */
                    332:            retval = true;              /* made a change */
                    333:            break;
                    334: /* For this case we must be careful:  if a following instruction is a
                    335: ** conditional branch, it is clearly depending on the result of the
                    336: ** arithmetic, so we must put in a compare against zero instead of deleting
                    337: ** the instruction.
                    338: */
                    339: 
                    340:        case UA_DEL:                    /* delete instruction */
                    341: 
                    342:            wchange();                  /* we will make a change */
                    343: 
                    344:            if ( ! isdeadcc(pf) )
                    345:            {
                    346:                chgop(pf,CMPW,"cmpw");
                    347:                pf->op1 = pf->op2;      /* always test second operand */
                    348:                pf->op2 = "&0";         /* compare to zero */
                    349:                pf->op3 = NULL;         /* for completeness */
                    350:                retval = true;          /* made a change */
                    351:            }
                    352:            else
                    353:            {
                    354:                ldelin2(pf);            /* preserve line number info */
                    355:                mvlivecc(pf);           /* preserve condition codes line info */
                    356:                DELNODE(pf);            /* not conditional; delete node */
                    357:                return(true);           /* say we changed something */
                    358:            }
                    359:            break;
                    360:        } /* end case that decides what to do */
                    361:        
                    362:        cop = pf->op;                   /* reset current op for changed inst. */
                    363: 
                    364:     } /* end useless arithmetic removal */
                    365: /* discard useless movw's
                    366: **
                    367: **     movw    O,O             ->      deleted
                    368: **
                    369: ** The movw must not be followed by a conditional jump, since we
                    370: ** must leave the condition codes set.  Note that this improvement
                    371: ** picks up some strange code generated above, like
                    372: **
                    373: **     mulw3   &1,%r0,%r0      ->      movw    %r0,%r0
                    374: **
                    375: */
                    376: 
                    377:     if (    pf->op == MOVW
                    378:        &&  strcmp(pf->op1,pf->op2) == 0
                    379:        &&  isdeadcc(pf)
                    380:        &&  isiros(pf->op1)             /* safe from mmio */
                    381:        )
                    382:     {
                    383:        wchange();                      /* changing the window */
                    384:        ldelin2(pf);                    /* preserve line number info */
                    385:        mvlivecc(pf);                   /* preserve condition codes line info */
                    386:        DELNODE(pf);                    /* delete the movw */
                    387:        return(true);
                    388:     }
                    389: /* change triadics to dyadics if possible
                    390: **
                    391: **     op3 O1,O2,O2            ->      op2 O1,O2
                    392: **
                    393: */
                    394: 
                    395:     if (istriadic(pf,&opn,&opst) 
                    396:        && strcmp(pf->op2,pf->op3) == 0
                    397:        && isiros(pf->op2)              /* safe from mmio */
                    398:        )
                    399: 
                    400:     /* triadic and last two operands match */
                    401: 
                    402:     {
                    403:        wchange();                      /* we're making a change */
                    404:        chgop(pf,opn,opst);             /* change the op code */
                    405:        pf->op3 = NULL;                 /* so we don't keep looking at 3rd
                    406:                                        ** operand
                    407:                                        */
                    408:        retval = true;                  /* remember that we made a change,
                    409:                                        ** but don't exit, as the next
                    410:                                        ** optimization may also apply.
                    411:                                        */
                    412:        cop = opn;                      /* changed op code */
                    413:     }
                    414:     /* falling through either way !! */
                    415: /* change multiplies and divides to shifts if power of 2 */
                    416: 
                    417: /*
                    418: **     udivw2 &2^n,O           ->      lrsw2 &n,O
                    419: **     udivw3 &2^n,O1,O2       ->      lrsw3 &n,O1,O2
                    420: **     mulw2 &2^n,O            ->      arsw2 &n,O
                    421: **     mulw3 &2^n,O1,O2        ->      arsw3 &n,O1,O2
                    422: **     umulw2 &2^n,O           ->      llsw2 &n,O
                    423: **     umulw3 &2^n,O1,O2       ->      llsw3 &n,O1,O2
                    424: **
                    425: ** Note that signed divide cannot safely be altered with these
                    426: ** transformations!
                    427: */
                    428: 
                    429:     switch (cop)                       /* dispatch on type */
                    430:     {
                    431:        int bit;                        /* temporary bit number if 2^n */
                    432: 
                    433:     case UDIVW2:
                    434:     case UDIVW3:
                    435:     case MULW2:
                    436:     case MULW3:
                    437:     case UMULW2:
                    438:     case UMULW3:
                    439: 
                    440:        if ( (bit = getbit(pf->op1)) < 0) /* if not power of 2, done this */
                    441:            break;
                    442: 
                    443:        wchange();                      /* about to change window */
                    444:        pf->op1 = getspace(1+2+1);      /* room for &dd\0 */
                    445:        (void) sprintf(pf->op1,"&%d",bit); /* write shift amount */
                    446:        switch (cop)                    /* now change op code as needed */
                    447:        {
                    448:        case UDIVW2:
                    449:            chgop(pf,LRSW2,"lrsw2"); break;
                    450:        case UDIVW3:
                    451:            chgop(pf,LRSW3,"lrsw3"); break;
                    452:        case MULW2:
                    453:            chgop(pf,ALSW2,"alsw2"); break;
                    454:        case MULW3:
                    455:            chgop(pf,ALSW3,"alsw3"); break;
                    456:        case UMULW2:
                    457:            chgop(pf,LLSW2,"llsw2"); break;
                    458:        case UMULW3:
                    459:            chgop(pf,LLSW3,"llsw3"); break;
                    460:        }
                    461:        retval = true;                  /* we changed something */
                    462:        cop = pf->op;                   /* changed op code, too */
                    463:     }
                    464: 
                    465: #ifndef M32                    /* applies only to 3B20S */
                    466: 
                    467: /* The 3B20 can do shifts and adds faster than multiplies for small
                    468: ** integer multipliers where the result ends up in a register.  Here
                    469: ** we pick such multiplies apart, arbitrarily stopping at 10 as an
                    470: ** upper bound.
                    471: */
                    472: 
                    473:     if (
                    474:            (
                    475:                cop == MULW2
                    476:            ||  cop == MULW3
                    477:            )
                    478:        &&  *pf->op1 == '&'             /* multiplier is small literal */
                    479:        &&  isreg(dest = (cop == MULW2 ? pf->op2 : pf->op3))
                    480:                                        /* remember dest.; must be reg. */
                    481:        &&  (mult = atol(pf->op1+1)) > 2/* positive multiplier (exclude
                    482:                                        ** 0, 1, 2
                    483:                                        */
                    484:        &&  mult <= 10                  /* arbitrary upper limit */
                    485:        )
                    486:     {
                    487:        static char regstring[] = "%rx";/* boiler-plate register name */
                    488:        char * temp = NULL;             /* string representing temp. used
                    489:                                        ** during "multiply"
                    490:                                        */
                    491:        NODE * new;                     /* pointer to new instruction node */
                    492: 
                    493: /* The approach works like this:
                    494: **
                    495: **     1.  Identify destination register and temporary register that
                    496: **             we will need to use.
                    497: **     2.  Determine live/dead data for new instructions.
                    498: **     3.  Add new instructions after the MULW_, but holding on to the
                    499: **             MULW_ as an anchor (since pf points at it).
                    500: **     4.  Delete MULW_ when done.
                    501: **
                    502: **     Note that the instruction sequences we create always set the
                    503: **     result indicators the same as if a multiply had been done.
                    504: */
                    505: 
                    506: /* Macro to add new instruction:
                    507: **     ptr     points to instruction to add after
                    508: **     opn     op code number of new instruction
                    509: **     opst    op code string of instruction
                    510: **     opn1    operand 1 for new instruction
                    511: **     opn2    operand 2 for new instruction
                    512: **     ld      live/dead data for new instruction
                    513: */
                    514: 
                    515: #define        addinst(ptr,opn,opst,opn1,opn2,ld) \
                    516:     { \
                    517:        last = insert(ptr);             /* get new node */ \
                    518:        chgop(last,opn,opst);           /* put in op code number, string */ \
                    519:        last->op1 = opn1;               /* put in operands */ \
                    520:        last->op2 = opn2;               \
                    521:        last->nlive = ld;               /* put in live/dead info. */ \
                    522:     }
                    523: /* Identify temporary and destination registers.
                    524: **
                    525: ** Destination is already in 'dest':  the destination of the MULW_.
                    526: ** 'temp' must be chosen for MULW2 or for MULW3 where the second
                    527: ** operand is not already in a register.
                    528: */
                    529: 
                    530:        /* f will remember whether we needed to "create" a temporary.
                    531:        ** We must do so for MULW2 or for MULW3 when 2nd operand not a reg.
                    532:        */
                    533: 
                    534:        if ( f = (
                    535:                    cop == MULW2        /* inst. is MULW2 */
                    536:                 ||  ! isreg(pf->op2)   /* MULW3 2nd operand not reg. */
                    537:                 )
                    538:            )
                    539: 
                    540:        {
                    541:            int j;                      /* register number */
                    542: 
                    543:            /* We're going to loop, trying to find a register to steal.
                    544:            ** Then we save a copy of the appropriate register string for
                    545:            ** the instructions we'll build.
                    546:            */
                    547: 
                    548:            for ( j = '0' + TEMPREG; j >= '0'; j--) /* go down from highest */
                    549:            {
                    550:                regstring[2] = (char) j; /* stick char in string */
                    551:                if (isdead(regstring,pf)) /* if dead, we can use it */
                    552:                {
                    553:                    temp = strcpy(getspace(sizeof regstring),regstring);
                    554:                    break;
                    555:                }
                    556:            }
                    557:        } /* end if that builds a temp. string */
                    558:        else                            /* MULW3 had reg. as 2nd operand */
                    559:            temp = pf->op2;             /* point at it as suitable temporary */
                    560: 
                    561: /* 'dest' and 'temp' now point at suitable strings representing registers.
                    562: ** Although we're not sure about the multiplier value, we know powers of
                    563: ** 2 have already been handled.  Therefore there is no danger of allocating
                    564: ** a string above without actually using it.
                    565: */
                    566: /* Build correct instruction sequence. */
                    567: 
                    568:        if (temp != NULL)               /* make sure we got a temporary */
                    569:        {
                    570:            NODE * last = pf;           /* remember last node in sequence */
                    571:            int ld;                     /* current live/dead bits */
                    572: 
                    573:            wchange();                  /* tell the world we're changing */
                    574: 
                    575:        /* Set up live/dead data.  We want to replicate the information in
                    576:        ** the current multiply node, plus we want to set 'temp' and 'dest'
                    577:        ** registers live.
                    578:        */
                    579: 
                    580:            makelive(dest,pf);          /* set destination live */
                    581:            ld = pf->nlive;             /* remember data */
                    582: 
                    583:            if (cop == MULW3)           /* On MULW3 we must load the dest. */
                    584:                addinst(last,MOVW,"movw",pf->op2,dest,ld);
                    585:            
                    586:        /* Now we change the live/dead information so 'temp' will appear live */
                    587: 
                    588:            makelive(temp,pf);
                    589:            ld = pf->nlive;
                    590: 
                    591:        /* If we created a temp, move the current destination (multiplicand)
                    592:        ** there now.
                    593:        */
                    594: 
                    595:            if (f)
                    596:                addinst(last,MOVW,"movw",dest,temp,ld);
                    597: 
                    598:        /* Now generate instruction sequences based on multiplier. */
                    599: 
                    600:            switch ((int) mult)         /* value known to be between 2, 10 */
                    601:            {
                    602:            case 3:
                    603:                addinst(last,LLSW2,"llsw2","&1",dest,ld);       /* *2 */
                    604:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *3 */
                    605:                break;
                    606:            case 5:
                    607:                addinst(last,LLSW2,"llsw2","&2",dest,ld);       /* *4 */
                    608:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *5 */
                    609:                break;
                    610:            case 6:
                    611:                addinst(last,LLSW2,"llsw2","&2",dest,ld);       /* *4 */
                    612:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *5 */
                    613:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *6 */
                    614:                break;
                    615:            case 7:
                    616:                addinst(last,LLSW2,"llsw2","&3",dest,ld);       /* *8 */
                    617:                addinst(last,SUBW2,"subw2",temp,dest,ld);       /* *7 */
                    618:                break;
                    619:            case 9:
                    620:                addinst(last,LLSW2,"llsw2","&3",dest,ld);       /* *8 */
                    621:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *9 */
                    622:                break;
                    623:            case 10:
                    624:                addinst(last,LLSW2,"llsw2","&3",dest,ld);       /* *8 */
                    625:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *9 */
                    626:                addinst(last,ADDW2,"addw2",temp,dest,ld);       /* *10 */
                    627:                break;
                    628:            }
                    629:       /* Done generating instructions.  Now clean up.
                    630:        ** First, fix up live/dead data so temp is dead after last
                    631:        ** instruction.  Then kill old node.
                    632:        */
                    633: 
                    634:            makedead(temp,last);
                    635:            ldelin(pf);         /* preserve line number info */
                    636:            DELNODE(pf);                /* delete the multiply */
                    637:            return(true);               /* we-ve changed something */
                    638:        } /* end if, testing for NULL temp */
                    639:     } /* end if, testing for multiply */
                    640: 
                    641: #endif /* ndef M32 */
                    642: 
                    643: #ifndef M32                    /* 3B20 only */
                    644: 
                    645: /* The 3B20 has special instructions to move a positive nibble to a
                    646: ** register.  It does less well with negative ones, since it puts
                    647: ** them in a large immediate value.  The following transformation
                    648: ** runs faster for small negative constants.
                    649: **
                    650: **     movw    &-n,R           ->      movw    &n,R
                    651: **                             ->      mnegw   R,R
                    652: **
                    653: **     when 1 <= n <= 15
                    654: */
                    655: 
                    656:     if (
                    657:            cop == MOVW
                    658:        &&  isreg(pf->op2)
                    659:        &&  isnegnib(pf->op1)
                    660:        )
                    661:     {
                    662:        NODE * new = insert(pf);        /* make new node after pf */
                    663: 
                    664:        wchange();                      /* we're making changes */
                    665:        *(pf->op1 = copyopn(pf->op1,-1,1)) = '&';
                    666:                                        /* copy operand, offset by 1,
                    667:                                        ** overwrite - with &
                    668:                                        */
                    669:        chgop(new,MNEGW,"mnegw");       /* fill in new node */
                    670:        new->op1 = new->op2 = pf->op2;
                    671:        new->nlive = pf->nlive;         /* replicate live/dead data for new
                    672:                                        ** node so it won't go away
                    673:                                        */
                    674:        return(true);
                    675:     }
                    676: 
                    677: #endif /* ndef M32 */
                    678: 
                    679: #ifndef M32                            /* 3B20 only */
                    680: 
                    681: /* From empirical studies it appears that triadic instructions should
                    682: ** not be used on the 3B20S when the destination is a register, because
                    683: ** an equivalent two-instruction sequence is faster.  The same applies
                    684: ** in another specialized triadic case below.
                    685: **
                    686: **     op3 O1,O2,R             ->      movw O2,R
                    687: **                             ->      op2 O1,R
                    688: **
                    689: **     if R not used in O1
                    690: **
                    691: **
                    692: **     op3 &n,R,O              ->      op2 &n,R
                    693: **                             ->      movw R,O
                    694: **
                    695: **     if R is dead
                    696: */
                    697: 
                    698:     if (istriadic(pf,&opn,&opst))      /* check triadic, save equiv. op code
                    699:                                        ** number and string
                    700:                                        */
                    701:     {
                    702: 
                    703:     /* first case:  op3 O1,O2,R */
                    704: 
                    705:        if ( isreg(pf->op3) && ! usesreg(pf->op1,pf->op3) )
                    706:                                        /* check R not used in O1 */
                    707:        {
                    708:            NODE * new = insert(pf);    /* add new node after pf */
                    709: 
                    710:            wchange();                  /* changing something */
                    711: 
                    712:            chgop(new,opn,opst);        /* set up new node with dyadic */
                    713:            new->op1 = pf->op1;         /* set O1 */
                    714:            new->op2 = pf->op3;         /* set R */
                    715:            new->nlive = pf->nlive;     /* propagate live/dead stuff */
                    716: 
                    717:            chgop(pf,MOVW,"movw");      /* modify original node */
                    718:            pf->op1 = pf->op2;          /* make first operand O2 */
                    719:            pf->op2 = pf->op3;          /* second is R */
                    720:            pf->op3 = NULL;             /* clean up third one */
                    721:            makelive(pf->op2,pf);       /* force R live; R may be dead
                    722:                                        ** after pl if pl is followed by a
                    723:                                        ** conditional branch.  We must make
                    724:                                        ** it live here.
                    725:                                        */
                    726:            return(true);
                    727:        }
                    728:        else if (isnib(pf->op1) && isdead(pf->op2,pf))
                    729:        /* (test for register implicit in "isdead") */
                    730: 
                    731:        /* second case:  op3 &n,R,O */
                    732: 
                    733:        {
                    734:            NODE * new = insert(pf);    /* add new following node */
                    735: 
                    736:            wchange();                  /* changing something */
                    737: 
                    738:            chgop(pf,opn,opst);         /* put dyadic in first node */
                    739: 
                    740:            chgop(new,MOVW,"movw");     /* second node is MOVW */
                    741:            new->op1 = pf->op2;         /* set R */
                    742:            new->op2 = pf->op3;         /* set O */
                    743:            new->nlive = pf->nlive;     /* propagate live/dead in movw */
                    744:            makelive(pf->op2,pf);       /* make R live after op2 */
                    745: 
                    746:            pf->op3 = NULL;             /* clean out 3rd operand of original */
                    747:            return(true);
                    748:        }
                    749:     }
                    750: 
                    751: #endif /* ndef M32 */
                    752: 
                    753: #ifdef IMPLLSW
                    754: 
                    755: /* For BELLMAC-32, a shift by one bit is more efficiently
                    756: ** done as an add.
                    757: **
                    758: **     llsw2 &1,O1             ->      addw2 O1,O1
                    759: **     
                    760: **     llsw3 &1,O1,O2          ->      addw3 O1,O1,O2
                    761: **
                    762: */
                    763: 
                    764: {
                    765:        if( strcmp( pf->op1, "&1" ) == 0 
                    766:            && isiros(pf->op2)          /* safe from mmio */
                    767:            ) {
                    768:                if( pf->op == LLSW2 ) {
                    769:                        chgop( pf, ADDW2, "addw2" );
                    770:                        pf->op1 = pf->op2;
                    771:                        return( true );
                    772:                }
                    773:                if( pf->op == LLSW3 ) {
                    774:                        chgop( pf, ADDW3, "addw3" );
                    775:                        pf->op1 = pf->op2;
                    776:                        return( true );
                    777:                }
                    778:        }
                    779: }
                    780: #endif /* IMPLLSW */
                    781: 
                    782:     return(retval);                    /* indicate whether anything changed */
                    783: }

unix.superglobalmegacorp.com

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