xref: /csrg-svn/usr.bin/pascal/src/cset.c (revision 62205)
148116Sbostic /*-
2*62205Sbostic  * Copyright (c) 1980, 1993
3*62205Sbostic  *	The Regents of the University of California.  All rights reserved.
448116Sbostic  *
548116Sbostic  * %sccs.include.redist.c%
622161Sdist  */
7750Speter 
815927Sthien #ifndef lint
9*62205Sbostic static char sccsid[] = "@(#)cset.c	8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11750Speter 
12750Speter #include "whoami.h"
13750Speter #include "0.h"
14750Speter #include "tree.h"
15750Speter #include "opcode.h"
16750Speter #include "objfmt.h"
1715927Sthien #include "tree_ty.h"
183072Smckusic #ifdef PC
19750Speter #include "pc.h"
2018455Sralph #include <pcc.h>
2110652Speter #include "align.h"
223072Smckusic #endif PC
23750Speter 
24750Speter /*
253072Smckusic  * CONSETS causes compile time constant sets to be constructed here.
263072Smckusic  *
273072Smckusic  * COMPSETSZE defines the maximum number of longs to be used in
283072Smckusic  *	constant set construction
293072Smckusic  */
303072Smckusic #define CONSETS
313072Smckusic #define COMPSETSZE 10
323072Smckusic 
333072Smckusic #define BITSPERBYTE 8
343072Smckusic #define BITSPERLONG 32
353072Smckusic #define LG2BITSBYTE 3
363072Smckusic #define MSKBITSBYTE 0x07
373072Smckusic #define LG2BITSLONG 5
383072Smckusic #define MSKBITSLONG 0x1f
393072Smckusic 
403072Smckusic /*
41750Speter  *	rummage through a `constant' set (i.e. anything within [ ]'s) tree
42750Speter  *	and decide if this is a compile time constant set or a runtime set.
43750Speter  *	this information is returned in a structure passed from the caller.
44750Speter  *	while rummaging, this also reorders the tree so that all ranges
45750Speter  *	preceed all singletons.
46750Speter  */
47750Speter bool
precset(r,settype,csetp)48750Speter precset( r , settype , csetp )
4915927Sthien 	struct tnode	*r;
50750Speter 	struct nl	*settype;
51750Speter 	struct csetstr	*csetp;
52750Speter {
5315927Sthien 	register struct tnode	*e;
54750Speter 	register struct nl	*t;
55750Speter 	register struct nl	*exptype;
5615927Sthien 	register struct tnode	*el;
5715927Sthien 	register struct tnode	*pairp;
5815927Sthien 	register struct tnode	*singp;
5915927Sthien 	struct tnode		*ip;
603072Smckusic 	int			lower;
613072Smckusic 	int			upper;
62750Speter 	bool			setofint;
63750Speter 
64750Speter 	csetp -> csettype = NIL;
65750Speter 	csetp -> paircnt = 0;
66750Speter 	csetp -> singcnt = 0;
67750Speter 	csetp -> comptime = TRUE;
68750Speter 	setofint = FALSE;
69750Speter 	if ( settype != NIL ) {
70750Speter 	    if ( settype -> class == SET ) {
71750Speter 		    /*
72750Speter 		     *	the easy case, we are told the type of the set.
73750Speter 		     */
74750Speter 		exptype = settype -> type;
75750Speter 	    } else {
76750Speter 		    /*
77750Speter 		     *	we are told the type, but it's not a set
78750Speter 		     *	supposedly possible if someone tries
79750Speter 		     *	e.g string context [1,2] = 'abc'
80750Speter 		     */
81750Speter 		error("Constant set involved in non set context");
82750Speter 		return csetp -> comptime;
83750Speter 	    }
84750Speter 	} else {
85750Speter 		/*
86750Speter 		 * So far we have no indication
87750Speter 		 * of what the set type should be.
88750Speter 		 * We "look ahead" and try to infer
89750Speter 		 * The type of the constant set
90750Speter 		 * by evaluating one of its members.
91750Speter 		 */
9215927Sthien 	    e = r->cset_node.el_list;
93750Speter 	    if (e == NIL) {
94750Speter 		    /*
951552Speter 		     *	tentative for [], return type of `intset'
96750Speter 		     */
9715927Sthien 		settype = lookup( (char *) intset );
981552Speter 		if ( settype == NIL ) {
991552Speter 		    panic( "empty set" );
1001552Speter 		}
1011552Speter 		settype = settype -> type;
1021552Speter 		if ( settype == NIL ) {
1031552Speter 		    return csetp -> comptime;
1041552Speter 		}
1051552Speter 		if ( isnta( settype , "t" ) ) {
1061552Speter 		    error("Set default type \"intset\" is not a set");
1071552Speter 		    return csetp -> comptime;
1081552Speter 		}
1091552Speter 		csetp -> csettype = settype;
1103170Smckusic 		setran( settype -> type );
1113072Smckusic 		if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1123072Smckusic 			csetp -> comptime = FALSE;
113750Speter 		return csetp -> comptime;
114750Speter 	    }
11515927Sthien 	    e = e->list_node.list;
116750Speter 	    if (e == NIL) {
117750Speter 		return csetp -> comptime;
118750Speter 	    }
11915927Sthien 	    if (e->tag == T_RANG) {
12015927Sthien 		    e = e->rang.expr1;
121750Speter 	    }
122750Speter 	    codeoff();
12315927Sthien 	    t = rvalue(e, NLNIL , RREQ );
124750Speter 	    codeon();
125750Speter 	    if (t == NIL) {
126750Speter 		return csetp -> comptime;
127750Speter 	    }
128750Speter 		/*
129750Speter 		 * The type of the set, settype, is
130750Speter 		 * deemed to be a set of the base type
131750Speter 		 * of t, which we call exptype.  If,
132750Speter 		 * however, this would involve a
133750Speter 		 * "set of integer", we cop out
134750Speter 		 * and use "intset"'s current scoped
135750Speter 		 * type instead.
136750Speter 		 */
137750Speter 	    if (isa(t, "r")) {
138750Speter 		    error("Sets may not have 'real' elements");
139750Speter 		    return csetp -> comptime;
140750Speter 	    }
141750Speter 	    if (isnta(t, "bcsi")) {
142750Speter 		    error("Set elements must be scalars, not %ss", nameof(t));
143750Speter 		    return csetp -> comptime;
144750Speter 	    }
145750Speter 	    if (isa(t, "i")) {
14615927Sthien 		    settype = lookup((char *) intset);
147750Speter 		    if (settype == NIL)
148750Speter 			    panic("intset");
149750Speter 		    settype = settype->type;
150750Speter 		    if (settype == NIL)
151750Speter 			    return csetp -> comptime;
152750Speter 		    if (isnta(settype, "t")) {
153750Speter 			    error("Set default type \"intset\" is not a set");
154750Speter 			    return csetp -> comptime;
155750Speter 		    }
156750Speter 		    exptype = settype->type;
157750Speter 			/*
158750Speter 			 *	say we are doing an intset
159750Speter 			 *	but, if we get out of range errors for intset
160750Speter 			 *	we punt constructing the set at	compile time.
161750Speter 			 */
162750Speter 		    setofint = TRUE;
163750Speter 	    } else {
164750Speter 			exptype = t->type;
165750Speter 			if (exptype == NIL)
166750Speter 				return csetp -> comptime;
167750Speter 			if (exptype->class != RANGE)
168750Speter 				exptype = exptype->type;
16915927Sthien 			settype = defnl((char *) 0, SET, exptype, 0);
170750Speter 	    }
171750Speter 	}
172750Speter 	csetp -> csettype = settype;
1733072Smckusic #	ifndef CONSETS
1743072Smckusic 	    csetp -> comptime = FALSE;
1753072Smckusic #	endif CONSETS
176750Speter 	setran( exptype );
1773072Smckusic 	if (((set.uprbp + 1) >> LG2BITSLONG) >= COMPSETSZE)
1783072Smckusic 		csetp -> comptime = FALSE;
179750Speter 	lower = set.lwrb;
180750Speter 	upper = set.lwrb + set.uprbp;
181750Speter 	pairp = NIL;
182750Speter 	singp = NIL;
183750Speter 	codeoff();
18415927Sthien 	while ( el = r->cset_node.el_list ) {
18515927Sthien 		e = el->list_node.list;
186750Speter 		if (e == NIL) {
187750Speter 			    /*
188750Speter 			     *	don't hang this one anywhere.
189750Speter 			     */
190750Speter 			csetp -> csettype = NIL;
19115927Sthien 			r->cset_node.el_list = el->list_node.next;
192750Speter 			continue;
193750Speter 		}
19415927Sthien 		if (e->tag == T_RANG) {
19515927Sthien 			if ( csetp -> comptime && constval( e->rang.expr2 ) ) {
1963072Smckusic #ifdef CONSETS
197750Speter 			    t = con.ctype;
1983072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
199750Speter 				if ( setofint ) {
200750Speter 				    csetp -> comptime = FALSE;
201750Speter 				} else {
2023072Smckusic 				    error("Range upper bound of %D out of set bounds" , ((long)con.crval) );
203750Speter 				    csetp -> csettype = NIL;
204750Speter 				}
205750Speter 			    }
2063072Smckusic #endif CONSETS
207750Speter 			} else {
208750Speter 			    csetp -> comptime = FALSE;
20915927Sthien 			    t = rvalue(e->rang.expr2, NLNIL , RREQ );
210750Speter 			    if (t == NIL) {
21115927Sthien 				    (void) rvalue(e->rang.expr1, NLNIL , RREQ );
212750Speter 				    goto pairhang;
213750Speter 			    }
214750Speter 			}
21515927Sthien 			if (incompat(t, exptype, e->rang.expr2)) {
216750Speter 				cerror("Upper bound of element type clashed with set type in constant set");
217750Speter 			}
21815927Sthien 			if ( csetp -> comptime && constval( e->rang.expr1 ) ) {
2193072Smckusic #ifdef CONSETS
220750Speter 			    t = con.ctype;
2213072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
222750Speter 				if ( setofint ) {
223750Speter 				    csetp -> comptime = FALSE;
224750Speter 				} else {
2253072Smckusic 				    error("Range lower bound of %D out of set bounds" , ((long)con.crval) );
226750Speter 				    csetp -> csettype = NIL;
227750Speter 				}
228750Speter 			    }
2293072Smckusic #endif CONSETS
230750Speter 			} else {
231750Speter 			    csetp -> comptime = FALSE;
23215927Sthien 			    t = rvalue(e->rang.expr1, NLNIL , RREQ );
233750Speter 			    if (t == NIL) {
234750Speter 				    goto pairhang;
235750Speter 			    }
236750Speter 			}
23715927Sthien 			if (incompat(t, exptype, e->rang.expr1)) {
238750Speter 				cerror("Lower bound of element type clashed with set type in constant set");
239750Speter 			}
240750Speter pairhang:
241750Speter 			    /*
242750Speter 			     *	remove this range from the tree list and
243750Speter 			     *	hang it on the pairs list.
244750Speter 			     */
24515927Sthien 			ip = el->list_node.next;
24615927Sthien 			el->list_node.next = pairp;
24715927Sthien 			pairp = r->cset_node.el_list;
24815927Sthien 			r->cset_node.el_list = ip;
249750Speter 			csetp -> paircnt++;
250750Speter 		} else {
251750Speter 			if ( csetp -> comptime && constval( e ) ) {
2523072Smckusic #ifdef CONSETS
253750Speter 			    t = con.ctype;
2543072Smckusic 			    if ( con.crval < lower || con.crval > upper ) {
255750Speter 				if ( setofint ) {
256750Speter 				    csetp -> comptime = FALSE;
257750Speter 				} else {
2583072Smckusic 				    error("Value of %D out of set bounds" , ((long)con.crval) );
259750Speter 				    csetp -> csettype = NIL;
260750Speter 				}
261750Speter 			    }
2623072Smckusic #endif CONSETS
263750Speter 			} else {
264750Speter 			    csetp -> comptime = FALSE;
26515927Sthien 			    t = rvalue( e, NLNIL , RREQ );
266750Speter 			    if (t == NIL) {
267750Speter 				    goto singhang;
268750Speter 			    }
269750Speter 			}
270750Speter 			if (incompat(t, exptype, e)) {
271750Speter 				cerror("Element type clashed with set type in constant set");
272750Speter 			}
273750Speter singhang:
274750Speter 			    /*
275750Speter 			     *	take this expression off the tree list and
276750Speter 			     *	hang it on the list of singletons.
277750Speter 			     */
27815927Sthien 			ip = el->list_node.next;
27915927Sthien 			el->list_node.next = singp;
28015927Sthien 			singp = r->cset_node.el_list;
28115927Sthien 			r->cset_node.el_list = ip;
282750Speter 			csetp -> singcnt++;
283750Speter 		}
284750Speter 	}
285750Speter 	codeon();
286750Speter #	ifdef PC
287750Speter 	    if ( pairp != NIL ) {
28815927Sthien 		for ( el = pairp ; el->list_node.next != NIL ; el = el->list_node.next ) /* void */;
28915927Sthien 		el->list_node.next = singp;
29015927Sthien 		r->cset_node.el_list = pairp;
291750Speter 	    } else {
29215927Sthien 		r->cset_node.el_list = singp;
293750Speter 	    }
294750Speter #	endif PC
295750Speter #	ifdef OBJ
296750Speter 	    if ( singp != NIL ) {
29715927Sthien 		for ( el = singp ; el->list_node.next != NIL ; el = el->list_node.next ) /* void */;
29815927Sthien 		el->list_node.next = pairp;
29915927Sthien 		r->cset_node.el_list = singp;
300750Speter 	    } else {
30115927Sthien 		r->cset_node.el_list = pairp;
302750Speter 	    }
303750Speter #	endif OBJ
304750Speter 	if ( csetp -> csettype == NIL ) {
305750Speter 	    csetp -> comptime = TRUE;
306750Speter 	}
307750Speter 	return csetp -> comptime;
308750Speter }
309750Speter 
3103072Smckusic #ifdef CONSETS
311750Speter     /*
312750Speter      *	mask[i] has the low i bits turned off.
313750Speter      */
314750Speter long	mask[] = {
3153072Smckusic #		ifdef DEC11
316750Speter 		    0xffffffff , 0xfffffffe , 0xfffffffc , 0xfffffff8 ,
317750Speter 		    0xfffffff0 , 0xffffffe0 , 0xffffffc0 , 0xffffff80 ,
318750Speter 		    0xffffff00 , 0xfffffe00 , 0xfffffc00 , 0xfffff800 ,
319750Speter 		    0xfffff000 , 0xffffe000 , 0xffffc000 , 0xffff8000 ,
320750Speter 		    0xffff0000 , 0xfffe0000 , 0xfffc0000 , 0xfff80000 ,
321750Speter 		    0xfff00000 , 0xffe00000 , 0xffc00000 , 0xff800000 ,
322750Speter 		    0xff000000 , 0xfe000000 , 0xfc000000 , 0xf8000000 ,
323750Speter 		    0xf0000000 , 0xe0000000 , 0xc0000000 , 0x80000000 ,
324750Speter 		    0x00000000
3253072Smckusic #		else
3263072Smckusic 		    0xffffffff , 0xfeffffff , 0xfcffffff , 0xf8ffffff ,
3273072Smckusic 		    0xf0ffffff , 0xe0ffffff , 0xc0ffffff , 0x80ffffff ,
3283072Smckusic 		    0x00ffffff , 0x00feffff , 0x00fcffff , 0x00f8ffff ,
3293072Smckusic 		    0x00f0ffff , 0x00e0ffff , 0x00c0ffff , 0x0080ffff ,
3303072Smckusic 		    0x0000ffff , 0x0000feff , 0x0000fcff , 0x0000f8ff ,
3313072Smckusic 		    0x0000f0ff , 0x0000e0ff , 0x0000c0ff , 0x000080ff ,
3323072Smckusic 		    0x000000ff , 0x000000fe , 0x000000fc , 0x000000f8 ,
3333072Smckusic 		    0x000000f0 , 0x000000e0 , 0x000000c0 , 0x00000080 ,
3343072Smckusic 		    0x00000000
3353072Smckusic #		endif DEC11
3363072Smckusic 	    };
337750Speter     /*
338750Speter      *	given a csetstr, either
339750Speter      *	    put out a compile time constant set and an lvalue to it.
340750Speter      *	or
341750Speter      *	    put out rvalues for the singletons and the pairs
342750Speter      *	    and counts of each.
343750Speter      */
3443072Smckusic #endif CONSETS
345750Speter postcset( r , csetp )
34615927Sthien     struct tnode	*r;
347750Speter     struct csetstr	*csetp;
348750Speter     {
34915927Sthien 	register struct tnode	*el;
35015927Sthien 	register struct tnode	*e;
351750Speter 	int		lower;
352750Speter 	int		upper;
353750Speter 	int		lowerdiv;
354750Speter 	int		lowermod;
355750Speter 	int		upperdiv;
356750Speter 	int		uppermod;
357750Speter 	long		*lp;
358750Speter 	long		*limit;
3593072Smckusic 	long		tempset[ COMPSETSZE ];
360750Speter 	long		temp;
3613072Smckusic 	char		*cp;
3623072Smckusic #	ifdef PC
36315927Sthien 	    int		label;
3643072Smckusic 	    char	labelname[ BUFSIZ ];
3653072Smckusic #	endif PC
366750Speter 
367750Speter 	if ( csetp -> comptime ) {
3683072Smckusic #ifdef CONSETS
369750Speter 	    setran( ( csetp -> csettype ) -> type );
3703072Smckusic 	    limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
371750Speter 	    for ( lp = &tempset[0] ; lp < limit ; lp++ ) {
372750Speter 		*lp = 0;
373750Speter 	    }
37415927Sthien 	    for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
37515927Sthien 		e = el->list_node.list;
37615927Sthien 		if ( e->tag == T_RANG ) {
37715927Sthien 		    (void) constval( e->rang.expr1 );
3783072Smckusic 		    lower = con.crval;
37915927Sthien 		    (void) constval( e->rang.expr2 );
3803072Smckusic 		    upper = con.crval;
381750Speter 		    if ( upper < lower ) {
382750Speter 			continue;
383750Speter 		    }
3843072Smckusic 		    lowerdiv = ( lower - set.lwrb ) >> LG2BITSLONG;
3853072Smckusic 		    lowermod = ( lower - set.lwrb ) & MSKBITSLONG;
3863072Smckusic 		    upperdiv = ( upper - set.lwrb ) >> LG2BITSLONG;
3873072Smckusic 		    uppermod = ( upper - set.lwrb ) & MSKBITSLONG;
388750Speter 		    temp = mask[ lowermod ];
389750Speter 		    if ( lowerdiv == upperdiv ) {
390750Speter 			temp &= ~mask[ uppermod + 1 ];
391750Speter 		    }
392750Speter 		    tempset[ lowerdiv ] |= temp;
393750Speter 		    limit = &tempset[ upperdiv-1 ];
394750Speter 		    for ( lp = &tempset[ lowerdiv+1 ] ; lp <= limit ; lp++ ) {
3953072Smckusic 			*lp |= 0xffffffff;
396750Speter 		    }
397750Speter 		    if ( lowerdiv != upperdiv ) {
398750Speter 			tempset[ upperdiv ] |= ~mask[ uppermod + 1 ];
399750Speter 		    }
400750Speter 		} else {
40115927Sthien 		    (void) constval( e );
4023072Smckusic 		    temp = con.crval - set.lwrb;
4033072Smckusic 		    cp = (char *)tempset;
4043072Smckusic 		    cp[temp >> LG2BITSBYTE] |= (1 << (temp & MSKBITSBYTE));
405750Speter 		}
406750Speter 	    }
4073315Speter 	    if ( !CGENNING )
408750Speter 		return;
409750Speter #	    ifdef PC
41015927Sthien 		label = (int) getlab();
41110652Speter 		putprintf("	.data" , 0 );
41210652Speter 		aligndot(A_SET);
41315927Sthien 		(void) putlab( (char *) label );
414750Speter 		lp = &( tempset[0] );
4153072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
41610652Speter 		while (lp < limit) {
41715927Sthien 		    putprintf("	.long	0x%x", 1, (int) (*lp++));
41810652Speter 		    for (temp = 2 ; temp <= 8 && lp < limit ; temp++) {
41915927Sthien 			putprintf(",0x%x", 1, (int) (*lp++));
420750Speter 		    }
42110652Speter 		    putprintf("", 0);
422750Speter 		}
42310652Speter 		putprintf("	.text", 0);
42415927Sthien 		sprintf( labelname , PREFIXFORMAT , LABELPREFIX , (char *) label );
42518455Sralph 		putleaf( PCC_ICON , 0 , 0 , PCCTM_PTR | PCCT_STRTY , labelname );
426750Speter #	    endif PC
427750Speter #	    ifdef OBJ
42815927Sthien 		(void) put(2, O_CON, (int)(((set.uprbp >> LG2BITSLONG) + 1) *
4293072Smckusic 				 (BITSPERLONG >> LG2BITSBYTE)));
430750Speter 		lp = &( tempset[0] );
4313072Smckusic 		limit = &tempset[ ( set.uprbp >> LG2BITSLONG ) + 1 ];
432750Speter 		while ( lp < limit ) {
43315927Sthien 		    (void) put(2, O_CASE4, (int) (*lp ++));
434750Speter 		}
435750Speter #	    endif OBJ
4363072Smckusic #else
4373072Smckusic 		panic("const cset");
4383072Smckusic #endif CONSETS
439750Speter 	} else {
440750Speter #	    ifdef PC
44118455Sralph 		putleaf( PCC_ICON , (int) csetp -> paircnt , 0 , PCCT_INT , (char *) 0 );
44218455Sralph 		putop( PCC_CM , PCCT_INT );
44318455Sralph 		putleaf( PCC_ICON , (int) csetp -> singcnt , 0 , PCCT_INT , (char *) 0 );
44418455Sralph 		putop( PCC_CM , PCCT_INT );
44515927Sthien 		for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
44615927Sthien 		    e = el->list_node.list;
44715927Sthien 		    if ( e->tag == T_RANG ) {
44815927Sthien 			(void) rvalue( e->rang.expr2 , NLNIL , RREQ );
44918455Sralph 			putop( PCC_CM , PCCT_INT );
45015927Sthien 			(void) rvalue( e->rang.expr1 , NLNIL , RREQ );
45118455Sralph 			putop( PCC_CM , PCCT_INT );
452750Speter 		    } else {
45315927Sthien 			(void) rvalue( e , NLNIL , RREQ );
45418455Sralph 			putop( PCC_CM , PCCT_INT );
455750Speter 		    }
456750Speter 		}
457750Speter #	    endif PC
458750Speter #	    ifdef OBJ
45915927Sthien 		for ( el = r->cset_node.el_list ; el != NIL ; el = el->list_node.next ) {
46015927Sthien 		    e = el->list_node.list;
46115927Sthien 		    if ( e->tag == T_RANG ) {
46215927Sthien 			(void) stkrval( e->rang.expr1 , NLNIL , (long) RREQ );
46315927Sthien 			(void) stkrval( e->rang.expr2 , NLNIL , (long) RREQ );
464750Speter 		    } else {
46515927Sthien 			(void) stkrval( e , NLNIL , (long) RREQ );
466750Speter 		    }
467750Speter 		}
46815927Sthien 		(void) put(2 , O_CON24 , (int)csetp -> singcnt );
46915927Sthien 		(void) put(2 , O_CON24 , (int)csetp -> paircnt );
470750Speter #	    endif OBJ
471750Speter 	}
472750Speter }
473