1*926Speter /* Copyright (c) 1980 Regents of the University of California */
2763Speter 
3*926Speter static	char sccsid[] = "@(#)pccaseop.c 1.2 09/27/80";
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*926Speter 
16763Speter     /*
17*926Speter      *	structure for a case:
18*926Speter      *	    its constant label, line number (for errors), and location label.
19*926Speter      */
20*926Speter struct ct {
21*926Speter     long	cconst;
22*926Speter     int		cline;
23*926Speter     int		clabel;
24*926Speter };
25*926Speter 
26*926Speter     /*
27*926Speter      *	the P2FORCE operator puts its operand into a register.
28*926Speter      *	these to keep from thinking of it as r0 all over.
29*926Speter      */
30*926Speter #define	FORCENAME	"r0"
31*926Speter #define	FORCENUMBER	0
32*926Speter 
33*926Speter     /*
34*926Speter      *	given a tree for a case statement, generate code for it.
35*926Speter      *	this computes the expression into a register,
36*926Speter      *	puts down the code for each of the cases,
37*926Speter      *	and then decides how to do the case switching.
38763Speter      *	tcase	[0]	T_CASE
39763Speter      *		[1]	lineof "case"
40763Speter      *		[2]	expression
41*926Speter      *		[3]	list of cased statements:
42763Speter      *			cstat	[0]	T_CSTAT
43763Speter      *				[1]	lineof ":"
44*926Speter      *				[2]	list of constant labels
45763Speter      *				[3]	statement
46763Speter      */
47763Speter pccaseop( tcase )
48763Speter     int	*tcase;
49*926Speter {
50*926Speter     struct nl	*exprtype;
51*926Speter     struct nl	*rangetype;
52*926Speter     long	low;
53*926Speter     long	high;
54*926Speter     long	exprctype;
55*926Speter     long	swlabel;
56*926Speter     long	endlabel;
57*926Speter     long	label;
58*926Speter     long	count;
59*926Speter     long	*cstatlp;
60*926Speter     long	*cstatp;
61*926Speter     long	*casep;
62*926Speter     struct ct	*ctab;
63*926Speter     struct ct	*ctp;
64*926Speter     long	i;
65*926Speter     long	nr;
66*926Speter     long	goc;
67*926Speter     int		casecmp();
68763Speter 
69*926Speter     goc = gocnt;
70*926Speter 	/*
71*926Speter 	 *  find out the type of the case expression
72*926Speter 	 *  even if the expression has errors (exprtype == NIL), continue.
73*926Speter 	 */
74*926Speter     line = tcase[1];
75*926Speter     exprtype = rvalue( (int *) tcase[2] , NIL  , RREQ );
76*926Speter     if ( exprtype != NIL ) {
77*926Speter 	if ( isnta( exprtype , "bcsi" ) ) {
78*926Speter 	    error("Case selectors cannot be %ss" , nameof( exprtype ) );
79*926Speter 	    exprtype = NIL;
80*926Speter 	} else {
81*926Speter 	    if ( exprtype -> class != RANGE ) {
82*926Speter 		rangetype = exprtype -> type;
83*926Speter 	    } else {
84*926Speter 		rangetype = exprtype;
85*926Speter 	    }
86*926Speter 	    if ( rangetype == NIL ) {
87763Speter 		exprtype = NIL;
88763Speter 	    } else {
89*926Speter 		low = rangetype -> range[0];
90*926Speter 		high = rangetype -> range[1];
91763Speter 	    }
92763Speter 	}
93*926Speter     }
94*926Speter     if ( exprtype != NIL ) {
95763Speter 	    /*
96*926Speter 	     *	put expression into a register
97*926Speter 	     *	save its c-type and jump to the code to do the switch.
98763Speter 	     */
99*926Speter 	putop( P2FORCE , P2INT );
100*926Speter 	putdot( filename , line );
101*926Speter 	exprctype = p2type( exprtype );
102*926Speter 	swlabel = getlab();
103*926Speter 	putjbr( swlabel );
104*926Speter     }
105*926Speter 	/*
106*926Speter 	 *  count the number of cases
107*926Speter 	 *  and allocate table for cases, lines, and labels
108*926Speter 	 *  default case goes in ctab[0].
109*926Speter 	 */
110*926Speter     count = 1;
111*926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
112*926Speter 	cstatp = cstatlp[1];
113*926Speter 	if ( cstatp == NIL ) {
114*926Speter 	    continue;
115763Speter 	}
116*926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
117*926Speter 	    count++;
118763Speter 	}
119*926Speter     }
120*926Speter 	/*
121*926Speter 	 */
122*926Speter     ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
123*926Speter     if ( ctab == (struct ct *) 0 ) {
124*926Speter 	error("Ran out of memory (case)");
125*926Speter 	pexit( DIED );
126*926Speter     }
127*926Speter 	/*
128*926Speter 	 *  pick up default label and label for after case statement.
129*926Speter 	 */
130*926Speter     ctab[0].clabel = getlab();
131*926Speter     endlabel = getlab();
132*926Speter 	/*
133*926Speter 	 *  generate code for each case
134*926Speter 	 *  filling in ctab for each.
135*926Speter 	 *  nr is for error if no case falls out bottom.
136*926Speter 	 */
137*926Speter     nr = 1;
138*926Speter     count = 0;
139*926Speter     for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
140*926Speter 	cstatp = cstatlp[1];
141*926Speter 	if ( cstatp == NIL ) {
142*926Speter 	    continue;
143*926Speter 	}
144*926Speter 	line = cstatp[1];
145*926Speter 	label = getlab();
146*926Speter 	for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
147*926Speter 	    gconst( casep[1] );
148*926Speter 	    if( exprtype == NIL || con.ctype == NIL ) {
149763Speter 		continue;
150763Speter 	    }
151*926Speter 	    if ( incompat( con.ctype , exprtype , NIL ) ) {
152*926Speter 		cerror("Case label type clashed with case selector expression type");
153*926Speter 		continue;
154763Speter 	    }
155*926Speter 	    if ( con.crval < low || con.crval > high ) {
156*926Speter 		error("Case label out of range");
157*926Speter 		continue;
158763Speter 	    }
159*926Speter 	    count++;
160*926Speter 	    ctab[ count ].cconst = con.crval;
161*926Speter 	    ctab[ count ].cline = line;
162*926Speter 	    ctab[ count ].clabel = label;
163763Speter 	}
164763Speter 	    /*
165*926Speter 	     *	put out the statement
166763Speter 	     */
167*926Speter 	putlab( label );
168*926Speter 	putcnt();
169*926Speter 	level++;
170*926Speter 	statement( cstatp[3] );
171*926Speter 	nr &= noreach;
172*926Speter 	noreach = 0;
173*926Speter 	level--;
174*926Speter 	if (gotos[cbn]) {
175*926Speter 		ungoto();
176763Speter 	}
177*926Speter 	putjbr( endlabel );
178763Speter     }
179*926Speter 	/*
180*926Speter 	 *	default action is to call error
181*926Speter 	 */
182*926Speter     putlab( ctab[0].clabel );
183*926Speter     putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" );
184*926Speter     putleaf( P2ICON , ECASE , 0 , P2INT , 0 );
185*926Speter     putleaf( P2REG , FORCENUMBER , 0 , P2INT , 0 );
186*926Speter     putop( P2LISTOP , P2INT );
187*926Speter     putop( P2CALL , P2INT );
188*926Speter     putdot( filename , line );
189*926Speter 	/*
190*926Speter 	 *  sort the cases
191*926Speter 	 */
192*926Speter     qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
193*926Speter 	/*
194*926Speter 	 *  check for duplicates
195*926Speter 	 */
196*926Speter     for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
197*926Speter 	if ( ctp[0].cconst == ctp[1].cconst ) {
198*926Speter 	    error("Muliply defined label in case, lines %d and %d" ,
199*926Speter 		    ctp[0].cline , ctp[1].cline );
200*926Speter 	}
201*926Speter     }
202*926Speter 	/*
203*926Speter 	 *  choose a switch algorithm and implement it:
204*926Speter 	 *	direct switch	>= 1/3 full and >= 4 cases.
205*926Speter 	 *	binary switch	not direct switch and > 8 cases.
206*926Speter 	 *	ifthenelse	not direct or binary switch.
207*926Speter 	 */
208*926Speter     putlab( swlabel );
209*926Speter     if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
210*926Speter 	directsw( ctab , count );
211*926Speter     } else if ( count > 8 ) {
212*926Speter 	binarysw( ctab , count );
213*926Speter     } else {
214*926Speter 	itesw( ctab , count );
215*926Speter     }
216*926Speter     putlab( endlabel );
217*926Speter     noreach = nr;
218*926Speter     if ( goc != gocnt ) {
219*926Speter 	    putcnt();
220*926Speter     }
221*926Speter }
222763Speter 
223*926Speter     /*
224*926Speter      *	direct switch
225*926Speter      */
226*926Speter directsw( ctab , count )
227*926Speter     struct ct	*ctab;
228*926Speter     int		count;
229*926Speter {
230*926Speter     int		fromlabel = getlab();
231*926Speter     long	i;
232*926Speter     long	j;
233*926Speter 
234*926Speter     putprintf( "	casel	%s,$%d,$%d" , 0 , FORCENAME ,
235*926Speter 	    ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
236*926Speter     putlab( fromlabel );
237*926Speter     i = 1;
238*926Speter     j = ctab[1].cconst;
239*926Speter     while ( i <= count ) {
240*926Speter 	if ( j == ctab[ i ].cconst ) {
241*926Speter 	    putprintf( "	.word	" , 1 );
242*926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
243*926Speter 	    putprintf( "-" , 1 );
244*926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
245*926Speter 	    i++;
246*926Speter 	} else {
247*926Speter 	    putprintf( "	.word	" , 1 );
248*926Speter 	    putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
249*926Speter 	    putprintf( "-" , 1 );
250*926Speter 	    putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
251*926Speter 	}
252*926Speter 	j++;
253*926Speter     }
254*926Speter     putjbr( ctab[0].clabel );
255*926Speter }
256*926Speter 
257*926Speter     /*
258*926Speter      *	binary switch
259*926Speter      *	special case out default label and start recursion.
260*926Speter      */
261*926Speter binarysw( ctab , count )
262*926Speter     struct ct	*ctab;
263*926Speter     int		count;
264*926Speter {
265*926Speter 
266*926Speter     bsrecur( ctab[0].clabel , &ctab[0] , count );
267*926Speter }
268*926Speter 
269*926Speter     /*
270*926Speter      *	recursive log( count ) search.
271*926Speter      */
272*926Speter bsrecur( deflabel , ctab , count )
273*926Speter     int		deflabel;
274*926Speter     struct ct	*ctab;
275*926Speter     int		count;
276*926Speter {
277*926Speter 
278*926Speter     if ( count <= 0 ) {
279*926Speter 	putprintf( "	jbr	L%d" , 0 , deflabel );
280*926Speter 	return;
281*926Speter     } else if ( count == 1 ) {
282*926Speter 	putprintf( "	cmpl	%s,$%d" , 0 , FORCENAME , ctab[1].cconst );
283*926Speter 	putprintf( "	jeql	L%d" , 0 , ctab[1].clabel );
284*926Speter 	putprintf( "	jbr	L%d" , 0 , deflabel );
285*926Speter 	return;
286*926Speter     } else {
287*926Speter 	int	half = ( count + 1 ) / 2;
288*926Speter 	int	gtrlabel = getlab();
289*926Speter 
290*926Speter 	putprintf( "	cmpl	%s,$%d" , 0 , FORCENAME , ctab[ half ].cconst );
291*926Speter 	putprintf( "	jeql	L%d" , 0 , ctab[ half ].clabel );
292*926Speter 	putprintf( "	jgtr	L%d" , 0 , gtrlabel );
293*926Speter 	bsrecur( deflabel , &ctab[0] , half - 1 );
294*926Speter 	putprintf( "L%d:" , 0 , gtrlabel );
295*926Speter 	bsrecur( deflabel , &ctab[ half ] , count - half );
296*926Speter 	return;
297*926Speter     }
298*926Speter }
299*926Speter 
300*926Speter itesw( ctab , count )
301*926Speter     struct ct	*ctab;
302*926Speter     int		count;
303*926Speter {
304*926Speter     int	i;
305*926Speter 
306*926Speter     for ( i = 1 ; i <= count ; i++ ) {
307*926Speter 	putprintf( "	cmpl	%s,$%d" , 0 , FORCENAME , ctab[ i ].cconst );
308*926Speter 	putprintf( "	jeql	L%d" , 0 , ctab[ i ].clabel );
309*926Speter     }
310*926Speter     putprintf( "	jbr	L%d" , 0 , ctab[0].clabel );
311*926Speter     return;
312*926Speter }
313*926Speter int
314*926Speter casecmp( this , that )
315*926Speter     struct ct 	*this;
316*926Speter     struct ct 	*that;
317*926Speter {
318*926Speter     if ( this -> cconst < that -> cconst ) {
319*926Speter 	return -1;
320*926Speter     } else if ( this -> cconst > that -> cconst ) {
321*926Speter 	return 1;
322*926Speter     } else {
323*926Speter 	return 0;
324*926Speter     }
325*926Speter }
326763Speter #endif PC
327