1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 #ifndef lint 4 static char sccsid[] = "@(#)rec.c 2.1 02/08/84"; 5 #endif 6 7 #include "whoami.h" 8 #include "0.h" 9 #include "tree.h" 10 #include "opcode.h" 11 #include "align.h" 12 #include "tree_ty.h" 13 14 /* 15 * set this to TRUE with adb to turn on record alignment/offset debugging. 16 */ 17 bool debug_records = FALSE; 18 #define DEBUG_RECORDS(x) if (debug_records) { x ; } else 19 20 /* 21 * Build a record namelist entry. 22 * Some of the processing here is somewhat involved. 23 * The basic structure we are building is as follows. 24 * 25 * Each record has a main RECORD entry, 26 * with an attached chain of fields as ->chain; 27 * these enclude all the fields in all the variants of this record. 28 * Fields are cons'ed to the front of the ->chain list as they are discovered. 29 * This is for reclook(), but not for sizing and aligning offsets. 30 * 31 * If there are variants to the record, NL_TAG points to the field which 32 * is the tag. If its name is NIL, the tag field is unnamed, and is not 33 * allocated any space in the record. 34 * Attached to NL_VARNT is a chain of VARNT structures 35 * describing each of the variants. These are further linked 36 * through ->chain. Each VARNT has, in ->range[0] the value of 37 * the associated constant, and each points at a RECORD describing 38 * the subrecord through NL_VTOREC. These pointers are not unique, 39 * more than one VARNT may reference the same RECORD. 40 * 41 * On the first pass, we traverse the parse tree and construct the namelist 42 * entries. This pass fills in the alignment of each record (including 43 * subrecords (the alignment of a record is the maximum of the alignments 44 * of any of its fields). 45 * A second pass over the namelist entries fills in the offsets of each field 46 * based on the alignments required. This second pass uses the NL_FIELDLIST 47 * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get 48 * to fields in the order in which they were declared. 49 * This second pass can not be folded into the first pass, 50 * as the starting offset of all variants is the same, 51 * so we must see all the variants (and especially must know their alignments) 52 * before assigning offsets. With the alignments calculated (by the first 53 * pass) this can be done in one top down pass, max'ing over the alignment of 54 * variants before assigning offsets to any of them. 55 */ 56 57 /* 58 * P0 points to the outermost RECORD for name searches. 59 */ 60 struct nl *P0; 61 62 struct nl * 63 tyrec(r, off) 64 struct tnode *r; 65 int off; 66 { 67 struct nl *recp; 68 69 DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off)); 70 /* 71 * build namelist structure for the outermost record type. 72 * then calculate offsets (starting at 0) of the fields 73 * in this record and its variant subrecords. 74 */ 75 recp = tyrec1(r, TRUE); 76 rec_offsets(recp, (long) 0); 77 return recp; 78 } 79 80 /* 81 * Define a record namelist entry. 82 * r is the tree for the record to be built. 83 * first is a boolean indicating whether this is an outermost record, 84 * for name lookups. 85 * p is the record we define here. 86 * P0was is a local which stacks the enclosing value of P0 in the stack frame, 87 * since tyrec1() is recursive. 88 */ 89 struct nl * 90 tyrec1(r, first) 91 register struct tnode *r; /* T_FLDLST */ 92 bool first; 93 { 94 register struct nl *p, *P0was; 95 96 DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first)); 97 p = defnl((char *) 0, RECORD, NLNIL, 0); 98 P0was = P0; 99 if (first) 100 P0 = p; 101 #ifndef PI0 102 p->align_info = A_MIN; 103 #endif 104 if (r != TR_NIL) { 105 fields(p, r->fldlst.fix_list); 106 variants(p, r->fldlst.variant); 107 } 108 P0 = P0was; 109 return (p); 110 } 111 112 /* 113 * Define the fixed part fields for p. 114 * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST]. 115 * the fieldlist is a tconc structure, and is manipulated 116 * just like newlist(), addlist(), fixlist() in the parser. 117 */ 118 fields(p, r) 119 struct nl *p; 120 struct tnode *r; /* T_LISTPP */ 121 { 122 register struct tnode *fp, *tp, *ip; 123 struct nl *jp; 124 struct nl *fieldnlp; 125 126 DEBUG_RECORDS(fprintf(stderr,"[fields]\n")); 127 for (fp = r; fp != TR_NIL; fp = fp->list_node.next) { 128 tp = fp->list_node.list; 129 if (tp == TR_NIL) 130 continue; 131 jp = gtype(tp->rfield.type); 132 line = tp->rfield.line_no; 133 for (ip = tp->rfield.id_list; ip != TR_NIL; 134 ip = ip->list_node.next) { 135 fieldnlp = deffld(p, (char *) ip->list_node.list, jp); 136 if ( p->ptr[NL_FIELDLIST] == NIL ) { 137 /* newlist */ 138 p->ptr[NL_FIELDLIST] = fieldnlp; 139 fieldnlp->ptr[NL_FIELDLIST] = fieldnlp; 140 } else { 141 /* addlist */ 142 fieldnlp->ptr[NL_FIELDLIST] = 143 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 144 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp; 145 p->ptr[NL_FIELDLIST] = fieldnlp; 146 } 147 } 148 } 149 if ( p->ptr[NL_FIELDLIST] != NIL ) { 150 /* fixlist */ 151 fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST]; 152 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL; 153 p->ptr[NL_FIELDLIST] = fieldnlp; 154 } 155 } 156 157 /* 158 * Define the variants for RECORD p. 159 */ 160 variants(p, r) 161 struct nl *p; 162 register struct tnode *r; /* T_TYVARPT */ 163 { 164 register struct tnode *vc, *v; 165 struct nl *vr; 166 struct nl *ct; 167 168 DEBUG_RECORDS(fprintf(stderr,"[variants]\n")); 169 if (r == TR_NIL) 170 return; 171 ct = gtype(r->varpt.type_id); 172 if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) { 173 error("Tag fields cannot be %ss" , nameof( ct ) ); 174 } 175 line = r->varpt.line_no; 176 /* 177 * Want it even if r[2] is NIL so 178 * we check its type in "new" and "dispose" 179 * calls -- link it to NL_TAG. 180 */ 181 p->ptr[NL_TAG] = deffld(p, r->varpt.cptr, ct); 182 for (vc = r->varpt.var_list; vc != TR_NIL; vc = vc->list_node.next) { 183 v = vc->list_node.list; 184 if (v == TR_NIL) 185 continue; 186 vr = tyrec1(v->tyvarnt.fld_list, FALSE); 187 #ifndef PI0 188 DEBUG_RECORDS( 189 fprintf(stderr, 190 "[variants] p->align_info %d vr->align_info %d\n", 191 p->align_info, vr->align_info)); 192 if (vr->align_info > p->align_info) { 193 p->align_info = vr->align_info; 194 } 195 #endif 196 line = v->tyvarnt.line_no; 197 for (v = v->tyvarnt.const_list; v != TR_NIL; 198 v = v->list_node.next) 199 (void) defvnt(p, v->list_node.list, vr, ct); 200 } 201 } 202 203 /* 204 * Define a field in subrecord p of record P0 205 * with name s and type t. 206 */ 207 struct nl * 208 deffld(p, s, t) 209 struct nl *p; 210 register char *s; 211 register struct nl *t; 212 { 213 register struct nl *fp; 214 215 DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s)); 216 if (reclook(P0, s) != NIL) { 217 #ifndef PI1 218 error("%s is a duplicate field name in this record", s); 219 #endif 220 s = NIL; 221 } 222 /* 223 * enter the field with its type 224 */ 225 fp = enter(defnl(s, FIELD, t, 0)); 226 /* 227 * if no name, then this is an unnamed tag, 228 * so don't link it into reclook()'s chain. 229 */ 230 if (s != NIL) { 231 fp->chain = P0->chain; 232 P0->chain = fp; 233 #ifndef PI0 234 /* 235 * and the alignment is propagated back. 236 */ 237 fp->align_info = align(t); 238 DEBUG_RECORDS( 239 fprintf(stderr, 240 "[deffld] fp->align_info %d p->align_info %d \n", 241 fp->align_info, p->align_info)); 242 if (fp->align_info > p->align_info) { 243 p->align_info = fp->align_info; 244 } 245 #endif 246 if (t != NIL) { 247 P0->nl_flags |= t->nl_flags & NFILES; 248 p->nl_flags |= t->nl_flags & NFILES; 249 } 250 } 251 return (fp); 252 } 253 254 /* 255 * Define a variant from the constant tree of t 256 * in subrecord p of record P0 where the casetype 257 * is ct and the variant record to be associated is vr. 258 */ 259 struct nl * 260 defvnt(p, t, vr, ct) 261 struct nl *p, *vr; 262 struct tnode *t; /* CHAR_CONST or SIGN_CONST */ 263 register struct nl *ct; 264 { 265 register struct nl *av; 266 267 gconst(t); 268 if (ct != NIL && incompat(con.ctype, ct , t )) { 269 #ifndef PI1 270 cerror("Variant label type incompatible with selector type"); 271 #endif 272 ct = NIL; 273 } 274 av = defnl((char *) 0, VARNT, ct, 0); 275 #ifndef PI1 276 if (ct != NIL) 277 uniqv(p); 278 #endif not PI1 279 av->chain = p->ptr[NL_VARNT]; 280 p->ptr[NL_VARNT] = av; 281 av->ptr[NL_VTOREC] = vr; 282 av->range[0] = con.crval; 283 return (av); 284 } 285 286 #ifndef PI1 287 /* 288 * Check that the constant label value 289 * is unique among the labels in this variant. 290 */ 291 uniqv(p) 292 struct nl *p; 293 { 294 register struct nl *vt; 295 296 for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain) 297 if (vt->range[0] == con.crval) { 298 error("Duplicate variant case label in record"); 299 return; 300 } 301 } 302 #endif 303 304 /* 305 * See if the field name s is defined 306 * in the record p, returning a pointer 307 * to it namelist entry if it is. 308 */ 309 struct nl * 310 reclook(p, s) 311 register struct nl *p; 312 char *s; 313 { 314 315 if (p == NIL || s == NIL) 316 return (NIL); 317 for (p = p->chain; p != NIL; p = p->chain) 318 if (p->symbol == s) 319 return (p); 320 return (NIL); 321 } 322 323 /* 324 * descend namelist entry for a record and assign offsets. 325 * fields go at the next higher offset that suits their alignment. 326 * all variants of a record start at the same offset, which is suitable 327 * for the alignment of their worst aligned field. thus the size of a 328 * record is independent of whether or not it is a variant 329 * (a desirable property). 330 * records come to us in the namelist, where they have been annotated 331 * with the maximum alignment their fields require. 332 * the starting offset is passed to us, and is passed recursively for 333 * variant records within records. 334 * the final maximum size of each record is recorded in the namelist 335 * in the value[NL_OFFS] field of the namelist for the record. 336 * 337 * this is supposed to match the offsets used by the c compiler 338 * so people can share records between modules in both languages. 339 */ 340 rec_offsets(recp, offset) 341 struct nl *recp; /* pointer to the namelist record */ 342 long offset; /* starting offset for this record/field */ 343 { 344 long origin; /* offset of next field */ 345 struct nl *fieldnlp; /* the current field */ 346 struct nl *varntnlp; /* the current variant */ 347 struct nl *vrecnlp; /* record for the current variant */ 348 349 if ( recp == NIL ) { 350 return; 351 } 352 origin = roundup((int) offset,(long) recp->align_info); 353 if (origin != offset) { 354 fprintf(stderr, 355 "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n", 356 offset, recp->align_info, origin); 357 panic("rec_offsets"); 358 } 359 DEBUG_RECORDS( 360 fprintf(stderr, 361 "[rec_offsets] offset %d recp->align %d origin %d\n", 362 offset, recp->align_info, origin)); 363 /* 364 * fixed fields are forward linked though ->ptr[NL_FIELDLIST] 365 * give them all suitable offsets. 366 */ 367 for ( fieldnlp = recp->ptr[NL_FIELDLIST]; 368 fieldnlp != NIL; 369 fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) { 370 origin = roundup((int) origin,(long) align(fieldnlp->type)); 371 fieldnlp->value[NL_OFFS] = origin; 372 DEBUG_RECORDS( 373 fprintf(stderr,"[rec_offsets] symbol %s origin %d\n", 374 fieldnlp->symbol, origin)); 375 origin += lwidth(fieldnlp->type); 376 } 377 /* 378 * this is the extent of the record, so far 379 */ 380 recp->value[NL_OFFS] = origin; 381 /* 382 * if we have a tag field, we have variants to deal with 383 */ 384 if ( recp->ptr[NL_TAG] ) { 385 /* 386 * if tag field is unnamed, then don't allocate space for it. 387 */ 388 fieldnlp = recp->ptr[NL_TAG]; 389 if ( fieldnlp->symbol != NIL ) { 390 origin = roundup((int) origin,(long) align(fieldnlp->type)); 391 fieldnlp->value[NL_OFFS] = origin; 392 DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n", 393 fieldnlp->symbol, origin)); 394 origin += lwidth(fieldnlp->type); 395 } 396 /* 397 * find maximum alignment of records of variants 398 */ 399 for ( varntnlp = recp->ptr[NL_VARNT]; 400 varntnlp != NIL; 401 varntnlp = varntnlp -> chain ) { 402 vrecnlp = varntnlp->ptr[NL_VTOREC]; 403 DEBUG_RECORDS( 404 fprintf(stderr, 405 "[rec_offsets] maxing variant %d align_info %d\n", 406 varntnlp->value[0], vrecnlp->align_info)); 407 origin = roundup((int) origin,(long) vrecnlp->align_info); 408 } 409 DEBUG_RECORDS( 410 fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin)); 411 /* 412 * assign offsets to fields of records of the variants 413 * keep maximum length of the current record. 414 */ 415 for ( varntnlp = recp->ptr[NL_VARNT]; 416 varntnlp != NIL; 417 varntnlp = varntnlp -> chain ) { 418 vrecnlp = varntnlp->ptr[NL_VTOREC]; 419 /* 420 * assign offsets to fields of the variant. 421 * recursive call on rec_offsets. 422 */ 423 rec_offsets(vrecnlp,origin); 424 /* 425 * extent of the record is the 426 * maximum extent of all variants 427 */ 428 if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) { 429 recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS]; 430 } 431 } 432 } 433 /* 434 * roundup the size of the record to its alignment 435 */ 436 DEBUG_RECORDS( 437 fprintf(stderr, 438 "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n", 439 recp->value[NL_OFFS], recp->align_info)); 440 recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info); 441 } 442