Annotation of 42BSD/ucb/pascal/src/pccaseop.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1980 Regents of the University of California */
                      2: 
                      3: static char sccsid[] = "@(#)pccaseop.c 1.12 6/10/83";
                      4: 
                      5: #include "whoami.h"
                      6: #ifdef PC
                      7:     /*
                      8:      * and the rest of the file
                      9:      */
                     10: #include "0.h"
                     11: #include "tree.h"
                     12: #include "objfmt.h"
                     13: #include "pcops.h"
                     14: #include "pc.h"
                     15: #include "tmps.h"
                     16: 
                     17:     /*
                     18:      * structure for a case: 
                     19:      *     its constant label, line number (for errors), and location label.
                     20:      */
                     21: struct ct {
                     22:     long       cconst;
                     23:     int                cline;
                     24:     int                clabel;
                     25: };
                     26: 
                     27:     /*
                     28:      * the P2FORCE operator puts its operand into a register.
                     29:      * these to keep from thinking of it as r0 all over.
                     30:      */
                     31: #ifdef vax
                     32: #   define     FORCENAME       "r0"
                     33: #endif vax
                     34: #ifdef mc68000
                     35: #   define     FORCENAME       "d0"
                     36: #   define     ADDRTEMP        "a0"
                     37: #endif mc68000
                     38: 
                     39:     /*
                     40:      * given a tree for a case statement, generate code for it.
                     41:      * this computes the expression into a register,
                     42:      * puts down the code for each of the cases,
                     43:      * and then decides how to do the case switching.
                     44:      * tcase   [0]     T_CASE
                     45:      *         [1]     lineof "case"
                     46:      *         [2]     expression
                     47:      *         [3]     list of cased statements:
                     48:      *                 cstat   [0]     T_CSTAT
                     49:      *                         [1]     lineof ":"
                     50:      *                         [2]     list of constant labels
                     51:      *                         [3]     statement
                     52:      */
                     53: pccaseop( tcase )
                     54:     int        *tcase;
                     55: {
                     56:     struct nl  *exprtype;
                     57:     struct nl  *exprnlp;
                     58:     struct nl  *rangetype;
                     59:     long       low;
                     60:     long       high;
                     61:     long       exprctype;
                     62:     long       swlabel;
                     63:     long       endlabel;
                     64:     long       label;
                     65:     long       count;
                     66:     long       *cstatlp;
                     67:     long       *cstatp;
                     68:     long       *casep;
                     69:     struct ct  *ctab;
                     70:     struct ct  *ctp;
                     71:     long       i;
                     72:     long       nr;
                     73:     long       goc;
                     74:     int                casecmp();
                     75:     bool       dupcases;
                     76: 
                     77:     goc = gocnt;
                     78:        /*
                     79:         *  find out the type of the case expression
                     80:         *  even if the expression has errors (exprtype == NIL), continue.
                     81:         */
                     82:     line = tcase[1];
                     83:     codeoff();
                     84:     exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
                     85:     codeon();
                     86:     if ( exprtype != NIL ) {
                     87:        if ( isnta( exprtype , "bcsi" ) ) {
                     88:            error("Case selectors cannot be %ss" , nameof( exprtype ) );
                     89:            exprtype = NIL;
                     90:        } else {
                     91:            if ( exprtype -> class != RANGE ) {
                     92:                rangetype = exprtype -> type;
                     93:            } else {
                     94:                rangetype = exprtype;
                     95:            }
                     96:            if ( rangetype == NIL ) {
                     97:                exprtype = NIL;
                     98:            } else {
                     99:                low = rangetype -> range[0];
                    100:                high = rangetype -> range[1];
                    101:            }
                    102:        }
                    103:     }
                    104:     if ( exprtype != NIL ) {
                    105:            /*
                    106:             *  compute and save the case expression.
                    107:             *  also, put expression into a register
                    108:             *  save its c-type and jump to the code to do the switch.
                    109:             */
                    110:        exprctype = p2type( exprtype );
                    111:        exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG );
                    112:        putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
                    113:                        exprnlp -> extra_flags , P2INT );
                    114:        (void) rvalue( (int *) tcase[2] , NIL , RREQ );
                    115:        sconv(exprctype, P2INT);
                    116:        putop( P2ASSIGN , P2INT );
                    117:        putop( P2FORCE , P2INT );
                    118:        putdot( filename , line );
                    119:        swlabel = getlab();
                    120:        putjbr( swlabel );
                    121:     }
                    122:        /*
                    123:         *  count the number of cases
                    124:         *  and allocate table for cases, lines, and labels
                    125:         *  default case goes in ctab[0].
                    126:         */
                    127:     count = 1;
                    128:     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
                    129:        cstatp = cstatlp[1];
                    130:        if ( cstatp == NIL ) {
                    131:            continue;
                    132:        }
                    133:        for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
                    134:            count++;
                    135:        }
                    136:     }
                    137:        /*
                    138:         */
                    139:     ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
                    140:     if ( ctab == (struct ct *) 0 ) {
                    141:        error("Ran out of memory (case)");
                    142:        pexit( DIED );
                    143:     }
                    144:        /*
                    145:         *  pick up default label and label for after case statement.
                    146:         */
                    147:     ctab[0].clabel = getlab();
                    148:     endlabel = getlab();
                    149:        /*
                    150:         *  generate code for each case
                    151:         *  filling in ctab for each.
                    152:         *  nr is for error if no case falls out bottom.
                    153:         */
                    154:     nr = 1;
                    155:     count = 0;
                    156:     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
                    157:        cstatp = cstatlp[1];
                    158:        if ( cstatp == NIL ) {
                    159:            continue;
                    160:        }
                    161:        line = cstatp[1];
                    162:        label = getlab();
                    163:        for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
                    164:            gconst( casep[1] );
                    165:            if( exprtype == NIL || con.ctype == NIL ) {
                    166:                continue;
                    167:            }
                    168:            if ( incompat( con.ctype , exprtype , NIL ) ) {
                    169:                cerror("Case label type clashed with case selector expression type");
                    170:                continue;
                    171:            }
                    172:            if ( con.crval < low || con.crval > high ) {
                    173:                error("Case label out of range");
                    174:                continue;
                    175:            }
                    176:            count++;
                    177:            ctab[ count ].cconst = con.crval;
                    178:            ctab[ count ].cline = line;
                    179:            ctab[ count ].clabel = label;
                    180:        }
                    181:            /*
                    182:             *  put out the statement
                    183:             */
                    184:        putlab( label );
                    185:        putcnt();
                    186:        level++;
                    187:        statement( cstatp[3] );
                    188:        nr = (nr && noreach);
                    189:        noreach = 0;
                    190:        level--;
                    191:        if (gotos[cbn]) {
                    192:                ungoto();
                    193:        }
                    194:        putjbr( endlabel );
                    195:     }
                    196:     noreach = nr;
                    197:        /*
                    198:         *      default action is to call error
                    199:         */
                    200:     putlab( ctab[0].clabel );
                    201:     putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" );
                    202:     putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
                    203:                    exprnlp -> extra_flags , P2INT );
                    204:     putop( P2CALL , P2INT );
                    205:     putdot( filename , line );
                    206:        /*
                    207:         *  sort the cases
                    208:         */
                    209:     qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
                    210:        /*
                    211:         *  check for duplicates
                    212:         */
                    213:     dupcases = FALSE;
                    214:     for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
                    215:        if ( ctp[0].cconst == ctp[1].cconst ) {
                    216:            error("Multiply defined label in case, lines %d and %d" ,
                    217:                    ctp[0].cline , ctp[1].cline );
                    218:            dupcases = TRUE;
                    219:        }
                    220:     }
                    221:     if ( dupcases ) {
                    222:        return;
                    223:     }
                    224:        /*
                    225:         *  choose a switch algorithm and implement it:
                    226:         *      direct switch   >= 1/3 full and >= 4 cases.
                    227:         *      binary switch   not direct switch and > 8 cases.
                    228:         *      ifthenelse      not direct or binary switch.
                    229:         */
                    230:     putlab( swlabel );
                    231:     if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
                    232:        directsw( ctab , count );
                    233:     } else if ( count > 8 ) {
                    234:        binarysw( ctab , count );
                    235:     } else {
                    236:        itesw( ctab , count );
                    237:     }
                    238:     putlab( endlabel );
                    239:     if ( goc != gocnt ) {
                    240:            putcnt();
                    241:     }
                    242: }
                    243: 
                    244:     /*
                    245:      * direct switch
                    246:      */
                    247: directsw( ctab , count )
                    248:     struct ct  *ctab;
                    249:     int                count;
                    250: {
                    251:     int                fromlabel = getlab();
                    252:     long       i;
                    253:     long       j;
                    254: 
                    255: #   ifdef vax
                    256:        if (opt('J')) {
                    257:            /*
                    258:             *  We have a table of absolute addresses.
                    259:             *
                    260:             *  subl2   to make r0 a 0-origin byte offset.
                    261:             *  cmpl    check against upper limit.
                    262:             *  blssu   error if out of bounds.
                    263:             *  ashl    to make r0 a 0-origin long offset,
                    264:             *  jmp     and indirect through it.
                    265:             */
                    266:            putprintf(" subl2   $%d,%s", 0, ctab[1].cconst, FORCENAME);
                    267:            putprintf(" cmpl    $%d,%s", 0,
                    268:                    ctab[count].cconst - ctab[1].cconst, FORCENAME);
                    269:            putprintf(" blssu   %s%d", 0, LABELPREFIX, ctab[0].clabel);
                    270:            putprintf(" ashl    $2,%s,%s", 0, FORCENAME, FORCENAME);
                    271:            putprintf(" jmp     *%s%d(%s)", 0,
                    272:                    LABELPREFIX, fromlabel, FORCENAME);
                    273:        } else {
                    274:            /*
                    275:             *  We can use the VAX casel instruction with a table
                    276:             *  of short relative offsets.
                    277:             */
                    278:            putprintf(" casel   %s,$%d,$%d" , 0 , FORCENAME ,
                    279:                    ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
                    280:        }
                    281: #   endif vax
                    282: #   ifdef mc68000
                    283:        /*
                    284:         *      subl    to make d0 a 0-origin byte offset.
                    285:         *      cmpl    check against upper limit.
                    286:         *      bhi     error if out of bounds.
                    287:         */
                    288:        putprintf("     subl    #%d,%s", 0, ctab[1].cconst, FORCENAME);
                    289:        putprintf("     cmpl    #%d,%s", 0,
                    290:                ctab[count].cconst - ctab[1].cconst, FORCENAME);
                    291:        putprintf("     bhi     %s%d", 0, LABELPREFIX, ctab[0].clabel);
                    292:        if (opt('J')) {
                    293:            /*
                    294:             *  We have a table of absolute addresses.
                    295:             *
                    296:             *  asll    to make d0 a 0-origin long offset.
                    297:             *  movl    pick up a jump-table entry
                    298:             *  jmp     and indirect through it.
                    299:             */
                    300:            putprintf(" asll    #2,%s", 0, FORCENAME, FORCENAME);
                    301:            putprintf(" movl    pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP);
                    302:            putprintf(" jmp     %s@", 0, ADDRTEMP);
                    303:        } else {
                    304:            /*
                    305:             *  We have a table of relative addresses.
                    306:             *
                    307:             *  addw    to make d0 a 0-origin word offset.
                    308:             *  movw    pick up a jump-table entry
                    309:             *  jmp     and indirect through it.
                    310:             */
                    311:            putprintf(" addw    %s,%s", 0, FORCENAME, FORCENAME);
                    312:            putprintf(" movw    pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
                    313:            putprintf(" jmp     pc@(2,%s:w)", 0, FORCENAME);
                    314:        }
                    315: #   endif mc68000
                    316:     putlab( fromlabel );
                    317:     i = 1;
                    318:     j = ctab[1].cconst;
                    319:     while ( i <= count ) {
                    320:        if ( j == ctab[ i ].cconst ) {
                    321:            if (opt('J')) {
                    322:                putprintf( "    .long   " , 1 );
                    323:                putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ i ].clabel );
                    324:            } else {
                    325:                putprintf( "    .word   " , 1 );
                    326:                putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
                    327:                putprintf( "-" , 1 );
                    328:                putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
                    329:            }
                    330:            i++;
                    331:        } else {
                    332:            if (opt('J')) {
                    333:                putprintf( "    .long   " , 1 );
                    334:                putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ 0 ].clabel );
                    335:            } else {
                    336:                putprintf( "    .word   " , 1 );
                    337:                putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
                    338:                putprintf( "-" , 1 );
                    339:                putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
                    340:            }
                    341:        }
                    342:        j++;
                    343:     }
                    344: #   ifdef vax
                    345:            /*
                    346:             *  execution continues here if value not in range of case.
                    347:             */
                    348:        if (!opt('J'))
                    349:            putjbr( ctab[0].clabel );
                    350: #   endif vax
                    351: }
                    352: 
                    353:     /*
                    354:      * binary switch
                    355:      * special case out default label and start recursion.
                    356:      */
                    357: binarysw( ctab , count )
                    358:     struct ct  *ctab;
                    359:     int                count;
                    360: {
                    361:     
                    362:     bsrecur( ctab[0].clabel , &ctab[0] , count );
                    363: }
                    364: 
                    365:     /*
                    366:      * recursive log( count ) search.
                    367:      */
                    368: bsrecur( deflabel , ctab , count )
                    369:     int                deflabel;
                    370:     struct ct  *ctab;
                    371:     int                count;
                    372: {
                    373: 
                    374:     if ( count <= 0 ) {
                    375:        putjbr(deflabel);
                    376:        return;
                    377:     } else if ( count == 1 ) {
                    378: #      ifdef vax
                    379:            putprintf(" cmpl    %s,$%d", 0, FORCENAME, ctab[1].cconst);
                    380:            putprintf(" jeql    %s%d", 0, LABELPREFIX, ctab[1].clabel);
                    381:            putjbr(deflabel);
                    382: #      endif vax
                    383: #      ifdef mc68000
                    384:            putprintf(" cmpl    #%d,%s", 0, ctab[1].cconst, FORCENAME);
                    385:            putprintf(" jeq     L%d", 0, LABELPREFIX, ctab[1].clabel);
                    386:            putjbr(deflabel);
                    387: #      endif mc68000
                    388:        return;
                    389:     } else {
                    390:        int     half = ( count + 1 ) / 2;
                    391:        int     gtrlabel = getlab();
                    392: 
                    393: #      ifdef vax
                    394:            putprintf(" cmpl    %s,$%d", 0, FORCENAME, ctab[half].cconst);
                    395:            putprintf(" jgtr    %s%d", 0, LABELPREFIX, gtrlabel);
                    396:            putprintf(" jeql    %s%d", 0, LABELPREFIX, ctab[half].clabel);
                    397: #      endif vax
                    398: #      ifdef mc68000
                    399:            putprintf(" cmpl    #%d,%s", 0, ctab[half].cconst, FORCENAME);
                    400:            putprintf(" jgt     %s%d", 0, LABELPREFIX, gtrlabel);
                    401:            putprintf(" jeq     %s%d", 0, LABELPREFIX, ctab[half].clabel);
                    402: #      endif mc68000
                    403:        bsrecur( deflabel , &ctab[0] , half - 1 );
                    404:        putlab(gtrlabel);
                    405:        bsrecur( deflabel , &ctab[ half ] , count - half );
                    406:        return;
                    407:     }
                    408: }
                    409: 
                    410: itesw( ctab , count )
                    411:     struct ct  *ctab;
                    412:     int                count;
                    413: {
                    414:     int        i;
                    415: 
                    416:     for ( i = 1 ; i <= count ; i++ ) {
                    417: #      ifdef vax
                    418:            putprintf(" cmpl    %s,$%d", 0, FORCENAME, ctab[i].cconst);
                    419:            putprintf(" jeql    %s%d", 0, LABELPREFIX, ctab[i].clabel);
                    420: #      endif vax
                    421: #      ifdef mc68000
                    422:            putprintf(" cmpl    #%d,%s", 0, ctab[i].cconst, FORCENAME);
                    423:            putprintf(" jeq     %s%d", 0, LABELPREFIX, ctab[i].clabel);
                    424: #      endif mc68000
                    425:     }
                    426:     putjbr(ctab[0].clabel);
                    427:     return;
                    428: }
                    429: int
                    430: casecmp( this , that )
                    431:     struct ct  *this;
                    432:     struct ct  *that;
                    433: {
                    434:     if ( this -> cconst < that -> cconst ) {
                    435:        return -1;
                    436:     } else if ( this -> cconst > that -> cconst ) {
                    437:        return 1;
                    438:     } else {
                    439:        return 0;
                    440:     }
                    441: }
                    442: #endif PC

unix.superglobalmegacorp.com

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