1*22182Sdist /* 2*22182Sdist * Copyright (c) 1980 Regents of the University of California. 3*22182Sdist * All rights reserved. The Berkeley software License Agreement 4*22182Sdist * specifies the terms and conditions for redistribution. 5*22182Sdist */ 6763Speter 715936Smckusick #ifndef lint 8*22182Sdist static char sccsid[] = "@(#)pccaseop.c 5.1 (Berkeley) 06/05/85"; 9*22182Sdist #endif not lint 10763Speter 11*22182Sdist 12763Speter #include "whoami.h" 13763Speter #ifdef PC 14763Speter /* 15763Speter * and the rest of the file 16763Speter */ 17763Speter #include "0.h" 18763Speter #include "tree.h" 19763Speter #include "objfmt.h" 2018463Sralph #include <pcc.h> 21763Speter #include "pc.h" 2211329Speter #include "tmps.h" 2315936Smckusick #include "tree_ty.h" 24926Speter 25763Speter /* 26926Speter * structure for a case: 27926Speter * its constant label, line number (for errors), and location label. 28926Speter */ 29926Speter struct ct { 30926Speter long cconst; 31926Speter int cline; 32926Speter int clabel; 33926Speter }; 34926Speter 35926Speter /* 3618463Sralph * the PCC_FORCE operator puts its operand into a register. 37926Speter * these to keep from thinking of it as r0 all over. 38926Speter */ 3910378Speter #ifdef vax 4010378Speter # define FORCENAME "r0" 4110378Speter #endif vax 4210378Speter #ifdef mc68000 4310378Speter # define FORCENAME "d0" 4412968Smckusick # define ADDRTEMP "a0" 4510378Speter #endif mc68000 46926Speter 47926Speter /* 48926Speter * given a tree for a case statement, generate code for it. 49926Speter * this computes the expression into a register, 50926Speter * puts down the code for each of the cases, 51926Speter * and then decides how to do the case switching. 52763Speter * tcase [0] T_CASE 53763Speter * [1] lineof "case" 54763Speter * [2] expression 55926Speter * [3] list of cased statements: 56763Speter * cstat [0] T_CSTAT 57763Speter * [1] lineof ":" 58926Speter * [2] list of constant labels 59763Speter * [3] statement 60763Speter */ 61763Speter pccaseop( tcase ) 6215936Smckusick WHI_CAS *tcase; 63926Speter { 64926Speter struct nl *exprtype; 653830Speter struct nl *exprnlp; 66926Speter struct nl *rangetype; 67926Speter long low; 68926Speter long high; 69926Speter long exprctype; 7015936Smckusick char *swlabel; 7115936Smckusick char *endlabel; 7215936Smckusick char *label; 7315936Smckusick int count; 7415936Smckusick struct tnode *cstatlp; 7515936Smckusick struct tnode *cstatp; 7615936Smckusick struct tnode *casep; 77926Speter struct ct *ctab; 78926Speter struct ct *ctp; 7915936Smckusick bool nr; 80926Speter long goc; 81926Speter int casecmp(); 821278Speter bool dupcases; 83763Speter 84926Speter goc = gocnt; 85926Speter /* 86926Speter * find out the type of the case expression 87926Speter * even if the expression has errors (exprtype == NIL), continue. 88926Speter */ 8915936Smckusick line = tcase->line_no; 903641Speter codeoff(); 9115936Smckusick exprtype = rvalue( tcase->expr , NLNIL , RREQ ); 923641Speter codeon(); 9315936Smckusick if ( exprtype != NLNIL ) { 94926Speter if ( isnta( exprtype , "bcsi" ) ) { 95926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) ); 9615936Smckusick exprtype = NLNIL; 97926Speter } else { 98926Speter if ( exprtype -> class != RANGE ) { 99926Speter rangetype = exprtype -> type; 100926Speter } else { 101926Speter rangetype = exprtype; 102926Speter } 10315936Smckusick if ( rangetype == NLNIL ) { 10415936Smckusick exprtype = NLNIL; 105763Speter } else { 106926Speter low = rangetype -> range[0]; 107926Speter high = rangetype -> range[1]; 108763Speter } 109763Speter } 110926Speter } 11115936Smckusick if ( exprtype != NLNIL ) { 112763Speter /* 1133641Speter * compute and save the case expression. 1143641Speter * also, put expression into a register 115926Speter * save its c-type and jump to the code to do the switch. 116763Speter */ 1173641Speter exprctype = p2type( exprtype ); 11815936Smckusick exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG ); 11915936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 12018463Sralph exprnlp -> extra_flags , PCCT_INT ); 12115936Smckusick (void) rvalue( tcase->expr , NLNIL , RREQ ); 12218463Sralph sconv((int) exprctype, (int) PCCT_INT); 12318463Sralph putop( PCC_ASSIGN , PCCT_INT ); 12418463Sralph putop( PCC_FORCE , PCCT_INT ); 125926Speter putdot( filename , line ); 126926Speter swlabel = getlab(); 12715936Smckusick putjbr( (long) swlabel ); 128926Speter } 129926Speter /* 130926Speter * count the number of cases 131926Speter * and allocate table for cases, lines, and labels 132926Speter * default case goes in ctab[0]. 133926Speter */ 134926Speter count = 1; 13515936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 13615936Smckusick cstatlp = cstatlp->list_node.next ) { 13715936Smckusick cstatp = cstatlp->list_node.list; 13815936Smckusick if ( cstatp == TR_NIL ) { 139926Speter continue; 140763Speter } 14115936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 14215936Smckusick casep = casep->list_node.next ) { 143926Speter count++; 144763Speter } 145926Speter } 146926Speter /* 147926Speter */ 148926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 149926Speter if ( ctab == (struct ct *) 0 ) { 150926Speter error("Ran out of memory (case)"); 151926Speter pexit( DIED ); 152926Speter } 153926Speter /* 154926Speter * pick up default label and label for after case statement. 155926Speter */ 15615936Smckusick ctab[0].clabel = (int) getlab(); 157926Speter endlabel = getlab(); 158926Speter /* 159926Speter * generate code for each case 160926Speter * filling in ctab for each. 161926Speter * nr is for error if no case falls out bottom. 162926Speter */ 16315936Smckusick nr = TRUE;; 164926Speter count = 0; 16515936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 16615936Smckusick cstatlp = cstatlp->list_node.next ) { 16715936Smckusick cstatp = cstatlp->list_node.list; 16815936Smckusick if ( cstatp == TR_NIL ) { 169926Speter continue; 170926Speter } 17115936Smckusick line = cstatp->c_stmnt.line_no; 172926Speter label = getlab(); 17315936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 17415936Smckusick casep = casep->list_node.next ) { 17515936Smckusick gconst( casep->list_node.list ); 17615936Smckusick if( exprtype == NLNIL || con.ctype == NIL ) { 177763Speter continue; 178763Speter } 17915936Smckusick if ( incompat( con.ctype , exprtype , TR_NIL ) ) { 180926Speter cerror("Case label type clashed with case selector expression type"); 181926Speter continue; 182763Speter } 183926Speter if ( con.crval < low || con.crval > high ) { 184926Speter error("Case label out of range"); 185926Speter continue; 186763Speter } 187926Speter count++; 188926Speter ctab[ count ].cconst = con.crval; 189926Speter ctab[ count ].cline = line; 19015936Smckusick ctab[ count ].clabel = (int) label; 191763Speter } 192763Speter /* 193926Speter * put out the statement 194763Speter */ 19515936Smckusick (void) putlab( label ); 196926Speter putcnt(); 197926Speter level++; 19815936Smckusick statement( cstatp->c_stmnt.stmnt ); 19915936Smckusick nr = (nr && noreach)?TRUE:FALSE; 20015936Smckusick noreach = FALSE; 201926Speter level--; 202926Speter if (gotos[cbn]) { 203926Speter ungoto(); 204763Speter } 20515936Smckusick putjbr( (long) endlabel ); 206763Speter } 2071278Speter noreach = nr; 208926Speter /* 209926Speter * default action is to call error 210926Speter */ 21115936Smckusick (void) putlab( (char *) ctab[0].clabel ); 21218463Sralph putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) , "_CASERNG" ); 21315936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 21418463Sralph exprnlp -> extra_flags , PCCT_INT ); 21518463Sralph putop( PCC_CALL , PCCT_INT ); 216926Speter putdot( filename , line ); 217926Speter /* 218926Speter * sort the cases 219926Speter */ 220926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 221926Speter /* 222926Speter * check for duplicates 223926Speter */ 2241278Speter dupcases = FALSE; 225926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 226926Speter if ( ctp[0].cconst == ctp[1].cconst ) { 2271278Speter error("Multiply defined label in case, lines %d and %d" , 22815936Smckusick (char *) ctp[0].cline , (char *) ctp[1].cline ); 2291278Speter dupcases = TRUE; 230926Speter } 231926Speter } 2321278Speter if ( dupcases ) { 2331278Speter return; 2341278Speter } 235926Speter /* 236926Speter * choose a switch algorithm and implement it: 237926Speter * direct switch >= 1/3 full and >= 4 cases. 238926Speter * binary switch not direct switch and > 8 cases. 239926Speter * ifthenelse not direct or binary switch. 240926Speter */ 24115936Smckusick (void) putlab( swlabel ); 242926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 243926Speter directsw( ctab , count ); 244926Speter } else if ( count > 8 ) { 245926Speter binarysw( ctab , count ); 246926Speter } else { 247926Speter itesw( ctab , count ); 248926Speter } 24915936Smckusick (void) putlab( endlabel ); 250926Speter if ( goc != gocnt ) { 251926Speter putcnt(); 252926Speter } 253926Speter } 254763Speter 255926Speter /* 256926Speter * direct switch 257926Speter */ 258926Speter directsw( ctab , count ) 259926Speter struct ct *ctab; 260926Speter int count; 261926Speter { 26215936Smckusick int fromlabel = (int) getlab(); 263926Speter long i; 264926Speter long j; 265926Speter 26610378Speter # ifdef vax 26712968Smckusick if (opt('J')) { 26810378Speter /* 26912968Smckusick * We have a table of absolute addresses. 27012968Smckusick * 27112968Smckusick * subl2 to make r0 a 0-origin byte offset. 27210378Speter * cmpl check against upper limit. 27317425Smckusick * jlssu error if out of bounds. 27412968Smckusick * ashl to make r0 a 0-origin long offset, 27510378Speter * jmp and indirect through it. 27610378Speter */ 27715936Smckusick putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME); 27812968Smckusick putprintf(" cmpl $%d,%s", 0, 27915936Smckusick (int) (ctab[count].cconst - ctab[1].cconst), 28015936Smckusick (int) FORCENAME); 28117425Smckusick putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel); 28215936Smckusick putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME); 28312968Smckusick putprintf(" jmp *%s%d(%s)", 0, 28415936Smckusick (int) LABELPREFIX, fromlabel, (int) FORCENAME); 28512968Smckusick } else { 28612968Smckusick /* 28712968Smckusick * We can use the VAX casel instruction with a table 28812968Smckusick * of short relative offsets. 28912968Smckusick */ 29015936Smckusick putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME , 29115936Smckusick (int) ctab[1].cconst , 29215936Smckusick (int) (ctab[ count ].cconst - ctab[1].cconst )); 29312968Smckusick } 29412968Smckusick # endif vax 29512968Smckusick # ifdef mc68000 29612968Smckusick /* 29712968Smckusick * subl to make d0 a 0-origin byte offset. 29812968Smckusick * cmpl check against upper limit. 29912968Smckusick * bhi error if out of bounds. 30012968Smckusick */ 30110378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 30210378Speter putprintf(" cmpl #%d,%s", 0, 30310378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME); 30410378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 30512968Smckusick if (opt('J')) { 30612968Smckusick /* 30712968Smckusick * We have a table of absolute addresses. 30812968Smckusick * 30912968Smckusick * asll to make d0 a 0-origin long offset. 31012968Smckusick * movl pick up a jump-table entry 31112968Smckusick * jmp and indirect through it. 31212968Smckusick */ 31312968Smckusick putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME); 31412968Smckusick putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP); 31512968Smckusick putprintf(" jmp %s@", 0, ADDRTEMP); 31612968Smckusick } else { 31712968Smckusick /* 31812968Smckusick * We have a table of relative addresses. 31912968Smckusick * 32012968Smckusick * addw to make d0 a 0-origin word offset. 32112968Smckusick * movw pick up a jump-table entry 32212968Smckusick * jmp and indirect through it. 32312968Smckusick */ 32412968Smckusick putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 32512968Smckusick putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 32612968Smckusick putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 32712968Smckusick } 32810378Speter # endif mc68000 32915936Smckusick (void) putlab( (char *) fromlabel ); 330926Speter i = 1; 331926Speter j = ctab[1].cconst; 332926Speter while ( i <= count ) { 333926Speter if ( j == ctab[ i ].cconst ) { 33412968Smckusick if (opt('J')) { 33512968Smckusick putprintf( " .long " , 1 ); 33615936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel ); 33712968Smckusick } else { 33812968Smckusick putprintf( " .word " , 1 ); 33915936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel ); 34012968Smckusick putprintf( "-" , 1 ); 34115936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 34212968Smckusick } 343926Speter i++; 344926Speter } else { 34512968Smckusick if (opt('J')) { 34612968Smckusick putprintf( " .long " , 1 ); 34715936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 34812968Smckusick } else { 34912968Smckusick putprintf( " .word " , 1 ); 35015936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 35112968Smckusick putprintf( "-" , 1 ); 35215936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 35312968Smckusick } 354926Speter } 355926Speter j++; 356926Speter } 35710378Speter # ifdef vax 35810378Speter /* 35910378Speter * execution continues here if value not in range of case. 36010378Speter */ 36112968Smckusick if (!opt('J')) 36215936Smckusick putjbr( (long) ctab[0].clabel ); 36310378Speter # endif vax 364926Speter } 365926Speter 366926Speter /* 367926Speter * binary switch 368926Speter * special case out default label and start recursion. 369926Speter */ 370926Speter binarysw( ctab , count ) 371926Speter struct ct *ctab; 372926Speter int count; 373926Speter { 374926Speter 375926Speter bsrecur( ctab[0].clabel , &ctab[0] , count ); 376926Speter } 377926Speter 378926Speter /* 379926Speter * recursive log( count ) search. 380926Speter */ 381926Speter bsrecur( deflabel , ctab , count ) 382926Speter int deflabel; 383926Speter struct ct *ctab; 384926Speter int count; 385926Speter { 386926Speter 387926Speter if ( count <= 0 ) { 38815936Smckusick putjbr((long) deflabel); 389926Speter return; 390926Speter } else if ( count == 1 ) { 39110378Speter # ifdef vax 39215936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst); 39315936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel); 39415936Smckusick putjbr((long) deflabel); 39510378Speter # endif vax 39610378Speter # ifdef mc68000 39715936Smckusick putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME); 39815936Smckusick putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel); 39915936Smckusick putjbr((long) deflabel); 40010378Speter # endif mc68000 401926Speter return; 402926Speter } else { 403926Speter int half = ( count + 1 ) / 2; 40415936Smckusick int gtrlabel = (int) getlab(); 405926Speter 40610378Speter # ifdef vax 40715936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst); 40815936Smckusick putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel); 40915936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 41010378Speter # endif vax 41110378Speter # ifdef mc68000 41215936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME); 41315936Smckusick putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel); 41415936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 41510378Speter # endif mc68000 416926Speter bsrecur( deflabel , &ctab[0] , half - 1 ); 41715936Smckusick (void) putlab((char *) gtrlabel); 418926Speter bsrecur( deflabel , &ctab[ half ] , count - half ); 419926Speter return; 420926Speter } 421926Speter } 422926Speter 423926Speter itesw( ctab , count ) 424926Speter struct ct *ctab; 425926Speter int count; 426926Speter { 427926Speter int i; 428926Speter 429926Speter for ( i = 1 ; i <= count ; i++ ) { 43010378Speter # ifdef vax 43115936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst); 43215936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 43310378Speter # endif vax 43410378Speter # ifdef mc68000 43515936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME); 43615936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 43710378Speter # endif mc68000 438926Speter } 43915936Smckusick putjbr((long) ctab[0].clabel); 440926Speter return; 441926Speter } 442926Speter int 443926Speter casecmp( this , that ) 444926Speter struct ct *this; 445926Speter struct ct *that; 446926Speter { 447926Speter if ( this -> cconst < that -> cconst ) { 448926Speter return -1; 449926Speter } else if ( this -> cconst > that -> cconst ) { 450926Speter return 1; 451926Speter } else { 452926Speter return 0; 453926Speter } 454926Speter } 455763Speter #endif PC 456