1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*929Speter static char sccsid[] = "@(#)pccaseop.c 1.3 09/29/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(); 68763Speter 69926Speter goc = gocnt; 70926Speter /* 71926Speter * find out the type of the case expression 72926Speter * even if the expression has errors (exprtype == NIL), continue. 73926Speter */ 74926Speter line = tcase[1]; 75926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 76926Speter if ( exprtype != NIL ) { 77926Speter if ( isnta( exprtype , "bcsi" ) ) { 78926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 79926Speter exprtype = NIL; 80926Speter } else { 81926Speter if ( exprtype -> class != RANGE ) { 82926Speter rangetype = exprtype -> type; 83926Speter } else { 84926Speter rangetype = exprtype; 85926Speter } 86926Speter if ( rangetype == NIL ) { 87763Speter exprtype = NIL; 88763Speter } else { 89926Speter low = rangetype -> range[0]; 90926Speter high = rangetype -> range[1]; 91763Speter } 92763Speter } 93926Speter } 94926Speter if ( exprtype != NIL ) { 95763Speter /* 96926Speter * put expression into a register 97926Speter * save its c-type and jump to the code to do the switch. 98763Speter */ 99926Speter putop( P2FORCE , P2INT ); 100926Speter putdot( filename , line ); 101926Speter exprctype = p2type( exprtype ); 102926Speter swlabel = getlab(); 103926Speter putjbr( swlabel ); 104926Speter } 105926Speter /* 106926Speter * count the number of cases 107926Speter * and allocate table for cases, lines, and labels 108926Speter * default case goes in ctab[0]. 109926Speter */ 110926Speter count = 1; 111926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 112926Speter cstatp = cstatlp[1]; 113926Speter if ( cstatp == NIL ) { 114926Speter continue; 115763Speter } 116926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 117926Speter count++; 118763Speter } 119926Speter } 120926Speter /* 121926Speter */ 122926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 123926Speter if ( ctab == (struct ct *) 0 ) { 124926Speter error("Ran out of memory (case)"); 125926Speter pexit( DIED ); 126926Speter } 127926Speter /* 128926Speter * pick up default label and label for after case statement. 129926Speter */ 130926Speter ctab[0].clabel = getlab(); 131926Speter endlabel = getlab(); 132926Speter /* 133926Speter * generate code for each case 134926Speter * filling in ctab for each. 135926Speter * nr is for error if no case falls out bottom. 136926Speter */ 137926Speter nr = 1; 138926Speter count = 0; 139926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 140926Speter cstatp = cstatlp[1]; 141926Speter if ( cstatp == NIL ) { 142926Speter continue; 143926Speter } 144926Speter line = cstatp[1]; 145926Speter label = getlab(); 146926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 147926Speter gconst( casep[1] ); 148926Speter if( exprtype == NIL || con.ctype == NIL ) { 149763Speter continue; 150763Speter } 151926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 152926Speter cerror("Case label type clashed with case selector expression type"); 153926Speter continue; 154763Speter } 155926Speter if ( con.crval < low || con.crval > high ) { 156926Speter error("Case label out of range"); 157926Speter continue; 158763Speter } 159926Speter count++; 160926Speter ctab[ count ].cconst = con.crval; 161926Speter ctab[ count ].cline = line; 162926Speter ctab[ count ].clabel = label; 163763Speter } 164763Speter /* 165926Speter * put out the statement 166763Speter */ 167926Speter putlab( label ); 168926Speter putcnt(); 169926Speter level++; 170926Speter statement( cstatp[3] ); 171926Speter nr &= noreach; 172926Speter noreach = 0; 173926Speter level--; 174926Speter if (gotos[cbn]) { 175926Speter ungoto(); 176763Speter } 177926Speter putjbr( endlabel ); 178763Speter } 179926Speter /* 180926Speter * default action is to call error 181926Speter */ 182926Speter putlab( ctab[0].clabel ); 183926Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" ); 184926Speter putleaf( P2ICON , ECASE , 0 , P2INT , 0 ); 185926Speter putleaf( P2REG , FORCENUMBER , 0 , P2INT , 0 ); 186926Speter putop( P2LISTOP , P2INT ); 187926Speter putop( P2CALL , P2INT ); 188926Speter putdot( filename , line ); 189926Speter /* 190926Speter * sort the cases 191926Speter */ 192926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 193926Speter /* 194926Speter * check for duplicates 195926Speter */ 196926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 197926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 198926Speter error("Muliply defined label in case, lines %d and %d" , 199926Speter ctp[0].cline , ctp[1].cline ); 200926Speter } 201926Speter } 202926Speter /* 203926Speter * choose a switch algorithm and implement it: 204926Speter * direct switch >= 1/3 full and >= 4 cases. 205926Speter * binary switch not direct switch and > 8 cases. 206926Speter * ifthenelse not direct or binary switch. 207926Speter */ 208926Speter putlab( swlabel ); 209926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 210926Speter directsw( ctab , count ); 211926Speter } else if ( count > 8 ) { 212926Speter binarysw( ctab , count ); 213926Speter } else { 214926Speter itesw( ctab , count ); 215926Speter } 216926Speter putlab( endlabel ); 217926Speter noreach = nr; 218926Speter if ( goc != gocnt ) { 219926Speter putcnt(); 220926Speter } 221926Speter } 222763Speter 223926Speter /* 224926Speter * direct switch 225926Speter */ 226926Speter directsw( ctab , count ) 227926Speter struct ct *ctab; 228926Speter int count; 229926Speter { 230926Speter int fromlabel = getlab(); 231926Speter long i; 232926Speter long j; 233926Speter 234926Speter putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME , 235926Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 236926Speter putlab( fromlabel ); 237926Speter i = 1; 238926Speter j = ctab[1].cconst; 239926Speter while ( i <= count ) { 240926Speter if ( j == ctab[ i ].cconst ) { 241926Speter putprintf( " .word " , 1 ); 242926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 243926Speter putprintf( "-" , 1 ); 244926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 245926Speter i++; 246926Speter } else { 247926Speter putprintf( " .word " , 1 ); 248926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 249926Speter putprintf( "-" , 1 ); 250926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 251926Speter } 252926Speter j++; 253926Speter } 254926Speter putjbr( ctab[0].clabel ); 255926Speter } 256926Speter 257926Speter /* 258926Speter * binary switch 259926Speter * special case out default label and start recursion. 260926Speter */ 261926Speter binarysw( ctab , count ) 262926Speter struct ct *ctab; 263926Speter int count; 264926Speter { 265926Speter 266926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 267926Speter } 268926Speter 269926Speter /* 270926Speter * recursive log( count ) search. 271926Speter */ 272926Speter bsrecur( deflabel , ctab , count ) 273926Speter int deflabel; 274926Speter struct ct *ctab; 275926Speter int count; 276926Speter { 277926Speter 278926Speter if ( count <= 0 ) { 279926Speter putprintf( " jbr L%d" , 0 , deflabel ); 280926Speter return; 281926Speter } else if ( count == 1 ) { 282926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[1].cconst ); 283926Speter putprintf( " jeql L%d" , 0 , ctab[1].clabel ); 284926Speter putprintf( " jbr L%d" , 0 , deflabel ); 285926Speter return; 286926Speter } else { 287926Speter int half = ( count + 1 ) / 2; 288926Speter int gtrlabel = getlab(); 289926Speter 290926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ half ].cconst ); 291*929Speter putprintf( " jgtr L%d" , 0 , gtrlabel ); 292926Speter putprintf( " jeql L%d" , 0 , ctab[ half ].clabel ); 293926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 294926Speter putprintf( "L%d:" , 0 , gtrlabel ); 295926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 296926Speter return; 297926Speter } 298926Speter } 299926Speter 300926Speter itesw( ctab , count ) 301926Speter struct ct *ctab; 302926Speter int count; 303926Speter { 304926Speter int i; 305926Speter 306926Speter for ( i = 1 ; i <= count ; i++ ) { 307926Speter putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ i ].cconst ); 308926Speter putprintf( " jeql L%d" , 0 , ctab[ i ].clabel ); 309926Speter } 310926Speter putprintf( " jbr L%d" , 0 , ctab[0].clabel ); 311926Speter return; 312926Speter } 313926Speter int 314926Speter casecmp( this , that ) 315926Speter struct ct *this; 316926Speter struct ct *that; 317926Speter { 318926Speter if ( this -> cconst < that -> cconst ) { 319926Speter return -1; 320926Speter } else if ( this -> cconst > that -> cconst ) { 321926Speter return 1; 322926Speter } else { 323926Speter return 0; 324926Speter } 325926Speter } 326763Speter #endif PC 327