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