|
|
1.1 root 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.2 (Berkeley) 11/12/86";
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: #if defined(vax) || defined(tahoe)
40: # define FORCENAME "r0"
41: #endif vax || tahoe
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:
296: # ifdef tahoe
297: if (opt('J')) {
298: /*
299: * We have a table of absolute addresses.
300: *
301: * subl2 to make r0 a 0-origin byte offset.
302: * cmpl check against upper limit.
303: * jlssu error if out of bounds.
304: * shal to make r0 a 0-origin long offset,
305: * jmp and indirect through it.
306: */
307: putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME);
308: putprintf(" cmpl $%d,%s", 0,
309: (int) (ctab[count].cconst - ctab[1].cconst),
310: (int) FORCENAME);
311: putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel);
312: putprintf(" shal $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME);
313: putprintf(" jmp *%s%d(%s)", 0,
314: (int) LABELPREFIX, fromlabel, (int) FORCENAME);
315: } else {
316: /*
317: * We can use the TAHOE casel instruction with a table
318: * of short relative offsets.
319: */
320: putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME ,
321: (int) ctab[1].cconst ,
322: (int) (ctab[ count ].cconst - ctab[1].cconst ));
323: putprintf(" .align 1", 0);
324: }
325: # endif tahoe
326:
327: # ifdef mc68000
328: /*
329: * subl to make d0 a 0-origin byte offset.
330: * cmpl check against upper limit.
331: * bhi error if out of bounds.
332: */
333: putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME);
334: putprintf(" cmpl #%d,%s", 0,
335: ctab[count].cconst - ctab[1].cconst, FORCENAME);
336: putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel);
337: if (opt('J')) {
338: /*
339: * We have a table of absolute addresses.
340: *
341: * asll to make d0 a 0-origin long offset.
342: * movl pick up a jump-table entry
343: * jmp and indirect through it.
344: */
345: putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME);
346: putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP);
347: putprintf(" jmp %s@", 0, ADDRTEMP);
348: } else {
349: /*
350: * We have a table of relative addresses.
351: *
352: * addw to make d0 a 0-origin word offset.
353: * movw pick up a jump-table entry
354: * jmp and indirect through it.
355: */
356: putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME);
357: putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
358: putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME);
359: }
360: # endif mc68000
361: (void) putlab( (char *) fromlabel );
362: i = 1;
363: j = ctab[1].cconst;
364: while ( i <= count ) {
365: if ( j == ctab[ i ].cconst ) {
366: if (opt('J')) {
367: putprintf( " .long " , 1 );
368: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel );
369: } else {
370: putprintf( " .word " , 1 );
371: putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel );
372: putprintf( "-" , 1 );
373: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
374: }
375: i++;
376: } else {
377: if (opt('J')) {
378: putprintf( " .long " , 1 );
379: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel );
380: } else {
381: putprintf( " .word " , 1 );
382: putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel );
383: putprintf( "-" , 1 );
384: putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
385: }
386: }
387: j++;
388: }
389: # if defined(vax) || defined(tahoe)
390: /*
391: * execution continues here if value not in range of case.
392: */
393: if (!opt('J'))
394: putjbr( (long) ctab[0].clabel );
395: # endif vax || tahoe
396: }
397:
398: /*
399: * binary switch
400: * special case out default label and start recursion.
401: */
402: binarysw( ctab , count )
403: struct ct *ctab;
404: int count;
405: {
406:
407: bsrecur( ctab[0].clabel , &ctab[0] , count );
408: }
409:
410: /*
411: * recursive log( count ) search.
412: */
413: bsrecur( deflabel , ctab , count )
414: int deflabel;
415: struct ct *ctab;
416: int count;
417: {
418:
419: if ( count <= 0 ) {
420: putjbr((long) deflabel);
421: return;
422: } else if ( count == 1 ) {
423: # if defined(vax) || defined(tahoe)
424: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst);
425: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel);
426: putjbr((long) deflabel);
427: # endif vax || tahoe
428: # ifdef mc68000
429: putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME);
430: putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel);
431: putjbr((long) deflabel);
432: # endif mc68000
433: return;
434: } else {
435: int half = ( count + 1 ) / 2;
436: int gtrlabel = (int) getlab();
437:
438: # if defined(vax) || defined(tahoe)
439: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst);
440: putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel);
441: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
442: # endif vax || tahoe
443: # ifdef mc68000
444: putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME);
445: putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel);
446: putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
447: # endif mc68000
448: bsrecur( deflabel , &ctab[0] , half - 1 );
449: (void) putlab((char *) gtrlabel);
450: bsrecur( deflabel , &ctab[ half ] , count - half );
451: return;
452: }
453: }
454:
455: itesw( ctab , count )
456: struct ct *ctab;
457: int count;
458: {
459: int i;
460:
461: for ( i = 1 ; i <= count ; i++ ) {
462: # if defined(vax) || defined(tahoe)
463: putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst);
464: putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
465: # endif vax || tahoe
466: # ifdef mc68000
467: putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME);
468: putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
469: # endif mc68000
470: }
471: putjbr((long) ctab[0].clabel);
472: return;
473: }
474: int
475: casecmp( this , that )
476: struct ct *this;
477: struct ct *that;
478: {
479: if ( this -> cconst < that -> cconst ) {
480: return -1;
481: } else if ( this -> cconst > that -> cconst ) {
482: return 1;
483: } else {
484: return 0;
485: }
486: }
487: #endif PC
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.