1926Speter /* Copyright (c) 1980 Regents of the University of California */ 2763Speter 315936Smckusick #ifndef lint 4*17425Smckusick static char sccsid[] = "@(#)pccaseop.c 2.2 11/26/84"; 515936Smckusick #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" 1815936Smckusick #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 ) 5715936Smckusick 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; 6515936Smckusick char *swlabel; 6615936Smckusick char *endlabel; 6715936Smckusick char *label; 6815936Smckusick int count; 6915936Smckusick struct tnode *cstatlp; 7015936Smckusick struct tnode *cstatp; 7115936Smckusick struct tnode *casep; 72926Speter struct ct *ctab; 73926Speter struct ct *ctp; 7415936Smckusick 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 */ 8415936Smckusick line = tcase->line_no; 853641Speter codeoff(); 8615936Smckusick exprtype = rvalue( tcase->expr , NLNIL , RREQ ); 873641Speter codeon(); 8815936Smckusick if ( exprtype != NLNIL ) { 89926Speter if ( isnta( exprtype , "bcsi" ) ) { 90926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 9115936Smckusick exprtype = NLNIL; 92926Speter } else { 93926Speter if ( exprtype -> class != RANGE ) { 94926Speter rangetype = exprtype -> type; 95926Speter } else { 96926Speter rangetype = exprtype; 97926Speter } 9815936Smckusick if ( rangetype == NLNIL ) { 9915936Smckusick exprtype = NLNIL; 100763Speter } else { 101926Speter low = rangetype -> range[0]; 102926Speter high = rangetype -> range[1]; 103763Speter } 104763Speter } 105926Speter } 10615936Smckusick 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 ); 11315936Smckusick exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG ); 11415936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 1153830Speter exprnlp -> extra_flags , P2INT ); 11615936Smckusick (void) rvalue( tcase->expr , NLNIL , RREQ ); 11715936Smckusick sconv((int) exprctype, (int) P2INT); 1183641Speter putop( P2ASSIGN , P2INT ); 119926Speter putop( P2FORCE , P2INT ); 120926Speter putdot( filename , line ); 121926Speter swlabel = getlab(); 12215936Smckusick 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; 13015936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 13115936Smckusick cstatlp = cstatlp->list_node.next ) { 13215936Smckusick cstatp = cstatlp->list_node.list; 13315936Smckusick if ( cstatp == TR_NIL ) { 134926Speter continue; 135763Speter } 13615936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 13715936Smckusick 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 */ 15115936Smckusick 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 */ 15815936Smckusick nr = TRUE;; 159926Speter count = 0; 16015936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 16115936Smckusick cstatlp = cstatlp->list_node.next ) { 16215936Smckusick cstatp = cstatlp->list_node.list; 16315936Smckusick if ( cstatp == TR_NIL ) { 164926Speter continue; 165926Speter } 16615936Smckusick line = cstatp->c_stmnt.line_no; 167926Speter label = getlab(); 16815936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 16915936Smckusick casep = casep->list_node.next ) { 17015936Smckusick gconst( casep->list_node.list ); 17115936Smckusick if( exprtype == NLNIL || con.ctype == NIL ) { 172763Speter continue; 173763Speter } 17415936Smckusick 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; 18515936Smckusick ctab[ count ].clabel = (int) label; 186763Speter } 187763Speter /* 188926Speter * put out the statement 189763Speter */ 19015936Smckusick (void) putlab( label ); 191926Speter putcnt(); 192926Speter level++; 19315936Smckusick statement( cstatp->c_stmnt.stmnt ); 19415936Smckusick nr = (nr && noreach)?TRUE:FALSE; 19515936Smckusick noreach = FALSE; 196926Speter level--; 197926Speter if (gotos[cbn]) { 198926Speter ungoto(); 199763Speter } 20015936Smckusick putjbr( (long) endlabel ); 201763Speter } 2021278Speter noreach = nr; 203926Speter /* 204926Speter * default action is to call error 205926Speter */ 20615936Smckusick (void) putlab( (char *) ctab[0].clabel ); 2075663Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" ); 20815936Smckusick 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" , 22315936Smckusick (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 */ 23615936Smckusick (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 } 24415936Smckusick (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 { 25715936Smckusick 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. 268*17425Smckusick * jlssu error if out of bounds. 26912968Smckusick * ashl to make r0 a 0-origin long offset, 27010378Speter * jmp and indirect through it. 27110378Speter */ 27215936Smckusick putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME); 27312968Smckusick putprintf(" cmpl $%d,%s", 0, 27415936Smckusick (int) (ctab[count].cconst - ctab[1].cconst), 27515936Smckusick (int) FORCENAME); 276*17425Smckusick putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel); 27715936Smckusick putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME); 27812968Smckusick putprintf(" jmp *%s%d(%s)", 0, 27915936Smckusick (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 */ 28515936Smckusick putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME , 28615936Smckusick (int) ctab[1].cconst , 28715936Smckusick (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 32415936Smckusick (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 ); 33115936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel ); 33212968Smckusick } else { 33312968Smckusick putprintf( " .word " , 1 ); 33415936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel ); 33512968Smckusick putprintf( "-" , 1 ); 33615936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 33712968Smckusick } 338926Speter i++; 339926Speter } else { 34012968Smckusick if (opt('J')) { 34112968Smckusick putprintf( " .long " , 1 ); 34215936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 34312968Smckusick } else { 34412968Smckusick putprintf( " .word " , 1 ); 34515936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 34612968Smckusick putprintf( "-" , 1 ); 34715936Smckusick 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')) 35715936Smckusick 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 ) { 38315936Smckusick putjbr((long) deflabel); 384926Speter return; 385926Speter } else if ( count == 1 ) { 38610378Speter # ifdef vax 38715936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst); 38815936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel); 38915936Smckusick putjbr((long) deflabel); 39010378Speter # endif vax 39110378Speter # ifdef mc68000 39215936Smckusick putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME); 39315936Smckusick putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel); 39415936Smckusick putjbr((long) deflabel); 39510378Speter # endif mc68000 396926Speter return; 397926Speter } else { 398926Speter int half = ( count + 1 ) / 2; 39915936Smckusick int gtrlabel = (int) getlab(); 400926Speter 40110378Speter # ifdef vax 40215936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst); 40315936Smckusick putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel); 40415936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 40510378Speter # endif vax 40610378Speter # ifdef mc68000 40715936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME); 40815936Smckusick putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel); 40915936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 41010378Speter # endif mc68000 411926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 41215936Smckusick (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 42615936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst); 42715936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 42810378Speter # endif vax 42910378Speter # ifdef mc68000 43015936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME); 43115936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 43210378Speter # endif mc68000 433926Speter } 43415936Smckusick 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