1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 3*15936Smckusick #ifndef lint 4*15936Smckusick static char sccsid[] = "@(#)pccaseop.c 1.12.1.1 02/04/84"; 5*15936Smckusick #endif 6763Speter 7763Speter #include "whoami.h" 8763Speter #ifdef PC 9763Speter /* 10763Speter * and the rest of the file 11763Speter */ 12763Speter #include "0.h" 13763Speter #include "tree.h" 14763Speter #include "objfmt.h" 15763Speter #include "pcops.h" 16763Speter #include "pc.h" 1711329Speter #include "tmps.h" 18*15936Smckusick #include "tree_ty.h" 19926Speter 20763Speter /* 21926Speter * structure for a case: 22926Speter * its constant label, line number (for errors), and location label. 23926Speter */ 24926Speter struct ct { 25926Speter long cconst; 26926Speter int cline; 27926Speter int clabel; 28926Speter }; 29926Speter 30926Speter /* 31926Speter * the P2FORCE operator puts its operand into a register. 32926Speter * these to keep from thinking of it as r0 all over. 33926Speter */ 3410378Speter #ifdef vax 3510378Speter # define FORCENAME "r0" 3610378Speter #endif vax 3710378Speter #ifdef mc68000 3810378Speter # define FORCENAME "d0" 3912968Smckusick # define ADDRTEMP "a0" 4010378Speter #endif mc68000 41926Speter 42926Speter /* 43926Speter * given a tree for a case statement, generate code for it. 44926Speter * this computes the expression into a register, 45926Speter * puts down the code for each of the cases, 46926Speter * and then decides how to do the case switching. 47763Speter * tcase [0] T_CASE 48763Speter * [1] lineof "case" 49763Speter * [2] expression 50926Speter * [3] list of cased statements: 51763Speter * cstat [0] T_CSTAT 52763Speter * [1] lineof ":" 53926Speter * [2] list of constant labels 54763Speter * [3] statement 55763Speter */ 56763Speter pccaseop( tcase ) 57*15936Smckusick WHI_CAS *tcase; 58926Speter { 59926Speter struct nl *exprtype; 603830Speter struct nl *exprnlp; 61926Speter struct nl *rangetype; 62926Speter long low; 63926Speter long high; 64926Speter long exprctype; 65*15936Smckusick char *swlabel; 66*15936Smckusick char *endlabel; 67*15936Smckusick char *label; 68*15936Smckusick int count; 69*15936Smckusick struct tnode *cstatlp; 70*15936Smckusick struct tnode *cstatp; 71*15936Smckusick struct tnode *casep; 72926Speter struct ct *ctab; 73926Speter struct ct *ctp; 74*15936Smckusick bool nr; 75926Speter long goc; 76926Speter int casecmp(); 771278Speter bool dupcases; 78763Speter 79926Speter goc = gocnt; 80926Speter /* 81926Speter * find out the type of the case expression 82926Speter * even if the expression has errors (exprtype == NIL), continue. 83926Speter */ 84*15936Smckusick line = tcase->line_no; 853641Speter codeoff(); 86*15936Smckusick exprtype = rvalue( tcase->expr , NLNIL , RREQ ); 873641Speter codeon(); 88*15936Smckusick if ( exprtype != NLNIL ) { 89926Speter if ( isnta( exprtype , "bcsi" ) ) { 90926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 91*15936Smckusick exprtype = NLNIL; 92926Speter } else { 93926Speter if ( exprtype -> class != RANGE ) { 94926Speter rangetype = exprtype -> type; 95926Speter } else { 96926Speter rangetype = exprtype; 97926Speter } 98*15936Smckusick if ( rangetype == NLNIL ) { 99*15936Smckusick exprtype = NLNIL; 100763Speter } else { 101926Speter low = rangetype -> range[0]; 102926Speter high = rangetype -> range[1]; 103763Speter } 104763Speter } 105926Speter } 106*15936Smckusick if ( exprtype != NLNIL ) { 107763Speter /* 1083641Speter * compute and save the case expression. 1093641Speter * also, put expression into a register 110926Speter * save its c-type and jump to the code to do the switch. 111763Speter */ 1123641Speter exprctype = p2type( exprtype ); 113*15936Smckusick exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG ); 114*15936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1153830Speter exprnlp -> extra_flags , P2INT ); 116*15936Smckusick (void) rvalue( tcase->expr , NLNIL , RREQ ); 117*15936Smckusick sconv((int) exprctype, (int) P2INT); 1183641Speter putop( P2ASSIGN , P2INT ); 119926Speter putop( P2FORCE , P2INT ); 120926Speter putdot( filename , line ); 121926Speter swlabel = getlab(); 122*15936Smckusick putjbr( (long) swlabel ); 123926Speter } 124926Speter /* 125926Speter * count the number of cases 126926Speter * and allocate table for cases, lines, and labels 127926Speter * default case goes in ctab[0]. 128926Speter */ 129926Speter count = 1; 130*15936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 131*15936Smckusick cstatlp = cstatlp->list_node.next ) { 132*15936Smckusick cstatp = cstatlp->list_node.list; 133*15936Smckusick if ( cstatp == TR_NIL ) { 134926Speter continue; 135763Speter } 136*15936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 137*15936Smckusick casep = casep->list_node.next ) { 138926Speter count++; 139763Speter } 140926Speter } 141926Speter /* 142926Speter */ 143926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 144926Speter if ( ctab == (struct ct *) 0 ) { 145926Speter error("Ran out of memory (case)"); 146926Speter pexit( DIED ); 147926Speter } 148926Speter /* 149926Speter * pick up default label and label for after case statement. 150926Speter */ 151*15936Smckusick ctab[0].clabel = (int) getlab(); 152926Speter endlabel = getlab(); 153926Speter /* 154926Speter * generate code for each case 155926Speter * filling in ctab for each. 156926Speter * nr is for error if no case falls out bottom. 157926Speter */ 158*15936Smckusick nr = TRUE;; 159926Speter count = 0; 160*15936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 161*15936Smckusick cstatlp = cstatlp->list_node.next ) { 162*15936Smckusick cstatp = cstatlp->list_node.list; 163*15936Smckusick if ( cstatp == TR_NIL ) { 164926Speter continue; 165926Speter } 166*15936Smckusick line = cstatp->c_stmnt.line_no; 167926Speter label = getlab(); 168*15936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 169*15936Smckusick casep = casep->list_node.next ) { 170*15936Smckusick gconst( casep->list_node.list ); 171*15936Smckusick if( exprtype == NLNIL || con.ctype == NIL ) { 172763Speter continue; 173763Speter } 174*15936Smckusick if ( incompat( con.ctype , exprtype , TR_NIL ) ) { 175926Speter cerror("Case label type clashed with case selector expression type"); 176926Speter continue; 177763Speter } 178926Speter if ( con.crval < low || con.crval > high ) { 179926Speter error("Case label out of range"); 180926Speter continue; 181763Speter } 182926Speter count++; 183926Speter ctab[ count ].cconst = con.crval; 184926Speter ctab[ count ].cline = line; 185*15936Smckusick ctab[ count ].clabel = (int) label; 186763Speter } 187763Speter /* 188926Speter * put out the statement 189763Speter */ 190*15936Smckusick (void) putlab( label ); 191926Speter putcnt(); 192926Speter level++; 193*15936Smckusick statement( cstatp->c_stmnt.stmnt ); 194*15936Smckusick nr = (nr && noreach)?TRUE:FALSE; 195*15936Smckusick noreach = FALSE; 196926Speter level--; 197926Speter if (gotos[cbn]) { 198926Speter ungoto(); 199763Speter } 200*15936Smckusick putjbr( (long) endlabel ); 201763Speter } 2021278Speter noreach = nr; 203926Speter /* 204926Speter * default action is to call error 205926Speter */ 206*15936Smckusick (void) putlab( (char *) ctab[0].clabel ); 2075663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 208*15936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 2093830Speter exprnlp -> extra_flags , P2INT ); 210926Speter putop( P2CALL , P2INT ); 211926Speter putdot( filename , line ); 212926Speter /* 213926Speter * sort the cases 214926Speter */ 215926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 216926Speter /* 217926Speter * check for duplicates 218926Speter */ 2191278Speter dupcases = FALSE; 220926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 221926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2221278Speter error("Multiply defined label in case, lines %d and %d" , 223*15936Smckusick (char *) ctp[0].cline , (char *) ctp[1].cline ); 2241278Speter dupcases = TRUE; 225926Speter } 226926Speter } 2271278Speter if ( dupcases ) { 2281278Speter return; 2291278Speter } 230926Speter /* 231926Speter * choose a switch algorithm and implement it: 232926Speter * direct switch >= 1/3 full and >= 4 cases. 233926Speter * binary switch not direct switch and > 8 cases. 234926Speter * ifthenelse not direct or binary switch. 235926Speter */ 236*15936Smckusick (void) putlab( swlabel ); 237926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 238926Speter directsw( ctab , count ); 239926Speter } else if ( count > 8 ) { 240926Speter binarysw( ctab , count ); 241926Speter } else { 242926Speter itesw( ctab , count ); 243926Speter } 244*15936Smckusick (void) putlab( endlabel ); 245926Speter if ( goc != gocnt ) { 246926Speter putcnt(); 247926Speter } 248926Speter } 249763Speter 250926Speter /* 251926Speter * direct switch 252926Speter */ 253926Speter directsw( ctab , count ) 254926Speter struct ct *ctab; 255926Speter int count; 256926Speter { 257*15936Smckusick int fromlabel = (int) getlab(); 258926Speter long i; 259926Speter long j; 260926Speter 26110378Speter # ifdef vax 26212968Smckusick if (opt('J')) { 26310378Speter /* 26412968Smckusick * We have a table of absolute addresses. 26512968Smckusick * 26612968Smckusick * subl2 to make r0 a 0-origin byte offset. 26710378Speter * cmpl check against upper limit. 26812968Smckusick * blssu error if out of bounds. 26912968Smckusick * ashl to make r0 a 0-origin long offset, 27010378Speter * jmp and indirect through it. 27110378Speter */ 272*15936Smckusick putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME); 27312968Smckusick putprintf(" cmpl $%d,%s", 0, 274*15936Smckusick (int) (ctab[count].cconst - ctab[1].cconst), 275*15936Smckusick (int) FORCENAME); 276*15936Smckusick putprintf(" blssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel); 277*15936Smckusick putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME); 27812968Smckusick putprintf(" jmp *%s%d(%s)", 0, 279*15936Smckusick (int) LABELPREFIX, fromlabel, (int) FORCENAME); 28012968Smckusick } else { 28112968Smckusick /* 28212968Smckusick * We can use the VAX casel instruction with a table 28312968Smckusick * of short relative offsets. 28412968Smckusick */ 285*15936Smckusick putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME , 286*15936Smckusick (int) ctab[1].cconst , 287*15936Smckusick (int) (ctab[ count ].cconst - ctab[1].cconst )); 28812968Smckusick } 28912968Smckusick # endif vax 29012968Smckusick # ifdef mc68000 29112968Smckusick /* 29212968Smckusick * subl to make d0 a 0-origin byte offset. 29312968Smckusick * cmpl check against upper limit. 29412968Smckusick * bhi error if out of bounds. 29512968Smckusick */ 29610378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 29710378Speter putprintf(" cmpl #%d,%s", 0, 29810378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 29910378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 30012968Smckusick if (opt('J')) { 30112968Smckusick /* 30212968Smckusick * We have a table of absolute addresses. 30312968Smckusick * 30412968Smckusick * asll to make d0 a 0-origin long offset. 30512968Smckusick * movl pick up a jump-table entry 30612968Smckusick * jmp and indirect through it. 30712968Smckusick */ 30812968Smckusick putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME); 30912968Smckusick putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP); 31012968Smckusick putprintf(" jmp %s@", 0, ADDRTEMP); 31112968Smckusick } else { 31212968Smckusick /* 31312968Smckusick * We have a table of relative addresses. 31412968Smckusick * 31512968Smckusick * addw to make d0 a 0-origin word offset. 31612968Smckusick * movw pick up a jump-table entry 31712968Smckusick * jmp and indirect through it. 31812968Smckusick */ 31912968Smckusick putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 32012968Smckusick putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 32112968Smckusick putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 32212968Smckusick } 32310378Speter # endif mc68000 324*15936Smckusick (void) putlab( (char *) fromlabel ); 325926Speter i = 1; 326926Speter j = ctab[1].cconst; 327926Speter while ( i <= count ) { 328926Speter if ( j == ctab[ i ].cconst ) { 32912968Smckusick if (opt('J')) { 33012968Smckusick putprintf( " .long " , 1 ); 331*15936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel ); 33212968Smckusick } else { 33312968Smckusick putprintf( " .word " , 1 ); 334*15936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel ); 33512968Smckusick putprintf( "-" , 1 ); 336*15936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 33712968Smckusick } 338926Speter i++; 339926Speter } else { 34012968Smckusick if (opt('J')) { 34112968Smckusick putprintf( " .long " , 1 ); 342*15936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 34312968Smckusick } else { 34412968Smckusick putprintf( " .word " , 1 ); 345*15936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 34612968Smckusick putprintf( "-" , 1 ); 347*15936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 34812968Smckusick } 349926Speter } 350926Speter j++; 351926Speter } 35210378Speter # ifdef vax 35310378Speter /* 35410378Speter * execution continues here if value not in range of case. 35510378Speter */ 35612968Smckusick if (!opt('J')) 357*15936Smckusick putjbr( (long) ctab[0].clabel ); 35810378Speter # endif vax 359926Speter } 360926Speter 361926Speter /* 362926Speter * binary switch 363926Speter * special case out default label and start recursion. 364926Speter */ 365926Speter binarysw( ctab , count ) 366926Speter struct ct *ctab; 367926Speter int count; 368926Speter { 369926Speter 370926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 371926Speter } 372926Speter 373926Speter /* 374926Speter * recursive log( count ) search. 375926Speter */ 376926Speter bsrecur( deflabel , ctab , count ) 377926Speter int deflabel; 378926Speter struct ct *ctab; 379926Speter int count; 380926Speter { 381926Speter 382926Speter if ( count <= 0 ) { 383*15936Smckusick putjbr((long) deflabel); 384926Speter return; 385926Speter } else if ( count == 1 ) { 38610378Speter # ifdef vax 387*15936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst); 388*15936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel); 389*15936Smckusick putjbr((long) deflabel); 39010378Speter # endif vax 39110378Speter # ifdef mc68000 392*15936Smckusick putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME); 393*15936Smckusick putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel); 394*15936Smckusick putjbr((long) deflabel); 39510378Speter # endif mc68000 396926Speter return; 397926Speter } else { 398926Speter int half = ( count + 1 ) / 2; 399*15936Smckusick int gtrlabel = (int) getlab(); 400926Speter 40110378Speter # ifdef vax 402*15936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst); 403*15936Smckusick putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel); 404*15936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 40510378Speter # endif vax 40610378Speter # ifdef mc68000 407*15936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME); 408*15936Smckusick putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel); 409*15936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 41010378Speter # endif mc68000 411926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 412*15936Smckusick (void) putlab((char *) gtrlabel); 413926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 414926Speter return; 415926Speter } 416926Speter } 417926Speter 418926Speter itesw( ctab , count ) 419926Speter struct ct *ctab; 420926Speter int count; 421926Speter { 422926Speter int i; 423926Speter 424926Speter for ( i = 1 ; i <= count ; i++ ) { 42510378Speter # ifdef vax 426*15936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst); 427*15936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 42810378Speter # endif vax 42910378Speter # ifdef mc68000 430*15936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME); 431*15936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 43210378Speter # endif mc68000 433926Speter } 434*15936Smckusick putjbr((long) ctab[0].clabel); 435926Speter return; 436926Speter } 437926Speter int 438926Speter casecmp( this , that ) 439926Speter struct ct *this; 440926Speter struct ct *that; 441926Speter { 442926Speter if ( this -> cconst < that -> cconst ) { 443926Speter return -1; 444926Speter } else if ( this -> cconst > that -> cconst ) { 445926Speter return 1; 446926Speter } else { 447926Speter return 0; 448926Speter } 449926Speter } 450763Speter #endif PC 451