1*48116Sbostic /*- 2*48116Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48116Sbostic * All rights reserved. 4*48116Sbostic * 5*48116Sbostic * %sccs.include.redist.c% 622187Sdist */ 7770Speter 814741Sthien #ifndef lint 9*48116Sbostic static char sccsid[] = "@(#)rec.c 5.3 (Berkeley) 04/16/91"; 10*48116Sbostic #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 * 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 * 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 * 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 * 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 * 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