xref: /csrg-svn/usr.bin/pascal/src/pccaseop.c (revision 11329)
1926Speter /* Copyright (c) 1980 Regents of the University of California */
2763Speter 
3*11329Speter static	char sccsid[] = "@(#)pccaseop.c 1.11 02/28/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"
15*11329Speter #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"
3610378Speter #endif mc68000
37926Speter 
38926Speter     /*
39926Speter      *	given a tree for a case statement, generate code for it.
40926Speter      *	this computes the expression into a register,
41926Speter      *	puts down the code for each of the cases,
42926Speter      *	and then decides how to do the case switching.
43763Speter      *	tcase	[0]	T_CASE
44763Speter      *		[1]	lineof "case"
45763Speter      *		[2]	expression
46926Speter      *		[3]	list of cased statements:
47763Speter      *			cstat	[0]	T_CSTAT
48763Speter      *				[1]	lineof ":"
49926Speter      *				[2]	list of constant labels
50763Speter      *				[3]	statement
51763Speter      */
52763Speter pccaseop( tcase )
53763Speter     int	*tcase;
54926Speter {
55926Speter     struct nl	*exprtype;
563830Speter     struct nl	*exprnlp;
57926Speter     struct nl	*rangetype;
58926Speter     long	low;
59926Speter     long	high;
60926Speter     long	exprctype;
61926Speter     long	swlabel;
62926Speter     long	endlabel;
63926Speter     long	label;
64926Speter     long	count;
65926Speter     long	*cstatlp;
66926Speter     long	*cstatp;
67926Speter     long	*casep;
68926Speter     struct ct	*ctab;
69926Speter     struct ct	*ctp;
70926Speter     long	i;
71926Speter     long	nr;
72926Speter     long	goc;
73926Speter     int		casecmp();
741278Speter     bool	dupcases;
75763Speter 
76926Speter     goc = gocnt;
77926Speter 	/*
78926Speter 	 *  find out the type of the case expression
79926Speter 	 *  even if the expression has errors (exprtype == NIL), continue.
80926Speter 	 */
81926Speter     line = tcase[1];
823641Speter     codeoff();
83926Speter     exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
843641Speter     codeon();
85926Speter     if ( exprtype != NIL ) {
86926Speter 	if ( isnta( exprtype , "bcsi" ) ) {
87926Speter 	    error("Case selectors cannot be %ss" , nameof( exprtype ) );
88926Speter 	    exprtype = NIL;
89926Speter 	} else {
90926Speter 	    if ( exprtype -> class != RANGE ) {
91926Speter 		rangetype = exprtype -> type;
92926Speter 	    } else {
93926Speter 		rangetype = exprtype;
94926Speter 	    }
95926Speter 	    if ( rangetype == NIL ) {
96763Speter 		exprtype = NIL;
97763Speter 	    } else {
98926Speter 		low = rangetype -> range[0];
99926Speter 		high = rangetype -> range[1];
100763Speter 	    }
101763Speter 	}
102926Speter     }
103926Speter     if ( exprtype != NIL ) {
104763Speter 	    /*
1053641Speter 	     *	compute and save the case expression.
1063641Speter 	     *	also, put expression into a register
107926Speter 	     *	save its c-type and jump to the code to do the switch.
108763Speter 	     */
1093641Speter 	exprctype = p2type( exprtype );
1103830Speter 	exprnlp = tmpalloc( sizeof (long) , nl + T4INT , NOREG );
1113830Speter 	putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
1123830Speter 			exprnlp -> extra_flags , P2INT );
1133641Speter 	(void) rvalue( (int *) tcase[2] , NIL , RREQ );
11410379Speter 	sconv(exprctype, P2INT);
1153641Speter 	putop( P2ASSIGN , P2INT );
116926Speter 	putop( P2FORCE , P2INT );
117926Speter 	putdot( filename , line );
118926Speter 	swlabel = getlab();
119926Speter 	putjbr( swlabel );
120926Speter     }
121926Speter 	/*
122926Speter 	 *  count the number of cases
123926Speter 	 *  and allocate table for cases, lines, and labels
124926Speter 	 *  default case goes in ctab[0].
125926Speter 	 */
126926Speter     count = 1;
127926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
128926Speter 	cstatp = cstatlp[1];
129926Speter 	if ( cstatp == NIL ) {
130926Speter 	    continue;
131763Speter 	}
132926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
133926Speter 	    count++;
134763Speter 	}
135926Speter     }
136926Speter 	/*
137926Speter 	 */
138926Speter     ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
139926Speter     if ( ctab == (struct ct *) 0 ) {
140926Speter 	error("Ran out of memory (case)");
141926Speter 	pexit( DIED );
142926Speter     }
143926Speter 	/*
144926Speter 	 *  pick up default label and label for after case statement.
145926Speter 	 */
146926Speter     ctab[0].clabel = getlab();
147926Speter     endlabel = getlab();
148926Speter 	/*
149926Speter 	 *  generate code for each case
150926Speter 	 *  filling in ctab for each.
151926Speter 	 *  nr is for error if no case falls out bottom.
152926Speter 	 */
153926Speter     nr = 1;
154926Speter     count = 0;
155926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
156926Speter 	cstatp = cstatlp[1];
157926Speter 	if ( cstatp == NIL ) {
158926Speter 	    continue;
159926Speter 	}
160926Speter 	line = cstatp[1];
161926Speter 	label = getlab();
162926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
163926Speter 	    gconst( casep[1] );
164926Speter 	    if( exprtype == NIL || con.ctype == NIL ) {
165763Speter 		continue;
166763Speter 	    }
167926Speter 	    if ( incompat( con.ctype , exprtype , NIL ) ) {
168926Speter 		cerror("Case label type clashed with case selector expression type");
169926Speter 		continue;
170763Speter 	    }
171926Speter 	    if ( con.crval < low || con.crval > high ) {
172926Speter 		error("Case label out of range");
173926Speter 		continue;
174763Speter 	    }
175926Speter 	    count++;
176926Speter 	    ctab[ count ].cconst = con.crval;
177926Speter 	    ctab[ count ].cline = line;
178926Speter 	    ctab[ count ].clabel = label;
179763Speter 	}
180763Speter 	    /*
181926Speter 	     *	put out the statement
182763Speter 	     */
183926Speter 	putlab( label );
184926Speter 	putcnt();
185926Speter 	level++;
186926Speter 	statement( cstatp[3] );
1873139Smckusic 	nr = (nr && noreach);
188926Speter 	noreach = 0;
189926Speter 	level--;
190926Speter 	if (gotos[cbn]) {
191926Speter 		ungoto();
192763Speter 	}
193926Speter 	putjbr( endlabel );
194763Speter     }
1951278Speter     noreach = nr;
196926Speter 	/*
197926Speter 	 *	default action is to call error
198926Speter 	 */
199926Speter     putlab( ctab[0].clabel );
2005663Smckusic     putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CASERNG" );
2013830Speter     putRV( 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
2023830Speter 		    exprnlp -> extra_flags , P2INT );
203926Speter     putop( P2CALL , P2INT );
204926Speter     putdot( filename , line );
205926Speter 	/*
206926Speter 	 *  sort the cases
207926Speter 	 */
208926Speter     qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
209926Speter 	/*
210926Speter 	 *  check for duplicates
211926Speter 	 */
2121278Speter     dupcases = FALSE;
213926Speter     for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
214926Speter 	if ( ctp[0].cconst == ctp[1].cconst ) {
2151278Speter 	    error("Multiply defined label in case, lines %d and %d" ,
216926Speter 		    ctp[0].cline , ctp[1].cline );
2171278Speter 	    dupcases = TRUE;
218926Speter 	}
219926Speter     }
2201278Speter     if ( dupcases ) {
2211278Speter 	return;
2221278Speter     }
223926Speter 	/*
224926Speter 	 *  choose a switch algorithm and implement it:
225926Speter 	 *	direct switch	>= 1/3 full and >= 4 cases.
226926Speter 	 *	binary switch	not direct switch and > 8 cases.
227926Speter 	 *	ifthenelse	not direct or binary switch.
228926Speter 	 */
229926Speter     putlab( swlabel );
230926Speter     if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
231926Speter 	directsw( ctab , count );
232926Speter     } else if ( count > 8 ) {
233926Speter 	binarysw( ctab , count );
234926Speter     } else {
235926Speter 	itesw( ctab , count );
236926Speter     }
237926Speter     putlab( endlabel );
238926Speter     if ( goc != gocnt ) {
239926Speter 	    putcnt();
240926Speter     }
241926Speter }
242763Speter 
243926Speter     /*
244926Speter      *	direct switch
245926Speter      */
246926Speter directsw( ctab , count )
247926Speter     struct ct	*ctab;
248926Speter     int		count;
249926Speter {
250926Speter     int		fromlabel = getlab();
251926Speter     long	i;
252926Speter     long	j;
253926Speter 
25410378Speter #   ifdef vax
25510378Speter 	putprintf("	casel	%s,$%d,$%d" , 0 , FORCENAME ,
25610378Speter 		ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
25710378Speter #   endif vax
25810378Speter #   ifdef mc68000
25910378Speter 	    /*
26010378Speter 	     *	subl	to make d0 a 0-origin byte offset.
26110378Speter 	     *	cmpl	check against upper limit.
26210378Speter 	     *	bhi	error if out of bounds.
26310378Speter 	     *	addw	to make d0 a 0-origin word offset.
26410378Speter 	     *	movw	pick up a jump-table entry
26510378Speter 	     *	jmp	and indirect through it.
26610378Speter 	     */
26710378Speter 	putprintf("	subl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
26810378Speter 	putprintf("	cmpl	#%d,%s", 0,
26910378Speter 		ctab[count].cconst - ctab[1].cconst, FORCENAME);
27010378Speter 	putprintf("	bhi	%s%d", 0, LABELPREFIX, ctab[0].clabel);
27110378Speter 	putprintf("	addw	%s,%s", 0, FORCENAME, FORCENAME);
27210378Speter 	putprintf("	movw	pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
27310378Speter 	putprintf("	jmp	pc@(2,%s:w)", 0, FORCENAME);
27410378Speter #   endif mc68000
275926Speter     putlab( fromlabel );
276926Speter     i = 1;
277926Speter     j = ctab[1].cconst;
278926Speter     while ( i <= count ) {
279926Speter 	if ( j == ctab[ i ].cconst ) {
280926Speter 	    putprintf( "	.word	" , 1 );
281926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
282926Speter 	    putprintf( "-" , 1 );
283926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
284926Speter 	    i++;
285926Speter 	} else {
286926Speter 	    putprintf( "	.word	" , 1 );
287926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
288926Speter 	    putprintf( "-" , 1 );
289926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
290926Speter 	}
291926Speter 	j++;
292926Speter     }
29310378Speter #   ifdef vax
29410378Speter 	    /*
29510378Speter 	     *	execution continues here if value not in range of case.
29610378Speter 	     */
29710378Speter 	putjbr( ctab[0].clabel );
29810378Speter #   endif vax
299926Speter }
300926Speter 
301926Speter     /*
302926Speter      *	binary switch
303926Speter      *	special case out default label and start recursion.
304926Speter      */
305926Speter binarysw( ctab , count )
306926Speter     struct ct	*ctab;
307926Speter     int		count;
308926Speter {
309926Speter 
310926Speter     bsrecur( ctab[0].clabel , &ctab[0] , count );
311926Speter }
312926Speter 
313926Speter     /*
314926Speter      *	recursive log( count ) search.
315926Speter      */
316926Speter bsrecur( deflabel , ctab , count )
317926Speter     int		deflabel;
318926Speter     struct ct	*ctab;
319926Speter     int		count;
320926Speter {
321926Speter 
322926Speter     if ( count <= 0 ) {
32310378Speter 	putjbr(deflabel);
324926Speter 	return;
325926Speter     } else if ( count == 1 ) {
32610378Speter #	ifdef vax
32710378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[1].cconst);
32810378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[1].clabel);
32910378Speter 	    putjbr(deflabel);
33010378Speter #	endif vax
33110378Speter #	ifdef mc68000
33210378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[1].cconst, FORCENAME);
33310378Speter 	    putprintf("	jeq	L%d", 0, LABELPREFIX, ctab[1].clabel);
33410378Speter 	    putjbr(deflabel);
33510378Speter #	endif mc68000
336926Speter 	return;
337926Speter     } else {
338926Speter 	int	half = ( count + 1 ) / 2;
339926Speter 	int	gtrlabel = getlab();
340926Speter 
34110378Speter #	ifdef vax
34210378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[half].cconst);
34310378Speter 	    putprintf("	jgtr	%s%d", 0, LABELPREFIX, gtrlabel);
34410378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[half].clabel);
34510378Speter #	endif vax
34610378Speter #	ifdef mc68000
34710378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[half].cconst, FORCENAME);
34810378Speter 	    putprintf("	jgt	%s%d", 0, LABELPREFIX, gtrlabel);
34910378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[half].clabel);
35010378Speter #	endif mc68000
351926Speter 	bsrecur( deflabel , &ctab[0] , half - 1 );
35210378Speter 	putlab(gtrlabel);
353926Speter 	bsrecur( deflabel , &ctab[ half ] , count - half );
354926Speter 	return;
355926Speter     }
356926Speter }
357926Speter 
358926Speter itesw( ctab , count )
359926Speter     struct ct	*ctab;
360926Speter     int		count;
361926Speter {
362926Speter     int	i;
363926Speter 
364926Speter     for ( i = 1 ; i <= count ; i++ ) {
36510378Speter #	ifdef vax
36610378Speter 	    putprintf("	cmpl	%s,$%d", 0, FORCENAME, ctab[i].cconst);
36710378Speter 	    putprintf("	jeql	%s%d", 0, LABELPREFIX, ctab[i].clabel);
36810378Speter #	endif vax
36910378Speter #	ifdef mc68000
37010378Speter 	    putprintf("	cmpl	#%d,%s", 0, ctab[i].cconst, FORCENAME);
37110378Speter 	    putprintf("	jeq	%s%d", 0, LABELPREFIX, ctab[i].clabel);
37210378Speter #	endif mc68000
373926Speter     }
37410378Speter     putjbr(ctab[0].clabel);
375926Speter     return;
376926Speter }
377926Speter int
378926Speter casecmp( this , that )
379926Speter     struct ct 	*this;
380926Speter     struct ct 	*that;
381926Speter {
382926Speter     if ( this -> cconst < that -> cconst ) {
383926Speter 	return -1;
384926Speter     } else if ( this -> cconst > that -> cconst ) {
385926Speter 	return 1;
386926Speter     } else {
387926Speter 	return 0;
388926Speter     }
389926Speter }
390763Speter #endif PC
391