1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*11329Speter static char sccsid[] = "@(#)pccaseop.c 1.11 02/28/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" 15*11329Speter #include "tmps.h" 16926Speter 17763Speter /* 18926Speter * structure for a case: 19926Speter * its constant label, line number (for errors), and location label. 20926Speter */ 21926Speter struct ct { 22926Speter long cconst; 23926Speter int cline; 24926Speter int clabel; 25926Speter }; 26926Speter 27926Speter /* 28926Speter * the P2FORCE operator puts its operand into a register. 29926Speter * these to keep from thinking of it as r0 all over. 30926Speter */ 3110378Speter #ifdef vax 3210378Speter # define FORCENAME "r0" 3310378Speter #endif vax 3410378Speter #ifdef mc68000 3510378Speter # define FORCENAME "d0" 3610378Speter #endif mc68000 37926Speter 38926Speter /* 39926Speter * given a tree for a case statement, generate code for it. 40926Speter * this computes the expression into a register, 41926Speter * puts down the code for each of the cases, 42926Speter * and then decides how to do the case switching. 43763Speter * tcase [0] T_CASE 44763Speter * [1] lineof "case" 45763Speter * [2] expression 46926Speter * [3] list of cased statements: 47763Speter * cstat [0] T_CSTAT 48763Speter * [1] lineof ":" 49926Speter * [2] list of constant labels 50763Speter * [3] statement 51763Speter */ 52763Speter pccaseop( tcase ) 53763Speter int *tcase; 54926Speter { 55926Speter struct nl *exprtype; 563830Speter struct nl *exprnlp; 57926Speter struct nl *rangetype; 58926Speter long low; 59926Speter long high; 60926Speter long exprctype; 61926Speter long swlabel; 62926Speter long endlabel; 63926Speter long label; 64926Speter long count; 65926Speter long *cstatlp; 66926Speter long *cstatp; 67926Speter long *casep; 68926Speter struct ct *ctab; 69926Speter struct ct *ctp; 70926Speter long i; 71926Speter long nr; 72926Speter long goc; 73926Speter int casecmp(); 741278Speter bool dupcases; 75763Speter 76926Speter goc = gocnt; 77926Speter /* 78926Speter * find out the type of the case expression 79926Speter * even if the expression has errors (exprtype == NIL), continue. 80926Speter */ 81926Speter line = tcase[1]; 823641Speter codeoff(); 83926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 843641Speter codeon(); 85926Speter if ( exprtype != NIL ) { 86926Speter if ( isnta( exprtype , "bcsi" ) ) { 87926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 88926Speter exprtype = NIL; 89926Speter } else { 90926Speter if ( exprtype -> class != RANGE ) { 91926Speter rangetype = exprtype -> type; 92926Speter } else { 93926Speter rangetype = exprtype; 94926Speter } 95926Speter if ( rangetype == NIL ) { 96763Speter exprtype = NIL; 97763Speter } else { 98926Speter low = rangetype -> range[0]; 99926Speter high = rangetype -> range[1]; 100763Speter } 101763Speter } 102926Speter } 103926Speter if ( exprtype != NIL ) { 104763Speter /* 1053641Speter * compute and save the case expression. 1063641Speter * also, put expression into a register 107926Speter * save its c-type and jump to the code to do the switch. 108763Speter */ 1093641Speter exprctype = p2type( exprtype ); 1103830Speter exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG ); 1113830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1123830Speter exprnlp -> extra_flags , P2INT ); 1133641Speter (void) rvalue( (int *) tcase[2] , NIL , RREQ ); 11410379Speter sconv(exprctype, P2INT); 1153641Speter putop( P2ASSIGN , P2INT ); 116926Speter putop( P2FORCE , P2INT ); 117926Speter putdot( filename , line ); 118926Speter swlabel = getlab(); 119926Speter putjbr( swlabel ); 120926Speter } 121926Speter /* 122926Speter * count the number of cases 123926Speter * and allocate table for cases, lines, and labels 124926Speter * default case goes in ctab[0]. 125926Speter */ 126926Speter count = 1; 127926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 128926Speter cstatp = cstatlp[1]; 129926Speter if ( cstatp == NIL ) { 130926Speter continue; 131763Speter } 132926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 133926Speter count++; 134763Speter } 135926Speter } 136926Speter /* 137926Speter */ 138926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 139926Speter if ( ctab == (struct ct *) 0 ) { 140926Speter error("Ran out of memory (case)"); 141926Speter pexit( DIED ); 142926Speter } 143926Speter /* 144926Speter * pick up default label and label for after case statement. 145926Speter */ 146926Speter ctab[0].clabel = getlab(); 147926Speter endlabel = getlab(); 148926Speter /* 149926Speter * generate code for each case 150926Speter * filling in ctab for each. 151926Speter * nr is for error if no case falls out bottom. 152926Speter */ 153926Speter nr = 1; 154926Speter count = 0; 155926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 156926Speter cstatp = cstatlp[1]; 157926Speter if ( cstatp == NIL ) { 158926Speter continue; 159926Speter } 160926Speter line = cstatp[1]; 161926Speter label = getlab(); 162926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 163926Speter gconst( casep[1] ); 164926Speter if( exprtype == NIL || con.ctype == NIL ) { 165763Speter continue; 166763Speter } 167926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 168926Speter cerror("Case label type clashed with case selector expression type"); 169926Speter continue; 170763Speter } 171926Speter if ( con.crval < low || con.crval > high ) { 172926Speter error("Case label out of range"); 173926Speter continue; 174763Speter } 175926Speter count++; 176926Speter ctab[ count ].cconst = con.crval; 177926Speter ctab[ count ].cline = line; 178926Speter ctab[ count ].clabel = label; 179763Speter } 180763Speter /* 181926Speter * put out the statement 182763Speter */ 183926Speter putlab( label ); 184926Speter putcnt(); 185926Speter level++; 186926Speter statement( cstatp[3] ); 1873139Smckusic nr = (nr && noreach); 188926Speter noreach = 0; 189926Speter level--; 190926Speter if (gotos[cbn]) { 191926Speter ungoto(); 192763Speter } 193926Speter putjbr( endlabel ); 194763Speter } 1951278Speter noreach = nr; 196926Speter /* 197926Speter * default action is to call error 198926Speter */ 199926Speter putlab( ctab[0].clabel ); 2005663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 2013830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 2023830Speter exprnlp -> extra_flags , P2INT ); 203926Speter putop( P2CALL , P2INT ); 204926Speter putdot( filename , line ); 205926Speter /* 206926Speter * sort the cases 207926Speter */ 208926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 209926Speter /* 210926Speter * check for duplicates 211926Speter */ 2121278Speter dupcases = FALSE; 213926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 214926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2151278Speter error("Multiply defined label in case, lines %d and %d" , 216926Speter ctp[0].cline , ctp[1].cline ); 2171278Speter dupcases = TRUE; 218926Speter } 219926Speter } 2201278Speter if ( dupcases ) { 2211278Speter return; 2221278Speter } 223926Speter /* 224926Speter * choose a switch algorithm and implement it: 225926Speter * direct switch >= 1/3 full and >= 4 cases. 226926Speter * binary switch not direct switch and > 8 cases. 227926Speter * ifthenelse not direct or binary switch. 228926Speter */ 229926Speter putlab( swlabel ); 230926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 231926Speter directsw( ctab , count ); 232926Speter } else if ( count > 8 ) { 233926Speter binarysw( ctab , count ); 234926Speter } else { 235926Speter itesw( ctab , count ); 236926Speter } 237926Speter putlab( endlabel ); 238926Speter if ( goc != gocnt ) { 239926Speter putcnt(); 240926Speter } 241926Speter } 242763Speter 243926Speter /* 244926Speter * direct switch 245926Speter */ 246926Speter directsw( ctab , count ) 247926Speter struct ct *ctab; 248926Speter int count; 249926Speter { 250926Speter int fromlabel = getlab(); 251926Speter long i; 252926Speter long j; 253926Speter 25410378Speter # ifdef vax 25510378Speter putprintf(" casel %s,$%d,$%d" , 0 , FORCENAME , 25610378Speter ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 25710378Speter # endif vax 25810378Speter # ifdef mc68000 25910378Speter /* 26010378Speter * subl to make d0 a 0-origin byte offset. 26110378Speter * cmpl check against upper limit. 26210378Speter * bhi error if out of bounds. 26310378Speter * addw to make d0 a 0-origin word offset. 26410378Speter * movw pick up a jump-table entry 26510378Speter * jmp and indirect through it. 26610378Speter */ 26710378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 26810378Speter putprintf(" cmpl #%d,%s", 0, 26910378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 27010378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 27110378Speter putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 27210378Speter putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 27310378Speter putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 27410378Speter # endif mc68000 275926Speter putlab( fromlabel ); 276926Speter i = 1; 277926Speter j = ctab[1].cconst; 278926Speter while ( i <= count ) { 279926Speter if ( j == ctab[ i ].cconst ) { 280926Speter putprintf( " .word " , 1 ); 281926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 282926Speter putprintf( "-" , 1 ); 283926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 284926Speter i++; 285926Speter } else { 286926Speter putprintf( " .word " , 1 ); 287926Speter putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 288926Speter putprintf( "-" , 1 ); 289926Speter putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 290926Speter } 291926Speter j++; 292926Speter } 29310378Speter # ifdef vax 29410378Speter /* 29510378Speter * execution continues here if value not in range of case. 29610378Speter */ 29710378Speter putjbr( ctab[0].clabel ); 29810378Speter # endif vax 299926Speter } 300926Speter 301926Speter /* 302926Speter * binary switch 303926Speter * special case out default label and start recursion. 304926Speter */ 305926Speter binarysw( ctab , count ) 306926Speter struct ct *ctab; 307926Speter int count; 308926Speter { 309926Speter 310926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 311926Speter } 312926Speter 313926Speter /* 314926Speter * recursive log( count ) search. 315926Speter */ 316926Speter bsrecur( deflabel , ctab , count ) 317926Speter int deflabel; 318926Speter struct ct *ctab; 319926Speter int count; 320926Speter { 321926Speter 322926Speter if ( count <= 0 ) { 32310378Speter putjbr(deflabel); 324926Speter return; 325926Speter } else if ( count == 1 ) { 32610378Speter # ifdef vax 32710378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[1].cconst); 32810378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[1].clabel); 32910378Speter putjbr(deflabel); 33010378Speter # endif vax 33110378Speter # ifdef mc68000 33210378Speter putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, FORCENAME); 33310378Speter putprintf(" jeq L%d", 0, LABELPREFIX, ctab[1].clabel); 33410378Speter putjbr(deflabel); 33510378Speter # endif mc68000 336926Speter return; 337926Speter } else { 338926Speter int half = ( count + 1 ) / 2; 339926Speter int gtrlabel = getlab(); 340926Speter 34110378Speter # ifdef vax 34210378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[half].cconst); 34310378Speter putprintf(" jgtr %s%d", 0, LABELPREFIX, gtrlabel); 34410378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[half].clabel); 34510378Speter # endif vax 34610378Speter # ifdef mc68000 34710378Speter putprintf(" cmpl #%d,%s", 0, ctab[half].cconst, FORCENAME); 34810378Speter putprintf(" jgt %s%d", 0, LABELPREFIX, gtrlabel); 34910378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[half].clabel); 35010378Speter # endif mc68000 351926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 35210378Speter putlab(gtrlabel); 353926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 354926Speter return; 355926Speter } 356926Speter } 357926Speter 358926Speter itesw( ctab , count ) 359926Speter struct ct *ctab; 360926Speter int count; 361926Speter { 362926Speter int i; 363926Speter 364926Speter for ( i = 1 ; i <= count ; i++ ) { 36510378Speter # ifdef vax 36610378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[i].cconst); 36710378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[i].clabel); 36810378Speter # endif vax 36910378Speter # ifdef mc68000 37010378Speter putprintf(" cmpl #%d,%s", 0, ctab[i].cconst, FORCENAME); 37110378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[i].clabel); 37210378Speter # endif mc68000 373926Speter } 37410378Speter putjbr(ctab[0].clabel); 375926Speter return; 376926Speter } 377926Speter int 378926Speter casecmp( this , that ) 379926Speter struct ct *this; 380926Speter struct ct *that; 381926Speter { 382926Speter if ( this -> cconst < that -> cconst ) { 383926Speter return -1; 384926Speter } else if ( this -> cconst > that -> cconst ) { 385926Speter return 1; 386926Speter } else { 387926Speter return 0; 388926Speter } 389926Speter } 390763Speter #endif PC 391