1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)pccaseop.c 5.1 (Berkeley) 6/5/85"; 9: #endif not lint 10: 11: 12: #include "whoami.h" 13: #ifdef PC 14: /* 15: * and the rest of the file 16: */ 17: #include "0.h" 18: #include "tree.h" 19: #include "objfmt.h" 20: #include <pcc.h> 21: #include "pc.h" 22: #include "tmps.h" 23: #include "tree_ty.h" 24: 25: /* 26: * structure for a case: 27: * its constant label, line number (for errors), and location label. 28: */ 29: struct ct { 30: long cconst; 31: int cline; 32: int clabel; 33: }; 34: 35: /* 36: * the PCC_FORCE operator puts its operand into a register. 37: * these to keep from thinking of it as r0 all over. 38: */ 39: #ifdef vax 40: # define FORCENAME "r0" 41: #endif vax 42: #ifdef mc68000 43: # define FORCENAME "d0" 44: # define ADDRTEMP "a0" 45: #endif mc68000 46: 47: /* 48: * given a tree for a case statement, generate code for it. 49: * this computes the expression into a register, 50: * puts down the code for each of the cases, 51: * and then decides how to do the case switching. 52: * tcase [0] T_CASE 53: * [1] lineof "case" 54: * [2] expression 55: * [3] list of cased statements: 56: * cstat [0] T_CSTAT 57: * [1] lineof ":" 58: * [2] list of constant labels 59: * [3] statement 60: */ 61: pccaseop( tcase ) 62: WHI_CAS *tcase; 63: { 64: struct nl *exprtype; 65: struct nl *exprnlp; 66: struct nl *rangetype; 67: long low; 68: long high; 69: long exprctype; 70: char *swlabel; 71: char *endlabel; 72: char *label; 73: int count; 74: struct tnode *cstatlp; 75: struct tnode *cstatp; 76: struct tnode *casep; 77: struct ct *ctab; 78: struct ct *ctp; 79: bool nr; 80: long goc; 81: int casecmp(); 82: bool dupcases; 83: 84: goc = gocnt; 85: /* 86: * find out the type of the case expression 87: * even if the expression has errors (exprtype == NIL), continue. 88: */ 89: line = tcase->line_no; 90: codeoff(); 91: exprtype = rvalue( tcase->expr , NLNIL , RREQ ); 92: codeon(); 93: if ( exprtype != NLNIL ) { 94: if ( isnta( exprtype , "bcsi" ) ) { 95: error("Case selectors cannot be %ss" , nameof( exprtype ) ); 96: exprtype = NLNIL; 97: } else { 98: if ( exprtype -> class != RANGE ) { 99: rangetype = exprtype -> type; 100: } else { 101: rangetype = exprtype; 102: } 103: if ( rangetype == NLNIL ) { 104: exprtype = NLNIL; 105: } else { 106: low = rangetype -> range[0]; 107: high = rangetype -> range[1]; 108: } 109: } 110: } 111: if ( exprtype != NLNIL ) { 112: /* 113: * compute and save the case expression. 114: * also, put expression into a register 115: * save its c-type and jump to the code to do the switch. 116: */ 117: exprctype = p2type( exprtype ); 118: exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG ); 119: putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 120: exprnlp -> extra_flags , PCCT_INT ); 121: (void) rvalue( tcase->expr , NLNIL , RREQ ); 122: sconv((int) exprctype, (int) PCCT_INT); 123: putop( PCC_ASSIGN , PCCT_INT ); 124: putop( PCC_FORCE , PCCT_INT ); 125: putdot( filename , line ); 126: swlabel = getlab(); 127: putjbr( (long) swlabel ); 128: } 129: /* 130: * count the number of cases 131: * and allocate table for cases, lines, and labels 132: * default case goes in ctab[0]. 133: */ 134: count = 1; 135: for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 136: cstatlp = cstatlp->list_node.next ) { 137: cstatp = cstatlp->list_node.list; 138: if ( cstatp == TR_NIL ) { 139: continue; 140: } 141: for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 142: casep = casep->list_node.next ) { 143: count++; 144: } 145: } 146: /* 147: */ 148: ctab = (struct ct *) malloc( count * sizeof( struct ct ) ); 149: if ( ctab == (struct ct *) 0 ) { 150: error("Ran out of memory (case)"); 151: pexit( DIED ); 152: } 153: /* 154: * pick up default label and label for after case statement. 155: */ 156: ctab[0].clabel = (int) getlab(); 157: endlabel = getlab(); 158: /* 159: * generate code for each case 160: * filling in ctab for each. 161: * nr is for error if no case falls out bottom. 162: */ 163: nr = TRUE;; 164: count = 0; 165: for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ; 166: cstatlp = cstatlp->list_node.next ) { 167: cstatp = cstatlp->list_node.list; 168: if ( cstatp == TR_NIL ) { 169: continue; 170: } 171: line = cstatp->c_stmnt.line_no; 172: label = getlab(); 173: for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ; 174: casep = casep->list_node.next ) { 175: gconst( casep->list_node.list ); 176: if( exprtype == NLNIL || con.ctype == NIL ) { 177: continue; 178: } 179: if ( incompat( con.ctype , exprtype , TR_NIL ) ) { 180: cerror("Case label type clashed with case selector expression type"); 181: continue; 182: } 183: if ( con.crval < low || con.crval > high ) { 184: error("Case label out of range"); 185: continue; 186: } 187: count++; 188: ctab[ count ].cconst = con.crval; 189: ctab[ count ].cline = line; 190: ctab[ count ].clabel = (int) label; 191: } 192: /* 193: * put out the statement 194: */ 195: (void) putlab( label ); 196: putcnt(); 197: level++; 198: statement( cstatp->c_stmnt.stmnt ); 199: nr = (nr && noreach)?TRUE:FALSE; 200: noreach = FALSE; 201: level--; 202: if (gotos[cbn]) { 203: ungoto(); 204: } 205: putjbr( (long) endlabel ); 206: } 207: noreach = nr; 208: /* 209: * default action is to call error 210: */ 211: (void) putlab( (char *) ctab[0].clabel ); 212: putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) , "_CASERNG" ); 213: putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] , 214: exprnlp -> extra_flags , PCCT_INT ); 215: putop( PCC_CALL , PCCT_INT ); 216: putdot( filename , line ); 217: /* 218: * sort the cases 219: */ 220: qsort( &ctab[1] , count , sizeof (struct ct) , casecmp ); 221: /* 222: * check for duplicates 223: */ 224: dupcases = FALSE; 225: for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) { 226: if ( ctp[0].cconst == ctp[1].cconst ) { 227: error("Multiply defined label in case, lines %d and %d" , 228: (char *) ctp[0].cline , (char *) ctp[1].cline ); 229: dupcases = TRUE; 230: } 231: } 232: if ( dupcases ) { 233: return; 234: } 235: /* 236: * choose a switch algorithm and implement it: 237: * direct switch >= 1/3 full and >= 4 cases. 238: * binary switch not direct switch and > 8 cases. 239: * ifthenelse not direct or binary switch. 240: */ 241: (void) putlab( swlabel ); 242: if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) { 243: directsw( ctab , count ); 244: } else if ( count > 8 ) { 245: binarysw( ctab , count ); 246: } else { 247: itesw( ctab , count ); 248: } 249: (void) putlab( endlabel ); 250: if ( goc != gocnt ) { 251: putcnt(); 252: } 253: } 254: 255: /* 256: * direct switch 257: */ 258: directsw( ctab , count ) 259: struct ct *ctab; 260: int count; 261: { 262: int fromlabel = (int) getlab(); 263: long i; 264: long j; 265: 266: # ifdef vax 267: if (opt('J')) { 268: /* 269: * We have a table of absolute addresses. 270: * 271: * subl2 to make r0 a 0-origin byte offset. 272: * cmpl check against upper limit. 273: * jlssu error if out of bounds. 274: * ashl to make r0 a 0-origin long offset, 275: * jmp and indirect through it. 276: */ 277: putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME); 278: putprintf(" cmpl $%d,%s", 0, 279: (int) (ctab[count].cconst - ctab[1].cconst), 280: (int) FORCENAME); 281: putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel); 282: putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME); 283: putprintf(" jmp *%s%d(%s)", 0, 284: (int) LABELPREFIX, fromlabel, (int) FORCENAME); 285: } else { 286: /* 287: * We can use the VAX casel instruction with a table 288: * of short relative offsets. 289: */ 290: putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME , 291: (int) ctab[1].cconst , 292: (int) (ctab[ count ].cconst - ctab[1].cconst )); 293: } 294: # endif vax 295: # ifdef mc68000 296: /* 297: * subl to make d0 a 0-origin byte offset. 298: * cmpl check against upper limit. 299: * bhi error if out of bounds. 300: */ 301: putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME); 302: putprintf(" cmpl #%d,%s", 0, 303: ctab[count].cconst - ctab[1].cconst, FORCENAME); 304: putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel); 305: if (opt('J')) { 306: /* 307: * We have a table of absolute addresses. 308: * 309: * asll to make d0 a 0-origin long offset. 310: * movl pick up a jump-table entry 311: * jmp and indirect through it. 312: */ 313: putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME); 314: putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP); 315: putprintf(" jmp %s@", 0, ADDRTEMP); 316: } else { 317: /* 318: * We have a table of relative addresses. 319: * 320: * addw to make d0 a 0-origin word offset. 321: * movw pick up a jump-table entry 322: * jmp and indirect through it. 323: */ 324: putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME); 325: putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME); 326: putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME); 327: } 328: # endif mc68000 329: (void) putlab( (char *) fromlabel ); 330: i = 1; 331: j = ctab[1].cconst; 332: while ( i <= count ) { 333: if ( j == ctab[ i ].cconst ) { 334: if (opt('J')) { 335: putprintf( " .long " , 1 ); 336: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel ); 337: } else { 338: putprintf( " .word " , 1 ); 339: putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel ); 340: putprintf( "-" , 1 ); 341: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 342: } 343: i++; 344: } else { 345: if (opt('J')) { 346: putprintf( " .long " , 1 ); 347: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 348: } else { 349: putprintf( " .word " , 1 ); 350: putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel ); 351: putprintf( "-" , 1 ); 352: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel ); 353: } 354: } 355: j++; 356: } 357: # ifdef vax 358: /* 359: * execution continues here if value not in range of case. 360: */ 361: if (!opt('J')) 362: putjbr( (long) ctab[0].clabel ); 363: # endif vax 364: } 365: 366: /* 367: * binary switch 368: * special case out default label and start recursion. 369: */ 370: binarysw( ctab , count ) 371: struct ct *ctab; 372: int count; 373: { 374: 375: bsrecur( ctab[0].clabel , &ctab[0] , count ); 376: } 377: 378: /* 379: * recursive log( count ) search. 380: */ 381: bsrecur( deflabel , ctab , count ) 382: int deflabel; 383: struct ct *ctab; 384: int count; 385: { 386: 387: if ( count <= 0 ) { 388: putjbr((long) deflabel); 389: return; 390: } else if ( count == 1 ) { 391: # ifdef vax 392: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst); 393: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel); 394: putjbr((long) deflabel); 395: # endif vax 396: # ifdef mc68000 397: putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME); 398: putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel); 399: putjbr((long) deflabel); 400: # endif mc68000 401: return; 402: } else { 403: int half = ( count + 1 ) / 2; 404: int gtrlabel = (int) getlab(); 405: 406: # ifdef vax 407: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst); 408: putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel); 409: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 410: # endif vax 411: # ifdef mc68000 412: putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME); 413: putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel); 414: putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel); 415: # endif mc68000 416: bsrecur( deflabel , &ctab[0] , half - 1 ); 417: (void) putlab((char *) gtrlabel); 418: bsrecur( deflabel , &ctab[ half ] , count - half ); 419: return; 420: } 421: } 422: 423: itesw( ctab , count ) 424: struct ct *ctab; 425: int count; 426: { 427: int i; 428: 429: for ( i = 1 ; i <= count ; i++ ) { 430: # ifdef vax 431: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst); 432: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 433: # endif vax 434: # ifdef mc68000 435: putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME); 436: putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel); 437: # endif mc68000 438: } 439: putjbr((long) ctab[0].clabel); 440: return; 441: } 442: int 443: casecmp( this , that ) 444: struct ct *this; 445: struct ct *that; 446: { 447: if ( this -> cconst < that -> cconst ) { 448: return -1; 449: } else if ( this -> cconst > that -> cconst ) { 450: return 1; 451: } else { 452: return 0; 453: } 454: } 455: #endif PC