xref: /csrg-svn/usr.bin/pascal/src/cset.c (revision 15927)
1750Speter /* Copyright (c) 1979 Regents of the University of California */
2750Speter 
3*15927Sthien #ifndef lint
4*15927Sthien static char sccsid[] = "@(#)cset.c 1.8 02/04/84";
5*15927Sthien #endif
6750Speter 
7750Speter #include "whoami.h"
8750Speter #include "0.h"
9750Speter #include "tree.h"
10750Speter #include "opcode.h"
11750Speter #include "objfmt.h"
12*15927Sthien #include "tree_ty.h"
133072Smckusic #ifdef PC
14750Speter #include "pc.h"
15750Speter #include "pcops.h"
1610652Speter #include "align.h"
173072Smckusic #endif PC
18750Speter 
19750Speter /*
203072Smckusic  * CONSETS causes compile time constant sets to be constructed here.
213072Smckusic  *
223072Smckusic  * COMPSETSZE defines the maximum number of longs to be used in
233072Smckusic  *	constant set construction
243072Smckusic  */
253072Smckusic #define CONSETS
263072Smckusic #define COMPSETSZE 10
273072Smckusic 
283072Smckusic #define BITSPERBYTE 8
293072Smckusic #define BITSPERLONG 32
303072Smckusic #define LG2BITSBYTE 3
313072Smckusic #define MSKBITSBYTE 0x07
323072Smckusic #define LG2BITSLONG 5
333072Smckusic #define MSKBITSLONG 0x1f
343072Smckusic 
353072Smckusic /*
36750Speter  *	rummage through a `constant' set (i.e. anything within [ ]'s) tree
37750Speter  *	and decide if this is a compile time constant set or a runtime set.
38750Speter  *	this information is returned in a structure passed from the caller.
39750Speter  *	while rummaging, this also reorders the tree so that all ranges
40750Speter  *	preceed all singletons.
41750Speter  */
42750Speter bool
43750Speter precset( r , settype , csetp )
44*15927Sthien 	struct tnode	*r;
45750Speter 	struct nl	*settype;
46750Speter 	struct csetstr	*csetp;
47750Speter {
48*15927Sthien 	register struct tnode	*e;
49750Speter 	register struct nl	*t;
50750Speter 	register struct nl	*exptype;
51*15927Sthien 	register struct tnode	*el;
52*15927Sthien 	register struct tnode	*pairp;
53*15927Sthien 	register struct tnode	*singp;
54*15927Sthien 	struct tnode		*ip;
553072Smckusic 	int			lower;
563072Smckusic 	int			upper;
57750Speter 	bool			setofint;
58750Speter 
59750Speter 	csetp -> csettype = NIL;
60750Speter 	csetp -> paircnt = 0;
61750Speter 	csetp -> singcnt = 0;
62750Speter 	csetp -> comptime = TRUE;
63750Speter 	setofint = FALSE;
64750Speter 	if ( settype != NIL ) {
65750Speter 	    if ( settype -> class == SET ) {
66750Speter 		    /*
67750Speter 		     *	the easy case, we are told the type of the set.
68750Speter 		     */
69750Speter 		exptype = settype -> type;
70750Speter 	    } else {
71750Speter 		    /*
72750Speter 		     *	we are told the type, but it's not a set
73750Speter 		     *	supposedly possible if someone tries
74750Speter 		     *	e.g string context [1,2] = 'abc'
75750Speter 		     */
76750Speter 		error("Constant set involved in non set context");
77750Speter 		return csetp -> comptime;
78750Speter 	    }
79750Speter 	} else {
80750Speter 		/*
81750Speter 		 * So far we have no indication
82750Speter 		 * of what the set type should be.
83750Speter 		 * We "look ahead" and try to infer
84750Speter 		 * The type of the constant set
85750Speter 		 * by evaluating one of its members.
86750Speter 		 */
87*15927Sthien 	    e = r->cset_node.el_list;
88750Speter 	    if (e == NIL) {
89750Speter 		    /*
901552Speter 		     *	tentative for [], return type of `intset'
91750Speter 		     */
92*15927Sthien 		settype = lookup( (char *) intset );
931552Speter 		if ( settype == NIL ) {
941552Speter 		    panic( "empty set" );
951552Speter 		}
961552Speter 		settype = settype -> type;
971552Speter 		if ( settype == NIL ) {
981552Speter 		    return csetp -> comptime;
991552Speter 		}
1001552Speter 		if ( isnta( settype , "t" ) ) {
1011552Speter 		    error("Set default type \"intset\" is not a set");
1021552Speter 		    return csetp -> comptime;
1031552Speter 		}
1041552Speter 		csetp -> csettype = settype;
1053170Smckusic 		setran( settype -> type );
1063072Smckusic 		if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1073072Smckusic 			csetp -> comptime = FALSE;
108750Speter 		return csetp -> comptime;
109750Speter 	    }
110*15927Sthien 	    e = e->list_node.list;
111750Speter 	    if (e == NIL) {
112750Speter 		return csetp -> comptime;
113750Speter 	    }
114*15927Sthien 	    if (e->tag == T_RANG) {
115*15927Sthien 		    e = e->rang.expr1;
116750Speter 	    }
117750Speter 	    codeoff();
118*15927Sthien 	    t = rvalue(e, NLNIL , RREQ );
119750Speter 	    codeon();
120750Speter 	    if (t == NIL) {
121750Speter 		return csetp -> comptime;
122750Speter 	    }
123750Speter 		/*
124750Speter 		 * The type of the set, settype, is
125750Speter 		 * deemed to be a set of the base type
126750Speter 		 * of t, which we call exptype.  If,
127750Speter 		 * however, this would involve a
128750Speter 		 * "set of integer", we cop out
129750Speter 		 * and use "intset"'s current scoped
130750Speter 		 * type instead.
131750Speter 		 */
132750Speter 	    if (isa(t, "r")) {
133750Speter 		    error("Sets may not have 'real' elements");
134750Speter 		    return csetp -> comptime;
135750Speter 	    }
136750Speter 	    if (isnta(t, "bcsi")) {
137750Speter 		    error("Set elements must be scalars, not %ss", nameof(t));
138750Speter 		    return csetp -> comptime;
139750Speter 	    }
140750Speter 	    if (isa(t, "i")) {
141*15927Sthien 		    settype = lookup((char *) intset);
142750Speter 		    if (settype == NIL)
143750Speter 			    panic("intset");
144750Speter 		    settype = settype->type;
145750Speter 		    if (settype == NIL)
146750Speter 			    return csetp -> comptime;
147750Speter 		    if (isnta(settype, "t")) {
148750Speter 			    error("Set default type \"intset\" is not a set");
149750Speter 			    return csetp -> comptime;
150750Speter 		    }
151750Speter 		    exptype = settype->type;
152750Speter 			/*
153750Speter 			 *	say we are doing an intset
154750Speter 			 *	but, if we get out of range errors for intset
155750Speter 			 *	we punt constructing the set at	compile time.
156750Speter 			 */
157750Speter 		    setofint = TRUE;
158750Speter 	    } else {
159750Speter 			exptype = t->type;
160750Speter 			if (exptype == NIL)
161750Speter 				return csetp -> comptime;
162750Speter 			if (exptype->class != RANGE)
163750Speter 				exptype = exptype->type;
164*15927Sthien 			settype = defnl((char *) 0, SET, exptype, 0);
165750Speter 	    }
166750Speter 	}
167750Speter 	csetp -> csettype = settype;
1683072Smckusic #	ifndef CONSETS
1693072Smckusic 	    csetp -> comptime = FALSE;
1703072Smckusic #	endif CONSETS
171750Speter 	setran( exptype );
1723072Smckusic 	if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1733072Smckusic 		csetp -> comptime = FALSE;
174750Speter 	lower = set.lwrb;
175750Speter 	upper = set.lwrb + set.uprbp;
176750Speter 	pairp = NIL;
177750Speter 	singp = NIL;
178750Speter 	codeoff();
179*15927Sthien 	while ( el = r->cset_node.el_list ) {
180*15927Sthien 		e = el->list_node.list;
181750Speter 		if (e == NIL) {
182750Speter 			    /*
183750Speter 			     *	don't hang this one anywhere.
184750Speter 			     */
185750Speter 			csetp -> csettype = NIL;
186*15927Sthien 			r->cset_node.el_list = el->list_node.next;
187750Speter 			continue;
188750Speter 		}
189*15927Sthien 		if (e->tag == T_RANG) {
190*15927Sthien 			if ( csetp -> comptime && constval( e->rang.expr2 ) ) {
1913072Smckusic #ifdef CONSETS
192750Speter 			    t = con.ctype;
1933072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
194750Speter 				if ( setofint ) {
195750Speter 				    csetp -> comptime = FALSE;
196750Speter 				} else {
1973072Smckusic 				    error("Range upper bound of %D out of set bounds" , ((long)con.crval) );
198750Speter 				    csetp -> csettype = NIL;
199750Speter 				}
200750Speter 			    }
2013072Smckusic #endif CONSETS
202750Speter 			} else {
203750Speter 			    csetp -> comptime = FALSE;
204*15927Sthien 			    t = rvalue(e->rang.expr2, NLNIL , RREQ );
205750Speter 			    if (t == NIL) {
206*15927Sthien 				    (void) rvalue(e->rang.expr1, NLNIL , RREQ );
207750Speter 				    goto pairhang;
208750Speter 			    }
209750Speter 			}
210*15927Sthien 			if (incompat(t, exptype, e->rang.expr2)) {
211750Speter 				cerror("Upper bound of element type clashed with set type in constant set");
212750Speter 			}
213*15927Sthien 			if ( csetp -> comptime && constval( e->rang.expr1 ) ) {
2143072Smckusic #ifdef CONSETS
215750Speter 			    t = con.ctype;
2163072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
217750Speter 				if ( setofint ) {
218750Speter 				    csetp -> comptime = FALSE;
219750Speter 				} else {
2203072Smckusic 				    error("Range lower bound of %D out of set bounds" , ((long)con.crval) );
221750Speter 				    csetp -> csettype = NIL;
222750Speter 				}
223750Speter 			    }
2243072Smckusic #endif CONSETS
225750Speter 			} else {
226750Speter 			    csetp -> comptime = FALSE;
227*15927Sthien 			    t = rvalue(e->rang.expr1, NLNIL , RREQ );
228750Speter 			    if (t == NIL) {
229750Speter 				    goto pairhang;
230750Speter 			    }
231750Speter 			}
232*15927Sthien 			if (incompat(t, exptype, e->rang.expr1)) {
233750Speter 				cerror("Lower bound of element type clashed with set type in constant set");
234750Speter 			}
235750Speter pairhang:
236750Speter 			    /*
237750Speter 			     *	remove this range from the tree list and
238750Speter 			     *	hang it on the pairs list.
239750Speter 			     */
240*15927Sthien 			ip = el->list_node.next;
241*15927Sthien 			el->list_node.next = pairp;
242*15927Sthien 			pairp = r->cset_node.el_list;
243*15927Sthien 			r->cset_node.el_list = ip;
244750Speter 			csetp -> paircnt++;
245750Speter 		} else {
246750Speter 			if ( csetp -> comptime && constval( e ) ) {
2473072Smckusic #ifdef CONSETS
248750Speter 			    t = con.ctype;
2493072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
250750Speter 				if ( setofint ) {
251750Speter 				    csetp -> comptime = FALSE;
252750Speter 				} else {
2533072Smckusic 				    error("Value of %D out of set bounds" , ((long)con.crval) );
254750Speter 				    csetp -> csettype = NIL;
255750Speter 				}
256750Speter 			    }
2573072Smckusic #endif CONSETS
258750Speter 			} else {
259750Speter 			    csetp -> comptime = FALSE;
260*15927Sthien 			    t = rvalue( e, NLNIL , RREQ );
261750Speter 			    if (t == NIL) {
262750Speter 				    goto singhang;
263750Speter 			    }
264750Speter 			}
265750Speter 			if (incompat(t, exptype, e)) {
266750Speter 				cerror("Element type clashed with set type in constant set");
267750Speter 			}
268750Speter singhang:
269750Speter 			    /*
270750Speter 			     *	take this expression off the tree list and
271750Speter 			     *	hang it on the list of singletons.
272750Speter 			     */
273*15927Sthien 			ip = el->list_node.next;
274*15927Sthien 			el->list_node.next = singp;
275*15927Sthien 			singp = r->cset_node.el_list;
276*15927Sthien 			r->cset_node.el_list = ip;
277750Speter 			csetp -> singcnt++;
278750Speter 		}
279750Speter 	}
280750Speter 	codeon();
281750Speter #	ifdef PC
282750Speter 	    if ( pairp != NIL ) {
283*15927Sthien 		for ( el = pairp ; el->list_node.next != NIL ; el = el->list_node.next ) /* void */;
284*15927Sthien 		el->list_node.next = singp;
285*15927Sthien 		r->cset_node.el_list = pairp;
286750Speter 	    } else {
287*15927Sthien 		r->cset_node.el_list = singp;
288750Speter 	    }
289750Speter #	endif PC
290750Speter #	ifdef OBJ
291750Speter 	    if ( singp != NIL ) {
292*15927Sthien 		for ( el = singp ; el->list_node.next != NIL ; el = el->list_node.next ) /* void */;
293*15927Sthien 		el->list_node.next = pairp;
294*15927Sthien 		r->cset_node.el_list = singp;
295750Speter 	    } else {
296*15927Sthien 		r->cset_node.el_list = pairp;
297750Speter 	    }
298750Speter #	endif OBJ
299750Speter 	if ( csetp -> csettype == NIL ) {
300750Speter 	    csetp -> comptime = TRUE;
301750Speter 	}
302750Speter 	return csetp -> comptime;
303750Speter }
304750Speter 
3053072Smckusic #ifdef CONSETS
306750Speter     /*
307750Speter      *	mask[i] has the low i bits turned off.
308750Speter      */
309750Speter long	mask[] = {
3103072Smckusic #		ifdef DEC11
311750Speter 		    0xffffffff , 0xfffffffe , 0xfffffffc , 0xfffffff8 ,
312750Speter 		    0xfffffff0 , 0xffffffe0 , 0xffffffc0 , 0xffffff80 ,
313750Speter 		    0xffffff00 , 0xfffffe00 , 0xfffffc00 , 0xfffff800 ,
314750Speter 		    0xfffff000 , 0xffffe000 , 0xffffc000 , 0xffff8000 ,
315750Speter 		    0xffff0000 , 0xfffe0000 , 0xfffc0000 , 0xfff80000 ,
316750Speter 		    0xfff00000 , 0xffe00000 , 0xffc00000 , 0xff800000 ,
317750Speter 		    0xff000000 , 0xfe000000 , 0xfc000000 , 0xf8000000 ,
318750Speter 		    0xf0000000 , 0xe0000000 , 0xc0000000 , 0x80000000 ,
319750Speter 		    0x00000000
3203072Smckusic #		else
3213072Smckusic 		    0xffffffff , 0xfeffffff , 0xfcffffff , 0xf8ffffff ,
3223072Smckusic 		    0xf0ffffff , 0xe0ffffff , 0xc0ffffff , 0x80ffffff ,
3233072Smckusic 		    0x00ffffff , 0x00feffff , 0x00fcffff , 0x00f8ffff ,
3243072Smckusic 		    0x00f0ffff , 0x00e0ffff , 0x00c0ffff , 0x0080ffff ,
3253072Smckusic 		    0x0000ffff , 0x0000feff , 0x0000fcff , 0x0000f8ff ,
3263072Smckusic 		    0x0000f0ff , 0x0000e0ff , 0x0000c0ff , 0x000080ff ,
3273072Smckusic 		    0x000000ff , 0x000000fe , 0x000000fc , 0x000000f8 ,
3283072Smckusic 		    0x000000f0 , 0x000000e0 , 0x000000c0 , 0x00000080 ,
3293072Smckusic 		    0x00000000
3303072Smckusic #		endif DEC11
3313072Smckusic 	    };
332750Speter     /*
333750Speter      *	given a csetstr, either
334750Speter      *	    put out a compile time constant set and an lvalue to it.
335750Speter      *	or
336750Speter      *	    put out rvalues for the singletons and the pairs
337750Speter      *	    and counts of each.
338750Speter      */
3393072Smckusic #endif CONSETS
340750Speter postcset( r , csetp )
341*15927Sthien     struct tnode	*r;
342750Speter     struct csetstr	*csetp;
343750Speter     {
344*15927Sthien 	register struct tnode	*el;
345*15927Sthien 	register struct tnode	*e;
346750Speter 	int		lower;
347750Speter 	int		upper;
348750Speter 	int		lowerdiv;
349750Speter 	int		lowermod;
350750Speter 	int		upperdiv;
351750Speter 	int		uppermod;
352750Speter 	long		*lp;
353750Speter 	long		*limit;
3543072Smckusic 	long		tempset[ COMPSETSZE ];
355750Speter 	long		temp;
3563072Smckusic 	char		*cp;
3573072Smckusic #	ifdef PC
358*15927Sthien 	    int		label;
3593072Smckusic 	    char	labelname[ BUFSIZ ];
3603072Smckusic #	endif PC
361750Speter 
362750Speter 	if ( csetp -> comptime ) {
3633072Smckusic #ifdef CONSETS
364750Speter 	    setran( ( csetp -> csettype ) -> type );
3653072Smckusic 	    limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
366750Speter 	    for ( lp = &tempset[0] ; lp < limit ; lp++ ) {
367750Speter 		*lp = 0;
368750Speter 	    }
369*15927Sthien 	    for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
370*15927Sthien 		e = el->list_node.list;
371*15927Sthien 		if ( e->tag == T_RANG ) {
372*15927Sthien 		    (void) constval( e->rang.expr1 );
3733072Smckusic 		    lower = con.crval;
374*15927Sthien 		    (void) constval( e->rang.expr2 );
3753072Smckusic 		    upper = con.crval;
376750Speter 		    if ( upper < lower ) {
377750Speter 			continue;
378750Speter 		    }
3793072Smckusic 		    lowerdiv = ( lower - set.lwrb ) >> LG2BITSLONG;
3803072Smckusic 		    lowermod = ( lower - set.lwrb ) & MSKBITSLONG;
3813072Smckusic 		    upperdiv = ( upper - set.lwrb ) >> LG2BITSLONG;
3823072Smckusic 		    uppermod = ( upper - set.lwrb ) & MSKBITSLONG;
383750Speter 		    temp = mask[ lowermod ];
384750Speter 		    if ( lowerdiv == upperdiv ) {
385750Speter 			temp &= ~mask[ uppermod + 1 ];
386750Speter 		    }
387750Speter 		    tempset[ lowerdiv ] |= temp;
388750Speter 		    limit = &tempset[ upperdiv-1 ];
389750Speter 		    for ( lp = &tempset[ lowerdiv+1 ] ; lp <= limit ; lp++ ) {
3903072Smckusic 			*lp |= 0xffffffff;
391750Speter 		    }
392750Speter 		    if ( lowerdiv != upperdiv ) {
393750Speter 			tempset[ upperdiv ] |= ~mask[ uppermod + 1 ];
394750Speter 		    }
395750Speter 		} else {
396*15927Sthien 		    (void) constval( e );
3973072Smckusic 		    temp = con.crval - set.lwrb;
3983072Smckusic 		    cp = (char *)tempset;
3993072Smckusic 		    cp[temp >> LG2BITSBYTE] |= (1 << (temp & MSKBITSBYTE));
400750Speter 		}
401750Speter 	    }
4023315Speter 	    if ( !CGENNING )
403750Speter 		return;
404750Speter #	    ifdef PC
405*15927Sthien 		label = (int) getlab();
40610652Speter 		putprintf("	.data" , 0 );
40710652Speter 		aligndot(A_SET);
408*15927Sthien 		(void) putlab( (char *) label );
409750Speter 		lp = &( tempset[0] );
4103072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
41110652Speter 		while (lp < limit) {
412*15927Sthien 		    putprintf("	.long	0x%x", 1, (int) (*lp++));
41310652Speter 		    for (temp = 2 ; temp <= 8 && lp < limit ; temp++) {
414*15927Sthien 			putprintf(",0x%x", 1, (int) (*lp++));
415750Speter 		    }
41610652Speter 		    putprintf("", 0);
417750Speter 		}
41810652Speter 		putprintf("	.text", 0);
419*15927Sthien 		sprintf( labelname , PREFIXFORMAT , LABELPREFIX , (char *) label );
420750Speter 		putleaf( P2ICON , 0 , 0 , P2PTR | P2STRTY , labelname );
421750Speter #	    endif PC
422750Speter #	    ifdef OBJ
423*15927Sthien 		(void) put(2, O_CON, (int)(((set.uprbp >> LG2BITSLONG) + 1) *
4243072Smckusic 				 (BITSPERLONG >> LG2BITSBYTE)));
425750Speter 		lp = &( tempset[0] );
4263072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
427750Speter 		while ( lp < limit ) {
428*15927Sthien 		    (void) put(2, O_CASE4, (int) (*lp ++));
429750Speter 		}
430750Speter #	    endif OBJ
4313072Smckusic #else
4323072Smckusic 		panic("const cset");
4333072Smckusic #endif CONSETS
434750Speter 	} else {
435750Speter #	    ifdef PC
436*15927Sthien 		putleaf( P2ICON , (int) csetp -> paircnt , 0 , P2INT , (char *) 0 );
437750Speter 		putop( P2LISTOP , P2INT );
438*15927Sthien 		putleaf( P2ICON , (int) csetp -> singcnt , 0 , P2INT , (char *) 0 );
439750Speter 		putop( P2LISTOP , P2INT );
440*15927Sthien 		for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
441*15927Sthien 		    e = el->list_node.list;
442*15927Sthien 		    if ( e->tag == T_RANG ) {
443*15927Sthien 			(void) rvalue( e->rang.expr2 , NLNIL , RREQ );
444750Speter 			putop( P2LISTOP , P2INT );
445*15927Sthien 			(void) rvalue( e->rang.expr1 , NLNIL , RREQ );
446750Speter 			putop( P2LISTOP , P2INT );
447750Speter 		    } else {
448*15927Sthien 			(void) rvalue( e , NLNIL , RREQ );
449750Speter 			putop( P2LISTOP , P2INT );
450750Speter 		    }
451750Speter 		}
452750Speter #	    endif PC
453750Speter #	    ifdef OBJ
454*15927Sthien 		for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
455*15927Sthien 		    e = el->list_node.list;
456*15927Sthien 		    if ( e->tag == T_RANG ) {
457*15927Sthien 			(void) stkrval( e->rang.expr1 , NLNIL , (long) RREQ );
458*15927Sthien 			(void) stkrval( e->rang.expr2 , NLNIL , (long) RREQ );
459750Speter 		    } else {
460*15927Sthien 			(void) stkrval( e , NLNIL , (long) RREQ );
461750Speter 		    }
462750Speter 		}
463*15927Sthien 		(void) put(2 , O_CON24 , (int)csetp -> singcnt );
464*15927Sthien 		(void) put(2 , O_CON24 , (int)csetp -> paircnt );
465750Speter #	    endif OBJ
466750Speter 	}
467750Speter }
468