1*926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*926Speter static char sccsid[] = "@(#)pccaseop.c 1.2 09/27/80"; 4763Speter 5763Speter #include "whoami.h" 6763Speter #ifdef PC 7763Speter /* 8763Speter * and the rest of the file 9763Speter */ 10763Speter #include "0.h" 11763Speter #include "tree.h" 12763Speter #include "objfmt.h" 13763Speter #include "pcops.h" 14763Speter #include "pc.h" 15*926Speter 16763Speter /* 17*926Speter * structure for a case: 18*926Speter * its constant label, line number (for errors), and location label. 19*926Speter */ 20*926Speter struct ct { 21*926Speter long cconst; 22*926Speter int cline; 23*926Speter int clabel; 24*926Speter }; 25*926Speter 26*926Speter /* 27*926Speter * the P2FORCE operator puts its operand into a register. 28*926Speter * these to keep from thinking of it as r0 all over. 29*926Speter */ 30*926Speter #define FORCENAME "r0" 31*926Speter #define FORCENUMBER 0 32*926Speter 33*926Speter /* 34*926Speter * given a tree for a case statement, generate code for it. 35*926Speter * this computes the expression into a register, 36*926Speter * puts down the code for each of the cases, 37*926Speter * and then decides how to do the case switching. 38763Speter * tcase [0] T_CASE 39763Speter * [1] lineof "case" 40763Speter * [2] expression 41*926Speter * [3] list of cased statements: 42763Speter * cstat [0] T_CSTAT 43763Speter * [1] lineof ":" 44*926Speter * [2] list of constant labels 45763Speter * [3] statement 46763Speter */ 47763Speter pccaseop( tcase ) 48763Speter int *tcase; 49*926Speter { 50*926Speter struct nl *exprtype; 51*926Speter struct nl *rangetype; 52*926Speter long low; 53*926Speter long high; 54*926Speter long exprctype; 55*926Speter long swlabel; 56*926Speter long endlabel; 57*926Speter long label; 58*926Speter long count; 59*926Speter long *cstatlp; 60*926Speter long *cstatp; 61*926Speter long *casep; 62*926Speter struct ct *ctab; 63*926Speter struct ct *ctp; 64*926Speter long i; 65*926Speter long nr; 66*926Speter long goc; 67*926Speter int casecmp(); 68763Speter 69*926Speter goc = gocnt; 70*926Speter /* 71*926Speter * find out the type of the case expression 72*926Speter * even if the expression has errors (exprtype == NIL), continue. 73*926Speter */ 74*926Speter line = tcase[1]; 75*926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 76*926Speter if ( exprtype != NIL ) { 77*926Speter if ( isnta( exprtype , "bcsi" ) ) { 78*926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 79*926Speter exprtype = NIL; 80*926Speter } else { 81*926Speter if ( exprtype -> class != RANGE ) { 82*926Speter rangetype = exprtype -> type; 83*926Speter } else { 84*926Speter rangetype = exprtype; 85*926Speter } 86*926Speter if ( rangetype == NIL ) { 87763Speter exprtype = NIL; 88763Speter } else { 89*926Speter low = rangetype -> range[0]; 90*926Speter high = rangetype -> range[1]; 91763Speter } 92763Speter } 93*926Speter } 94*926Speter if ( exprtype != NIL ) { 95763Speter /* 96*926Speter * put expression into a register 97*926Speter * save its c-type and jump to the code to do the switch. 98763Speter */ 99*926Speter putop( P2FORCE , P2INT ); 100*926Speter putdot( filename , line ); 101*926Speter exprctype = p2type( exprtype ); 102*926Speter swlabel = getlab(); 103*926Speter putjbr( swlabel ); 104*926Speter } 105*926Speter /* 106*926Speter * count the number of cases 107*926Speter * and allocate table for cases, lines, and labels 108*926Speter * default case goes in ctab[0]. 109*926Speter */ 110*926Speter count = 1; 111*926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 112*926Speter cstatp = cstatlp[1]; 113*926Speter if ( cstatp == NIL ) { 114*926Speter continue; 115763Speter } 116*926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 117*926Speter count++; 118763Speter } 119*926Speter } 120*926Speter /* 121*926Speter */ 122*926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 123*926Speter if ( ctab == (struct ct *) 0 ) { 124*926Speter error("Ran out of memory (case)"); 125*926Speter pexit( DIED ); 126*926Speter } 127*926Speter /* 128*926Speter * pick up default label and label for after case statement. 129*926Speter */ 130*926Speter ctab[0].clabel = getlab(); 131*926Speter endlabel = getlab(); 132*926Speter /* 133*926Speter * generate code for each case 134*926Speter * filling in ctab for each. 135*926Speter * nr is for error if no case falls out bottom. 136*926Speter */ 137*926Speter nr = 1; 138*926Speter count = 0; 139*926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 140*926Speter cstatp = cstatlp[1]; 141*926Speter if ( cstatp == NIL ) { 142*926Speter continue; 143*926Speter } 144*926Speter line = cstatp[1]; 145*926Speter label = getlab(); 146*926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 147*926Speter gconst( casep[1] ); 148*926Speter if( exprtype == NIL || con.ctype == NIL ) { 149763Speter continue; 150763Speter } 151*926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 152*926Speter cerror("Case label type clashed with case selector expression type"); 153*926Speter continue; 154763Speter } 155*926Speter if ( con.crval < low || con.crval > high ) { 156*926Speter error("Case label out of range"); 157*926Speter continue; 158763Speter } 159*926Speter count++; 160*926Speter ctab[ count ].cconst = con.crval; 161*926Speter ctab[ count ].cline = line; 162*926Speter ctab[ count ].clabel = label; 163763Speter } 164763Speter /* 165*926Speter * put out the statement 166763Speter */ 167*926Speter putlab( label ); 168*926Speter putcnt(); 169*926Speter level++; 170*926Speter statement( cstatp[3] ); 171*926Speter nr &= noreach; 172*926Speter noreach = 0; 173*926Speter level--; 174*926Speter if (gotos[cbn]) { 175*926Speter ungoto(); 176763Speter } 177*926Speter putjbr( endlabel ); 178763Speter } 179*926Speter /* 180*926Speter * default action is to call error 181*926Speter */ 182*926Speter putlab( ctab[0].clabel ); 183*926Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" ); 184*926Speter putleaf( P2ICON , ECASE , 0 , P2INT , 0 ); 185*926Speter putleaf( P2REG , FORCENUMBER , 0 , P2INT , 0 ); 186*926Speter putop( P2LISTOP , P2INT ); 187*926Speter putop( P2CALL , P2INT ); 188*926Speter putdot( filename , line ); 189*926Speter /* 190*926Speter * sort the cases 191*926Speter */ 192*926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 193*926Speter /* 194*926Speter * check for duplicates 195*926Speter */ 196*926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 197*926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 198*926Speter error("Muliply defined label in case, lines %d and %d" , 199*926Speter ctp[0].cline , ctp[1].cline ); 200*926Speter } 201*926Speter } 202*926Speter /* 203*926Speter * choose a switch algorithm and implement it: 204*926Speter * direct switch >= 1/3 full and >= 4 cases. 205*926Speter * binary switch not direct switch and > 8 cases. 206*926Speter * ifthenelse not direct or binary switch. 207*926Speter */ 208*926Speter putlab( swlabel ); 209*926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 210*926Speter directsw( ctab , count ); 211*926Speter } else if ( count > 8 ) { 212*926Speter binarysw( ctab , count ); 213*926Speter } else { 214*926Speter itesw( ctab , count ); 215*926Speter } 216*926Speter putlab( endlabel ); 217*926Speter noreach = nr; 218*926Speter if ( goc != gocnt ) { 219*926Speter putcnt(); 220*926Speter } 221*926Speter } 222763Speter 223*926Speter /* 224*926Speter * direct switch 225*926Speter */ 226*926Speter directsw( ctab , count ) 227*926Speter struct ct *ctab; 228*926Speter int count; 229*926Speter { 230*926Speter int fromlabel = getlab(); 231*926Speter long i; 232*926Speter long j; 233*926Speter 234*926Speter putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME , 235*926Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 236*926Speter putlab( fromlabel ); 237*926Speter i = 1; 238*926Speter j = ctab[1].cconst; 239*926Speter while ( i <= count ) { 240*926Speter if ( j == ctab[ i ].cconst ) { 241*926Speter putprintf( " .word " , 1 ); 242*926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 243*926Speter putprintf( "-" , 1 ); 244*926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 245*926Speter i++; 246*926Speter } else { 247*926Speter putprintf( " .word " , 1 ); 248*926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 249*926Speter putprintf( "-" , 1 ); 250*926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 251*926Speter } 252*926Speter j++; 253*926Speter } 254*926Speter putjbr( ctab[0].clabel ); 255*926Speter } 256*926Speter 257*926Speter /* 258*926Speter * binary switch 259*926Speter * special case out default label and start recursion. 260*926Speter */ 261*926Speter binarysw( ctab , count ) 262*926Speter struct ct *ctab; 263*926Speter int count; 264*926Speter { 265*926Speter 266*926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 267*926Speter } 268*926Speter 269*926Speter /* 270*926Speter * recursive log( count ) search. 271*926Speter */ 272*926Speter bsrecur( deflabel , ctab , count ) 273*926Speter int deflabel; 274*926Speter struct ct *ctab; 275*926Speter int count; 276*926Speter { 277*926Speter 278*926Speter if ( count <= 0 ) { 279*926Speter putprintf( " jbr L%d" , 0 , deflabel ); 280*926Speter return; 281*926Speter } else if ( count == 1 ) { 282*926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[1].cconst ); 283*926Speter putprintf( " jeql L%d" , 0 , ctab[1].clabel ); 284*926Speter putprintf( " jbr L%d" , 0 , deflabel ); 285*926Speter return; 286*926Speter } else { 287*926Speter int half = ( count + 1 ) / 2; 288*926Speter int gtrlabel = getlab(); 289*926Speter 290*926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ half ].cconst ); 291*926Speter putprintf( " jeql L%d" , 0 , ctab[ half ].clabel ); 292*926Speter putprintf( " jgtr L%d" , 0 , gtrlabel ); 293*926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 294*926Speter putprintf( "L%d:" , 0 , gtrlabel ); 295*926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 296*926Speter return; 297*926Speter } 298*926Speter } 299*926Speter 300*926Speter itesw( ctab , count ) 301*926Speter struct ct *ctab; 302*926Speter int count; 303*926Speter { 304*926Speter int i; 305*926Speter 306*926Speter for ( i = 1 ; i <= count ; i++ ) { 307*926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ i ].cconst ); 308*926Speter putprintf( " jeql L%d" , 0 , ctab[ i ].clabel ); 309*926Speter } 310*926Speter putprintf( " jbr L%d" , 0 , ctab[0].clabel ); 311*926Speter return; 312*926Speter } 313*926Speter int 314*926Speter casecmp( this , that ) 315*926Speter struct ct *this; 316*926Speter struct ct *that; 317*926Speter { 318*926Speter if ( this -> cconst < that -> cconst ) { 319*926Speter return -1; 320*926Speter } else if ( this -> cconst > that -> cconst ) { 321*926Speter return 1; 322*926Speter } else { 323*926Speter return 0; 324*926Speter } 325*926Speter } 326763Speter #endif PC 327