148116Sbostic /*-
2*62215Sbostic * Copyright (c) 1980, 1993
3*62215Sbostic * The Regents of the University of California. All rights reserved.
448116Sbostic *
548116Sbostic * %sccs.include.redist.c%
622187Sdist */
7770Speter
814741Sthien #ifndef lint
9*62215Sbostic static char sccsid[] = "@(#)rec.c 8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11770Speter
12770Speter #include "whoami.h"
13770Speter #include "0.h"
14770Speter #include "tree.h"
15770Speter #include "opcode.h"
168681Speter #include "align.h"
1714741Sthien #include "tree_ty.h"
18770Speter
198681Speter /*
208681Speter * set this to TRUE with adb to turn on record alignment/offset debugging.
218681Speter */
228681Speter bool debug_records = FALSE;
238681Speter #define DEBUG_RECORDS(x) if (debug_records) { x ; } else
248681Speter
25770Speter /*
26770Speter * Build a record namelist entry.
27770Speter * Some of the processing here is somewhat involved.
28770Speter * The basic structure we are building is as follows.
29770Speter *
308681Speter * Each record has a main RECORD entry,
318681Speter * with an attached chain of fields as ->chain;
3214741Sthien * these enclude all the fields in all the variants of this record.
338681Speter * Fields are cons'ed to the front of the ->chain list as they are discovered.
348681Speter * This is for reclook(), but not for sizing and aligning offsets.
35770Speter *
368681Speter * If there are variants to the record, NL_TAG points to the field which
378681Speter * is the tag. If its name is NIL, the tag field is unnamed, and is not
388681Speter * allocated any space in the record.
39770Speter * Attached to NL_VARNT is a chain of VARNT structures
40770Speter * describing each of the variants. These are further linked
41770Speter * through ->chain. Each VARNT has, in ->range[0] the value of
42770Speter * the associated constant, and each points at a RECORD describing
43770Speter * the subrecord through NL_VTOREC. These pointers are not unique,
44770Speter * more than one VARNT may reference the same RECORD.
45770Speter *
468681Speter * On the first pass, we traverse the parse tree and construct the namelist
478681Speter * entries. This pass fills in the alignment of each record (including
488681Speter * subrecords (the alignment of a record is the maximum of the alignments
498681Speter * of any of its fields).
508681Speter * A second pass over the namelist entries fills in the offsets of each field
518681Speter * based on the alignments required. This second pass uses the NL_FIELDLIST
528681Speter * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get
538681Speter * to fields in the order in which they were declared.
548681Speter * This second pass can not be folded into the first pass,
558681Speter * as the starting offset of all variants is the same,
568681Speter * so we must see all the variants (and especially must know their alignments)
578681Speter * before assigning offsets. With the alignments calculated (by the first
588681Speter * pass) this can be done in one top down pass, max'ing over the alignment of
598681Speter * variants before assigning offsets to any of them.
60770Speter */
61770Speter
62770Speter /*
63770Speter * P0 points to the outermost RECORD for name searches.
64770Speter */
65770Speter struct nl *P0;
66770Speter
678681Speter struct nl *
tyrec(r,off)68770Speter tyrec(r, off)
6914741Sthien struct tnode *r;
7014741Sthien int off;
71770Speter {
728681Speter struct nl *recp;
73770Speter
748681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off));
758681Speter /*
768681Speter * build namelist structure for the outermost record type.
778681Speter * then calculate offsets (starting at 0) of the fields
788681Speter * in this record and its variant subrecords.
798681Speter */
808681Speter recp = tyrec1(r, TRUE);
8114741Sthien rec_offsets(recp, (long) 0);
828681Speter return recp;
83770Speter }
84770Speter
85770Speter /*
86770Speter * Define a record namelist entry.
878681Speter * r is the tree for the record to be built.
888681Speter * first is a boolean indicating whether this is an outermost record,
898681Speter * for name lookups.
908681Speter * p is the record we define here.
918681Speter * P0was is a local which stacks the enclosing value of P0 in the stack frame,
928681Speter * since tyrec1() is recursive.
93770Speter */
94770Speter struct nl *
tyrec1(r,first)958681Speter tyrec1(r, first)
9614741Sthien register struct tnode *r; /* T_FLDLST */
978681Speter bool first;
98770Speter {
99770Speter register struct nl *p, *P0was;
100770Speter
1018681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first));
10214741Sthien p = defnl((char *) 0, RECORD, NLNIL, 0);
103770Speter P0was = P0;
104770Speter if (first)
105770Speter P0 = p;
106770Speter #ifndef PI0
1078681Speter p->align_info = A_MIN;
108770Speter #endif
10914741Sthien if (r != TR_NIL) {
11014741Sthien fields(p, r->fldlst.fix_list);
11114741Sthien variants(p, r->fldlst.variant);
112770Speter }
113770Speter P0 = P0was;
114770Speter return (p);
115770Speter }
116770Speter
117770Speter /*
118770Speter * Define the fixed part fields for p.
1198681Speter * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST].
1208681Speter * the fieldlist is a tconc structure, and is manipulated
1218681Speter * just like newlist(), addlist(), fixlist() in the parser.
122770Speter */
123770Speter fields(p, r)
124770Speter struct nl *p;
12514741Sthien struct tnode *r; /* T_LISTPP */
126770Speter {
12714741Sthien register struct tnode *fp, *tp, *ip;
1288681Speter struct nl *jp;
1298681Speter struct nl *fieldnlp;
130770Speter
1318681Speter DEBUG_RECORDS(fprintf(stderr,"[fields]\n"));
13214741Sthien for (fp = r; fp != TR_NIL; fp = fp->list_node.next) {
13314741Sthien tp = fp->list_node.list;
13414741Sthien if (tp == TR_NIL)
135770Speter continue;
13614741Sthien jp = gtype(tp->rfield.type);
13714741Sthien line = tp->rfield.line_no;
13814741Sthien for (ip = tp->rfield.id_list; ip != TR_NIL;
13914741Sthien ip = ip->list_node.next) {
14014741Sthien fieldnlp = deffld(p, (char *) ip->list_node.list, jp);
1418681Speter if ( p->ptr[NL_FIELDLIST] == NIL ) {
1428681Speter /* newlist */
1438681Speter p->ptr[NL_FIELDLIST] = fieldnlp;
1448681Speter fieldnlp->ptr[NL_FIELDLIST] = fieldnlp;
1458681Speter } else {
1468681Speter /* addlist */
1478681Speter fieldnlp->ptr[NL_FIELDLIST] =
1488681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
1498681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp;
1508681Speter p->ptr[NL_FIELDLIST] = fieldnlp;
1518681Speter }
1528681Speter }
153770Speter }
1548681Speter if ( p->ptr[NL_FIELDLIST] != NIL ) {
1558681Speter /* fixlist */
1568681Speter fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
1578681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL;
1588681Speter p->ptr[NL_FIELDLIST] = fieldnlp;
1598681Speter }
160770Speter }
161770Speter
162770Speter /*
163770Speter * Define the variants for RECORD p.
164770Speter */
165770Speter variants(p, r)
166770Speter struct nl *p;
16714741Sthien register struct tnode *r; /* T_TYVARPT */
168770Speter {
16914741Sthien register struct tnode *vc, *v;
17014741Sthien struct nl *vr;
171770Speter struct nl *ct;
172770Speter
1738681Speter DEBUG_RECORDS(fprintf(stderr,"[variants]\n"));
17414741Sthien if (r == TR_NIL)
175770Speter return;
17614741Sthien ct = gtype(r->varpt.type_id);
17714741Sthien if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) {
178770Speter error("Tag fields cannot be %ss" , nameof( ct ) );
179770Speter }
18014741Sthien line = r->varpt.line_no;
181770Speter /*
182770Speter * Want it even if r[2] is NIL so
183770Speter * we check its type in "new" and "dispose"
184770Speter * calls -- link it to NL_TAG.
185770Speter */
18614741Sthien p->ptr[NL_TAG] = deffld(p, r->varpt.cptr, ct);
18714741Sthien for (vc = r->varpt.var_list; vc != TR_NIL; vc = vc->list_node.next) {
18814741Sthien v = vc->list_node.list;
18914741Sthien if (v == TR_NIL)
190770Speter continue;
19114741Sthien vr = tyrec1(v->tyvarnt.fld_list, FALSE);
192770Speter #ifndef PI0
1938681Speter DEBUG_RECORDS(
1948681Speter fprintf(stderr,
1958681Speter "[variants] p->align_info %d vr->align_info %d\n",
1968681Speter p->align_info, vr->align_info));
1978681Speter if (vr->align_info > p->align_info) {
1988681Speter p->align_info = vr->align_info;
1998681Speter }
200770Speter #endif
20114741Sthien line = v->tyvarnt.line_no;
20214741Sthien for (v = v->tyvarnt.const_list; v != TR_NIL;
20314741Sthien v = v->list_node.next)
20414741Sthien (void) defvnt(p, v->list_node.list, vr, ct);
205770Speter }
206770Speter }
207770Speter
208770Speter /*
209770Speter * Define a field in subrecord p of record P0
210770Speter * with name s and type t.
211770Speter */
212770Speter struct nl *
deffld(p,s,t)213770Speter deffld(p, s, t)
214770Speter struct nl *p;
215770Speter register char *s;
216770Speter register struct nl *t;
217770Speter {
218770Speter register struct nl *fp;
219770Speter
2208681Speter DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s));
221770Speter if (reclook(P0, s) != NIL) {
222770Speter #ifndef PI1
223770Speter error("%s is a duplicate field name in this record", s);
224770Speter #endif
225770Speter s = NIL;
226770Speter }
227770Speter /*
2288681Speter * enter the field with its type
229770Speter */
230770Speter fp = enter(defnl(s, FIELD, t, 0));
2318681Speter /*
2328681Speter * if no name, then this is an unnamed tag,
2338681Speter * so don't link it into reclook()'s chain.
2348681Speter */
235770Speter if (s != NIL) {
236770Speter fp->chain = P0->chain;
237770Speter P0->chain = fp;
238770Speter #ifndef PI0
239770Speter /*
2408681Speter * and the alignment is propagated back.
241770Speter */
2428681Speter fp->align_info = align(t);
2438681Speter DEBUG_RECORDS(
2448681Speter fprintf(stderr,
2458681Speter "[deffld] fp->align_info %d p->align_info %d \n",
2468681Speter fp->align_info, p->align_info));
2478681Speter if (fp->align_info > p->align_info) {
2488681Speter p->align_info = fp->align_info;
2498681Speter }
250770Speter #endif
251770Speter if (t != NIL) {
252770Speter P0->nl_flags |= t->nl_flags & NFILES;
253770Speter p->nl_flags |= t->nl_flags & NFILES;
254770Speter }
255770Speter }
256770Speter return (fp);
257770Speter }
258770Speter
259770Speter /*
260770Speter * Define a variant from the constant tree of t
261770Speter * in subrecord p of record P0 where the casetype
262770Speter * is ct and the variant record to be associated is vr.
263770Speter */
264770Speter struct nl *
defvnt(p,t,vr,ct)265770Speter defvnt(p, t, vr, ct)
266770Speter struct nl *p, *vr;
26714741Sthien struct tnode *t; /* CHAR_CONST or SIGN_CONST */
268770Speter register struct nl *ct;
269770Speter {
270770Speter register struct nl *av;
271770Speter
272770Speter gconst(t);
273770Speter if (ct != NIL && incompat(con.ctype, ct , t )) {
274770Speter #ifndef PI1
275770Speter cerror("Variant label type incompatible with selector type");
276770Speter #endif
277770Speter ct = NIL;
278770Speter }
27914741Sthien av = defnl((char *) 0, VARNT, ct, 0);
280770Speter #ifndef PI1
281770Speter if (ct != NIL)
282770Speter uniqv(p);
2838681Speter #endif not PI1
284770Speter av->chain = p->ptr[NL_VARNT];
285770Speter p->ptr[NL_VARNT] = av;
286770Speter av->ptr[NL_VTOREC] = vr;
287770Speter av->range[0] = con.crval;
288770Speter return (av);
289770Speter }
290770Speter
291770Speter #ifndef PI1
292770Speter /*
293770Speter * Check that the constant label value
294770Speter * is unique among the labels in this variant.
295770Speter */
296770Speter uniqv(p)
297770Speter struct nl *p;
298770Speter {
299770Speter register struct nl *vt;
300770Speter
301770Speter for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain)
302770Speter if (vt->range[0] == con.crval) {
303770Speter error("Duplicate variant case label in record");
304770Speter return;
305770Speter }
306770Speter }
307770Speter #endif
308770Speter
309770Speter /*
310770Speter * See if the field name s is defined
311770Speter * in the record p, returning a pointer
312770Speter * to it namelist entry if it is.
313770Speter */
314770Speter struct nl *
reclook(p,s)315770Speter reclook(p, s)
316770Speter register struct nl *p;
317770Speter char *s;
318770Speter {
319770Speter
320770Speter if (p == NIL || s == NIL)
321770Speter return (NIL);
322770Speter for (p = p->chain; p != NIL; p = p->chain)
323770Speter if (p->symbol == s)
324770Speter return (p);
325770Speter return (NIL);
326770Speter }
3278681Speter
3288681Speter /*
3298681Speter * descend namelist entry for a record and assign offsets.
3308681Speter * fields go at the next higher offset that suits their alignment.
3318681Speter * all variants of a record start at the same offset, which is suitable
3328681Speter * for the alignment of their worst aligned field. thus the size of a
3338681Speter * record is independent of whether or not it is a variant
3348681Speter * (a desirable property).
3358681Speter * records come to us in the namelist, where they have been annotated
3368681Speter * with the maximum alignment their fields require.
3378681Speter * the starting offset is passed to us, and is passed recursively for
3388681Speter * variant records within records.
3398681Speter * the final maximum size of each record is recorded in the namelist
3408681Speter * in the value[NL_OFFS] field of the namelist for the record.
3418681Speter *
3428681Speter * this is supposed to match the offsets used by the c compiler
3438681Speter * so people can share records between modules in both languages.
3448681Speter */
3458681Speter rec_offsets(recp, offset)
3468681Speter struct nl *recp; /* pointer to the namelist record */
3478681Speter long offset; /* starting offset for this record/field */
3488681Speter {
3498681Speter long origin; /* offset of next field */
3508681Speter struct nl *fieldnlp; /* the current field */
3518681Speter struct nl *varntnlp; /* the current variant */
3528681Speter struct nl *vrecnlp; /* record for the current variant */
3538681Speter
3548681Speter if ( recp == NIL ) {
3558681Speter return;
3568681Speter }
35714741Sthien origin = roundup((int) offset,(long) recp->align_info);
3588681Speter if (origin != offset) {
3598681Speter fprintf(stderr,
3608681Speter "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n",
3618681Speter offset, recp->align_info, origin);
3628681Speter panic("rec_offsets");
3638681Speter }
3648681Speter DEBUG_RECORDS(
3658681Speter fprintf(stderr,
3668681Speter "[rec_offsets] offset %d recp->align %d origin %d\n",
3678681Speter offset, recp->align_info, origin));
3688681Speter /*
3698681Speter * fixed fields are forward linked though ->ptr[NL_FIELDLIST]
3708681Speter * give them all suitable offsets.
3718681Speter */
3728681Speter for ( fieldnlp = recp->ptr[NL_FIELDLIST];
3738681Speter fieldnlp != NIL;
3748681Speter fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) {
37514741Sthien origin = roundup((int) origin,(long) align(fieldnlp->type));
3768681Speter fieldnlp->value[NL_OFFS] = origin;
3778681Speter DEBUG_RECORDS(
3788681Speter fprintf(stderr,"[rec_offsets] symbol %s origin %d\n",
3798681Speter fieldnlp->symbol, origin));
3808681Speter origin += lwidth(fieldnlp->type);
3818681Speter }
3828681Speter /*
3838681Speter * this is the extent of the record, so far
3848681Speter */
3858681Speter recp->value[NL_OFFS] = origin;
3868681Speter /*
3878681Speter * if we have a tag field, we have variants to deal with
3888681Speter */
3898681Speter if ( recp->ptr[NL_TAG] ) {
3908681Speter /*
3918681Speter * if tag field is unnamed, then don't allocate space for it.
3928681Speter */
3938681Speter fieldnlp = recp->ptr[NL_TAG];
3948681Speter if ( fieldnlp->symbol != NIL ) {
39514741Sthien origin = roundup((int) origin,(long) align(fieldnlp->type));
3968681Speter fieldnlp->value[NL_OFFS] = origin;
39730801Sbostic DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin %d\n",
3988681Speter fieldnlp->symbol, origin));
3998681Speter origin += lwidth(fieldnlp->type);
4008681Speter }
4018681Speter /*
4028681Speter * find maximum alignment of records of variants
4038681Speter */
4048681Speter for ( varntnlp = recp->ptr[NL_VARNT];
4058681Speter varntnlp != NIL;
4068681Speter varntnlp = varntnlp -> chain ) {
4078681Speter vrecnlp = varntnlp->ptr[NL_VTOREC];
4088681Speter DEBUG_RECORDS(
4098681Speter fprintf(stderr,
4108681Speter "[rec_offsets] maxing variant %d align_info %d\n",
4118681Speter varntnlp->value[0], vrecnlp->align_info));
41214741Sthien origin = roundup((int) origin,(long) vrecnlp->align_info);
4138681Speter }
4148681Speter DEBUG_RECORDS(
4158681Speter fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin));
4168681Speter /*
4178681Speter * assign offsets to fields of records of the variants
4188681Speter * keep maximum length of the current record.
4198681Speter */
4208681Speter for ( varntnlp = recp->ptr[NL_VARNT];
4218681Speter varntnlp != NIL;
4228681Speter varntnlp = varntnlp -> chain ) {
4238681Speter vrecnlp = varntnlp->ptr[NL_VTOREC];
4248681Speter /*
4258681Speter * assign offsets to fields of the variant.
4268681Speter * recursive call on rec_offsets.
4278681Speter */
4288681Speter rec_offsets(vrecnlp,origin);
4298681Speter /*
4308681Speter * extent of the record is the
4318681Speter * maximum extent of all variants
4328681Speter */
4338681Speter if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) {
4348681Speter recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS];
4358681Speter }
4368681Speter }
4378681Speter }
4388681Speter /*
4398681Speter * roundup the size of the record to its alignment
4408681Speter */
4418681Speter DEBUG_RECORDS(
4428681Speter fprintf(stderr,
4438681Speter "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n",
4448681Speter recp->value[NL_OFFS], recp->align_info));
44514741Sthien recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info);
4468681Speter }
447