1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*3641Speter static char sccsid[] = "@(#)pccaseop.c 1.6 04/30/81"; 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 32926Speter /* 33926Speter * given a tree for a case statement, generate code for it. 34926Speter * this computes the expression into a register, 35926Speter * puts down the code for each of the cases, 36926Speter * and then decides how to do the case switching. 37763Speter * tcase [0] T_CASE 38763Speter * [1] lineof "case" 39763Speter * [2] expression 40926Speter * [3] list of cased statements: 41763Speter * cstat [0] T_CSTAT 42763Speter * [1] lineof ":" 43926Speter * [2] list of constant labels 44763Speter * [3] statement 45763Speter */ 46763Speter pccaseop( tcase ) 47763Speter int *tcase; 48926Speter { 49926Speter struct nl *exprtype; 50*3641Speter int exproff; 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(); 681278Speter 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]; 76*3641Speter codeoff(); 77926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 78*3641Speter codeon(); 79926Speter if ( exprtype != NIL ) { 80926Speter if ( isnta( exprtype , "bcsi" ) ) { 81926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 82926Speter exprtype = NIL; 83926Speter } else { 84926Speter if ( exprtype -> class != RANGE ) { 85926Speter rangetype = exprtype -> type; 86926Speter } else { 87926Speter rangetype = exprtype; 88926Speter } 89926Speter if ( rangetype == NIL ) { 90763Speter exprtype = NIL; 91763Speter } else { 92926Speter low = rangetype -> range[0]; 93926Speter high = rangetype -> range[1]; 94763Speter } 95763Speter } 96926Speter } 97926Speter if ( exprtype != NIL ) { 98763Speter /* 99*3641Speter * compute and save the case expression. 100*3641Speter * also, put expression into a register 101926Speter * save its c-type and jump to the code to do the switch. 102763Speter */ 103*3641Speter exprctype = p2type( exprtype ); 104*3641Speter exproff = tmpalloc( sizeof (long) , nl + T4INT , NOREG ); 105*3641Speter putRV( 0 , cbn , exproff , P2INT ); 106*3641Speter (void) rvalue( (int *) tcase[2] , NIL , RREQ ); 107*3641Speter putop( P2ASSIGN , P2INT ); 108926Speter putop( P2FORCE , P2INT ); 109926Speter putdot( filename , line ); 110926Speter swlabel = getlab(); 111926Speter putjbr( swlabel ); 112926Speter } 113926Speter /* 114926Speter * count the number of cases 115926Speter * and allocate table for cases, lines, and labels 116926Speter * default case goes in ctab[0]. 117926Speter */ 118926Speter count = 1; 119926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 120926Speter cstatp = cstatlp[1]; 121926Speter if ( cstatp == NIL ) { 122926Speter continue; 123763Speter } 124926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 125926Speter count++; 126763Speter } 127926Speter } 128926Speter /* 129926Speter */ 130926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 131926Speter if ( ctab == (struct ct *) 0 ) { 132926Speter error("Ran out of memory (case)"); 133926Speter pexit( DIED ); 134926Speter } 135926Speter /* 136926Speter * pick up default label and label for after case statement. 137926Speter */ 138926Speter ctab[0].clabel = getlab(); 139926Speter endlabel = getlab(); 140926Speter /* 141926Speter * generate code for each case 142926Speter * filling in ctab for each. 143926Speter * nr is for error if no case falls out bottom. 144926Speter */ 145926Speter nr = 1; 146926Speter count = 0; 147926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 148926Speter cstatp = cstatlp[1]; 149926Speter if ( cstatp == NIL ) { 150926Speter continue; 151926Speter } 152926Speter line = cstatp[1]; 153926Speter label = getlab(); 154926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 155926Speter gconst( casep[1] ); 156926Speter if( exprtype == NIL || con.ctype == NIL ) { 157763Speter continue; 158763Speter } 159926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 160926Speter cerror("Case label type clashed with case selector expression type"); 161926Speter continue; 162763Speter } 163926Speter if ( con.crval < low || con.crval > high ) { 164926Speter error("Case label out of range"); 165926Speter continue; 166763Speter } 167926Speter count++; 168926Speter ctab[ count ].cconst = con.crval; 169926Speter ctab[ count ].cline = line; 170926Speter ctab[ count ].clabel = label; 171763Speter } 172763Speter /* 173926Speter * put out the statement 174763Speter */ 175926Speter putlab( label ); 176926Speter putcnt(); 177926Speter level++; 178926Speter statement( cstatp[3] ); 1793139Smckusic nr = (nr && noreach); 180926Speter noreach = 0; 181926Speter level--; 182926Speter if (gotos[cbn]) { 183926Speter ungoto(); 184763Speter } 185926Speter putjbr( endlabel ); 186763Speter } 1871278Speter noreach = nr; 188926Speter /* 189926Speter * default action is to call error 190926Speter */ 191926Speter putlab( ctab[0].clabel ); 192926Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" ); 193926Speter putleaf( P2ICON , ECASE , 0 , P2INT , 0 ); 194*3641Speter putRV( 0 , cbn , exproff , P2INT ); 195926Speter putop( P2LISTOP , P2INT ); 196926Speter putop( P2CALL , P2INT ); 197926Speter putdot( filename , line ); 198926Speter /* 199926Speter * sort the cases 200926Speter */ 201926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 202926Speter /* 203926Speter * check for duplicates 204926Speter */ 2051278Speter dupcases = FALSE; 206926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 207926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2081278Speter error("Multiply defined label in case, lines %d and %d" , 209926Speter ctp[0].cline , ctp[1].cline ); 2101278Speter dupcases = TRUE; 211926Speter } 212926Speter } 2131278Speter if ( dupcases ) { 2141278Speter return; 2151278Speter } 216926Speter /* 217926Speter * choose a switch algorithm and implement it: 218926Speter * direct switch >= 1/3 full and >= 4 cases. 219926Speter * binary switch not direct switch and > 8 cases. 220926Speter * ifthenelse not direct or binary switch. 221926Speter */ 222926Speter putlab( swlabel ); 223926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 224926Speter directsw( ctab , count ); 225926Speter } else if ( count > 8 ) { 226926Speter binarysw( ctab , count ); 227926Speter } else { 228926Speter itesw( ctab , count ); 229926Speter } 230926Speter putlab( endlabel ); 231926Speter if ( goc != gocnt ) { 232926Speter putcnt(); 233926Speter } 234926Speter } 235763Speter 236926Speter /* 237926Speter * direct switch 238926Speter */ 239926Speter directsw( ctab , count ) 240926Speter struct ct *ctab; 241926Speter int count; 242926Speter { 243926Speter int fromlabel = getlab(); 244926Speter long i; 245926Speter long j; 246926Speter 247926Speter putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME , 248926Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 249926Speter putlab( fromlabel ); 250926Speter i = 1; 251926Speter j = ctab[1].cconst; 252926Speter while ( i <= count ) { 253926Speter if ( j == ctab[ i ].cconst ) { 254926Speter putprintf( " .word " , 1 ); 255926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 256926Speter putprintf( "-" , 1 ); 257926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 258926Speter i++; 259926Speter } else { 260926Speter putprintf( " .word " , 1 ); 261926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 262926Speter putprintf( "-" , 1 ); 263926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 264926Speter } 265926Speter j++; 266926Speter } 267926Speter putjbr( ctab[0].clabel ); 268926Speter } 269926Speter 270926Speter /* 271926Speter * binary switch 272926Speter * special case out default label and start recursion. 273926Speter */ 274926Speter binarysw( ctab , count ) 275926Speter struct ct *ctab; 276926Speter int count; 277926Speter { 278926Speter 279926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 280926Speter } 281926Speter 282926Speter /* 283926Speter * recursive log( count ) search. 284926Speter */ 285926Speter bsrecur( deflabel , ctab , count ) 286926Speter int deflabel; 287926Speter struct ct *ctab; 288926Speter int count; 289926Speter { 290926Speter 291926Speter if ( count <= 0 ) { 292926Speter putprintf( " jbr L%d" , 0 , deflabel ); 293926Speter return; 294926Speter } else if ( count == 1 ) { 295926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[1].cconst ); 296926Speter putprintf( " jeql L%d" , 0 , ctab[1].clabel ); 297926Speter putprintf( " jbr L%d" , 0 , deflabel ); 298926Speter return; 299926Speter } else { 300926Speter int half = ( count + 1 ) / 2; 301926Speter int gtrlabel = getlab(); 302926Speter 303926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ half ].cconst ); 304929Speter putprintf( " jgtr L%d" , 0 , gtrlabel ); 305926Speter putprintf( " jeql L%d" , 0 , ctab[ half ].clabel ); 306926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 307926Speter putprintf( "L%d:" , 0 , gtrlabel ); 308926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 309926Speter return; 310926Speter } 311926Speter } 312926Speter 313926Speter itesw( ctab , count ) 314926Speter struct ct *ctab; 315926Speter int count; 316926Speter { 317926Speter int i; 318926Speter 319926Speter for ( i = 1 ; i <= count ; i++ ) { 320926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ i ].cconst ); 321926Speter putprintf( " jeql L%d" , 0 , ctab[ i ].clabel ); 322926Speter } 323926Speter putprintf( " jbr L%d" , 0 , ctab[0].clabel ); 324926Speter return; 325926Speter } 326926Speter int 327926Speter casecmp( this , that ) 328926Speter struct ct *this; 329926Speter struct ct *that; 330926Speter { 331926Speter if ( this -> cconst < that -> cconst ) { 332926Speter return -1; 333926Speter } else if ( this -> cconst > that -> cconst ) { 334926Speter return 1; 335926Speter } else { 336926Speter return 0; 337926Speter } 338926Speter } 339763Speter #endif PC 340