1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*5663Smckusic static char sccsid[] = "@(#)pccaseop.c 1.8 02/02/82"; 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; 503830Speter struct nl *exprnlp; 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]; 763641Speter codeoff(); 77926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 783641Speter 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 /* 993641Speter * compute and save the case expression. 1003641Speter * also, put expression into a register 101926Speter * save its c-type and jump to the code to do the switch. 102763Speter */ 1033641Speter exprctype = p2type( exprtype ); 1043830Speter exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG ); 1053830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1063830Speter exprnlp -> extra_flags , P2INT ); 1073641Speter (void) rvalue( (int *) tcase[2] , NIL , RREQ ); 1083641Speter putop( P2ASSIGN , P2INT ); 109926Speter putop( P2FORCE , P2INT ); 110926Speter putdot( filename , line ); 111926Speter swlabel = getlab(); 112926Speter putjbr( swlabel ); 113926Speter } 114926Speter /* 115926Speter * count the number of cases 116926Speter * and allocate table for cases, lines, and labels 117926Speter * default case goes in ctab[0]. 118926Speter */ 119926Speter count = 1; 120926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 121926Speter cstatp = cstatlp[1]; 122926Speter if ( cstatp == NIL ) { 123926Speter continue; 124763Speter } 125926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 126926Speter count++; 127763Speter } 128926Speter } 129926Speter /* 130926Speter */ 131926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 132926Speter if ( ctab == (struct ct *) 0 ) { 133926Speter error("Ran out of memory (case)"); 134926Speter pexit( DIED ); 135926Speter } 136926Speter /* 137926Speter * pick up default label and label for after case statement. 138926Speter */ 139926Speter ctab[0].clabel = getlab(); 140926Speter endlabel = getlab(); 141926Speter /* 142926Speter * generate code for each case 143926Speter * filling in ctab for each. 144926Speter * nr is for error if no case falls out bottom. 145926Speter */ 146926Speter nr = 1; 147926Speter count = 0; 148926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 149926Speter cstatp = cstatlp[1]; 150926Speter if ( cstatp == NIL ) { 151926Speter continue; 152926Speter } 153926Speter line = cstatp[1]; 154926Speter label = getlab(); 155926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 156926Speter gconst( casep[1] ); 157926Speter if( exprtype == NIL || con.ctype == NIL ) { 158763Speter continue; 159763Speter } 160926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 161926Speter cerror("Case label type clashed with case selector expression type"); 162926Speter continue; 163763Speter } 164926Speter if ( con.crval < low || con.crval > high ) { 165926Speter error("Case label out of range"); 166926Speter continue; 167763Speter } 168926Speter count++; 169926Speter ctab[ count ].cconst = con.crval; 170926Speter ctab[ count ].cline = line; 171926Speter ctab[ count ].clabel = label; 172763Speter } 173763Speter /* 174926Speter * put out the statement 175763Speter */ 176926Speter putlab( label ); 177926Speter putcnt(); 178926Speter level++; 179926Speter statement( cstatp[3] ); 1803139Smckusic nr = (nr && noreach); 181926Speter noreach = 0; 182926Speter level--; 183926Speter if (gotos[cbn]) { 184926Speter ungoto(); 185763Speter } 186926Speter putjbr( endlabel ); 187763Speter } 1881278Speter noreach = nr; 189926Speter /* 190926Speter * default action is to call error 191926Speter */ 192926Speter putlab( ctab[0].clabel ); 193*5663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 1943830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1953830Speter exprnlp -> extra_flags , 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