|
|
1.1 ! root 1: /* ! 2: * n0/i386/bind.c ! 3: * Machine-specific parts of the C compiler parser. ! 4: * i386. ! 5: */ ! 6: ! 7: #ifdef vax ! 8: #include "INC$LIB:cc0.h" ! 9: #else ! 10: #include "cc0.h" ! 11: #endif ! 12: ! 13: /* Local stack: local offset and register mask. */ ! 14: typedef struct locals { ! 15: struct locals *l_lstp; ! 16: ival_t l_lofs; ! 17: int l_mask; ! 18: } LOCALS; ! 19: ! 20: LOCALS *clstp; /* Local stack */ ! 21: ival_t clofs; /* Current local offset */ ! 22: int cmask; /* Current mask */ ! 23: ival_t llofs; /* Last local offset reported */ ! 24: int lmask; /* Last register mask reported */ ! 25: int alignment; /* Alignment from #pragma */ ! 26: ! 27: /* ! 28: * This table is indexed by C type to obtain the size ! 29: * in bytes of a machine object. ! 30: */ ! 31: int mysizes[] = { ! 32: 0, /* T_NONE */ ! 33: 1, 1, /* T_CHAR T_UCHAR */ ! 34: 2, 2, /* T_SHORT T_USHORT */ ! 35: 4, 4, /* T_INT T_UINT */ ! 36: 4, /* T_PTR */ ! 37: 4, 4, /* T_LONG T_ULONG */ ! 38: 4, 8, /* T_FLOAT T_DOUBLE */ ! 39: 0, /* T_VOID */ ! 40: 0, 0, /* T_STRUCT T_FSTRUCT */ ! 41: 0, 0, /* T_UNION T_FUNION */ ! 42: 0, 0 /* T_ENUM T_FENUM */ ! 43: }; ! 44: ! 45: /* ! 46: * This table is indexed by C type to obtain the machine type, ! 47: * as defined in 'mch.h'. ! 48: */ ! 49: char mytypes[] = { ! 50: 0, /* T_NONE */ ! 51: S8, U8, /* T_CHAR T_UCHAR */ ! 52: S16, U16, /* T_SHORT T_USHORT */ ! 53: S32, U32, /* T_INT T_UINT */ ! 54: PTR, /* T_PTR */ ! 55: S32, U32, /* T_LONG T_ULONG */ ! 56: F32, F64, /* T_FLOAT T_DOUBLE */ ! 57: S32, /* T_VOID */ ! 58: BLK, 0, /* T_STRUCT T_FSTRUCT */ ! 59: BLK, 0, /* T_UNION T_FUNION */ ! 60: 0, 0 /* T_ENUM T_FENUM */ ! 61: }; ! 62: ! 63: /* ! 64: * main() calls this routine to perform machine-dependent parser setup. ! 65: */ ! 66: vinit() ! 67: { ! 68: #if MONOLITHIC ! 69: alignment = 0; ! 70: #endif ! 71: } ! 72: ! 73: /* ! 74: * Empty the local binding stack and mark the unavailable registers. ! 75: */ ! 76: initlocals() ! 77: { ! 78: clstp = NULL; ! 79: llofs = clofs = 0; ! 80: lmask = cmask = BESP|BEBP; ! 81: bput(AUTOS); ! 82: iput(clofs); ! 83: iput((ival_t)cmask); ! 84: } ! 85: ! 86: /* ! 87: * Save the current state of the local bindings. ! 88: */ ! 89: savelocals() ! 90: { ! 91: register LOCALS *lstp; ! 92: ! 93: lstp = (LOCALS *) new(sizeof(LOCALS)); ! 94: lstp->l_lstp = clstp; ! 95: lstp->l_lofs = clofs; ! 96: lstp->l_mask = cmask; ! 97: clstp = lstp; ! 98: } ! 99: ! 100: /* ! 101: * Restore locals. ! 102: * Tell the code generator if it changes. ! 103: */ ! 104: restlocals() ! 105: { ! 106: register LOCALS *lstp; ! 107: ! 108: if ((lstp=clstp) == NULL) ! 109: cbotch("restlocals"); ! 110: clstp = lstp->l_lstp; ! 111: clofs = lstp->l_lofs; ! 112: cmask = lstp->l_mask; ! 113: putautos(); ! 114: free((char *) lstp); ! 115: } ! 116: ! 117: /* ! 118: * Inform the code generator (and perhaps the optimizer) ! 119: * about the current automatic variable allocation. ! 120: */ ! 121: putautos() ! 122: { ! 123: if (clofs != llofs || cmask != lmask) { ! 124: llofs = clofs; ! 125: lmask = cmask; ! 126: bput(AUTOS); ! 127: iput(-clofs); ! 128: iput((ival_t)cmask); ! 129: } ! 130: } ! 131: ! 132: /* ! 133: * Bind locals to the correct place on the stack frame. ! 134: * Locals grow down from EBP, e.g. EBP-4, EBP-8, etc. ! 135: */ ! 136: bindlocal(sp) register SYM *sp; ! 137: { ! 138: register int c, regno; ! 139: ! 140: if ((c = sp->s_class) == C_REG) { ! 141: if ((regno = grabreg(sp)) >= 0) { ! 142: sp->s_value = regno; ! 143: return; ! 144: } ! 145: /* Demote register local to auto. */ ! 146: setclass(sp, C_AUTO); ! 147: } ! 148: if (c==C_AUTO || c==C_REG) { ! 149: clofs -= ssize(sp); ! 150: /* Keep stack dword-aligned. */ ! 151: if ((clofs & 3) != 0) ! 152: clofs &= ~3; ! 153: sp->s_value = clofs; ! 154: if (clofs >= 0) ! 155: cerror("auto \"%s\" is not addressable", sp->s_id); ! 156: } ! 157: } ! 158: ! 159: /* ! 160: * Attempt to get a register for symbol 'sp'. ! 161: * Only integer dword objects go in registers currently. ! 162: * Chars, shorts and floats could go in registers if loadreg() were changed. ! 163: * Return register id if successful, -1 otherwise. ! 164: */ ! 165: grabreg(sp) register SYM *sp; ! 166: { ! 167: register DIM *dp; ! 168: register int type; ! 169: ! 170: if ((dp = sp->s_dp) != NULL) ! 171: return (dp->d_type == D_PTR) ? allocreg() : -1; ! 172: type = sp->s_type; ! 173: if (type >= T_INT && type <= T_ULONG) ! 174: return allocreg(); ! 175: return -1; ! 176: } ! 177: /* ! 178: * Allocate a register. ! 179: * Currently allocates EBX, ESI and EDI. ! 180: * Return register id if successful, -1 otherwise. ! 181: */ ! 182: int ! 183: allocreg() ! 184: { ! 185: if ((cmask&BEBX) == 0) { ! 186: cmask |= BEBX; ! 187: return EBX; ! 188: } else if ((cmask&BESI) == 0) { ! 189: cmask |= BESI; ! 190: return ESI; ! 191: } else if ((cmask&BEDI) == 0) { ! 192: cmask |= BEDI; ! 193: return EDI; ! 194: } else ! 195: return -1; ! 196: } ! 197: ! 198: /* ! 199: * Bind arguments. ! 200: * Stack frame during function execution: ! 201: * ... ! 202: * ebp+8 arg1 ! 203: * ebp+4 return address ! 204: * ebp saved ebp ! 205: * ebp-4 auto1 ! 206: * ... ! 207: ebp-n autolast ! 208: * ebp-n-4 saved esi [if required] ! 209: * ebp-n-8 saved edi [if required] ! 210: * ebp-n-12 saved ebx [if required] ! 211: */ ! 212: bindargs() ! 213: { ! 214: register SYM *sp; ! 215: register int i; ! 216: register ival_t offset; ! 217: ! 218: offset = 8; /* arg1 offset */ ! 219: for (i = 0; i < nargs; ++i) { ! 220: sp = args[i]; ! 221: if (sp->s_class != C_PREG) ! 222: sp->s_class = C_PAUTO; ! 223: sp->s_value = offset; ! 224: offset += ssize(sp); ! 225: /* Keep parameters dword-aligned. */ ! 226: if ((offset & 3) != 0) ! 227: offset = (offset + 3) & ~3; ! 228: } ! 229: } ! 230: ! 231: /* ! 232: * Copy register arguments from the stack into the register. ! 233: * Change class of the argument to plain register. ! 234: * Note that bindargs() has put the stack displacement ! 235: * into the 's_value' field of the argument symbol. ! 236: */ ! 237: loadargs() ! 238: { ! 239: register SYM *sp; ! 240: register int i, r; ! 241: register ival_t v; ! 242: ! 243: for (i = 0; i < nargs; ++i) { ! 244: sp = args[i]; ! 245: if (sp->s_class == C_PREG) { ! 246: if ((r=grabreg(sp)) >= 0) { ! 247: v = sp->s_value; /* stack offset */ ! 248: sp->s_class = C_REG; ! 249: sp->s_value = r; /* register number */ ! 250: loadreg(sp, v); ! 251: continue; ! 252: } ! 253: /* Demote parametric register to parametric auto. */ ! 254: setclass(sp, C_PAUTO); ! 255: } ! 256: } ! 257: } ! 258: ! 259: /* ! 260: * Change the storage class of sp. ! 261: * Issue a 'strict' warning if desired. ! 262: */ ! 263: setclass(sp, c) register SYM *sp; int c; ! 264: { ! 265: sp->s_class = c; ! 266: if (isvariant(VSNREG)) ! 267: cstrict("identifier \"%s\" not bound to register", sp->s_id); ! 268: } ! 269: ! 270: /* ! 271: * Load symbol 'sp' from offset 'offset' in the frame. ! 272: * Since register variables are always dwords, ! 273: * the type can always be setup to T_INT. ! 274: */ ! 275: loadreg(sp, offset) SYM *sp; ival_t offset; ! 276: { ! 277: register TREE *lp, *rp, *tp; ! 278: ! 279: newtree(sizeof(TREE)); ! 280: lp = talloc(); ! 281: lp->t_op = REG; ! 282: lp->t_type = T_INT; ! 283: lp->t_reg = sp->s_value; ! 284: rp = talloc(); ! 285: rp->t_op = PID; ! 286: rp->t_type = T_INT; ! 287: rp->t_offs = offset; ! 288: tp = build(ASSIGN, lp, rp); ! 289: putautos(); ! 290: tput(EEXPR, 0, tp); ! 291: } ! 292: ! 293: /* ! 294: * Process a #pragma. ! 295: * Currently recognizes only "#pragma align [n]". ! 296: * Return 1 if recognized, 0 if not. ! 297: */ ! 298: pragma(p) char *p; ! 299: { ! 300: static char align[] = "align"; ! 301: ! 302: while (*p == ' ' || *p == '\t') ! 303: ++p; ! 304: if (strncmp(align, p, sizeof(align)-1) == 0) { ! 305: alignment = atoi(p + sizeof(align)-1); ! 306: if (alignment < 0) { ! 307: cerror("#pragma align: bad alignment %d", alignment); ! 308: alignment = 0; ! 309: } ! 310: return 1; ! 311: } ! 312: return 0; ! 313: } ! 314: ! 315: /* ! 316: * Look at type 't', DIM list 'dp' and field width 'w' (0 for non fields) ! 317: * and return the bit offset of the base of the structure member. ! 318: * The 'offset' argument is the current bit offset in the structure or union. ! 319: * Check for fields that are too wide, bad field base types, and arrange ! 320: * that the byte, word or dword that spans the field can be grabbed in one grab. ! 321: * See comments in bindlocal() above concerning reals and bitfield alignment. ! 322: */ ! 323: long ! 324: fieldalign(t, dp, ip, w, offset) ! 325: register DIM *dp; ! 326: INFO *ip; ! 327: register int w; ! 328: long offset; ! 329: { ! 330: register long bitwidth, amask, a; ! 331: ! 332: /* ! 333: * Find bit width of type t; ! 334: * e.g. 8 for char, 16 for short, 32 for int or ptr. ! 335: */ ! 336: if (dp != NULL) { ! 337: switch(dp->d_type) { ! 338: case D_FUNC: t = T_PTR; break; ! 339: case D_PTR: t = T_PTR; break; ! 340: case D_ARRAY: break; ! 341: case D_MOSAR: break; ! 342: default: cbotch("fieldalign %d", dp->d_type); ! 343: } ! 344: } else if (t == T_FENUM) ! 345: t = T_INT; ! 346: else if (t == T_ENUM) ! 347: t = ip->i_type; ! 348: if (alignment == 0) { ! 349: if (t == T_STRUCT || t == T_UNION) ! 350: bitwidth = 8 * saligntype(ip); ! 351: else ! 352: bitwidth = 8 * mysizes[t]; ! 353: if (bitwidth == 0) ! 354: bitwidth = 32; ! 355: amask = bitwidth - 1; ! 356: } else { ! 357: if (t == T_STRUCT || t == T_UNION) ! 358: a = saligntype(ip); ! 359: else ! 360: a = (mysizes[t] == 0) ? 4 : mysizes[t]; ! 361: amask = 8 * ((a < alignment) ? a : alignment) - 1; ! 362: bitwidth = 8 * a; ! 363: } ! 364: if (w != 0) { ! 365: /* Nonzero width bitfield. */ ! 366: if (dp != NULL) ! 367: cerror("non scalar field"); ! 368: if (bitwidth > 32) ! 369: cerror("bad base type for field"); ! 370: #if 0 ! 371: if (w > bitwidth) ! 372: cerror("field too wide"); ! 373: #endif ! 374: /* Bump to next alignment boundary if necessary. */ ! 375: if ((offset & amask) + w > bitwidth) ! 376: offset = (offset + amask) & ~amask; ! 377: } else { ! 378: /* Zero width bitfield or non field. */ ! 379: offset = (offset + amask) & ~amask; ! 380: } ! 381: return offset; ! 382: } ! 383: ! 384: /* ! 385: * Convert a tree into its low level form. ! 386: * Fill in the machine type byte looking at the C type ! 387: * and the segment information. ! 388: */ ! 389: TREE * ! 390: transform(tp, why, above) register TREE *tp; int why, above; ! 391: { ! 392: register TREE *lp; ! 393: register int t; ! 394: register int wd; ! 395: ! 396: /* ! 397: * The way that this code looks at the DIM lists to decide ! 398: * what type of conversion is inserted makes me sick. ! 399: * The correct type of conversion node (MUL, DIV, etc.) ! 400: * should really be inserted when the tree is constructed, ! 401: * guided by a table. ! 402: */ ! 403: if (tp->t_op == CONVERT) { ! 404: lp = tp->t_lp; ! 405: if (tp->t_dp!=NULL && lp->t_dp==NULL && why!=REXPR) { ! 406: tp->t_op = MUL; ! 407: tp->t_dp = NULL; ! 408: if (lp->t_type != T_INT) ! 409: tp->t_lp = bconvert(lp, T_INT, NULL,NULL,NULL); ! 410: tp->t_type = T_INT; ! 411: } else if (tp->t_dp==NULL && lp->t_dp!=NULL && tp->t_rp!=NULL) { ! 412: tp->t_op = DIV; ! 413: lp->t_dp = NULL; ! 414: lp->t_type = T_INT; ! 415: } ! 416: } ! 417: ! 418: /* Fixup any remaining ZCONs. */ ! 419: if (tp->t_op == ZCON) { ! 420: tp->t_op = ICON; ! 421: tp->t_type = T_INT; ! 422: tp->t_ival = tp->t_zval; ! 423: } ! 424: ! 425: /* Set the type field. */ ! 426: if (tp->t_dp != NULL) ! 427: tp->t_type = mytypes[T_PTR]; ! 428: else if ((t=tp->t_type)==T_FSTRUCT || t==T_FUNION || t==T_FENUM) { ! 429: unksize(t, tp->t_ip); ! 430: tp->t_type = S32; /* default to S32 */ ! 431: } else { ! 432: if (t == T_ENUM) ! 433: t = tp->t_ip->i_type; /* enum base type */ ! 434: tp->t_type = mytypes[t]; ! 435: } ! 436: ! 437: if (tp->t_op >= MIOBASE) { ! 438: wd = why; ! 439: if (why == REXPR) ! 440: wd = EEXPR; ! 441: tp->t_lp = transform(tp->t_lp, wd, tp->t_op); ! 442: if (tp->t_op!=FIELD && tp->t_rp!=NULL) ! 443: tp->t_rp = transform(tp->t_rp, wd, -1); ! 444: if (tp->t_op==CONVERT && tp->t_rp==NULL) { ! 445: lp = tp->t_lp; ! 446: if (tp->t_type == lp->t_type) ! 447: tp = lp; ! 448: } ! 449: } ! 450: return tp; ! 451: } ! 452: ! 453: /* ! 454: * Check if the operator 'op' applied to C types 'lt' and 'rt' ! 455: * (which are outputs from tltype(), which means that all pointers ! 456: * have been converted to type T_PTR) involves no conversions. ! 457: * This means the code generator must deal with the type mismatch. ! 458: */ ! 459: noconvert(op, lt, rt) register int op, lt, rt; ! 460: { ! 461: if (op==ASSIGN || op==CAST || (op>=EQ && op<=ULT)) { ! 462: if ((lt>=T_CHAR && lt<=T_UCHAR) ! 463: && (rt>=T_CHAR && rt<=T_UCHAR)) ! 464: return 1; /* 8-bit types */ ! 465: if ((lt>=T_SHORT && lt<=T_USHORT) ! 466: && (rt>=T_SHORT && rt<=T_USHORT)) ! 467: return 1; /* 16-bit types */ ! 468: if ((lt>=T_INT && lt<=T_ULONG) ! 469: && (rt>=T_INT && rt<=T_ULONG)) ! 470: return 1; /* 32-bit types */ ! 471: if (op==CAST && lt==T_FLOAT && rt==T_DOUBLE) ! 472: return 1; /* (float)double */ ! 473: } ! 474: return 0; ! 475: } ! 476: ! 477: /* ! 478: * Align the location counter well enough for the object 'sp'. ! 479: */ ! 480: align(sp) SYM *sp; ! 481: { ! 482: bput(ALIGN); ! 483: bput(aligntype(sp)); ! 484: } ! 485: ! 486: /* ! 487: * Return the appropriate alignment type for 'sp'. ! 488: * The alignment type is 1 for byte, 2 for word, 4 for dword. ! 489: */ ! 490: aligntype(sp) SYM *sp; ! 491: { ! 492: register int type, atype, dtype; ! 493: register DIM *dp; ! 494: ! 495: if (alignment != 0) ! 496: return alignment; /* use #pragma-defined alignment */ ! 497: type = sp->s_type; ! 498: atype = mysizes[type]; ! 499: if ((dp = sp->s_dp) != NULL) { ! 500: while (dp != NULL ! 501: && ((dtype = dp->d_type) == D_ARRAY || dtype == D_MOSAR)) ! 502: dp = dp->d_dp; ! 503: if (dtype == D_PTR || dtype == D_FUNC) ! 504: return 4; /* pointer to, function returning */ ! 505: } ! 506: if (atype == 1 || atype == 2 || (atype == 4 && type != T_PTR)) ! 507: return atype; /* chars, shorts, ints, longs, floats */ ! 508: else if (type == T_DOUBLE) ! 509: return 4; /* dword alignment, not qword */ ! 510: else if (type == T_STRUCT || type == T_UNION) ! 511: return saligntype(sp->s_ip); ! 512: else if (type == T_ENUM) ! 513: return mytypes[sp->s_ip->i_type]; /* enum base type */ ! 514: else if (type == T_FSTRUCT || type == T_FUNION || type == T_FENUM) { ! 515: cerror("alignment of %s \"%s\" is not known", ! 516: (type == T_FSTRUCT) ? "struct" ! 517: : (type == T_FUNION) ? "union" ! 518: : "enum", ! 519: sp->s_id); ! 520: return 4; ! 521: } ! 522: /* T_NONE, T_PTR, T_VOID */ ! 523: cbotch("aligntype type=%d", type); ! 524: } ! 525: ! 526: /* ! 527: * Run down a struct INFO list to find alignment type. ! 528: */ ! 529: int ! 530: saligntype(ip) register INFO *ip; ! 531: { ! 532: register int i, j, max, n; ! 533: ! 534: if (alignment != 0) ! 535: return alignment; ! 536: n = ip->i_nsp; /* number of members */ ! 537: for (i = max = 0; i < n; i++) { ! 538: j = aligntype(ip->i_sp[i]); ! 539: if (j > max) ! 540: max = j; ! 541: } ! 542: return max; ! 543: } ! 544: ! 545: /* ! 546: * Given a field type, return an appropriate alignment type. ! 547: */ ! 548: int ! 549: faligntype(t) register int t; ! 550: { ! 551: if (t <= T_ULONG && t != T_PTR) ! 552: return mysizes[t]; ! 553: cbotch("faligntype %d", t); ! 554: } ! 555: ! 556: /* ! 557: * Check object sizes for overflow. ! 558: */ ! 559: sizeof_t ! 560: szcheck(n, a, s) sizeof_t n; int a; char *s; ! 561: { ! 562: return n; ! 563: } ! 564: ! 565: #if FOLD_DOUBLES ! 566: /* ! 567: * Convert DCON to/from host double. ! 568: * Used by the double constant folder in n0/fold.c. ! 569: * Assumes host fp representation == target fp representation! ! 570: * The byte orders of the double and DCON are reversed. ! 571: */ ! 572: double ! 573: dval_to_d(tp) TREE *tp; ! 574: { ! 575: double d; ! 576: register char *src, *dst; ! 577: ! 578: for (src = tp->t_dval, dst = ((char *)&d) + sizeof(d) - 1; dst >= &d; ) ! 579: *dst-- = *src++; ! 580: return d; ! 581: } ! 582: ! 583: void ! 584: d_to_dval(tp, d) TREE *tp; double d; ! 585: { ! 586: register char *src, *dst; ! 587: ! 588: for (dst = tp->t_dval, src = ((char *)&d) + sizeof(d) - 1; src >= &d; ) ! 589: *dst++ = *src--; ! 590: } ! 591: #endif ! 592: ! 593: /* end of n0/i386/bind.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.