1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*10379Speter static char sccsid[] = "@(#)pccaseop.c 1.10 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 */ 3010378Speter #ifdef vax 3110378Speter # define FORCENAME "r0" 3210378Speter #endif vax 3310378Speter #ifdef mc68000 3410378Speter # define FORCENAME "d0" 3510378Speter #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 ); 113*10379Speter sconv(exprctype, P2INT); 1143641Speter putop( P2ASSIGN , P2INT ); 115926Speter putop( P2FORCE , P2INT ); 116926Speter putdot( filename , line ); 117926Speter swlabel = getlab(); 118926Speter putjbr( swlabel ); 119926Speter } 120926Speter /* 121926Speter * count the number of cases 122926Speter * and allocate table for cases, lines, and labels 123926Speter * default case goes in ctab[0]. 124926Speter */ 125926Speter count = 1; 126926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 127926Speter cstatp = cstatlp[1]; 128926Speter if ( cstatp == NIL ) { 129926Speter continue; 130763Speter } 131926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 132926Speter count++; 133763Speter } 134926Speter } 135926Speter /* 136926Speter */ 137926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 138926Speter if ( ctab == (struct ct *) 0 ) { 139926Speter error("Ran out of memory (case)"); 140926Speter pexit( DIED ); 141926Speter } 142926Speter /* 143926Speter * pick up default label and label for after case statement. 144926Speter */ 145926Speter ctab[0].clabel = getlab(); 146926Speter endlabel = getlab(); 147926Speter /* 148926Speter * generate code for each case 149926Speter * filling in ctab for each. 150926Speter * nr is for error if no case falls out bottom. 151926Speter */ 152926Speter nr = 1; 153926Speter count = 0; 154926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 155926Speter cstatp = cstatlp[1]; 156926Speter if ( cstatp == NIL ) { 157926Speter continue; 158926Speter } 159926Speter line = cstatp[1]; 160926Speter label = getlab(); 161926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 162926Speter gconst( casep[1] ); 163926Speter if( exprtype == NIL || con.ctype == NIL ) { 164763Speter continue; 165763Speter } 166926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 167926Speter cerror("Case label type clashed with case selector expression type"); 168926Speter continue; 169763Speter } 170926Speter if ( con.crval < low || con.crval > high ) { 171926Speter error("Case label out of range"); 172926Speter continue; 173763Speter } 174926Speter count++; 175926Speter ctab[ count ].cconst = con.crval; 176926Speter ctab[ count ].cline = line; 177926Speter ctab[ count ].clabel = label; 178763Speter } 179763Speter /* 180926Speter * put out the statement 181763Speter */ 182926Speter putlab( label ); 183926Speter putcnt(); 184926Speter level++; 185926Speter statement( cstatp[3] ); 1863139Smckusic nr = (nr && noreach); 187926Speter noreach = 0; 188926Speter level--; 189926Speter if (gotos[cbn]) { 190926Speter ungoto(); 191763Speter } 192926Speter putjbr( endlabel ); 193763Speter } 1941278Speter noreach = nr; 195926Speter /* 196926Speter * default action is to call error 197926Speter */ 198926Speter putlab( ctab[0].clabel ); 1995663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 2003830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 2013830Speter exprnlp -> extra_flags , P2INT ); 202926Speter putop( P2CALL , P2INT ); 203926Speter putdot( filename , line ); 204926Speter /* 205926Speter * sort the cases 206926Speter */ 207926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 208926Speter /* 209926Speter * check for duplicates 210926Speter */ 2111278Speter dupcases = FALSE; 212926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 213926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2141278Speter error("Multiply defined label in case, lines %d and %d" , 215926Speter ctp[0].cline , ctp[1].cline ); 2161278Speter dupcases = TRUE; 217926Speter } 218926Speter } 2191278Speter if ( dupcases ) { 2201278Speter return; 2211278Speter } 222926Speter /* 223926Speter * choose a switch algorithm and implement it: 224926Speter * direct switch >= 1/3 full and >= 4 cases. 225926Speter * binary switch not direct switch and > 8 cases. 226926Speter * ifthenelse not direct or binary switch. 227926Speter */ 228926Speter putlab( swlabel ); 229926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 230926Speter directsw( ctab , count ); 231926Speter } else if ( count > 8 ) { 232926Speter binarysw( ctab , count ); 233926Speter } else { 234926Speter itesw( ctab , count ); 235926Speter } 236926Speter putlab( endlabel ); 237926Speter if ( goc != gocnt ) { 238926Speter putcnt(); 239926Speter } 240926Speter } 241763Speter 242926Speter /* 243926Speter * direct switch 244926Speter */ 245926Speter directsw( ctab , count ) 246926Speter struct ct *ctab; 247926Speter int count; 248926Speter { 249926Speter int fromlabel = getlab(); 250926Speter long i; 251926Speter long j; 252926Speter 25310378Speter # ifdef vax 25410378Speter putprintf(" casel %s,$%d,$%d" , 0 , FORCENAME , 25510378Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 25610378Speter # endif vax 25710378Speter # ifdef mc68000 25810378Speter /* 25910378Speter * subl to make d0 a 0-origin byte offset. 26010378Speter * cmpl check against upper limit. 26110378Speter * bhi error if out of bounds. 26210378Speter * addw to make d0 a 0-origin word offset. 26310378Speter * movw pick up a jump-table entry 26410378Speter * jmp and indirect through it. 26510378Speter */ 26610378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 26710378Speter putprintf(" cmpl #%d,%s", 0, 26810378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 26910378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 27010378Speter putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 27110378Speter putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 27210378Speter putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 27310378Speter # endif mc68000 274926Speter putlab( fromlabel ); 275926Speter i = 1; 276926Speter j = ctab[1].cconst; 277926Speter while ( i <= count ) { 278926Speter if ( j == ctab[ i ].cconst ) { 279926Speter putprintf( " .word " , 1 ); 280926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 281926Speter putprintf( "-" , 1 ); 282926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 283926Speter i++; 284926Speter } else { 285926Speter putprintf( " .word " , 1 ); 286926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 287926Speter putprintf( "-" , 1 ); 288926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 289926Speter } 290926Speter j++; 291926Speter } 29210378Speter # ifdef vax 29310378Speter /* 29410378Speter * execution continues here if value not in range of case. 29510378Speter */ 29610378Speter putjbr( ctab[0].clabel ); 29710378Speter # endif vax 298926Speter } 299926Speter 300926Speter /* 301926Speter * binary switch 302926Speter * special case out default label and start recursion. 303926Speter */ 304926Speter binarysw( ctab , count ) 305926Speter struct ct *ctab; 306926Speter int count; 307926Speter { 308926Speter 309926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 310926Speter } 311926Speter 312926Speter /* 313926Speter * recursive log( count ) search. 314926Speter */ 315926Speter bsrecur( deflabel , ctab , count ) 316926Speter int deflabel; 317926Speter struct ct *ctab; 318926Speter int count; 319926Speter { 320926Speter 321926Speter if ( count <= 0 ) { 32210378Speter putjbr(deflabel); 323926Speter return; 324926Speter } else if ( count == 1 ) { 32510378Speter # ifdef vax 32610378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[1].cconst); 32710378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[1].clabel); 32810378Speter putjbr(deflabel); 32910378Speter # endif vax 33010378Speter # ifdef mc68000 33110378Speter putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, FORCENAME); 33210378Speter putprintf(" jeq L%d", 0, LABELPREFIX, ctab[1].clabel); 33310378Speter putjbr(deflabel); 33410378Speter # endif mc68000 335926Speter return; 336926Speter } else { 337926Speter int half = ( count + 1 ) / 2; 338926Speter int gtrlabel = getlab(); 339926Speter 34010378Speter # ifdef vax 34110378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[half].cconst); 34210378Speter putprintf(" jgtr %s%d", 0, LABELPREFIX, gtrlabel); 34310378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[half].clabel); 34410378Speter # endif vax 34510378Speter # ifdef mc68000 34610378Speter putprintf(" cmpl #%d,%s", 0, ctab[half].cconst, FORCENAME); 34710378Speter putprintf(" jgt %s%d", 0, LABELPREFIX, gtrlabel); 34810378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[half].clabel); 34910378Speter # endif mc68000 350926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 35110378Speter putlab(gtrlabel); 352926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 353926Speter return; 354926Speter } 355926Speter } 356926Speter 357926Speter itesw( ctab , count ) 358926Speter struct ct *ctab; 359926Speter int count; 360926Speter { 361926Speter int i; 362926Speter 363926Speter for ( i = 1 ; i <= count ; i++ ) { 36410378Speter # ifdef vax 36510378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[i].cconst); 36610378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[i].clabel); 36710378Speter # endif vax 36810378Speter # ifdef mc68000 36910378Speter putprintf(" cmpl #%d,%s", 0, ctab[i].cconst, FORCENAME); 37010378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[i].clabel); 37110378Speter # endif mc68000 372926Speter } 37310378Speter putjbr(ctab[0].clabel); 374926Speter return; 375926Speter } 376926Speter int 377926Speter casecmp( this , that ) 378926Speter struct ct *this; 379926Speter struct ct *that; 380926Speter { 381926Speter if ( this -> cconst < that -> cconst ) { 382926Speter return -1; 383926Speter } else if ( this -> cconst > that -> cconst ) { 384926Speter return 1; 385926Speter } else { 386926Speter return 0; 387926Speter } 388926Speter } 389763Speter #endif PC 390