1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*12968Smckusick static char sccsid[] = "@(#)pccaseop.c 1.12 06/10/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" 1511329Speter #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" 36*12968Smckusick # define ADDRTEMP "a0" 3710378Speter #endif mc68000 38926Speter 39926Speter /* 40926Speter * given a tree for a case statement, generate code for it. 41926Speter * this computes the expression into a register, 42926Speter * puts down the code for each of the cases, 43926Speter * and then decides how to do the case switching. 44763Speter * tcase [0] T_CASE 45763Speter * [1] lineof "case" 46763Speter * [2] expression 47926Speter * [3] list of cased statements: 48763Speter * cstat [0] T_CSTAT 49763Speter * [1] lineof ":" 50926Speter * [2] list of constant labels 51763Speter * [3] statement 52763Speter */ 53763Speter pccaseop( tcase ) 54763Speter int *tcase; 55926Speter { 56926Speter struct nl *exprtype; 573830Speter struct nl *exprnlp; 58926Speter struct nl *rangetype; 59926Speter long low; 60926Speter long high; 61926Speter long exprctype; 62926Speter long swlabel; 63926Speter long endlabel; 64926Speter long label; 65926Speter long count; 66926Speter long *cstatlp; 67926Speter long *cstatp; 68926Speter long *casep; 69926Speter struct ct *ctab; 70926Speter struct ct *ctp; 71926Speter long i; 72926Speter long nr; 73926Speter long goc; 74926Speter int casecmp(); 751278Speter bool dupcases; 76763Speter 77926Speter goc = gocnt; 78926Speter /* 79926Speter * find out the type of the case expression 80926Speter * even if the expression has errors (exprtype == NIL), continue. 81926Speter */ 82926Speter line = tcase[1]; 833641Speter codeoff(); 84926Speter exprtype = rvalue( (int *) tcase[2] , NIL , RREQ ); 853641Speter codeon(); 86926Speter if ( exprtype != NIL ) { 87926Speter if ( isnta( exprtype , "bcsi" ) ) { 88926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 89926Speter exprtype = NIL; 90926Speter } else { 91926Speter if ( exprtype -> class != RANGE ) { 92926Speter rangetype = exprtype -> type; 93926Speter } else { 94926Speter rangetype = exprtype; 95926Speter } 96926Speter if ( rangetype == NIL ) { 97763Speter exprtype = NIL; 98763Speter } else { 99926Speter low = rangetype -> range[0]; 100926Speter high = rangetype -> range[1]; 101763Speter } 102763Speter } 103926Speter } 104926Speter if ( exprtype != NIL ) { 105763Speter /* 1063641Speter * compute and save the case expression. 1073641Speter * also, put expression into a register 108926Speter * save its c-type and jump to the code to do the switch. 109763Speter */ 1103641Speter exprctype = p2type( exprtype ); 1113830Speter exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG ); 1123830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1133830Speter exprnlp -> extra_flags , P2INT ); 1143641Speter (void) rvalue( (int *) tcase[2] , NIL , RREQ ); 11510379Speter sconv(exprctype, P2INT); 1163641Speter putop( P2ASSIGN , P2INT ); 117926Speter putop( P2FORCE , P2INT ); 118926Speter putdot( filename , line ); 119926Speter swlabel = getlab(); 120926Speter putjbr( swlabel ); 121926Speter } 122926Speter /* 123926Speter * count the number of cases 124926Speter * and allocate table for cases, lines, and labels 125926Speter * default case goes in ctab[0]. 126926Speter */ 127926Speter count = 1; 128926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 129926Speter cstatp = cstatlp[1]; 130926Speter if ( cstatp == NIL ) { 131926Speter continue; 132763Speter } 133926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 134926Speter count++; 135763Speter } 136926Speter } 137926Speter /* 138926Speter */ 139926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 140926Speter if ( ctab == (struct ct *) 0 ) { 141926Speter error("Ran out of memory (case)"); 142926Speter pexit( DIED ); 143926Speter } 144926Speter /* 145926Speter * pick up default label and label for after case statement. 146926Speter */ 147926Speter ctab[0].clabel = getlab(); 148926Speter endlabel = getlab(); 149926Speter /* 150926Speter * generate code for each case 151926Speter * filling in ctab for each. 152926Speter * nr is for error if no case falls out bottom. 153926Speter */ 154926Speter nr = 1; 155926Speter count = 0; 156926Speter for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) { 157926Speter cstatp = cstatlp[1]; 158926Speter if ( cstatp == NIL ) { 159926Speter continue; 160926Speter } 161926Speter line = cstatp[1]; 162926Speter label = getlab(); 163926Speter for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) { 164926Speter gconst( casep[1] ); 165926Speter if( exprtype == NIL || con.ctype == NIL ) { 166763Speter continue; 167763Speter } 168926Speter if ( incompat( con.ctype , exprtype , NIL ) ) { 169926Speter cerror("Case label type clashed with case selector expression type"); 170926Speter continue; 171763Speter } 172926Speter if ( con.crval < low || con.crval > high ) { 173926Speter error("Case label out of range"); 174926Speter continue; 175763Speter } 176926Speter count++; 177926Speter ctab[ count ].cconst = con.crval; 178926Speter ctab[ count ].cline = line; 179926Speter ctab[ count ].clabel = label; 180763Speter } 181763Speter /* 182926Speter * put out the statement 183763Speter */ 184926Speter putlab( label ); 185926Speter putcnt(); 186926Speter level++; 187926Speter statement( cstatp[3] ); 1883139Smckusic nr = (nr && noreach); 189926Speter noreach = 0; 190926Speter level--; 191926Speter if (gotos[cbn]) { 192926Speter ungoto(); 193763Speter } 194926Speter putjbr( endlabel ); 195763Speter } 1961278Speter noreach = nr; 197926Speter /* 198926Speter * default action is to call error 199926Speter */ 200926Speter putlab( ctab[0].clabel ); 2015663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 2023830Speter putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] , 2033830Speter exprnlp -> extra_flags , P2INT ); 204926Speter putop( P2CALL , P2INT ); 205926Speter putdot( filename , line ); 206926Speter /* 207926Speter * sort the cases 208926Speter */ 209926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 210926Speter /* 211926Speter * check for duplicates 212926Speter */ 2131278Speter dupcases = FALSE; 214926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 215926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2161278Speter error("Multiply defined label in case, lines %d and %d" , 217926Speter ctp[0].cline , ctp[1].cline ); 2181278Speter dupcases = TRUE; 219926Speter } 220926Speter } 2211278Speter if ( dupcases ) { 2221278Speter return; 2231278Speter } 224926Speter /* 225926Speter * choose a switch algorithm and implement it: 226926Speter * direct switch >= 1/3 full and >= 4 cases. 227926Speter * binary switch not direct switch and > 8 cases. 228926Speter * ifthenelse not direct or binary switch. 229926Speter */ 230926Speter putlab( swlabel ); 231926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 232926Speter directsw( ctab , count ); 233926Speter } else if ( count > 8 ) { 234926Speter binarysw( ctab , count ); 235926Speter } else { 236926Speter itesw( ctab , count ); 237926Speter } 238926Speter putlab( endlabel ); 239926Speter if ( goc != gocnt ) { 240926Speter putcnt(); 241926Speter } 242926Speter } 243763Speter 244926Speter /* 245926Speter * direct switch 246926Speter */ 247926Speter directsw( ctab , count ) 248926Speter struct ct *ctab; 249926Speter int count; 250926Speter { 251926Speter int fromlabel = getlab(); 252926Speter long i; 253926Speter long j; 254926Speter 25510378Speter # ifdef vax 256*12968Smckusick if (opt('J')) { 25710378Speter /* 258*12968Smckusick * We have a table of absolute addresses. 259*12968Smckusick * 260*12968Smckusick * subl2 to make r0 a 0-origin byte offset. 26110378Speter * cmpl check against upper limit. 262*12968Smckusick * blssu error if out of bounds. 263*12968Smckusick * ashl to make r0 a 0-origin long offset, 26410378Speter * jmp and indirect through it. 26510378Speter */ 266*12968Smckusick putprintf(" subl2 $%d,%s", 0, ctab[1].cconst, FORCENAME); 267*12968Smckusick putprintf(" cmpl $%d,%s", 0, 268*12968Smckusick ctab[count].cconst - ctab[1].cconst, FORCENAME); 269*12968Smckusick putprintf(" blssu %s%d", 0, LABELPREFIX, ctab[0].clabel); 270*12968Smckusick putprintf(" ashl $2,%s,%s", 0, FORCENAME, FORCENAME); 271*12968Smckusick putprintf(" jmp *%s%d(%s)", 0, 272*12968Smckusick LABELPREFIX, fromlabel, FORCENAME); 273*12968Smckusick } else { 274*12968Smckusick /* 275*12968Smckusick * We can use the VAX casel instruction with a table 276*12968Smckusick * of short relative offsets. 277*12968Smckusick */ 278*12968Smckusick putprintf(" casel %s,$%d,$%d" , 0 , FORCENAME , 279*12968Smckusick ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst ); 280*12968Smckusick } 281*12968Smckusick # endif vax 282*12968Smckusick # ifdef mc68000 283*12968Smckusick /* 284*12968Smckusick * subl to make d0 a 0-origin byte offset. 285*12968Smckusick * cmpl check against upper limit. 286*12968Smckusick * bhi error if out of bounds. 287*12968Smckusick */ 28810378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 28910378Speter putprintf(" cmpl #%d,%s", 0, 29010378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 29110378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 292*12968Smckusick if (opt('J')) { 293*12968Smckusick /* 294*12968Smckusick * We have a table of absolute addresses. 295*12968Smckusick * 296*12968Smckusick * asll to make d0 a 0-origin long offset. 297*12968Smckusick * movl pick up a jump-table entry 298*12968Smckusick * jmp and indirect through it. 299*12968Smckusick */ 300*12968Smckusick putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME); 301*12968Smckusick putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP); 302*12968Smckusick putprintf(" jmp %s@", 0, ADDRTEMP); 303*12968Smckusick } else { 304*12968Smckusick /* 305*12968Smckusick * We have a table of relative addresses. 306*12968Smckusick * 307*12968Smckusick * addw to make d0 a 0-origin word offset. 308*12968Smckusick * movw pick up a jump-table entry 309*12968Smckusick * jmp and indirect through it. 310*12968Smckusick */ 311*12968Smckusick putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 312*12968Smckusick putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 313*12968Smckusick putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 314*12968Smckusick } 31510378Speter # endif mc68000 316926Speter putlab( fromlabel ); 317926Speter i = 1; 318926Speter j = ctab[1].cconst; 319926Speter while ( i <= count ) { 320926Speter if ( j == ctab[ i ].cconst ) { 321*12968Smckusick if (opt('J')) { 322*12968Smckusick putprintf( " .long " , 1 ); 323*12968Smckusick putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ i ].clabel ); 324*12968Smckusick } else { 325*12968Smckusick putprintf( " .word " , 1 ); 326*12968Smckusick putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel ); 327*12968Smckusick putprintf( "-" , 1 ); 328*12968Smckusick putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 329*12968Smckusick } 330926Speter i++; 331926Speter } else { 332*12968Smckusick if (opt('J')) { 333*12968Smckusick putprintf( " .long " , 1 ); 334*12968Smckusick putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ 0 ].clabel ); 335*12968Smckusick } else { 336*12968Smckusick putprintf( " .word " , 1 ); 337*12968Smckusick putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel ); 338*12968Smckusick putprintf( "-" , 1 ); 339*12968Smckusick putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel ); 340*12968Smckusick } 341926Speter } 342926Speter j++; 343926Speter } 34410378Speter # ifdef vax 34510378Speter /* 34610378Speter * execution continues here if value not in range of case. 34710378Speter */ 348*12968Smckusick if (!opt('J')) 349*12968Smckusick putjbr( ctab[0].clabel ); 35010378Speter # endif vax 351926Speter } 352926Speter 353926Speter /* 354926Speter * binary switch 355926Speter * special case out default label and start recursion. 356926Speter */ 357926Speter binarysw( ctab , count ) 358926Speter struct ct *ctab; 359926Speter int count; 360926Speter { 361926Speter 362926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 363926Speter } 364926Speter 365926Speter /* 366926Speter * recursive log( count ) search. 367926Speter */ 368926Speter bsrecur( deflabel , ctab , count ) 369926Speter int deflabel; 370926Speter struct ct *ctab; 371926Speter int count; 372926Speter { 373926Speter 374926Speter if ( count <= 0 ) { 37510378Speter putjbr(deflabel); 376926Speter return; 377926Speter } else if ( count == 1 ) { 37810378Speter # ifdef vax 37910378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[1].cconst); 38010378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[1].clabel); 38110378Speter putjbr(deflabel); 38210378Speter # endif vax 38310378Speter # ifdef mc68000 38410378Speter putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, FORCENAME); 38510378Speter putprintf(" jeq L%d", 0, LABELPREFIX, ctab[1].clabel); 38610378Speter putjbr(deflabel); 38710378Speter # endif mc68000 388926Speter return; 389926Speter } else { 390926Speter int half = ( count + 1 ) / 2; 391926Speter int gtrlabel = getlab(); 392926Speter 39310378Speter # ifdef vax 39410378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[half].cconst); 39510378Speter putprintf(" jgtr %s%d", 0, LABELPREFIX, gtrlabel); 39610378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[half].clabel); 39710378Speter # endif vax 39810378Speter # ifdef mc68000 39910378Speter putprintf(" cmpl #%d,%s", 0, ctab[half].cconst, FORCENAME); 40010378Speter putprintf(" jgt %s%d", 0, LABELPREFIX, gtrlabel); 40110378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[half].clabel); 40210378Speter # endif mc68000 403926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 40410378Speter putlab(gtrlabel); 405926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 406926Speter return; 407926Speter } 408926Speter } 409926Speter 410926Speter itesw( ctab , count ) 411926Speter struct ct *ctab; 412926Speter int count; 413926Speter { 414926Speter int i; 415926Speter 416926Speter for ( i = 1 ; i <= count ; i++ ) { 41710378Speter # ifdef vax 41810378Speter putprintf(" cmpl %s,$%d", 0, FORCENAME, ctab[i].cconst); 41910378Speter putprintf(" jeql %s%d", 0, LABELPREFIX, ctab[i].clabel); 42010378Speter # endif vax 42110378Speter # ifdef mc68000 42210378Speter putprintf(" cmpl #%d,%s", 0, ctab[i].cconst, FORCENAME); 42310378Speter putprintf(" jeq %s%d", 0, LABELPREFIX, ctab[i].clabel); 42410378Speter # endif mc68000 425926Speter } 42610378Speter putjbr(ctab[0].clabel); 427926Speter return; 428926Speter } 429926Speter int 430926Speter casecmp( this , that ) 431926Speter struct ct *this; 432926Speter struct ct *that; 433926Speter { 434926Speter if ( this -> cconst < that -> cconst ) { 435926Speter return -1; 436926Speter } else if ( this -> cconst > that -> cconst ) { 437926Speter return 1; 438926Speter } else { 439926Speter return 0; 440926Speter } 441926Speter } 442763Speter #endif PC 443