Annotation of researchv9/jerq/sgs/optim/w1opt.c, revision 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.