xref: /csrg-svn/usr.bin/pascal/src/cset.c (revision 10652)
1750Speter /* Copyright (c) 1979 Regents of the University of California */
2750Speter 
3*10652Speter static char sccsid[] = "@(#)cset.c 1.7 02/01/83";
4750Speter 
5750Speter #include "whoami.h"
6750Speter #include "0.h"
7750Speter #include "tree.h"
8750Speter #include "opcode.h"
9750Speter #include "objfmt.h"
103072Smckusic #ifdef PC
11750Speter #include "pc.h"
12750Speter #include "pcops.h"
13*10652Speter #include "align.h"
143072Smckusic #endif PC
15750Speter 
16750Speter /*
173072Smckusic  * CONSETS causes compile time constant sets to be constructed here.
183072Smckusic  *
193072Smckusic  * COMPSETSZE defines the maximum number of longs to be used in
203072Smckusic  *	constant set construction
213072Smckusic  */
223072Smckusic #define CONSETS
233072Smckusic #define COMPSETSZE 10
243072Smckusic 
253072Smckusic #define BITSPERBYTE 8
263072Smckusic #define BITSPERLONG 32
273072Smckusic #define LG2BITSBYTE 3
283072Smckusic #define MSKBITSBYTE 0x07
293072Smckusic #define LG2BITSLONG 5
303072Smckusic #define MSKBITSLONG 0x1f
313072Smckusic 
323072Smckusic /*
33750Speter  *	rummage through a `constant' set (i.e. anything within [ ]'s) tree
34750Speter  *	and decide if this is a compile time constant set or a runtime set.
35750Speter  *	this information is returned in a structure passed from the caller.
36750Speter  *	while rummaging, this also reorders the tree so that all ranges
37750Speter  *	preceed all singletons.
38750Speter  */
39750Speter bool
40750Speter precset( r , settype , csetp )
41750Speter 	int		*r;
42750Speter 	struct nl	*settype;
43750Speter 	struct csetstr	*csetp;
44750Speter {
45750Speter 	register int		*e;
46750Speter 	register struct nl	*t;
47750Speter 	register struct nl	*exptype;
48750Speter 	register int		*el;
49750Speter 	register int		*pairp;
50750Speter 	register int		*singp;
51750Speter 	int			*ip;
523072Smckusic 	int			lower;
533072Smckusic 	int			upper;
54750Speter 	bool			setofint;
55750Speter 
56750Speter 	csetp -> csettype = NIL;
57750Speter 	csetp -> paircnt = 0;
58750Speter 	csetp -> singcnt = 0;
59750Speter 	csetp -> comptime = TRUE;
60750Speter 	setofint = FALSE;
61750Speter 	if ( settype != NIL ) {
62750Speter 	    if ( settype -> class == SET ) {
63750Speter 		    /*
64750Speter 		     *	the easy case, we are told the type of the set.
65750Speter 		     */
66750Speter 		exptype = settype -> type;
67750Speter 	    } else {
68750Speter 		    /*
69750Speter 		     *	we are told the type, but it's not a set
70750Speter 		     *	supposedly possible if someone tries
71750Speter 		     *	e.g string context [1,2] = 'abc'
72750Speter 		     */
73750Speter 		error("Constant set involved in non set context");
74750Speter 		return csetp -> comptime;
75750Speter 	    }
76750Speter 	} else {
77750Speter 		/*
78750Speter 		 * So far we have no indication
79750Speter 		 * of what the set type should be.
80750Speter 		 * We "look ahead" and try to infer
81750Speter 		 * The type of the constant set
82750Speter 		 * by evaluating one of its members.
83750Speter 		 */
84750Speter 	    e = r[2];
85750Speter 	    if (e == NIL) {
86750Speter 		    /*
871552Speter 		     *	tentative for [], return type of `intset'
88750Speter 		     */
891552Speter 		settype = lookup( intset );
901552Speter 		if ( settype == NIL ) {
911552Speter 		    panic( "empty set" );
921552Speter 		}
931552Speter 		settype = settype -> type;
941552Speter 		if ( settype == NIL ) {
951552Speter 		    return csetp -> comptime;
961552Speter 		}
971552Speter 		if ( isnta( settype , "t" ) ) {
981552Speter 		    error("Set default type \"intset\" is not a set");
991552Speter 		    return csetp -> comptime;
1001552Speter 		}
1011552Speter 		csetp -> csettype = settype;
1023170Smckusic 		setran( settype -> type );
1033072Smckusic 		if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1043072Smckusic 			csetp -> comptime = FALSE;
105750Speter 		return csetp -> comptime;
106750Speter 	    }
107750Speter 	    e = e[1];
108750Speter 	    if (e == NIL) {
109750Speter 		return csetp -> comptime;
110750Speter 	    }
111750Speter 	    if (e[0] == T_RANG) {
112750Speter 		    e = e[1];
113750Speter 	    }
114750Speter 	    codeoff();
115750Speter 	    t = rvalue(e, NIL , RREQ );
116750Speter 	    codeon();
117750Speter 	    if (t == NIL) {
118750Speter 		return csetp -> comptime;
119750Speter 	    }
120750Speter 		/*
121750Speter 		 * The type of the set, settype, is
122750Speter 		 * deemed to be a set of the base type
123750Speter 		 * of t, which we call exptype.  If,
124750Speter 		 * however, this would involve a
125750Speter 		 * "set of integer", we cop out
126750Speter 		 * and use "intset"'s current scoped
127750Speter 		 * type instead.
128750Speter 		 */
129750Speter 	    if (isa(t, "r")) {
130750Speter 		    error("Sets may not have 'real' elements");
131750Speter 		    return csetp -> comptime;
132750Speter 	    }
133750Speter 	    if (isnta(t, "bcsi")) {
134750Speter 		    error("Set elements must be scalars, not %ss", nameof(t));
135750Speter 		    return csetp -> comptime;
136750Speter 	    }
137750Speter 	    if (isa(t, "i")) {
138750Speter 		    settype = lookup(intset);
139750Speter 		    if (settype == NIL)
140750Speter 			    panic("intset");
141750Speter 		    settype = settype->type;
142750Speter 		    if (settype == NIL)
143750Speter 			    return csetp -> comptime;
144750Speter 		    if (isnta(settype, "t")) {
145750Speter 			    error("Set default type \"intset\" is not a set");
146750Speter 			    return csetp -> comptime;
147750Speter 		    }
148750Speter 		    exptype = settype->type;
149750Speter 			/*
150750Speter 			 *	say we are doing an intset
151750Speter 			 *	but, if we get out of range errors for intset
152750Speter 			 *	we punt constructing the set at	compile time.
153750Speter 			 */
154750Speter 		    setofint = TRUE;
155750Speter 	    } else {
156750Speter 			exptype = t->type;
157750Speter 			if (exptype == NIL)
158750Speter 				return csetp -> comptime;
159750Speter 			if (exptype->class != RANGE)
160750Speter 				exptype = exptype->type;
161750Speter 			settype = defnl(0, SET, exptype, 0);
162750Speter 	    }
163750Speter 	}
164750Speter 	csetp -> csettype = settype;
1653072Smckusic #	ifndef CONSETS
1663072Smckusic 	    csetp -> comptime = FALSE;
1673072Smckusic #	endif CONSETS
168750Speter 	setran( exptype );
1693072Smckusic 	if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1703072Smckusic 		csetp -> comptime = FALSE;
171750Speter 	lower = set.lwrb;
172750Speter 	upper = set.lwrb + set.uprbp;
173750Speter 	pairp = NIL;
174750Speter 	singp = NIL;
175750Speter 	codeoff();
176750Speter 	while ( el = r[2] ) {
177750Speter 		e = el[1];
178750Speter 		if (e == NIL) {
179750Speter 			    /*
180750Speter 			     *	don't hang this one anywhere.
181750Speter 			     */
182750Speter 			csetp -> csettype = NIL;
183750Speter 			r[2] = el[2];
184750Speter 			continue;
185750Speter 		}
186750Speter 		if (e[0] == T_RANG) {
187750Speter 			if ( csetp -> comptime && constval( e[2] ) ) {
1883072Smckusic #ifdef CONSETS
189750Speter 			    t = con.ctype;
1903072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
191750Speter 				if ( setofint ) {
192750Speter 				    csetp -> comptime = FALSE;
193750Speter 				} else {
1943072Smckusic 				    error("Range upper bound of %D out of set bounds" , ((long)con.crval) );
195750Speter 				    csetp -> csettype = NIL;
196750Speter 				}
197750Speter 			    }
1983072Smckusic #endif CONSETS
199750Speter 			} else {
200750Speter 			    csetp -> comptime = FALSE;
201750Speter 			    t = rvalue(e[2], NIL , RREQ );
202750Speter 			    if (t == NIL) {
203750Speter 				    rvalue(e[1], NIL , RREQ );
204750Speter 				    goto pairhang;
205750Speter 			    }
206750Speter 			}
207750Speter 			if (incompat(t, exptype, e[2])) {
208750Speter 				cerror("Upper bound of element type clashed with set type in constant set");
209750Speter 			}
210750Speter 			if ( csetp -> comptime && constval( e[1] ) ) {
2113072Smckusic #ifdef CONSETS
212750Speter 			    t = con.ctype;
2133072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
214750Speter 				if ( setofint ) {
215750Speter 				    csetp -> comptime = FALSE;
216750Speter 				} else {
2173072Smckusic 				    error("Range lower bound of %D out of set bounds" , ((long)con.crval) );
218750Speter 				    csetp -> csettype = NIL;
219750Speter 				}
220750Speter 			    }
2213072Smckusic #endif CONSETS
222750Speter 			} else {
223750Speter 			    csetp -> comptime = FALSE;
224750Speter 			    t = rvalue(e[1], NIL , RREQ );
225750Speter 			    if (t == NIL) {
226750Speter 				    goto pairhang;
227750Speter 			    }
228750Speter 			}
229750Speter 			if (incompat(t, exptype, e[1])) {
230750Speter 				cerror("Lower bound of element type clashed with set type in constant set");
231750Speter 			}
232750Speter pairhang:
233750Speter 			    /*
234750Speter 			     *	remove this range from the tree list and
235750Speter 			     *	hang it on the pairs list.
236750Speter 			     */
237750Speter 			ip = el[2];
238750Speter 			el[2] = pairp;
239750Speter 			pairp = r[2];
240750Speter 			r[2] = ip;
241750Speter 			csetp -> paircnt++;
242750Speter 		} else {
243750Speter 			if ( csetp -> comptime && constval( e ) ) {
2443072Smckusic #ifdef CONSETS
245750Speter 			    t = con.ctype;
2463072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
247750Speter 				if ( setofint ) {
248750Speter 				    csetp -> comptime = FALSE;
249750Speter 				} else {
2503072Smckusic 				    error("Value of %D out of set bounds" , ((long)con.crval) );
251750Speter 				    csetp -> csettype = NIL;
252750Speter 				}
253750Speter 			    }
2543072Smckusic #endif CONSETS
255750Speter 			} else {
256750Speter 			    csetp -> comptime = FALSE;
257750Speter 			    t = rvalue((int *) e, NLNIL , RREQ );
258750Speter 			    if (t == NIL) {
259750Speter 				    goto singhang;
260750Speter 			    }
261750Speter 			}
262750Speter 			if (incompat(t, exptype, e)) {
263750Speter 				cerror("Element type clashed with set type in constant set");
264750Speter 			}
265750Speter singhang:
266750Speter 			    /*
267750Speter 			     *	take this expression off the tree list and
268750Speter 			     *	hang it on the list of singletons.
269750Speter 			     */
270750Speter 			ip = el[2];
271750Speter 			el[2] = singp;
272750Speter 			singp = r[2];
273750Speter 			r[2] = ip;
274750Speter 			csetp -> singcnt++;
275750Speter 		}
276750Speter 	}
277750Speter 	codeon();
278750Speter #	ifdef PC
279750Speter 	    if ( pairp != NIL ) {
280750Speter 		for ( el = pairp ; el[2] != NIL ; el = el[2] ) /* void */;
281750Speter 		el[2] = singp;
282750Speter 		r[2] = pairp;
283750Speter 	    } else {
284750Speter 		r[2] = singp;
285750Speter 	    }
286750Speter #	endif PC
287750Speter #	ifdef OBJ
288750Speter 	    if ( singp != NIL ) {
289750Speter 		for ( el = singp ; el[2] != NIL ; el = el[2] ) /* void */;
290750Speter 		el[2] = pairp;
291750Speter 		r[2] = singp;
292750Speter 	    } else {
293750Speter 		r[2] = pairp;
294750Speter 	    }
295750Speter #	endif OBJ
296750Speter 	if ( csetp -> csettype == NIL ) {
297750Speter 	    csetp -> comptime = TRUE;
298750Speter 	}
299750Speter 	return csetp -> comptime;
300750Speter }
301750Speter 
3023072Smckusic #ifdef CONSETS
303750Speter     /*
304750Speter      *	mask[i] has the low i bits turned off.
305750Speter      */
306750Speter long	mask[] = {
3073072Smckusic #		ifdef DEC11
308750Speter 		    0xffffffff , 0xfffffffe , 0xfffffffc , 0xfffffff8 ,
309750Speter 		    0xfffffff0 , 0xffffffe0 , 0xffffffc0 , 0xffffff80 ,
310750Speter 		    0xffffff00 , 0xfffffe00 , 0xfffffc00 , 0xfffff800 ,
311750Speter 		    0xfffff000 , 0xffffe000 , 0xffffc000 , 0xffff8000 ,
312750Speter 		    0xffff0000 , 0xfffe0000 , 0xfffc0000 , 0xfff80000 ,
313750Speter 		    0xfff00000 , 0xffe00000 , 0xffc00000 , 0xff800000 ,
314750Speter 		    0xff000000 , 0xfe000000 , 0xfc000000 , 0xf8000000 ,
315750Speter 		    0xf0000000 , 0xe0000000 , 0xc0000000 , 0x80000000 ,
316750Speter 		    0x00000000
3173072Smckusic #		else
3183072Smckusic 		    0xffffffff , 0xfeffffff , 0xfcffffff , 0xf8ffffff ,
3193072Smckusic 		    0xf0ffffff , 0xe0ffffff , 0xc0ffffff , 0x80ffffff ,
3203072Smckusic 		    0x00ffffff , 0x00feffff , 0x00fcffff , 0x00f8ffff ,
3213072Smckusic 		    0x00f0ffff , 0x00e0ffff , 0x00c0ffff , 0x0080ffff ,
3223072Smckusic 		    0x0000ffff , 0x0000feff , 0x0000fcff , 0x0000f8ff ,
3233072Smckusic 		    0x0000f0ff , 0x0000e0ff , 0x0000c0ff , 0x000080ff ,
3243072Smckusic 		    0x000000ff , 0x000000fe , 0x000000fc , 0x000000f8 ,
3253072Smckusic 		    0x000000f0 , 0x000000e0 , 0x000000c0 , 0x00000080 ,
3263072Smckusic 		    0x00000000
3273072Smckusic #		endif DEC11
3283072Smckusic 	    };
329750Speter     /*
330750Speter      *	given a csetstr, either
331750Speter      *	    put out a compile time constant set and an lvalue to it.
332750Speter      *	or
333750Speter      *	    put out rvalues for the singletons and the pairs
334750Speter      *	    and counts of each.
335750Speter      */
3363072Smckusic #endif CONSETS
337750Speter postcset( r , csetp )
338750Speter     int			*r;
339750Speter     struct csetstr	*csetp;
340750Speter     {
341750Speter 	register int	*el;
342750Speter 	register int	*e;
343750Speter 	int		lower;
344750Speter 	int		upper;
345750Speter 	int		lowerdiv;
346750Speter 	int		lowermod;
347750Speter 	int		upperdiv;
348750Speter 	int		uppermod;
349750Speter 	int		label;
350750Speter 	long		*lp;
351750Speter 	long		*limit;
3523072Smckusic 	long		tempset[ COMPSETSZE ];
353750Speter 	long		temp;
3543072Smckusic 	char		*cp;
3553072Smckusic #	ifdef PC
3563072Smckusic 	    char	labelname[ BUFSIZ ];
3573072Smckusic #	endif PC
358750Speter 
359750Speter 	if ( csetp -> comptime ) {
3603072Smckusic #ifdef CONSETS
361750Speter 	    setran( ( csetp -> csettype ) -> type );
3623072Smckusic 	    limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
363750Speter 	    for ( lp = &tempset[0] ; lp < limit ; lp++ ) {
364750Speter 		*lp = 0;
365750Speter 	    }
366750Speter 	    for ( el = r[2] ; el != NIL ; el = el[2] ) {
367750Speter 		e = el[1];
368750Speter 		if ( e[0] == T_RANG ) {
369750Speter 		    constval( e[1] );
3703072Smckusic 		    lower = con.crval;
371750Speter 		    constval( e[2] );
3723072Smckusic 		    upper = con.crval;
373750Speter 		    if ( upper < lower ) {
374750Speter 			continue;
375750Speter 		    }
3763072Smckusic 		    lowerdiv = ( lower - set.lwrb ) >> LG2BITSLONG;
3773072Smckusic 		    lowermod = ( lower - set.lwrb ) & MSKBITSLONG;
3783072Smckusic 		    upperdiv = ( upper - set.lwrb ) >> LG2BITSLONG;
3793072Smckusic 		    uppermod = ( upper - set.lwrb ) & MSKBITSLONG;
380750Speter 		    temp = mask[ lowermod ];
381750Speter 		    if ( lowerdiv == upperdiv ) {
382750Speter 			temp &= ~mask[ uppermod + 1 ];
383750Speter 		    }
384750Speter 		    tempset[ lowerdiv ] |= temp;
385750Speter 		    limit = &tempset[ upperdiv-1 ];
386750Speter 		    for ( lp = &tempset[ lowerdiv+1 ] ; lp <= limit ; lp++ ) {
3873072Smckusic 			*lp |= 0xffffffff;
388750Speter 		    }
389750Speter 		    if ( lowerdiv != upperdiv ) {
390750Speter 			tempset[ upperdiv ] |= ~mask[ uppermod + 1 ];
391750Speter 		    }
392750Speter 		} else {
393750Speter 		    constval( e );
3943072Smckusic 		    temp = con.crval - set.lwrb;
3953072Smckusic 		    cp = (char *)tempset;
3963072Smckusic 		    cp[temp >> LG2BITSBYTE] |= (1 << (temp & MSKBITSBYTE));
397750Speter 		}
398750Speter 	    }
3993315Speter 	    if ( !CGENNING )
400750Speter 		return;
401750Speter #	    ifdef PC
402750Speter 		label = getlab();
403*10652Speter 		putprintf("	.data" , 0 );
404*10652Speter 		aligndot(A_SET);
405750Speter 		putlab( label );
406750Speter 		lp = &( tempset[0] );
4073072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
408*10652Speter 		while (lp < limit) {
409*10652Speter 		    putprintf("	.long	0x%x", 1, *lp++);
410*10652Speter 		    for (temp = 2 ; temp <= 8 && lp < limit ; temp++) {
411*10652Speter 			putprintf(",0x%x", 1, *lp++);
412750Speter 		    }
413*10652Speter 		    putprintf("", 0);
414750Speter 		}
415*10652Speter 		putprintf("	.text", 0);
416750Speter 		sprintf( labelname , PREFIXFORMAT , LABELPREFIX , label );
417750Speter 		putleaf( P2ICON , 0 , 0 , P2PTR | P2STRTY , labelname );
418750Speter #	    endif PC
419750Speter #	    ifdef OBJ
4203072Smckusic 		put(2, O_CON, (int)(((set.uprbp >> LG2BITSLONG) + 1) *
4213072Smckusic 				 (BITSPERLONG >> LG2BITSBYTE)));
422750Speter 		lp = &( tempset[0] );
4233072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
424750Speter 		while ( lp < limit ) {
4253072Smckusic 		    put(2, O_CASE4, *lp ++);
426750Speter 		}
427750Speter #	    endif OBJ
4283072Smckusic #else
4293072Smckusic 		panic("const cset");
4303072Smckusic #endif CONSETS
431750Speter 	} else {
432750Speter #	    ifdef PC
433750Speter 		putleaf( P2ICON , csetp -> paircnt , 0 , P2INT , 0 );
434750Speter 		putop( P2LISTOP , P2INT );
435750Speter 		putleaf( P2ICON , csetp -> singcnt , 0 , P2INT , 0 );
436750Speter 		putop( P2LISTOP , P2INT );
437750Speter 		for ( el = r[2] ; el != NIL ; el = el[2] ) {
438750Speter 		    e = el[1];
439750Speter 		    if ( e[0] == T_RANG ) {
440750Speter 			rvalue( e[2] , NIL , RREQ );
441750Speter 			putop( P2LISTOP , P2INT );
442750Speter 			rvalue( e[1] , NIL , RREQ );
443750Speter 			putop( P2LISTOP , P2INT );
444750Speter 		    } else {
445750Speter 			rvalue( e , NIL , RREQ );
446750Speter 			putop( P2LISTOP , P2INT );
447750Speter 		    }
448750Speter 		}
449750Speter #	    endif PC
450750Speter #	    ifdef OBJ
451750Speter 		for ( el = r[2] ; el != NIL ; el = el[2] ) {
452750Speter 		    e = el[1];
453750Speter 		    if ( e[0] == T_RANG ) {
4541884Speter 			stkrval( e[1] , NIL , RREQ );
455750Speter 			stkrval( e[2] , NIL , RREQ );
456750Speter 		    } else {
457750Speter 			stkrval( e , NIL , RREQ );
458750Speter 		    }
459750Speter 		}
4603072Smckusic 		put(2 , O_CON24 , (int)csetp -> singcnt );
4613072Smckusic 		put(2 , O_CON24 , (int)csetp -> paircnt );
462750Speter #	    endif OBJ
463750Speter 	}
464750Speter }
465