1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*1278Speter static char sccsid[] = "@(#)pccaseop.c 1.4 10/09/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" 15926Speter 16763Speter /* 17926Speter * structure for a case: 18926Speter * its constant label, line number (for errors), and location label. 19926Speter */ 20926Speter struct ct { 21926Speter long cconst; 22926Speter int cline; 23926Speter int clabel; 24926Speter }; 25926Speter 26926Speter /* 27926Speter * the P2FORCE operator puts its operand into a register. 28926Speter * these to keep from thinking of it as r0 all over. 29926Speter */ 30926Speter #define FORCENAME "r0" 31926Speter #define FORCENUMBER 0 32926Speter 33926Speter /* 34926Speter * given a tree for a case statement, generate code for it. 35926Speter * this computes the expression into a register, 36926Speter * puts down the code for each of the cases, 37926Speter * and then decides how to do the case switching. 38763Speter * tcase [0] T_CASE 39763Speter * [1] lineof "case" 40763Speter * [2] expression 41926Speter * [3] list of cased statements: 42763Speter * cstat [0] T_CSTAT 43763Speter * [1] lineof ":" 44926Speter * [2] list of constant labels 45763Speter * [3] statement 46763Speter */ 47763Speter pccaseop( tcase ) 48763Speter int *tcase; 49926Speter { 50926Speter struct nl *exprtype; 51926Speter struct nl *rangetype; 52926Speter long low; 53926Speter long high; 54926Speter long exprctype; 55926Speter long swlabel; 56926Speter long endlabel; 57926Speter long label; 58926Speter long count; 59926Speter long *cstatlp; 60926Speter long *cstatp; 61926Speter long *casep; 62926Speter struct ct *ctab; 63926Speter struct ct *ctp; 64926Speter long i; 65926Speter long nr; 66926Speter long goc; 67926Speter int casecmp(); 68*1278Speter bool dupcases; 69763Speter 70926Speter goc = gocnt; 71926Speter /* 72926Speter * find out the type of the case expression 73926Speter * even if the expression has errors (exprtype == NIL), continue. 74926Speter */ 75926Speter line = tcase[1]; 76926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 77926Speter if ( exprtype != NIL ) { 78926Speter if ( isnta( exprtype , "bcsi" ) ) { 79926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 80926Speter exprtype = NIL; 81926Speter } else { 82926Speter if ( exprtype -> class != RANGE ) { 83926Speter rangetype = exprtype -> type; 84926Speter } else { 85926Speter rangetype = exprtype; 86926Speter } 87926Speter if ( rangetype == NIL ) { 88763Speter exprtype = NIL; 89763Speter } else { 90926Speter low = rangetype -> range[0]; 91926Speter high = rangetype -> range[1]; 92763Speter } 93763Speter } 94926Speter } 95926Speter if ( exprtype != NIL ) { 96763Speter /* 97926Speter * put expression into a register 98926Speter * save its c-type and jump to the code to do the switch. 99763Speter */ 100926Speter putop( P2FORCE , P2INT ); 101926Speter putdot( filename , line ); 102926Speter exprctype = p2type( exprtype ); 103926Speter swlabel = getlab(); 104926Speter putjbr( swlabel ); 105926Speter } 106926Speter /* 107926Speter * count the number of cases 108926Speter * and allocate table for cases, lines, and labels 109926Speter * default case goes in ctab[0]. 110926Speter */ 111926Speter count = 1; 112926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 113926Speter cstatp = cstatlp[1]; 114926Speter if ( cstatp == NIL ) { 115926Speter continue; 116763Speter } 117926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 118926Speter count++; 119763Speter } 120926Speter } 121926Speter /* 122926Speter */ 123926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 124926Speter if ( ctab == (struct ct *) 0 ) { 125926Speter error("Ran out of memory (case)"); 126926Speter pexit( DIED ); 127926Speter } 128926Speter /* 129926Speter * pick up default label and label for after case statement. 130926Speter */ 131926Speter ctab[0].clabel = getlab(); 132926Speter endlabel = getlab(); 133926Speter /* 134926Speter * generate code for each case 135926Speter * filling in ctab for each. 136926Speter * nr is for error if no case falls out bottom. 137926Speter */ 138926Speter nr = 1; 139926Speter count = 0; 140926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 141926Speter cstatp = cstatlp[1]; 142926Speter if ( cstatp == NIL ) { 143926Speter continue; 144926Speter } 145926Speter line = cstatp[1]; 146926Speter label = getlab(); 147926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 148926Speter gconst( casep[1] ); 149926Speter if( exprtype == NIL || con.ctype == NIL ) { 150763Speter continue; 151763Speter } 152926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 153926Speter cerror("Case label type clashed with case selector expression type"); 154926Speter continue; 155763Speter } 156926Speter if ( con.crval < low || con.crval > high ) { 157926Speter error("Case label out of range"); 158926Speter continue; 159763Speter } 160926Speter count++; 161926Speter ctab[ count ].cconst = con.crval; 162926Speter ctab[ count ].cline = line; 163926Speter ctab[ count ].clabel = label; 164763Speter } 165763Speter /* 166926Speter * put out the statement 167763Speter */ 168926Speter putlab( label ); 169926Speter putcnt(); 170926Speter level++; 171926Speter statement( cstatp[3] ); 172926Speter nr &= noreach; 173926Speter noreach = 0; 174926Speter level--; 175926Speter if (gotos[cbn]) { 176926Speter ungoto(); 177763Speter } 178926Speter putjbr( endlabel ); 179763Speter } 180*1278Speter noreach = nr; 181926Speter /* 182926Speter * default action is to call error 183926Speter */ 184926Speter putlab( ctab[0].clabel ); 185926Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" ); 186926Speter putleaf( P2ICON , ECASE , 0 , P2INT , 0 ); 187926Speter putleaf( P2REG , FORCENUMBER , 0 , P2INT , 0 ); 188926Speter putop( P2LISTOP , P2INT ); 189926Speter putop( P2CALL , P2INT ); 190926Speter putdot( filename , line ); 191926Speter /* 192926Speter * sort the cases 193926Speter */ 194926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 195926Speter /* 196926Speter * check for duplicates 197926Speter */ 198*1278Speter dupcases = FALSE; 199926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 200926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 201*1278Speter error("Multiply defined label in case, lines %d and %d" , 202926Speter ctp[0].cline , ctp[1].cline ); 203*1278Speter dupcases = TRUE; 204926Speter } 205926Speter } 206*1278Speter if ( dupcases ) { 207*1278Speter return; 208*1278Speter } 209926Speter /* 210926Speter * choose a switch algorithm and implement it: 211926Speter * direct switch >= 1/3 full and >= 4 cases. 212926Speter * binary switch not direct switch and > 8 cases. 213926Speter * ifthenelse not direct or binary switch. 214926Speter */ 215926Speter putlab( swlabel ); 216926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 217926Speter directsw( ctab , count ); 218926Speter } else if ( count > 8 ) { 219926Speter binarysw( ctab , count ); 220926Speter } else { 221926Speter itesw( ctab , count ); 222926Speter } 223926Speter putlab( endlabel ); 224926Speter if ( goc != gocnt ) { 225926Speter putcnt(); 226926Speter } 227926Speter } 228763Speter 229926Speter /* 230926Speter * direct switch 231926Speter */ 232926Speter directsw( ctab , count ) 233926Speter struct ct *ctab; 234926Speter int count; 235926Speter { 236926Speter int fromlabel = getlab(); 237926Speter long i; 238926Speter long j; 239926Speter 240926Speter putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME , 241926Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 242926Speter putlab( fromlabel ); 243926Speter i = 1; 244926Speter j = ctab[1].cconst; 245926Speter while ( i <= count ) { 246926Speter if ( j == ctab[ i ].cconst ) { 247926Speter putprintf( " .word " , 1 ); 248926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 249926Speter putprintf( "-" , 1 ); 250926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 251926Speter i++; 252926Speter } else { 253926Speter putprintf( " .word " , 1 ); 254926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 255926Speter putprintf( "-" , 1 ); 256926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 257926Speter } 258926Speter j++; 259926Speter } 260926Speter putjbr( ctab[0].clabel ); 261926Speter } 262926Speter 263926Speter /* 264926Speter * binary switch 265926Speter * special case out default label and start recursion. 266926Speter */ 267926Speter binarysw( ctab , count ) 268926Speter struct ct *ctab; 269926Speter int count; 270926Speter { 271926Speter 272926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 273926Speter } 274926Speter 275926Speter /* 276926Speter * recursive log( count ) search. 277926Speter */ 278926Speter bsrecur( deflabel , ctab , count ) 279926Speter int deflabel; 280926Speter struct ct *ctab; 281926Speter int count; 282926Speter { 283926Speter 284926Speter if ( count <= 0 ) { 285926Speter putprintf( " jbr L%d" , 0 , deflabel ); 286926Speter return; 287926Speter } else if ( count == 1 ) { 288926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[1].cconst ); 289926Speter putprintf( " jeql L%d" , 0 , ctab[1].clabel ); 290926Speter putprintf( " jbr L%d" , 0 , deflabel ); 291926Speter return; 292926Speter } else { 293926Speter int half = ( count + 1 ) / 2; 294926Speter int gtrlabel = getlab(); 295926Speter 296926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ half ].cconst ); 297929Speter putprintf( " jgtr L%d" , 0 , gtrlabel ); 298926Speter putprintf( " jeql L%d" , 0 , ctab[ half ].clabel ); 299926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 300926Speter putprintf( "L%d:" , 0 , gtrlabel ); 301926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 302926Speter return; 303926Speter } 304926Speter } 305926Speter 306926Speter itesw( ctab , count ) 307926Speter struct ct *ctab; 308926Speter int count; 309926Speter { 310926Speter int i; 311926Speter 312926Speter for ( i = 1 ; i <= count ; i++ ) { 313926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ i ].cconst ); 314926Speter putprintf( " jeql L%d" , 0 , ctab[ i ].clabel ); 315926Speter } 316926Speter putprintf( " jbr L%d" , 0 , ctab[0].clabel ); 317926Speter return; 318926Speter } 319926Speter int 320926Speter casecmp( this , that ) 321926Speter struct ct *this; 322926Speter struct ct *that; 323926Speter { 324926Speter if ( this -> cconst < that -> cconst ) { 325926Speter return -1; 326926Speter } else if ( this -> cconst > that -> cconst ) { 327926Speter return 1; 328926Speter } else { 329926Speter return 0; 330926Speter } 331926Speter } 332763Speter #endif PC 333