xref: /csrg-svn/usr.bin/pascal/src/pccaseop.c (revision 10378)
1926Speter /* Copyright (c) 1980 Regents of the University of California */
2763Speter 
3*10378Speter static	char sccsid[] = "@(#)pccaseop.c 1.8.1.2 01/17/83";
4763Speter 
5763Speter #include "whoami.h"
6763Speter #ifdef PC
7763Speter     /*
8763Speter      *	and the rest of the file
9763Speter      */
10763Speter #include "0.h"
11763Speter #include "tree.h"
12763Speter #include "objfmt.h"
13763Speter #include "pcops.h"
14763Speter #include "pc.h"
15926Speter 
16763Speter     /*
17926Speter      *	structure for a case:
18926Speter      *	    its constant label, line number (for errors), and location label.
19926Speter      */
20926Speter struct ct {
21926Speter     long	cconst;
22926Speter     int		cline;
23926Speter     int		clabel;
24926Speter };
25926Speter 
26926Speter     /*
27926Speter      *	the P2FORCE operator puts its operand into a register.
28926Speter      *	these to keep from thinking of it as r0 all over.
29926Speter      */
30*10378Speter #ifdef vax
31*10378Speter #   define	FORCENAME	"r0"
32*10378Speter #endif vax
33*10378Speter #ifdef mc68000
34*10378Speter #   define	FORCENAME	"d0"
35*10378Speter #endif mc68000
36926Speter 
37926Speter     /*
38926Speter      *	given a tree for a case statement, generate code for it.
39926Speter      *	this computes the expression into a register,
40926Speter      *	puts down the code for each of the cases,
41926Speter      *	and then decides how to do the case switching.
42763Speter      *	tcase	[0]	T_CASE
43763Speter      *		[1]	lineof "case"
44763Speter      *		[2]	expression
45926Speter      *		[3]	list of cased statements:
46763Speter      *			cstat	[0]	T_CSTAT
47763Speter      *				[1]	lineof ":"
48926Speter      *				[2]	list of constant labels
49763Speter      *				[3]	statement
50763Speter      */
51763Speter pccaseop( tcase )
52763Speter     int	*tcase;
53926Speter {
54926Speter     struct nl	*exprtype;
553830Speter     struct nl	*exprnlp;
56926Speter     struct nl	*rangetype;
57926Speter     long	low;
58926Speter     long	high;
59926Speter     long	exprctype;
60926Speter     long	swlabel;
61926Speter     long	endlabel;
62926Speter     long	label;
63926Speter     long	count;
64926Speter     long	*cstatlp;
65926Speter     long	*cstatp;
66926Speter     long	*casep;
67926Speter     struct ct	*ctab;
68926Speter     struct ct	*ctp;
69926Speter     long	i;
70926Speter     long	nr;
71926Speter     long	goc;
72926Speter     int		casecmp();
731278Speter     bool	dupcases;
74763Speter 
75926Speter     goc = gocnt;
76926Speter 	/*
77926Speter 	 *  find out the type of the case expression
78926Speter 	 *  even if the expression has errors (exprtype == NIL), continue.
79926Speter 	 */
80926Speter     line = tcase[1];
813641Speter     codeoff();
82926Speter     exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
833641Speter     codeon();
84926Speter     if ( exprtype != NIL ) {
85926Speter 	if ( isnta( exprtype , "bcsi" ) ) {
86926Speter 	    error("Case selectors cannot be %ss" , nameof( exprtype ) );
87926Speter 	    exprtype = NIL;
88926Speter 	} else {
89926Speter 	    if ( exprtype -> class != RANGE ) {
90926Speter 		rangetype = exprtype -> type;
91926Speter 	    } else {
92926Speter 		rangetype = exprtype;
93926Speter 	    }
94926Speter 	    if ( rangetype == NIL ) {
95763Speter 		exprtype = NIL;
96763Speter 	    } else {
97926Speter 		low = rangetype -> range[0];
98926Speter 		high = rangetype -> range[1];
99763Speter 	    }
100763Speter 	}
101926Speter     }
102926Speter     if ( exprtype != NIL ) {
103763Speter 	    /*
1043641Speter 	     *	compute and save the case expression.
1053641Speter 	     *	also, put expression into a register
106926Speter 	     *	save its c-type and jump to the code to do the switch.
107763Speter 	     */
1083641Speter 	exprctype = p2type( exprtype );
1093830Speter 	exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG );
1103830Speter 	putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
1113830Speter 			exprnlp -> extra_flags , P2INT );
1123641Speter 	(void) rvalue( (int *) tcase[2] , NIL , RREQ );
1133641Speter 	putop( P2ASSIGN , P2INT );
114926Speter 	putop( P2FORCE , P2INT );
115926Speter 	putdot( filename , line );
116926Speter 	swlabel = getlab();
117926Speter 	putjbr( swlabel );
118926Speter     }
119926Speter 	/*
120926Speter 	 *  count the number of cases
121926Speter 	 *  and allocate table for cases, lines, and labels
122926Speter 	 *  default case goes in ctab[0].
123926Speter 	 */
124926Speter     count = 1;
125926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
126926Speter 	cstatp = cstatlp[1];
127926Speter 	if ( cstatp == NIL ) {
128926Speter 	    continue;
129763Speter 	}
130926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
131926Speter 	    count++;
132763Speter 	}
133926Speter     }
134926Speter 	/*
135926Speter 	 */
136926Speter     ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
137926Speter     if ( ctab == (struct ct *) 0 ) {
138926Speter 	error("Ran out of memory (case)");
139926Speter 	pexit( DIED );
140926Speter     }
141926Speter 	/*
142926Speter 	 *  pick up default label and label for after case statement.
143926Speter 	 */
144926Speter     ctab[0].clabel = getlab();
145926Speter     endlabel = getlab();
146926Speter 	/*
147926Speter 	 *  generate code for each case
148926Speter 	 *  filling in ctab for each.
149926Speter 	 *  nr is for error if no case falls out bottom.
150926Speter 	 */
151926Speter     nr = 1;
152926Speter     count = 0;
153926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
154926Speter 	cstatp = cstatlp[1];
155926Speter 	if ( cstatp == NIL ) {
156926Speter 	    continue;
157926Speter 	}
158926Speter 	line = cstatp[1];
159926Speter 	label = getlab();
160926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
161926Speter 	    gconst( casep[1] );
162926Speter 	    if( exprtype == NIL || con.ctype == NIL ) {
163763Speter 		continue;
164763Speter 	    }
165926Speter 	    if ( incompat( con.ctype , exprtype , NIL ) ) {
166926Speter 		cerror("Case label type clashed with case selector expression type");
167926Speter 		continue;
168763Speter 	    }
169926Speter 	    if ( con.crval < low || con.crval > high ) {
170926Speter 		error("Case label out of range");
171926Speter 		continue;
172763Speter 	    }
173926Speter 	    count++;
174926Speter 	    ctab[ count ].cconst = con.crval;
175926Speter 	    ctab[ count ].cline = line;
176926Speter 	    ctab[ count ].clabel = label;
177763Speter 	}
178763Speter 	    /*
179926Speter 	     *	put out the statement
180763Speter 	     */
181926Speter 	putlab( label );
182926Speter 	putcnt();
183926Speter 	level++;
184926Speter 	statement( cstatp[3] );
1853139Smckusic 	nr = (nr && noreach);
186926Speter 	noreach = 0;
187926Speter 	level--;
188926Speter 	if (gotos[cbn]) {
189926Speter 		ungoto();
190763Speter 	}
191926Speter 	putjbr( endlabel );
192763Speter     }
1931278Speter     noreach = nr;
194926Speter 	/*
195926Speter 	 *	default action is to call error
196926Speter 	 */
197926Speter     putlab( ctab[0].clabel );
1985663Smckusic     putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" );
1993830Speter     putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
2003830Speter 		    exprnlp -> extra_flags , P2INT );
201926Speter     putop( P2CALL , P2INT );
202926Speter     putdot( filename , line );
203926Speter 	/*
204926Speter 	 *  sort the cases
205926Speter 	 */
206926Speter     qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
207926Speter 	/*
208926Speter 	 *  check for duplicates
209926Speter 	 */
2101278Speter     dupcases = FALSE;
211926Speter     for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
212926Speter 	if ( ctp[0].cconst == ctp[1].cconst ) {
2131278Speter 	    error("Multiply defined label in case, lines %d and %d" ,
214926Speter 		    ctp[0].cline , ctp[1].cline );
2151278Speter 	    dupcases = TRUE;
216926Speter 	}
217926Speter     }
2181278Speter     if ( dupcases ) {
2191278Speter 	return;
2201278Speter     }
221926Speter 	/*
222926Speter 	 *  choose a switch algorithm and implement it:
223926Speter 	 *	direct switch	>= 1/3 full and >= 4 cases.
224926Speter 	 *	binary switch	not direct switch and > 8 cases.
225926Speter 	 *	ifthenelse	not direct or binary switch.
226926Speter 	 */
227926Speter     putlab( swlabel );
228926Speter     if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
229926Speter 	directsw( ctab , count );
230926Speter     } else if ( count > 8 ) {
231926Speter 	binarysw( ctab , count );
232926Speter     } else {
233926Speter 	itesw( ctab , count );
234926Speter     }
235926Speter     putlab( endlabel );
236926Speter     if ( goc != gocnt ) {
237926Speter 	    putcnt();
238926Speter     }
239926Speter }
240763Speter 
241926Speter     /*
242926Speter      *	direct switch
243926Speter      */
244926Speter directsw( ctab , count )
245926Speter     struct ct	*ctab;
246926Speter     int		count;
247926Speter {
248926Speter     int		fromlabel = getlab();
249926Speter     long	i;
250926Speter     long	j;
251926Speter 
252*10378Speter #   ifdef vax
253*10378Speter 	putprintf("	casel	%s,$%d,$%d" , 0 , FORCENAME ,
254*10378Speter 		ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
255*10378Speter #   endif vax
256*10378Speter #   ifdef mc68000
257*10378Speter 	    /*
258*10378Speter 	     *	subl	to make d0 a 0-origin byte offset.
259*10378Speter 	     *	cmpl	check against upper limit.
260*10378Speter 	     *	bhi	error if out of bounds.
261*10378Speter 	     *	addw	to make d0 a 0-origin word offset.
262*10378Speter 	     *	movw	pick up a jump-table entry
263*10378Speter 	     *	jmp	and indirect through it.
264*10378Speter 	     */
265*10378Speter 	putprintf("	subl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
266*10378Speter 	putprintf("	cmpl	#%d,%s", 0,
267*10378Speter 		ctab[count].cconst - ctab[1].cconst, FORCENAME);
268*10378Speter 	putprintf("	bhi	%s%d", 0, LABELPREFIX, ctab[0].clabel);
269*10378Speter 	putprintf("	addw	%s,%s", 0, FORCENAME, FORCENAME);
270*10378Speter 	putprintf("	movw	pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
271*10378Speter 	putprintf("	jmp	pc@(2,%s:w)", 0, FORCENAME);
272*10378Speter #   endif mc68000
273926Speter     putlab( fromlabel );
274926Speter     i = 1;
275926Speter     j = ctab[1].cconst;
276926Speter     while ( i <= count ) {
277926Speter 	if ( j == ctab[ i ].cconst ) {
278926Speter 	    putprintf( "	.word	" , 1 );
279926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
280926Speter 	    putprintf( "-" , 1 );
281926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
282926Speter 	    i++;
283926Speter 	} else {
284926Speter 	    putprintf( "	.word	" , 1 );
285926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
286926Speter 	    putprintf( "-" , 1 );
287926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
288926Speter 	}
289926Speter 	j++;
290926Speter     }
291*10378Speter #   ifdef vax
292*10378Speter 	    /*
293*10378Speter 	     *	execution continues here if value not in range of case.
294*10378Speter 	     */
295*10378Speter 	putjbr( ctab[0].clabel );
296*10378Speter #   endif vax
297926Speter }
298926Speter 
299926Speter     /*
300926Speter      *	binary switch
301926Speter      *	special case out default label and start recursion.
302926Speter      */
303926Speter binarysw( ctab , count )
304926Speter     struct ct	*ctab;
305926Speter     int		count;
306926Speter {
307926Speter 
308926Speter     bsrecur( ctab[0].clabel , &ctab[0] , count );
309926Speter }
310926Speter 
311926Speter     /*
312926Speter      *	recursive log( count ) search.
313926Speter      */
314926Speter bsrecur( deflabel , ctab , count )
315926Speter     int		deflabel;
316926Speter     struct ct	*ctab;
317926Speter     int		count;
318926Speter {
319926Speter 
320926Speter     if ( count <= 0 ) {
321*10378Speter 	putjbr(deflabel);
322926Speter 	return;
323926Speter     } else if ( count == 1 ) {
324*10378Speter #	ifdef vax
325*10378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[1].cconst);
326*10378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[1].clabel);
327*10378Speter 	    putjbr(deflabel);
328*10378Speter #	endif vax
329*10378Speter #	ifdef mc68000
330*10378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
331*10378Speter 	    putprintf("	jeq	L%d", 0, LABELPREFIX, ctab[1].clabel);
332*10378Speter 	    putjbr(deflabel);
333*10378Speter #	endif mc68000
334926Speter 	return;
335926Speter     } else {
336926Speter 	int	half = ( count + 1 ) / 2;
337926Speter 	int	gtrlabel = getlab();
338926Speter 
339*10378Speter #	ifdef vax
340*10378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[half].cconst);
341*10378Speter 	    putprintf("	jgtr	%s%d", 0, LABELPREFIX, gtrlabel);
342*10378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[half].clabel);
343*10378Speter #	endif vax
344*10378Speter #	ifdef mc68000
345*10378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[half].cconst, FORCENAME);
346*10378Speter 	    putprintf("	jgt	%s%d", 0, LABELPREFIX, gtrlabel);
347*10378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[half].clabel);
348*10378Speter #	endif mc68000
349926Speter 	bsrecur( deflabel , &ctab[0] , half - 1 );
350*10378Speter 	putlab(gtrlabel);
351926Speter 	bsrecur( deflabel , &ctab[ half ] , count - half );
352926Speter 	return;
353926Speter     }
354926Speter }
355926Speter 
356926Speter itesw( ctab , count )
357926Speter     struct ct	*ctab;
358926Speter     int		count;
359926Speter {
360926Speter     int	i;
361926Speter 
362926Speter     for ( i = 1 ; i <= count ; i++ ) {
363*10378Speter #	ifdef vax
364*10378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[i].cconst);
365*10378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[i].clabel);
366*10378Speter #	endif vax
367*10378Speter #	ifdef mc68000
368*10378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[i].cconst, FORCENAME);
369*10378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[i].clabel);
370*10378Speter #	endif mc68000
371926Speter     }
372*10378Speter     putjbr(ctab[0].clabel);
373926Speter     return;
374926Speter }
375926Speter int
376926Speter casecmp( this , that )
377926Speter     struct ct 	*this;
378926Speter     struct ct 	*that;
379926Speter {
380926Speter     if ( this -> cconst < that -> cconst ) {
381926Speter 	return -1;
382926Speter     } else if ( this -> cconst > that -> cconst ) {
383926Speter 	return 1;
384926Speter     } else {
385926Speter 	return 0;
386926Speter     }
387926Speter }
388763Speter #endif PC
389