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