xref: /csrg-svn/usr.bin/pascal/src/pccaseop.c (revision 12968)
1926Speter /* Copyright (c) 1980 Regents of the University of California */
2763Speter 
3*12968Smckusick static char sccsid[] = "@(#)pccaseop.c 1.12 06/10/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"
1511329Speter #include "tmps.h"
16926Speter 
17763Speter     /*
18926Speter      *	structure for a case:
19926Speter      *	    its constant label, line number (for errors), and location label.
20926Speter      */
21926Speter struct ct {
22926Speter     long	cconst;
23926Speter     int		cline;
24926Speter     int		clabel;
25926Speter };
26926Speter 
27926Speter     /*
28926Speter      *	the P2FORCE operator puts its operand into a register.
29926Speter      *	these to keep from thinking of it as r0 all over.
30926Speter      */
3110378Speter #ifdef vax
3210378Speter #   define	FORCENAME	"r0"
3310378Speter #endif vax
3410378Speter #ifdef mc68000
3510378Speter #   define	FORCENAME	"d0"
36*12968Smckusick #   define	ADDRTEMP	"a0"
3710378Speter #endif mc68000
38926Speter 
39926Speter     /*
40926Speter      *	given a tree for a case statement, generate code for it.
41926Speter      *	this computes the expression into a register,
42926Speter      *	puts down the code for each of the cases,
43926Speter      *	and then decides how to do the case switching.
44763Speter      *	tcase	[0]	T_CASE
45763Speter      *		[1]	lineof "case"
46763Speter      *		[2]	expression
47926Speter      *		[3]	list of cased statements:
48763Speter      *			cstat	[0]	T_CSTAT
49763Speter      *				[1]	lineof ":"
50926Speter      *				[2]	list of constant labels
51763Speter      *				[3]	statement
52763Speter      */
53763Speter pccaseop( tcase )
54763Speter     int	*tcase;
55926Speter {
56926Speter     struct nl	*exprtype;
573830Speter     struct nl	*exprnlp;
58926Speter     struct nl	*rangetype;
59926Speter     long	low;
60926Speter     long	high;
61926Speter     long	exprctype;
62926Speter     long	swlabel;
63926Speter     long	endlabel;
64926Speter     long	label;
65926Speter     long	count;
66926Speter     long	*cstatlp;
67926Speter     long	*cstatp;
68926Speter     long	*casep;
69926Speter     struct ct	*ctab;
70926Speter     struct ct	*ctp;
71926Speter     long	i;
72926Speter     long	nr;
73926Speter     long	goc;
74926Speter     int		casecmp();
751278Speter     bool	dupcases;
76763Speter 
77926Speter     goc = gocnt;
78926Speter 	/*
79926Speter 	 *  find out the type of the case expression
80926Speter 	 *  even if the expression has errors (exprtype == NIL), continue.
81926Speter 	 */
82926Speter     line = tcase[1];
833641Speter     codeoff();
84926Speter     exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
853641Speter     codeon();
86926Speter     if ( exprtype != NIL ) {
87926Speter 	if ( isnta( exprtype , "bcsi" ) ) {
88926Speter 	    error("Case selectors cannot be %ss" , nameof( exprtype ) );
89926Speter 	    exprtype = NIL;
90926Speter 	} else {
91926Speter 	    if ( exprtype -> class != RANGE ) {
92926Speter 		rangetype = exprtype -> type;
93926Speter 	    } else {
94926Speter 		rangetype = exprtype;
95926Speter 	    }
96926Speter 	    if ( rangetype == NIL ) {
97763Speter 		exprtype = NIL;
98763Speter 	    } else {
99926Speter 		low = rangetype -> range[0];
100926Speter 		high = rangetype -> range[1];
101763Speter 	    }
102763Speter 	}
103926Speter     }
104926Speter     if ( exprtype != NIL ) {
105763Speter 	    /*
1063641Speter 	     *	compute and save the case expression.
1073641Speter 	     *	also, put expression into a register
108926Speter 	     *	save its c-type and jump to the code to do the switch.
109763Speter 	     */
1103641Speter 	exprctype = p2type( exprtype );
1113830Speter 	exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG );
1123830Speter 	putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
1133830Speter 			exprnlp -> extra_flags , P2INT );
1143641Speter 	(void) rvalue( (int *) tcase[2] , NIL , RREQ );
11510379Speter 	sconv(exprctype, P2INT);
1163641Speter 	putop( P2ASSIGN , P2INT );
117926Speter 	putop( P2FORCE , P2INT );
118926Speter 	putdot( filename , line );
119926Speter 	swlabel = getlab();
120926Speter 	putjbr( swlabel );
121926Speter     }
122926Speter 	/*
123926Speter 	 *  count the number of cases
124926Speter 	 *  and allocate table for cases, lines, and labels
125926Speter 	 *  default case goes in ctab[0].
126926Speter 	 */
127926Speter     count = 1;
128926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
129926Speter 	cstatp = cstatlp[1];
130926Speter 	if ( cstatp == NIL ) {
131926Speter 	    continue;
132763Speter 	}
133926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
134926Speter 	    count++;
135763Speter 	}
136926Speter     }
137926Speter 	/*
138926Speter 	 */
139926Speter     ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
140926Speter     if ( ctab == (struct ct *) 0 ) {
141926Speter 	error("Ran out of memory (case)");
142926Speter 	pexit( DIED );
143926Speter     }
144926Speter 	/*
145926Speter 	 *  pick up default label and label for after case statement.
146926Speter 	 */
147926Speter     ctab[0].clabel = getlab();
148926Speter     endlabel = getlab();
149926Speter 	/*
150926Speter 	 *  generate code for each case
151926Speter 	 *  filling in ctab for each.
152926Speter 	 *  nr is for error if no case falls out bottom.
153926Speter 	 */
154926Speter     nr = 1;
155926Speter     count = 0;
156926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
157926Speter 	cstatp = cstatlp[1];
158926Speter 	if ( cstatp == NIL ) {
159926Speter 	    continue;
160926Speter 	}
161926Speter 	line = cstatp[1];
162926Speter 	label = getlab();
163926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
164926Speter 	    gconst( casep[1] );
165926Speter 	    if( exprtype == NIL || con.ctype == NIL ) {
166763Speter 		continue;
167763Speter 	    }
168926Speter 	    if ( incompat( con.ctype , exprtype , NIL ) ) {
169926Speter 		cerror("Case label type clashed with case selector expression type");
170926Speter 		continue;
171763Speter 	    }
172926Speter 	    if ( con.crval < low || con.crval > high ) {
173926Speter 		error("Case label out of range");
174926Speter 		continue;
175763Speter 	    }
176926Speter 	    count++;
177926Speter 	    ctab[ count ].cconst = con.crval;
178926Speter 	    ctab[ count ].cline = line;
179926Speter 	    ctab[ count ].clabel = label;
180763Speter 	}
181763Speter 	    /*
182926Speter 	     *	put out the statement
183763Speter 	     */
184926Speter 	putlab( label );
185926Speter 	putcnt();
186926Speter 	level++;
187926Speter 	statement( cstatp[3] );
1883139Smckusic 	nr = (nr && noreach);
189926Speter 	noreach = 0;
190926Speter 	level--;
191926Speter 	if (gotos[cbn]) {
192926Speter 		ungoto();
193763Speter 	}
194926Speter 	putjbr( endlabel );
195763Speter     }
1961278Speter     noreach = nr;
197926Speter 	/*
198926Speter 	 *	default action is to call error
199926Speter 	 */
200926Speter     putlab( ctab[0].clabel );
2015663Smckusic     putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" );
2023830Speter     putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
2033830Speter 		    exprnlp -> extra_flags , P2INT );
204926Speter     putop( P2CALL , P2INT );
205926Speter     putdot( filename , line );
206926Speter 	/*
207926Speter 	 *  sort the cases
208926Speter 	 */
209926Speter     qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
210926Speter 	/*
211926Speter 	 *  check for duplicates
212926Speter 	 */
2131278Speter     dupcases = FALSE;
214926Speter     for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
215926Speter 	if ( ctp[0].cconst == ctp[1].cconst ) {
2161278Speter 	    error("Multiply defined label in case, lines %d and %d" ,
217926Speter 		    ctp[0].cline , ctp[1].cline );
2181278Speter 	    dupcases = TRUE;
219926Speter 	}
220926Speter     }
2211278Speter     if ( dupcases ) {
2221278Speter 	return;
2231278Speter     }
224926Speter 	/*
225926Speter 	 *  choose a switch algorithm and implement it:
226926Speter 	 *	direct switch	>= 1/3 full and >= 4 cases.
227926Speter 	 *	binary switch	not direct switch and > 8 cases.
228926Speter 	 *	ifthenelse	not direct or binary switch.
229926Speter 	 */
230926Speter     putlab( swlabel );
231926Speter     if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
232926Speter 	directsw( ctab , count );
233926Speter     } else if ( count > 8 ) {
234926Speter 	binarysw( ctab , count );
235926Speter     } else {
236926Speter 	itesw( ctab , count );
237926Speter     }
238926Speter     putlab( endlabel );
239926Speter     if ( goc != gocnt ) {
240926Speter 	    putcnt();
241926Speter     }
242926Speter }
243763Speter 
244926Speter     /*
245926Speter      *	direct switch
246926Speter      */
247926Speter directsw( ctab , count )
248926Speter     struct ct	*ctab;
249926Speter     int		count;
250926Speter {
251926Speter     int		fromlabel = getlab();
252926Speter     long	i;
253926Speter     long	j;
254926Speter 
25510378Speter #   ifdef vax
256*12968Smckusick 	if (opt('J')) {
25710378Speter 	    /*
258*12968Smckusick 	     *	We have a table of absolute addresses.
259*12968Smckusick 	     *
260*12968Smckusick 	     *	subl2	to make r0 a 0-origin byte offset.
26110378Speter 	     *	cmpl	check against upper limit.
262*12968Smckusick 	     *	blssu	error if out of bounds.
263*12968Smckusick 	     *	ashl	to make r0 a 0-origin long offset,
26410378Speter 	     *	jmp	and indirect through it.
26510378Speter 	     */
266*12968Smckusick 	    putprintf("	subl2	$%d,%s", 0, ctab[1].cconst, FORCENAME);
267*12968Smckusick 	    putprintf("	cmpl	$%d,%s", 0,
268*12968Smckusick 		    ctab[count].cconst - ctab[1].cconst, FORCENAME);
269*12968Smckusick 	    putprintf("	blssu	%s%d", 0, LABELPREFIX, ctab[0].clabel);
270*12968Smckusick 	    putprintf("	ashl	$2,%s,%s", 0, FORCENAME, FORCENAME);
271*12968Smckusick 	    putprintf("	jmp	*%s%d(%s)", 0,
272*12968Smckusick 		    LABELPREFIX, fromlabel, FORCENAME);
273*12968Smckusick 	} else {
274*12968Smckusick 	    /*
275*12968Smckusick 	     *	We can use the VAX casel instruction with a table
276*12968Smckusick 	     *	of short relative offsets.
277*12968Smckusick 	     */
278*12968Smckusick 	    putprintf("	casel	%s,$%d,$%d" , 0 , FORCENAME ,
279*12968Smckusick 		    ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
280*12968Smckusick 	}
281*12968Smckusick #   endif vax
282*12968Smckusick #   ifdef mc68000
283*12968Smckusick 	/*
284*12968Smckusick 	 *	subl	to make d0 a 0-origin byte offset.
285*12968Smckusick 	 *	cmpl	check against upper limit.
286*12968Smckusick 	 *	bhi	error if out of bounds.
287*12968Smckusick 	 */
28810378Speter 	putprintf("	subl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
28910378Speter 	putprintf("	cmpl	#%d,%s", 0,
29010378Speter 		ctab[count].cconst - ctab[1].cconst, FORCENAME);
29110378Speter 	putprintf("	bhi	%s%d", 0, LABELPREFIX, ctab[0].clabel);
292*12968Smckusick 	if (opt('J')) {
293*12968Smckusick 	    /*
294*12968Smckusick 	     *	We have a table of absolute addresses.
295*12968Smckusick 	     *
296*12968Smckusick 	     *	asll	to make d0 a 0-origin long offset.
297*12968Smckusick 	     *	movl	pick up a jump-table entry
298*12968Smckusick 	     *	jmp	and indirect through it.
299*12968Smckusick 	     */
300*12968Smckusick 	    putprintf("	asll	#2,%s", 0, FORCENAME, FORCENAME);
301*12968Smckusick 	    putprintf("	movl	pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP);
302*12968Smckusick 	    putprintf("	jmp	%s@", 0, ADDRTEMP);
303*12968Smckusick 	} else {
304*12968Smckusick 	    /*
305*12968Smckusick 	     *	We have a table of relative addresses.
306*12968Smckusick 	     *
307*12968Smckusick 	     *	addw	to make d0 a 0-origin word offset.
308*12968Smckusick 	     *	movw	pick up a jump-table entry
309*12968Smckusick 	     *	jmp	and indirect through it.
310*12968Smckusick 	     */
311*12968Smckusick 	    putprintf("	addw	%s,%s", 0, FORCENAME, FORCENAME);
312*12968Smckusick 	    putprintf("	movw	pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
313*12968Smckusick 	    putprintf("	jmp	pc@(2,%s:w)", 0, FORCENAME);
314*12968Smckusick 	}
31510378Speter #   endif mc68000
316926Speter     putlab( fromlabel );
317926Speter     i = 1;
318926Speter     j = ctab[1].cconst;
319926Speter     while ( i <= count ) {
320926Speter 	if ( j == ctab[ i ].cconst ) {
321*12968Smckusick 	    if (opt('J')) {
322*12968Smckusick 		putprintf( "	.long	" , 1 );
323*12968Smckusick 		putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ i ].clabel );
324*12968Smckusick 	    } else {
325*12968Smckusick 		putprintf( "	.word	" , 1 );
326*12968Smckusick 		putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
327*12968Smckusick 		putprintf( "-" , 1 );
328*12968Smckusick 		putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
329*12968Smckusick 	    }
330926Speter 	    i++;
331926Speter 	} else {
332*12968Smckusick 	    if (opt('J')) {
333*12968Smckusick 		putprintf( "	.long	" , 1 );
334*12968Smckusick 		putprintf( PREFIXFORMAT , 0 , LABELPREFIX , ctab[ 0 ].clabel );
335*12968Smckusick 	    } else {
336*12968Smckusick 		putprintf( "	.word	" , 1 );
337*12968Smckusick 		putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
338*12968Smckusick 		putprintf( "-" , 1 );
339*12968Smckusick 		putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
340*12968Smckusick 	    }
341926Speter 	}
342926Speter 	j++;
343926Speter     }
34410378Speter #   ifdef vax
34510378Speter 	    /*
34610378Speter 	     *	execution continues here if value not in range of case.
34710378Speter 	     */
348*12968Smckusick 	if (!opt('J'))
349*12968Smckusick 	    putjbr( ctab[0].clabel );
35010378Speter #   endif vax
351926Speter }
352926Speter 
353926Speter     /*
354926Speter      *	binary switch
355926Speter      *	special case out default label and start recursion.
356926Speter      */
357926Speter binarysw( ctab , count )
358926Speter     struct ct	*ctab;
359926Speter     int		count;
360926Speter {
361926Speter 
362926Speter     bsrecur( ctab[0].clabel , &ctab[0] , count );
363926Speter }
364926Speter 
365926Speter     /*
366926Speter      *	recursive log( count ) search.
367926Speter      */
368926Speter bsrecur( deflabel , ctab , count )
369926Speter     int		deflabel;
370926Speter     struct ct	*ctab;
371926Speter     int		count;
372926Speter {
373926Speter 
374926Speter     if ( count <= 0 ) {
37510378Speter 	putjbr(deflabel);
376926Speter 	return;
377926Speter     } else if ( count == 1 ) {
37810378Speter #	ifdef vax
37910378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[1].cconst);
38010378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[1].clabel);
38110378Speter 	    putjbr(deflabel);
38210378Speter #	endif vax
38310378Speter #	ifdef mc68000
38410378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
38510378Speter 	    putprintf("	jeq	L%d", 0, LABELPREFIX, ctab[1].clabel);
38610378Speter 	    putjbr(deflabel);
38710378Speter #	endif mc68000
388926Speter 	return;
389926Speter     } else {
390926Speter 	int	half = ( count + 1 ) / 2;
391926Speter 	int	gtrlabel = getlab();
392926Speter 
39310378Speter #	ifdef vax
39410378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[half].cconst);
39510378Speter 	    putprintf("	jgtr	%s%d", 0, LABELPREFIX, gtrlabel);
39610378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[half].clabel);
39710378Speter #	endif vax
39810378Speter #	ifdef mc68000
39910378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[half].cconst, FORCENAME);
40010378Speter 	    putprintf("	jgt	%s%d", 0, LABELPREFIX, gtrlabel);
40110378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[half].clabel);
40210378Speter #	endif mc68000
403926Speter 	bsrecur( deflabel , &ctab[0] , half - 1 );
40410378Speter 	putlab(gtrlabel);
405926Speter 	bsrecur( deflabel , &ctab[ half ] , count - half );
406926Speter 	return;
407926Speter     }
408926Speter }
409926Speter 
410926Speter itesw( ctab , count )
411926Speter     struct ct	*ctab;
412926Speter     int		count;
413926Speter {
414926Speter     int	i;
415926Speter 
416926Speter     for ( i = 1 ; i <= count ; i++ ) {
41710378Speter #	ifdef vax
41810378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[i].cconst);
41910378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[i].clabel);
42010378Speter #	endif vax
42110378Speter #	ifdef mc68000
42210378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[i].cconst, FORCENAME);
42310378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[i].clabel);
42410378Speter #	endif mc68000
425926Speter     }
42610378Speter     putjbr(ctab[0].clabel);
427926Speter     return;
428926Speter }
429926Speter int
430926Speter casecmp( this , that )
431926Speter     struct ct 	*this;
432926Speter     struct ct 	*that;
433926Speter {
434926Speter     if ( this -> cconst < that -> cconst ) {
435926Speter 	return -1;
436926Speter     } else if ( this -> cconst > that -> cconst ) {
437926Speter 	return 1;
438926Speter     } else {
439926Speter 	return 0;
440926Speter     }
441926Speter }
442763Speter #endif PC
443