1770Speter /* Copyright (c) 1979 Regents of the University of California */ 2770Speter 3*8681Speter static char sccsid[] = "@(#)rec.c 1.5 10/19/82"; 4770Speter 5770Speter #include "whoami.h" 6770Speter #include "0.h" 7770Speter #include "tree.h" 8770Speter #include "opcode.h" 9*8681Speter #include "align.h" 10770Speter 11*8681Speter /* 12*8681Speter * set this to TRUE with adb to turn on record alignment/offset debugging. 13*8681Speter */ 14*8681Speter bool debug_records = FALSE; 15*8681Speter #define DEBUG_RECORDS(x) if (debug_records) { x ; } else 16*8681Speter 17770Speter /* 18770Speter * Build a record namelist entry. 19770Speter * Some of the processing here is somewhat involved. 20770Speter * The basic structure we are building is as follows. 21770Speter * 22*8681Speter * Each record has a main RECORD entry, 23*8681Speter * with an attached chain of fields as ->chain; 24*8681Speter * these include all the fields in all the variants of this record. 25*8681Speter * Fields are cons'ed to the front of the ->chain list as they are discovered. 26*8681Speter * This is for reclook(), but not for sizing and aligning offsets. 27770Speter * 28*8681Speter * If there are variants to the record, NL_TAG points to the field which 29*8681Speter * is the tag. If its name is NIL, the tag field is unnamed, and is not 30*8681Speter * allocated any space in the record. 31770Speter * Attached to NL_VARNT is a chain of VARNT structures 32770Speter * describing each of the variants. These are further linked 33770Speter * through ->chain. Each VARNT has, in ->range[0] the value of 34770Speter * the associated constant, and each points at a RECORD describing 35770Speter * the subrecord through NL_VTOREC. These pointers are not unique, 36770Speter * more than one VARNT may reference the same RECORD. 37770Speter * 38*8681Speter * On the first pass, we traverse the parse tree and construct the namelist 39*8681Speter * entries. This pass fills in the alignment of each record (including 40*8681Speter * subrecords (the alignment of a record is the maximum of the alignments 41*8681Speter * of any of its fields). 42*8681Speter * A second pass over the namelist entries fills in the offsets of each field 43*8681Speter * based on the alignments required. This second pass uses the NL_FIELDLIST 44*8681Speter * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get 45*8681Speter * to fields in the order in which they were declared. 46*8681Speter * This second pass can not be folded into the first pass, 47*8681Speter * as the starting offset of all variants is the same, 48*8681Speter * so we must see all the variants (and especially must know their alignments) 49*8681Speter * before assigning offsets. With the alignments calculated (by the first 50*8681Speter * pass) this can be done in one top down pass, max'ing over the alignment of 51*8681Speter * variants before assigning offsets to any of them. 52770Speter */ 53770Speter 54770Speter /* 55770Speter * P0 points to the outermost RECORD for name searches. 56770Speter */ 57770Speter struct nl *P0; 58770Speter 59*8681Speter struct nl * 60770Speter tyrec(r, off) 61770Speter int *r, off; 62770Speter { 63*8681Speter struct nl *recp; 64770Speter 65*8681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off)); 66*8681Speter /* 67*8681Speter * build namelist structure for the outermost record type. 68*8681Speter * then calculate offsets (starting at 0) of the fields 69*8681Speter * in this record and its variant subrecords. 70*8681Speter */ 71*8681Speter recp = tyrec1(r, TRUE); 72*8681Speter rec_offsets(recp, 0); 73*8681Speter return recp; 74770Speter } 75770Speter 76770Speter /* 77770Speter * Define a record namelist entry. 78*8681Speter * r is the tree for the record to be built. 79*8681Speter * first is a boolean indicating whether this is an outermost record, 80*8681Speter * for name lookups. 81*8681Speter * p is the record we define here. 82*8681Speter * P0was is a local which stacks the enclosing value of P0 in the stack frame, 83*8681Speter * since tyrec1() is recursive. 84770Speter */ 85770Speter struct nl * 86*8681Speter tyrec1(r, first) 87770Speter register int *r; 88*8681Speter bool first; 89770Speter { 90770Speter register struct nl *p, *P0was; 91770Speter 92*8681Speter DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first)); 93770Speter p = defnl(0, RECORD, 0, 0); 94770Speter P0was = P0; 95770Speter if (first) 96770Speter P0 = p; 97770Speter #ifndef PI0 98*8681Speter p->align_info = A_MIN; 99770Speter #endif 100770Speter if (r != NIL) { 101770Speter fields(p, r[2]); 102770Speter variants(p, r[3]); 103770Speter } 104770Speter P0 = P0was; 105770Speter return (p); 106770Speter } 107770Speter 108770Speter /* 109770Speter * Define the fixed part fields for p. 110*8681Speter * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST]. 111*8681Speter * the fieldlist is a tconc structure, and is manipulated 112*8681Speter * just like newlist(), addlist(), fixlist() in the parser. 113770Speter */ 114770Speter fields(p, r) 115770Speter struct nl *p; 116770Speter int *r; 117770Speter { 118*8681Speter register int *fp, *tp, *ip; 119*8681Speter struct nl *jp; 120*8681Speter struct nl *fieldnlp; 121770Speter 122*8681Speter DEBUG_RECORDS(fprintf(stderr,"[fields]\n")); 123770Speter for (fp = r; fp != NIL; fp = fp[2]) { 124770Speter tp = fp[1]; 125770Speter if (tp == NIL) 126770Speter continue; 127770Speter jp = gtype(tp[3]); 128770Speter line = tp[1]; 129*8681Speter for (ip = tp[2]; ip != NIL; ip = ip[2]) { 130*8681Speter fieldnlp = deffld(p, ip[1], jp); 131*8681Speter if ( p->ptr[NL_FIELDLIST] == NIL ) { 132*8681Speter /* newlist */ 133*8681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 134*8681Speter fieldnlp->ptr[NL_FIELDLIST] = fieldnlp; 135*8681Speter } else { 136*8681Speter /* addlist */ 137*8681Speter fieldnlp->ptr[NL_FIELDLIST] = 138*8681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 139*8681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp; 140*8681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 141*8681Speter } 142*8681Speter } 143770Speter } 144*8681Speter if ( p->ptr[NL_FIELDLIST] != NIL ) { 145*8681Speter /* fixlist */ 146*8681Speter fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 147*8681Speter p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL; 148*8681Speter p->ptr[NL_FIELDLIST] = fieldnlp; 149*8681Speter } 150770Speter } 151770Speter 152770Speter /* 153770Speter * Define the variants for RECORD p. 154770Speter */ 155770Speter variants(p, r) 156770Speter struct nl *p; 157770Speter register int *r; 158770Speter { 159770Speter register int *vc, *v; 160770Speter int *vr; 161770Speter struct nl *ct; 162770Speter 163*8681Speter DEBUG_RECORDS(fprintf(stderr,"[variants]\n")); 164770Speter if (r == NIL) 165770Speter return; 166770Speter ct = gtype(r[3]); 1673405Speter if ( ( ct != NIL ) && ( isnta( ct , "bcsi" ) ) ) { 168770Speter error("Tag fields cannot be %ss" , nameof( ct ) ); 169770Speter } 170770Speter line = r[1]; 171770Speter /* 172770Speter * Want it even if r[2] is NIL so 173770Speter * we check its type in "new" and "dispose" 174770Speter * calls -- link it to NL_TAG. 175770Speter */ 176770Speter p->ptr[NL_TAG] = deffld(p, r[2], ct); 177770Speter for (vc = r[4]; vc != NIL; vc = vc[2]) { 178770Speter v = vc[1]; 179770Speter if (v == NIL) 180770Speter continue; 181*8681Speter vr = tyrec1(v[3], FALSE); 182770Speter #ifndef PI0 183*8681Speter DEBUG_RECORDS( 184*8681Speter fprintf(stderr, 185*8681Speter "[variants] p->align_info %d vr->align_info %d\n", 186*8681Speter p->align_info, vr->align_info)); 187*8681Speter if (vr->align_info > p->align_info) { 188*8681Speter p->align_info = vr->align_info; 189*8681Speter } 190770Speter #endif 191770Speter line = v[1]; 192770Speter for (v = v[2]; v != NIL; v = v[2]) 193770Speter defvnt(p, v[1], vr, ct); 194770Speter } 195770Speter } 196770Speter 197770Speter /* 198770Speter * Define a field in subrecord p of record P0 199770Speter * with name s and type t. 200770Speter */ 201770Speter struct nl * 202770Speter deffld(p, s, t) 203770Speter struct nl *p; 204770Speter register char *s; 205770Speter register struct nl *t; 206770Speter { 207770Speter register struct nl *fp; 208770Speter 209*8681Speter DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s)); 210770Speter if (reclook(P0, s) != NIL) { 211770Speter #ifndef PI1 212770Speter error("%s is a duplicate field name in this record", s); 213770Speter #endif 214770Speter s = NIL; 215770Speter } 216770Speter /* 217*8681Speter * enter the field with its type 218770Speter */ 219770Speter fp = enter(defnl(s, FIELD, t, 0)); 220*8681Speter /* 221*8681Speter * if no name, then this is an unnamed tag, 222*8681Speter * so don't link it into reclook()'s chain. 223*8681Speter */ 224770Speter if (s != NIL) { 225770Speter fp->chain = P0->chain; 226770Speter P0->chain = fp; 227770Speter #ifndef PI0 228770Speter /* 229*8681Speter * and the alignment is propagated back. 230770Speter */ 231*8681Speter fp->align_info = align(t); 232*8681Speter DEBUG_RECORDS( 233*8681Speter fprintf(stderr, 234*8681Speter "[deffld] fp->align_info %d p->align_info %d \n", 235*8681Speter fp->align_info, p->align_info)); 236*8681Speter if (fp->align_info > p->align_info) { 237*8681Speter p->align_info = fp->align_info; 238*8681Speter } 239770Speter #endif 240770Speter if (t != NIL) { 241770Speter P0->nl_flags |= t->nl_flags & NFILES; 242770Speter p->nl_flags |= t->nl_flags & NFILES; 243770Speter } 244770Speter } 245770Speter return (fp); 246770Speter } 247770Speter 248770Speter /* 249770Speter * Define a variant from the constant tree of t 250770Speter * in subrecord p of record P0 where the casetype 251770Speter * is ct and the variant record to be associated is vr. 252770Speter */ 253770Speter struct nl * 254770Speter defvnt(p, t, vr, ct) 255770Speter struct nl *p, *vr; 256770Speter int *t; 257770Speter register struct nl *ct; 258770Speter { 259770Speter register struct nl *av; 260770Speter 261770Speter gconst(t); 262770Speter if (ct != NIL && incompat(con.ctype, ct , t )) { 263770Speter #ifndef PI1 264770Speter cerror("Variant label type incompatible with selector type"); 265770Speter #endif 266770Speter ct = NIL; 267770Speter } 268770Speter av = defnl(0, VARNT, ct, 0); 269770Speter #ifndef PI1 270770Speter if (ct != NIL) 271770Speter uniqv(p); 272*8681Speter #endif not PI1 273770Speter av->chain = p->ptr[NL_VARNT]; 274770Speter p->ptr[NL_VARNT] = av; 275770Speter av->ptr[NL_VTOREC] = vr; 276770Speter av->range[0] = con.crval; 277770Speter return (av); 278770Speter } 279770Speter 280770Speter #ifndef PI1 281770Speter /* 282770Speter * Check that the constant label value 283770Speter * is unique among the labels in this variant. 284770Speter */ 285770Speter uniqv(p) 286770Speter struct nl *p; 287770Speter { 288770Speter register struct nl *vt; 289770Speter 290770Speter for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain) 291770Speter if (vt->range[0] == con.crval) { 292770Speter error("Duplicate variant case label in record"); 293770Speter return; 294770Speter } 295770Speter } 296770Speter #endif 297770Speter 298770Speter /* 299770Speter * See if the field name s is defined 300770Speter * in the record p, returning a pointer 301770Speter * to it namelist entry if it is. 302770Speter */ 303770Speter struct nl * 304770Speter reclook(p, s) 305770Speter register struct nl *p; 306770Speter char *s; 307770Speter { 308770Speter 309770Speter if (p == NIL || s == NIL) 310770Speter return (NIL); 311770Speter for (p = p->chain; p != NIL; p = p->chain) 312770Speter if (p->symbol == s) 313770Speter return (p); 314770Speter return (NIL); 315770Speter } 316*8681Speter 317*8681Speter /* 318*8681Speter * descend namelist entry for a record and assign offsets. 319*8681Speter * fields go at the next higher offset that suits their alignment. 320*8681Speter * all variants of a record start at the same offset, which is suitable 321*8681Speter * for the alignment of their worst aligned field. thus the size of a 322*8681Speter * record is independent of whether or not it is a variant 323*8681Speter * (a desirable property). 324*8681Speter * records come to us in the namelist, where they have been annotated 325*8681Speter * with the maximum alignment their fields require. 326*8681Speter * the starting offset is passed to us, and is passed recursively for 327*8681Speter * variant records within records. 328*8681Speter * the final maximum size of each record is recorded in the namelist 329*8681Speter * in the value[NL_OFFS] field of the namelist for the record. 330*8681Speter * 331*8681Speter * this is supposed to match the offsets used by the c compiler 332*8681Speter * so people can share records between modules in both languages. 333*8681Speter */ 334*8681Speter rec_offsets(recp, offset) 335*8681Speter struct nl *recp; /* pointer to the namelist record */ 336*8681Speter long offset; /* starting offset for this record/field */ 337*8681Speter { 338*8681Speter long origin; /* offset of next field */ 339*8681Speter struct nl *fieldnlp; /* the current field */ 340*8681Speter struct nl *varntnlp; /* the current variant */ 341*8681Speter struct nl *vrecnlp; /* record for the current variant */ 342*8681Speter long alignment; /* maximum alignment for any variant */ 343*8681Speter 344*8681Speter if ( recp == NIL ) { 345*8681Speter return; 346*8681Speter } 347*8681Speter origin = roundup(offset,recp->align_info); 348*8681Speter if (origin != offset) { 349*8681Speter fprintf(stderr, 350*8681Speter "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n", 351*8681Speter offset, recp->align_info, origin); 352*8681Speter panic("rec_offsets"); 353*8681Speter } 354*8681Speter DEBUG_RECORDS( 355*8681Speter fprintf(stderr, 356*8681Speter "[rec_offsets] offset %d recp->align %d origin %d\n", 357*8681Speter offset, recp->align_info, origin)); 358*8681Speter /* 359*8681Speter * fixed fields are forward linked though ->ptr[NL_FIELDLIST] 360*8681Speter * give them all suitable offsets. 361*8681Speter */ 362*8681Speter for ( fieldnlp = recp->ptr[NL_FIELDLIST]; 363*8681Speter fieldnlp != NIL; 364*8681Speter fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) { 365*8681Speter origin = roundup(origin,align(fieldnlp->type)); 366*8681Speter fieldnlp->value[NL_OFFS] = origin; 367*8681Speter DEBUG_RECORDS( 368*8681Speter fprintf(stderr,"[rec_offsets] symbol %s origin %d\n", 369*8681Speter fieldnlp->symbol, origin)); 370*8681Speter origin += lwidth(fieldnlp->type); 371*8681Speter } 372*8681Speter /* 373*8681Speter * this is the extent of the record, so far 374*8681Speter */ 375*8681Speter recp->value[NL_OFFS] = origin; 376*8681Speter /* 377*8681Speter * if we have a tag field, we have variants to deal with 378*8681Speter */ 379*8681Speter if ( recp->ptr[NL_TAG] ) { 380*8681Speter /* 381*8681Speter * if tag field is unnamed, then don't allocate space for it. 382*8681Speter */ 383*8681Speter fieldnlp = recp->ptr[NL_TAG]; 384*8681Speter if ( fieldnlp->symbol != NIL ) { 385*8681Speter origin = roundup(origin,align(fieldnlp->type)); 386*8681Speter fieldnlp->value[NL_OFFS] = origin; 387*8681Speter DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n", 388*8681Speter fieldnlp->symbol, origin)); 389*8681Speter origin += lwidth(fieldnlp->type); 390*8681Speter } 391*8681Speter /* 392*8681Speter * find maximum alignment of records of variants 393*8681Speter */ 394*8681Speter for ( varntnlp = recp->ptr[NL_VARNT]; 395*8681Speter varntnlp != NIL; 396*8681Speter varntnlp = varntnlp -> chain ) { 397*8681Speter vrecnlp = varntnlp->ptr[NL_VTOREC]; 398*8681Speter DEBUG_RECORDS( 399*8681Speter fprintf(stderr, 400*8681Speter "[rec_offsets] maxing variant %d align_info %d\n", 401*8681Speter varntnlp->value[0], vrecnlp->align_info)); 402*8681Speter origin = roundup(origin,vrecnlp->align_info); 403*8681Speter } 404*8681Speter DEBUG_RECORDS( 405*8681Speter fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin)); 406*8681Speter /* 407*8681Speter * assign offsets to fields of records of the variants 408*8681Speter * keep maximum length of the current record. 409*8681Speter */ 410*8681Speter for ( varntnlp = recp->ptr[NL_VARNT]; 411*8681Speter varntnlp != NIL; 412*8681Speter varntnlp = varntnlp -> chain ) { 413*8681Speter vrecnlp = varntnlp->ptr[NL_VTOREC]; 414*8681Speter /* 415*8681Speter * assign offsets to fields of the variant. 416*8681Speter * recursive call on rec_offsets. 417*8681Speter */ 418*8681Speter rec_offsets(vrecnlp,origin); 419*8681Speter /* 420*8681Speter * extent of the record is the 421*8681Speter * maximum extent of all variants 422*8681Speter */ 423*8681Speter if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) { 424*8681Speter recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS]; 425*8681Speter } 426*8681Speter } 427*8681Speter } 428*8681Speter /* 429*8681Speter * roundup the size of the record to its alignment 430*8681Speter */ 431*8681Speter DEBUG_RECORDS( 432*8681Speter fprintf(stderr, 433*8681Speter "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n", 434*8681Speter recp->value[NL_OFFS], recp->align_info)); 435*8681Speter recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],recp->align_info); 436*8681Speter } 437