1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*10378Speter static char sccsid[] = "@(#)pccaseop.c 1.8.1.2 01/17/83"; 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 */ 30*10378Speter #ifdef vax 31*10378Speter # define FORCENAME "r0" 32*10378Speter #endif vax 33*10378Speter #ifdef mc68000 34*10378Speter # define FORCENAME "d0" 35*10378Speter #endif mc68000 36926Speter 37926Speter /* 38926Speter * given a tree for a case statement, generate code for it. 39926Speter * this computes the expression into a register, 40926Speter * puts down the code for each of the cases, 41926Speter * and then decides how to do the case switching. 42763Speter * tcase [0] T_CASE 43763Speter * [1] lineof "case" 44763Speter * [2] expression 45926Speter * [3] list of cased statements: 46763Speter * cstat [0] T_CSTAT 47763Speter * [1] lineof ":" 48926Speter * [2] list of constant labels 49763Speter * [3] statement 50763Speter */ 51763Speter pccaseop( tcase ) 52763Speter int *tcase; 53926Speter { 54926Speter struct nl *exprtype; 553830Speter struct nl *exprnlp; 56926Speter struct nl *rangetype; 57926Speter long low; 58926Speter long high; 59926Speter long exprctype; 60926Speter long swlabel; 61926Speter long endlabel; 62926Speter long label; 63926Speter long count; 64926Speter long *cstatlp; 65926Speter long *cstatp; 66926Speter long *casep; 67926Speter struct ct *ctab; 68926Speter struct ct *ctp; 69926Speter long i; 70926Speter long nr; 71926Speter long goc; 72926Speter int casecmp(); 731278Speter bool dupcases; 74763Speter 75926Speter goc = gocnt; 76926Speter /* 77926Speter * find out the type of the case expression 78926Speter * even if the expression has errors (exprtype == NIL), continue. 79926Speter */ 80926Speter line = tcase[1]; 813641Speter codeoff(); 82926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 833641Speter codeon(); 84926Speter if ( exprtype != NIL ) { 85926Speter if ( isnta( exprtype , "bcsi" ) ) { 86926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 87926Speter exprtype = NIL; 88926Speter } else { 89926Speter if ( exprtype -> class != RANGE ) { 90926Speter rangetype = exprtype -> type; 91926Speter } else { 92926Speter rangetype = exprtype; 93926Speter } 94926Speter if ( rangetype == NIL ) { 95763Speter exprtype = NIL; 96763Speter } else { 97926Speter low = rangetype -> range[0]; 98926Speter high = rangetype -> range[1]; 99763Speter } 100763Speter } 101926Speter } 102926Speter if ( exprtype != NIL ) { 103763Speter /* 1043641Speter * compute and save the case expression. 1053641Speter * also, put expression into a register 106926Speter * save its c-type and jump to the code to do the switch. 107763Speter */ 1083641Speter exprctype = p2type( exprtype ); 1093830Speter exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG ); 1103830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1113830Speter exprnlp -> extra_flags , P2INT ); 1123641Speter (void) rvalue( (int *) tcase[2] , NIL , RREQ ); 1133641Speter putop( P2ASSIGN , P2INT ); 114926Speter putop( P2FORCE , P2INT ); 115926Speter putdot( filename , line ); 116926Speter swlabel = getlab(); 117926Speter putjbr( swlabel ); 118926Speter } 119926Speter /* 120926Speter * count the number of cases 121926Speter * and allocate table for cases, lines, and labels 122926Speter * default case goes in ctab[0]. 123926Speter */ 124926Speter count = 1; 125926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 126926Speter cstatp = cstatlp[1]; 127926Speter if ( cstatp == NIL ) { 128926Speter continue; 129763Speter } 130926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 131926Speter count++; 132763Speter } 133926Speter } 134926Speter /* 135926Speter */ 136926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 137926Speter if ( ctab == (struct ct *) 0 ) { 138926Speter error("Ran out of memory (case)"); 139926Speter pexit( DIED ); 140926Speter } 141926Speter /* 142926Speter * pick up default label and label for after case statement. 143926Speter */ 144926Speter ctab[0].clabel = getlab(); 145926Speter endlabel = getlab(); 146926Speter /* 147926Speter * generate code for each case 148926Speter * filling in ctab for each. 149926Speter * nr is for error if no case falls out bottom. 150926Speter */ 151926Speter nr = 1; 152926Speter count = 0; 153926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 154926Speter cstatp = cstatlp[1]; 155926Speter if ( cstatp == NIL ) { 156926Speter continue; 157926Speter } 158926Speter line = cstatp[1]; 159926Speter label = getlab(); 160926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 161926Speter gconst( casep[1] ); 162926Speter if( exprtype == NIL || con.ctype == NIL ) { 163763Speter continue; 164763Speter } 165926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 166926Speter cerror("Case label type clashed with case selector expression type"); 167926Speter continue; 168763Speter } 169926Speter if ( con.crval < low || con.crval > high ) { 170926Speter error("Case label out of range"); 171926Speter continue; 172763Speter } 173926Speter count++; 174926Speter ctab[ count ].cconst = con.crval; 175926Speter ctab[ count ].cline = line; 176926Speter ctab[ count ].clabel = label; 177763Speter } 178763Speter /* 179926Speter * put out the statement 180763Speter */ 181926Speter putlab( label ); 182926Speter putcnt(); 183926Speter level++; 184926Speter statement( cstatp[3] ); 1853139Smckusic nr = (nr && noreach); 186926Speter noreach = 0; 187926Speter level--; 188926Speter if (gotos[cbn]) { 189926Speter ungoto(); 190763Speter } 191926Speter putjbr( endlabel ); 192763Speter } 1931278Speter noreach = nr; 194926Speter /* 195926Speter * default action is to call error 196926Speter */ 197926Speter putlab( ctab[0].clabel ); 1985663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 1993830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 2003830Speter exprnlp -> extra_flags , P2INT ); 201926Speter putop( P2CALL , P2INT ); 202926Speter putdot( filename , line ); 203926Speter /* 204926Speter * sort the cases 205926Speter */ 206926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 207926Speter /* 208926Speter * check for duplicates 209926Speter */ 2101278Speter dupcases = FALSE; 211926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 212926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2131278Speter error("Multiply defined label in case, lines %d and %d" , 214926Speter ctp[0].cline , ctp[1].cline ); 2151278Speter dupcases = TRUE; 216926Speter } 217926Speter } 2181278Speter if ( dupcases ) { 2191278Speter return; 2201278Speter } 221926Speter /* 222926Speter * choose a switch algorithm and implement it: 223926Speter * direct switch >= 1/3 full and >= 4 cases. 224926Speter * binary switch not direct switch and > 8 cases. 225926Speter * ifthenelse not direct or binary switch. 226926Speter */ 227926Speter putlab( swlabel ); 228926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 229926Speter directsw( ctab , count ); 230926Speter } else if ( count > 8 ) { 231926Speter binarysw( ctab , count ); 232926Speter } else { 233926Speter itesw( ctab , count ); 234926Speter } 235926Speter putlab( endlabel ); 236926Speter if ( goc != gocnt ) { 237926Speter putcnt(); 238926Speter } 239926Speter } 240763Speter 241926Speter /* 242926Speter * direct switch 243926Speter */ 244926Speter directsw( ctab , count ) 245926Speter struct ct *ctab; 246926Speter int count; 247926Speter { 248926Speter int fromlabel = getlab(); 249926Speter long i; 250926Speter long j; 251926Speter 252*10378Speter # ifdef vax 253*10378Speter putprintf(" casel %s,$%d,$%d" , 0 , FORCENAME , 254*10378Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 255*10378Speter # endif vax 256*10378Speter # ifdef mc68000 257*10378Speter /* 258*10378Speter * subl to make d0 a 0-origin byte offset. 259*10378Speter * cmpl check against upper limit. 260*10378Speter * bhi error if out of bounds. 261*10378Speter * addw to make d0 a 0-origin word offset. 262*10378Speter * movw pick up a jump-table entry 263*10378Speter * jmp and indirect through it. 264*10378Speter */ 265*10378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 266*10378Speter putprintf(" cmpl #%d,%s", 0, 267*10378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 268*10378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 269*10378Speter putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 270*10378Speter putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 271*10378Speter putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 272*10378Speter # endif mc68000 273926Speter putlab( fromlabel ); 274926Speter i = 1; 275926Speter j = ctab[1].cconst; 276926Speter while ( i <= count ) { 277926Speter if ( j == ctab[ i ].cconst ) { 278926Speter putprintf( " .word " , 1 ); 279926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 280926Speter putprintf( "-" , 1 ); 281926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 282926Speter i++; 283926Speter } else { 284926Speter putprintf( " .word " , 1 ); 285926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 286926Speter putprintf( "-" , 1 ); 287926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 288926Speter } 289926Speter j++; 290926Speter } 291*10378Speter # ifdef vax 292*10378Speter /* 293*10378Speter * execution continues here if value not in range of case. 294*10378Speter */ 295*10378Speter putjbr( ctab[0].clabel ); 296*10378Speter # endif vax 297926Speter } 298926Speter 299926Speter /* 300926Speter * binary switch 301926Speter * special case out default label and start recursion. 302926Speter */ 303926Speter binarysw( ctab , count ) 304926Speter struct ct *ctab; 305926Speter int count; 306926Speter { 307926Speter 308926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 309926Speter } 310926Speter 311926Speter /* 312926Speter * recursive log( count ) search. 313926Speter */ 314926Speter bsrecur( deflabel , ctab , count ) 315926Speter int deflabel; 316926Speter struct ct *ctab; 317926Speter int count; 318926Speter { 319926Speter 320926Speter if ( count <= 0 ) { 321*10378Speter putjbr(deflabel); 322926Speter return; 323926Speter } else if ( count == 1 ) { 324*10378Speter # ifdef vax 325*10378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[1].cconst); 326*10378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[1].clabel); 327*10378Speter putjbr(deflabel); 328*10378Speter # endif vax 329*10378Speter # ifdef mc68000 330*10378Speter putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, FORCENAME); 331*10378Speter putprintf(" jeq L%d", 0, LABELPREFIX, ctab[1].clabel); 332*10378Speter putjbr(deflabel); 333*10378Speter # endif mc68000 334926Speter return; 335926Speter } else { 336926Speter int half = ( count + 1 ) / 2; 337926Speter int gtrlabel = getlab(); 338926Speter 339*10378Speter # ifdef vax 340*10378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[half].cconst); 341*10378Speter putprintf(" jgtr %s%d", 0, LABELPREFIX, gtrlabel); 342*10378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[half].clabel); 343*10378Speter # endif vax 344*10378Speter # ifdef mc68000 345*10378Speter putprintf(" cmpl #%d,%s", 0, ctab[half].cconst, FORCENAME); 346*10378Speter putprintf(" jgt %s%d", 0, LABELPREFIX, gtrlabel); 347*10378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[half].clabel); 348*10378Speter # endif mc68000 349926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 350*10378Speter putlab(gtrlabel); 351926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 352926Speter return; 353926Speter } 354926Speter } 355926Speter 356926Speter itesw( ctab , count ) 357926Speter struct ct *ctab; 358926Speter int count; 359926Speter { 360926Speter int i; 361926Speter 362926Speter for ( i = 1 ; i <= count ; i++ ) { 363*10378Speter # ifdef vax 364*10378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[i].cconst); 365*10378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[i].clabel); 366*10378Speter # endif vax 367*10378Speter # ifdef mc68000 368*10378Speter putprintf(" cmpl #%d,%s", 0, ctab[i].cconst, FORCENAME); 369*10378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[i].clabel); 370*10378Speter # endif mc68000 371926Speter } 372*10378Speter putjbr(ctab[0].clabel); 373926Speter return; 374926Speter } 375926Speter int 376926Speter casecmp( this , that ) 377926Speter struct ct *this; 378926Speter struct ct *that; 379926Speter { 380926Speter if ( this -> cconst < that -> cconst ) { 381926Speter return -1; 382926Speter } else if ( this -> cconst > that -> cconst ) { 383926Speter return 1; 384926Speter } else { 385926Speter return 0; 386926Speter } 387926Speter } 388763Speter #endif PC 389