1770Speter /* Copyright (c) 1979 Regents of the University of California */ 2770Speter 3*14741Sthien #ifndef lint 4*14741Sthien static char sccsid[] = "@(#)rec.c 1.6 08/19/83"; 5*14741Sthien #endif 6770Speter 7770Speter #include "whoami.h" 8770Speter #include "0.h" 9770Speter #include "tree.h" 10770Speter #include "opcode.h" 118681Speter #include "align.h" 12*14741Sthien #include "tree_ty.h" 13770Speter 148681Speter /* 158681Speter * set this to TRUE with adb to turn on record alignment/offset debugging. 168681Speter */ 178681Speter bool debug_records = FALSE; 188681Speter #define DEBUG_RECORDS(x) if (debug_records) { x ; } else 198681Speter 20770Speter /* 21770Speter * Build a record namelist entry. 22770Speter * Some of the processing here is somewhat involved. 23770Speter * The basic structure we are building is as follows. 24770Speter * 258681Speter * Each record has a main RECORD entry, 268681Speter * with an attached chain of fields as ->chain; 27*14741Sthien * these enclude all the fields in all the variants of this record. 288681Speter * Fields are cons'ed to the front of the ->chain list as they are discovered. 298681Speter * This is for reclook(), but not for sizing and aligning offsets. 30770Speter * 318681Speter * If there are variants to the record, NL_TAG points to the field which 328681Speter * is the tag. If its name is NIL, the tag field is unnamed, and is not 338681Speter * allocated any space in the record. 34770Speter * Attached to NL_VARNT is a chain of VARNT structures 35770Speter * describing each of the variants. These are further linked 36770Speter * through ->chain. Each VARNT has, in ->range[0] the value of 37770Speter * the associated constant, and each points at a RECORD describing 38770Speter * the subrecord through NL_VTOREC. These pointers are not unique, 39770Speter * more than one VARNT may reference the same RECORD. 40770Speter * 418681Speter * On the first pass, we traverse the parse tree and construct the namelist 428681Speter * entries. This pass fills in the alignment of each record (including 438681Speter * subrecords (the alignment of a record is the maximum of the alignments 448681Speter * of any of its fields). 458681Speter * A second pass over the namelist entries fills in the offsets of each field 468681Speter * based on the alignments required. This second pass uses the NL_FIELDLIST 478681Speter * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get 488681Speter * to fields in the order in which they were declared. 498681Speter * This second pass can not be folded into the first pass, 508681Speter * as the starting offset of all variants is the same, 518681Speter * so we must see all the variants (and especially must know their alignments) 528681Speter * before assigning offsets. With the alignments calculated (by the first 538681Speter * pass) this can be done in one top down pass, max'ing over the alignment of 548681Speter * variants before assigning offsets to any of them. 55770Speter */ 56770Speter 57770Speter /* 58770Speter * P0 points to the outermost RECORD for name searches. 59770Speter */ 60770Speter struct nl *P0; 61770Speter 628681Speter struct nl * 63770Speter tyrec(r, off) 64*14741Sthien struct tnode *r; 65*14741Sthien int off; 66770Speter { 678681Speter struct nl *recp; 68770Speter 698681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off)); 708681Speter /* 718681Speter * build namelist structure for the outermost record type. 728681Speter * then calculate offsets (starting at 0) of the fields 738681Speter * in this record and its variant subrecords. 748681Speter */ 758681Speter recp = tyrec1(r, TRUE); 76*14741Sthien rec_offsets(recp, (long) 0); 778681Speter return recp; 78770Speter } 79770Speter 80770Speter /* 81770Speter * Define a record namelist entry. 828681Speter * r is the tree for the record to be built. 838681Speter * first is a boolean indicating whether this is an outermost record, 848681Speter * for name lookups. 858681Speter * p is the record we define here. 868681Speter * P0was is a local which stacks the enclosing value of P0 in the stack frame, 878681Speter * since tyrec1() is recursive. 88770Speter */ 89770Speter struct nl * 908681Speter tyrec1(r, first) 91*14741Sthien register struct tnode *r; /* T_FLDLST */ 928681Speter bool first; 93770Speter { 94770Speter register struct nl *p, *P0was; 95770Speter 968681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first)); 97*14741Sthien p = defnl((char *) 0, RECORD, NLNIL, 0); 98770Speter P0was = P0; 99770Speter if (first) 100770Speter P0 = p; 101770Speter #ifndef PI0 1028681Speter p->align_info = A_MIN; 103770Speter #endif 104*14741Sthien if (r != TR_NIL) { 105*14741Sthien fields(p, r->fldlst.fix_list); 106*14741Sthien variants(p, r->fldlst.variant); 107770Speter } 108770Speter P0 = P0was; 109770Speter return (p); 110770Speter } 111770Speter 112770Speter /* 113770Speter * Define the fixed part fields for p. 1148681Speter * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST]. 1158681Speter * the fieldlist is a tconc structure, and is manipulated 1168681Speter * just like newlist(), addlist(), fixlist() in the parser. 117770Speter */ 118770Speter fields(p, r) 119770Speter struct nl *p; 120*14741Sthien struct tnode *r; /* T_LISTPP */ 121770Speter { 122*14741Sthien register struct tnode *fp, *tp, *ip; 1238681Speter struct nl *jp; 1248681Speter struct nl *fieldnlp; 125770Speter 1268681Speter DEBUG_RECORDS(fprintf(stderr,"[fields]\n")); 127*14741Sthien for (fp = r; fp != TR_NIL; fp = fp->list_node.next) { 128*14741Sthien tp = fp->list_node.list; 129*14741Sthien if (tp == TR_NIL) 130770Speter continue; 131*14741Sthien jp = gtype(tp->rfield.type); 132*14741Sthien line = tp->rfield.line_no; 133*14741Sthien for (ip = tp->rfield.id_list; ip != TR_NIL; 134*14741Sthien ip = ip->list_node.next) { 135*14741Sthien fieldnlp = deffld(p, (char *) ip->list_node.list, jp); 1368681Speter if ( p->ptr[NL_FIELDLIST] == NIL ) { 1378681Speter /* newlist */ 1388681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 1398681Speter fieldnlp->ptr[NL_FIELDLIST] = fieldnlp; 1408681Speter } else { 1418681Speter /* addlist */ 1428681Speter fieldnlp->ptr[NL_FIELDLIST] = 1438681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 1448681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp; 1458681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 1468681Speter } 1478681Speter } 148770Speter } 1498681Speter if ( p->ptr[NL_FIELDLIST] != NIL ) { 1508681Speter /* fixlist */ 1518681Speter fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 1528681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL; 1538681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 1548681Speter } 155770Speter } 156770Speter 157770Speter /* 158770Speter * Define the variants for RECORD p. 159770Speter */ 160770Speter variants(p, r) 161770Speter struct nl *p; 162*14741Sthien register struct tnode *r; /* T_TYVARPT */ 163770Speter { 164*14741Sthien register struct tnode *vc, *v; 165*14741Sthien struct nl *vr; 166770Speter struct nl *ct; 167770Speter 1688681Speter DEBUG_RECORDS(fprintf(stderr,"[variants]\n")); 169*14741Sthien if (r == TR_NIL) 170770Speter return; 171*14741Sthien ct = gtype(r->varpt.type_id); 172*14741Sthien if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) { 173770Speter error("Tag fields cannot be %ss" , nameof( ct ) ); 174770Speter } 175*14741Sthien line = r->varpt.line_no; 176770Speter /* 177770Speter * Want it even if r[2] is NIL so 178770Speter * we check its type in "new" and "dispose" 179770Speter * calls -- link it to NL_TAG. 180770Speter */ 181*14741Sthien p->ptr[NL_TAG] = deffld(p, r->varpt.cptr, ct); 182*14741Sthien for (vc = r->varpt.var_list; vc != TR_NIL; vc = vc->list_node.next) { 183*14741Sthien v = vc->list_node.list; 184*14741Sthien if (v == TR_NIL) 185770Speter continue; 186*14741Sthien vr = tyrec1(v->tyvarnt.fld_list, FALSE); 187770Speter #ifndef PI0 1888681Speter DEBUG_RECORDS( 1898681Speter fprintf(stderr, 1908681Speter "[variants] p->align_info %d vr->align_info %d\n", 1918681Speter p->align_info, vr->align_info)); 1928681Speter if (vr->align_info > p->align_info) { 1938681Speter p->align_info = vr->align_info; 1948681Speter } 195770Speter #endif 196*14741Sthien line = v->tyvarnt.line_no; 197*14741Sthien for (v = v->tyvarnt.const_list; v != TR_NIL; 198*14741Sthien v = v->list_node.next) 199*14741Sthien (void) defvnt(p, v->list_node.list, vr, ct); 200770Speter } 201770Speter } 202770Speter 203770Speter /* 204770Speter * Define a field in subrecord p of record P0 205770Speter * with name s and type t. 206770Speter */ 207770Speter struct nl * 208770Speter deffld(p, s, t) 209770Speter struct nl *p; 210770Speter register char *s; 211770Speter register struct nl *t; 212770Speter { 213770Speter register struct nl *fp; 214770Speter 2158681Speter DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s)); 216770Speter if (reclook(P0, s) != NIL) { 217770Speter #ifndef PI1 218770Speter error("%s is a duplicate field name in this record", s); 219770Speter #endif 220770Speter s = NIL; 221770Speter } 222770Speter /* 2238681Speter * enter the field with its type 224770Speter */ 225770Speter fp = enter(defnl(s, FIELD, t, 0)); 2268681Speter /* 2278681Speter * if no name, then this is an unnamed tag, 2288681Speter * so don't link it into reclook()'s chain. 2298681Speter */ 230770Speter if (s != NIL) { 231770Speter fp->chain = P0->chain; 232770Speter P0->chain = fp; 233770Speter #ifndef PI0 234770Speter /* 2358681Speter * and the alignment is propagated back. 236770Speter */ 2378681Speter fp->align_info = align(t); 2388681Speter DEBUG_RECORDS( 2398681Speter fprintf(stderr, 2408681Speter "[deffld] fp->align_info %d p->align_info %d \n", 2418681Speter fp->align_info, p->align_info)); 2428681Speter if (fp->align_info > p->align_info) { 2438681Speter p->align_info = fp->align_info; 2448681Speter } 245770Speter #endif 246770Speter if (t != NIL) { 247770Speter P0->nl_flags |= t->nl_flags & NFILES; 248770Speter p->nl_flags |= t->nl_flags & NFILES; 249770Speter } 250770Speter } 251770Speter return (fp); 252770Speter } 253770Speter 254770Speter /* 255770Speter * Define a variant from the constant tree of t 256770Speter * in subrecord p of record P0 where the casetype 257770Speter * is ct and the variant record to be associated is vr. 258770Speter */ 259770Speter struct nl * 260770Speter defvnt(p, t, vr, ct) 261770Speter struct nl *p, *vr; 262*14741Sthien struct tnode *t; /* CHAR_CONST or SIGN_CONST */ 263770Speter register struct nl *ct; 264770Speter { 265770Speter register struct nl *av; 266770Speter 267770Speter gconst(t); 268770Speter if (ct != NIL && incompat(con.ctype, ct , t )) { 269770Speter #ifndef PI1 270770Speter cerror("Variant label type incompatible with selector type"); 271770Speter #endif 272770Speter ct = NIL; 273770Speter } 274*14741Sthien av = defnl((char *) 0, VARNT, ct, 0); 275770Speter #ifndef PI1 276770Speter if (ct != NIL) 277770Speter uniqv(p); 2788681Speter #endif not PI1 279770Speter av->chain = p->ptr[NL_VARNT]; 280770Speter p->ptr[NL_VARNT] = av; 281770Speter av->ptr[NL_VTOREC] = vr; 282770Speter av->range[0] = con.crval; 283770Speter return (av); 284770Speter } 285770Speter 286770Speter #ifndef PI1 287770Speter /* 288770Speter * Check that the constant label value 289770Speter * is unique among the labels in this variant. 290770Speter */ 291770Speter uniqv(p) 292770Speter struct nl *p; 293770Speter { 294770Speter register struct nl *vt; 295770Speter 296770Speter for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain) 297770Speter if (vt->range[0] == con.crval) { 298770Speter error("Duplicate variant case label in record"); 299770Speter return; 300770Speter } 301770Speter } 302770Speter #endif 303770Speter 304770Speter /* 305770Speter * See if the field name s is defined 306770Speter * in the record p, returning a pointer 307770Speter * to it namelist entry if it is. 308770Speter */ 309770Speter struct nl * 310770Speter reclook(p, s) 311770Speter register struct nl *p; 312770Speter char *s; 313770Speter { 314770Speter 315770Speter if (p == NIL || s == NIL) 316770Speter return (NIL); 317770Speter for (p = p->chain; p != NIL; p = p->chain) 318770Speter if (p->symbol == s) 319770Speter return (p); 320770Speter return (NIL); 321770Speter } 3228681Speter 3238681Speter /* 3248681Speter * descend namelist entry for a record and assign offsets. 3258681Speter * fields go at the next higher offset that suits their alignment. 3268681Speter * all variants of a record start at the same offset, which is suitable 3278681Speter * for the alignment of their worst aligned field. thus the size of a 3288681Speter * record is independent of whether or not it is a variant 3298681Speter * (a desirable property). 3308681Speter * records come to us in the namelist, where they have been annotated 3318681Speter * with the maximum alignment their fields require. 3328681Speter * the starting offset is passed to us, and is passed recursively for 3338681Speter * variant records within records. 3348681Speter * the final maximum size of each record is recorded in the namelist 3358681Speter * in the value[NL_OFFS] field of the namelist for the record. 3368681Speter * 3378681Speter * this is supposed to match the offsets used by the c compiler 3388681Speter * so people can share records between modules in both languages. 3398681Speter */ 3408681Speter rec_offsets(recp, offset) 3418681Speter struct nl *recp; /* pointer to the namelist record */ 3428681Speter long offset; /* starting offset for this record/field */ 3438681Speter { 3448681Speter long origin; /* offset of next field */ 3458681Speter struct nl *fieldnlp; /* the current field */ 3468681Speter struct nl *varntnlp; /* the current variant */ 3478681Speter struct nl *vrecnlp; /* record for the current variant */ 3488681Speter 3498681Speter if ( recp == NIL ) { 3508681Speter return; 3518681Speter } 352*14741Sthien origin = roundup((int) offset,(long) recp->align_info); 3538681Speter if (origin != offset) { 3548681Speter fprintf(stderr, 3558681Speter "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n", 3568681Speter offset, recp->align_info, origin); 3578681Speter panic("rec_offsets"); 3588681Speter } 3598681Speter DEBUG_RECORDS( 3608681Speter fprintf(stderr, 3618681Speter "[rec_offsets] offset %d recp->align %d origin %d\n", 3628681Speter offset, recp->align_info, origin)); 3638681Speter /* 3648681Speter * fixed fields are forward linked though ->ptr[NL_FIELDLIST] 3658681Speter * give them all suitable offsets. 3668681Speter */ 3678681Speter for ( fieldnlp = recp->ptr[NL_FIELDLIST]; 3688681Speter fieldnlp != NIL; 3698681Speter fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) { 370*14741Sthien origin = roundup((int) origin,(long) align(fieldnlp->type)); 3718681Speter fieldnlp->value[NL_OFFS] = origin; 3728681Speter DEBUG_RECORDS( 3738681Speter fprintf(stderr,"[rec_offsets] symbol %s origin %d\n", 3748681Speter fieldnlp->symbol, origin)); 3758681Speter origin += lwidth(fieldnlp->type); 3768681Speter } 3778681Speter /* 3788681Speter * this is the extent of the record, so far 3798681Speter */ 3808681Speter recp->value[NL_OFFS] = origin; 3818681Speter /* 3828681Speter * if we have a tag field, we have variants to deal with 3838681Speter */ 3848681Speter if ( recp->ptr[NL_TAG] ) { 3858681Speter /* 3868681Speter * if tag field is unnamed, then don't allocate space for it. 3878681Speter */ 3888681Speter fieldnlp = recp->ptr[NL_TAG]; 3898681Speter if ( fieldnlp->symbol != NIL ) { 390*14741Sthien origin = roundup((int) origin,(long) align(fieldnlp->type)); 3918681Speter fieldnlp->value[NL_OFFS] = origin; 3928681Speter DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n", 3938681Speter fieldnlp->symbol, origin)); 3948681Speter origin += lwidth(fieldnlp->type); 3958681Speter } 3968681Speter /* 3978681Speter * find maximum alignment of records of variants 3988681Speter */ 3998681Speter for ( varntnlp = recp->ptr[NL_VARNT]; 4008681Speter varntnlp != NIL; 4018681Speter varntnlp = varntnlp -> chain ) { 4028681Speter vrecnlp = varntnlp->ptr[NL_VTOREC]; 4038681Speter DEBUG_RECORDS( 4048681Speter fprintf(stderr, 4058681Speter "[rec_offsets] maxing variant %d align_info %d\n", 4068681Speter varntnlp->value[0], vrecnlp->align_info)); 407*14741Sthien origin = roundup((int) origin,(long) vrecnlp->align_info); 4088681Speter } 4098681Speter DEBUG_RECORDS( 4108681Speter fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin)); 4118681Speter /* 4128681Speter * assign offsets to fields of records of the variants 4138681Speter * keep maximum length of the current record. 4148681Speter */ 4158681Speter for ( varntnlp = recp->ptr[NL_VARNT]; 4168681Speter varntnlp != NIL; 4178681Speter varntnlp = varntnlp -> chain ) { 4188681Speter vrecnlp = varntnlp->ptr[NL_VTOREC]; 4198681Speter /* 4208681Speter * assign offsets to fields of the variant. 4218681Speter * recursive call on rec_offsets. 4228681Speter */ 4238681Speter rec_offsets(vrecnlp,origin); 4248681Speter /* 4258681Speter * extent of the record is the 4268681Speter * maximum extent of all variants 4278681Speter */ 4288681Speter if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) { 4298681Speter recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS]; 4308681Speter } 4318681Speter } 4328681Speter } 4338681Speter /* 4348681Speter * roundup the size of the record to its alignment 4358681Speter */ 4368681Speter DEBUG_RECORDS( 4378681Speter fprintf(stderr, 4388681Speter "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n", 4398681Speter recp->value[NL_OFFS], recp->align_info)); 440*14741Sthien recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info); 4418681Speter } 442