|
|
1.1 ! root 1: /* ! 2: * The routines in this file print addresses, generate function ! 3: * prologue and epilogue sequences, ! 4: * compile switches and perform other non-tree-like functions. ! 5: * Both SMALL and LARGE model iAPX-86. ! 6: */ ! 7: #ifdef vax ! 8: #include "INC$LIB:cc1.h" ! 9: #else ! 10: #include "cc1.h" ! 11: #endif ! 12: ! 13: /* ! 14: * These machine dependent variables hold values ! 15: * that are used by the machine dependent parts ! 16: * of register and/or temporary storage allocation. ! 17: * They are set up by routines in this file. ! 18: */ ! 19: int maxauto; /* Max autos in this function */ ! 20: int maxtemp; /* Max temps in this function */ ! 21: int curtemp; /* Current temp */ ! 22: PREGSET regbusy; /* Busy flags */ ! 23: ! 24: /* ! 25: * This table, indexed by register code, ! 26: * yields the correct addressing mode for the ! 27: * register. This is either stashed in an AFIELD or ! 28: * written out to the intermediate file. ! 29: */ ! 30: static short ramode[] = { ! 31: A_RAX, A_RDX, A_RBX, A_RCX, ! 32: A_RSI, A_RDI, A_RSP, A_RBP, ! 33: 0, ! 34: A_RES, A_RCS, A_RSS, A_RDS, ! 35: 0, 0, ! 36: 0, 0, ! 37: 0, 0, 0, 0, ! 38: 0, 0, 0, 0, ! 39: A_RAL, A_RBL, A_RCL, A_RDL, ! 40: A_RAH, A_RBH, A_RCH, A_RDH ! 41: }; ! 42: ! 43: /* ! 44: * Machine-dependent coder initialization. ! 45: * The i8086 version zeros patcache[] entries which are ! 46: * inconsistent with specified machine-dependent variants. ! 47: * This lets the coder decide when the compiler is executed ! 48: * whether to use certain code tables entries. ! 49: * Code tables using 80186 instructions include P80186 pattern flag. ! 50: * Code tables using 80287 instructions include P80287 pattern flag. ! 51: * Code tables using 8087 instructions should include P8087 pattern flag, ! 52: * but this flag is currently unimplemented in the tables; ! 53: * the tables are instead conditionalized for NDP or no NDP when tabgen'ed. ! 54: */ ! 55: coderinit() ! 56: { ! 57: extern int patcsize; ! 58: register int i; ! 59: register PATFLAG *pfp; ! 60: register PATFLAG pflag; ! 61: ! 62: for (pfp=patcache, i=0; i < patcsize; pfp++, i++) { ! 63: if (((pflag = *pfp) & MDPFLAGS) != 0) ! 64: *pfp = ((notvariant(V80287) && ((pflag&P80287)!=0)) ! 65: || (notvariant(V80186) && ((pflag&P80186)!=0))) ! 66: ? 0 : (pflag & ~MDPFLAGS); ! 67: } ! 68: } ! 69: ! 70: /* ! 71: * Function prolog. ! 72: * Clear out max. values of autos ! 73: * and temps. ! 74: */ ! 75: doprolog() ! 76: { ! 77: blkflab = 0; ! 78: maxauto = 0; ! 79: maxtemp = 0; ! 80: } ! 81: ! 82: /* ! 83: * This routine gets called just before ! 84: * the EPILOG item is put out. It puts out a ! 85: * single AUTOS item; this item tells CC2 how much ! 86: * auto space should be reserved. ! 87: * The second ival_t of the AUTOS record (the register ! 88: * mask) is not used by CC2. ! 89: */ ! 90: doepilog() ! 91: { ! 92: bput(AUTOS); ! 93: iput(maxtemp); ! 94: iput(0); ! 95: } ! 96: ! 97: /* ! 98: * Read in and treasure up a new ! 99: * automatic (and register) variable allocation ! 100: * item. The CC1 phase will toss out a single AUTOS ! 101: * item, just before the EPILOG, to tell CC2 how many ! 102: * bytes of automatic storage should be reserved. ! 103: * CC0 tosses one of these for each auto or register bound so that ! 104: * allocated space is not clobbered by temps during auto initialization. ! 105: */ ! 106: doautos() ! 107: { ! 108: maxauto = iget(); ! 109: regbusy = iget(); ! 110: } ! 111: ! 112: /* ! 113: * Unconditional jump. ! 114: */ ! 115: genubr(n) ! 116: { ! 117: genl(ZJMP, n); ! 118: } ! 119: ! 120: /* ! 121: * Conditional jump. ! 122: */ ! 123: gencbr(c, n) ! 124: { ! 125: genl(optab[c-MIOBASE][0], n); ! 126: } ! 127: ! 128: /* ! 129: * Generate code for switches. ! 130: * Look for special cases, etc. and ! 131: * generate the best type of switch ! 132: * logic. ! 133: * The switch value is in AX. ! 134: */ ! 135: genswitch(def, n) ! 136: { ! 137: register ival_t l, r, u; ! 138: register int i, lab0, lab1; ! 139: register int adjust; ! 140: register char *opp; ! 141: ! 142: /* ! 143: * If "n" is small pretend the ! 144: * user said: ! 145: * if (ax == case0) ! 146: * goto caselabel0; ! 147: * if (ax == case1) ! 148: * goto caselabel1; ! 149: * ... ! 150: */ ! 151: if (n < 3) { ! 152: for (i=0; i<n; ++i) { ! 153: if ((l = cases[i].c_val) == 0) ! 154: genrr(ZOR, A_RAX, A_RAX); ! 155: else ! 156: genri(ZCMP, A_RAX, l); ! 157: gencbr(EQ, cases[i].c_lab); ! 158: } ! 159: genubr(def); ! 160: return; ! 161: } ! 162: /* ! 163: * Try for a direct jump table ! 164: * if it seems reasonable to do so. ! 165: */ ! 166: l = cases[0].c_val; ! 167: u = cases[n-1].c_val; ! 168: r = u-l; ! 169: if (r>0 && r<=3*n) { ! 170: if ((adjust=l) != 0) { ! 171: opp = &optab[SUB-MIOBASE][0]; ! 172: if (adjust < 0) { ! 173: opp = &optab[ADD-MIOBASE][0]; ! 174: adjust = -adjust; ! 175: } ! 176: if (adjust == 1) ! 177: genr(opp[1], A_RAX); ! 178: else ! 179: genri(opp[0], A_RAX, adjust); ! 180: } ! 181: genri(ZCMP, A_RAX, r); ! 182: gencbr(UGT, def); ! 183: genri(ZSAL, A_RAX, 1); ! 184: genrr(ZMOV, A_RBX, A_RAX); ! 185: lab0 = newlab(); ! 186: genone(ZIJMP, A_LID|A_CS|A_XBX, lab0); ! 187: genlab(lab0); ! 188: for (i=0; l<=u; ++l) { ! 189: lab0 = def; ! 190: if (l == cases[i].c_val) ! 191: lab0 = cases[i++].c_lab; ! 192: genl(ZLPTR, lab0); ! 193: } ! 194: return; ! 195: } ! 196: /* ! 197: * Table search. ! 198: */ ! 199: lab0 = newlab(); ! 200: gentwo(ZMOV, A_RBX, A_OFFS|A_LID|A_IMM, -2, lab0); ! 201: genri(ZMOV, A_RCX, n); ! 202: lab1 = newlab(); ! 203: genlab(lab1); ! 204: genr(ZINC, A_RBX); ! 205: genr(ZINC, A_RBX); ! 206: gentwo(ZCMP, A_RAX, A_CS|A_XBX); ! 207: genl(ZLOOPNE, lab1); ! 208: gencbr(NE, def); ! 209: genone(ZIJMP, A_OFFS|A_CS|A_XBX, 2*n); ! 210: genlab(lab0); ! 211: for (i=0; i<n; ++i) ! 212: genone(ZWORD, A_OFFS|A_DIR, cases[i].c_val); ! 213: for (i=0; i<n; ++i) ! 214: genl(ZLPTR, cases[i].c_lab); ! 215: } ! 216: ! 217: /* ! 218: * Output an address. ! 219: * "tp" is a pointer to a TREE. ! 220: * The "nsef" flag is true if no side effects are desired; ! 221: * it can be set from the code tables ! 222: * and is used to supress escape bytes on "LEA" instructions. ! 223: * The "pfx" array holds "npfx" address prefix bytes. ! 224: * There is some strangeness here. ! 225: * In memory a is LO and a+2 is HI; ! 226: * this is not the same for constants. ! 227: */ ! 228: genadr(tp, nsef, npfx, pfx) ! 229: register TREE *tp; ! 230: unsigned char pfx[]; ! 231: { ! 232: register int op; ! 233: register int bias; ! 234: register int memf; ! 235: register int byte; ! 236: register int reg; ! 237: register ival_t ival; ! 238: int mode; ! 239: int offs; ! 240: lval_t loffs; ! 241: int lidn; ! 242: SYM *gidp; ! 243: ! 244: static char basebias[] = { ! 245: 0, 0, /* S8, U8, */ ! 246: 1, 1, /* S16, U16, */ ! 247: 2, 2, /* S32, U32, */ ! 248: 2, 4, /* F32, F64, */ ! 249: 0, /* BLK, */ ! 250: 0, 1, /* FLD8, FLD16, */ ! 251: 2, 2, /* LPTR, LPTRB, */ ! 252: 1, 1 /* SPTR, SPTRB */ ! 253: }; ! 254: ! 255: while ((op=tp->t_op) == LEAF) ! 256: tp = tp->t_lp; ! 257: /* ! 258: * The "HI" and "LO" options, ! 259: * when applied to a register node, must ! 260: * arrange to call the "hihalf" and ! 261: * "lohalf" macros. ! 262: */ ! 263: if (op==REG && (reg=tp->t_reg)!=FPAC) { ! 264: while (npfx--) { ! 265: if (pfx[npfx] == M_LO) ! 266: reg = lohalf(reg); ! 267: else ! 268: reg = hihalf(reg); ! 269: } ! 270: iput(ramode[reg]); ! 271: return; ! 272: } ! 273: /* ! 274: * For constants and memory locations, ! 275: * the "HI" and "LO" macros dial the ! 276: * selected byte or word out of the operand. ! 277: * Watch out for the "_fpac_" register, ! 278: * which is actually 64 bits of memory. ! 279: */ ! 280: offs = 0; ! 281: if (npfx) { ! 282: memf = 0; ! 283: if (op!=ICON && op!=LCON && op!=DCON) ! 284: ++memf; ! 285: if (op == REG) ! 286: bias = 4; ! 287: else ! 288: bias = basebias[tp->t_type]; ! 289: while (npfx--) { ! 290: byte = pfx[npfx]; ! 291: if (memf && bias == 2) { ! 292: if (byte == M_HI) ! 293: offs += 2; ! 294: } else if (byte == M_LO) ! 295: offs += bias; ! 296: bias >>= 1; ! 297: } ! 298: } ! 299: /* ! 300: * This "REG" is the floating point ! 301: * pseudo register, which is actually a memory ! 302: * array, 4 words long, called "_fpac_". ! 303: */ ! 304: if (op == REG) { ! 305: iput(A_OFFS|A_GID|A_DIR); ! 306: iput(offs); ! 307: nput("_fpac"); ! 308: return; ! 309: } ! 310: /* ! 311: * Constant nodes are used as immediate ! 312: * operands of instructions. Pull the appropriate ! 313: * 16 bit chunk, and write it out as an immediate ! 314: * operand. ! 315: */ ! 316: if (op == DCON) { ! 317: ival = tp->t_dval[7-offs] & 0377; ! 318: ival |= tp->t_dval[6-offs] << 8; ! 319: iput(A_OFFS|A_IMM); ! 320: iput(ival); ! 321: return; ! 322: } ! 323: if (op == LCON) { ! 324: ival = lower(tp->t_lval); ! 325: if (offs == 0) ! 326: ival = upper(tp->t_lval); ! 327: iput(A_OFFS|A_IMM); ! 328: iput(ival); ! 329: return; ! 330: } ! 331: if (op == ICON) { ! 332: ival = tp->t_ival; ! 333: iput(A_OFFS|A_IMM); ! 334: iput(ival); ! 335: return; ! 336: } ! 337: /* ! 338: * Collect address. ! 339: * Turn the "f" argument on in the call ! 340: * to "gencoll" if this is a "lea", so that it ! 341: * won't generate immediate mode addressing ! 342: * when it shouldn't. ! 343: */ ! 344: mode = A_DIR; ! 345: loffs = offs; ! 346: if (gencoll(tp, &mode, &loffs, &lidn, &gidp, 0, nsef) == 0) ! 347: cbotch("collect"); ! 348: /* ! 349: * No prefix byte on an immediate or on ! 350: * a "lea" (which is indicated by the "nsef" flag ! 351: * being set by the macro in the table. ! 352: */ ! 353: if ((mode&A_AMOD)==A_IMM || nsef!=0) ! 354: mode &= ~A_PREFX; ! 355: offs = loffs; ! 356: if (offs == 0) ! 357: iput(mode); ! 358: else { ! 359: iput(mode|A_OFFS); ! 360: iput(offs); ! 361: } ! 362: if ((mode&A_LID) != 0) ! 363: iput(lidn); ! 364: else if ((mode&A_GID) != 0) ! 365: sput(gidp->s_id); ! 366: } ! 367: ! 368: /* ! 369: * Walk down an address tree, building up ! 370: * the addressing mode, the offset and the symbol base ! 371: * for a general addressing item. Store the data back through ! 372: * the argument pointers. The caller must set the initial mode ! 373: * to "A_DIR" and the offset to 0. ! 374: */ ! 375: gencoll(tp, modep, offsp, lidnp, gidpp, s, f) ! 376: TREE *tp; ! 377: int *modep; ! 378: lval_t *offsp; ! 379: int *lidnp; ! 380: SYM **gidpp; ! 381: { ! 382: register int op; ! 383: register lval_t offs; ! 384: register int seg; ! 385: ! 386: while ((op=tp->t_op) == LEAF) ! 387: tp = tp->t_lp; ! 388: switch (op) { ! 389: ! 390: case ADDR: ! 391: if (gencoll(tp->t_lp, modep, offsp, lidnp, gidpp, s, f) == 0) ! 392: return (0); ! 393: if (f == 0) { ! 394: *modep &= ~A_AMOD; ! 395: *modep |= A_IMM; ! 396: } ! 397: break; ! 398: ! 399: case STAR: ! 400: if (gencoll(tp->t_lp, modep, offsp, lidnp, gidpp, s, 1) == 0) ! 401: return (0); ! 402: break; ! 403: ! 404: case ADD: ! 405: case SUB: ! 406: if (gencoll(tp->t_lp, modep, offsp, lidnp, gidpp, s, f) == 0) ! 407: return (0); ! 408: if (op == SUB) ! 409: s = !s; ! 410: if (gencoll(tp->t_rp, modep, offsp, lidnp, gidpp, s, f) == 0) ! 411: return (0); ! 412: break; ! 413: ! 414: case ICON: ! 415: case LCON: ! 416: offs = grabnval(tp); ! 417: if (s != 0) ! 418: offs = -offs; ! 419: *offsp += offs; ! 420: break; ! 421: ! 422: case LID: ! 423: if ((*modep&(A_GID|A_LID))!=0 || s!=0) ! 424: return (0); ! 425: *modep |= A_LID; ! 426: *lidnp = tp->t_label; ! 427: goto lidgid; ! 428: ! 429: case GID: ! 430: if ((*modep&(A_GID|A_LID))!=0 || s!=0) ! 431: return (0); ! 432: *modep |= A_GID; ! 433: *gidpp = tp->t_sp; ! 434: lidgid: ! 435: *offsp += tp->t_offs; ! 436: /* ! 437: * The parser may have told the code generator ! 438: * where this symbol is located. ! 439: * Apply a CS: escape if the output writer ! 440: * will put it in the CODE or module_CODE segment. ! 441: * This only affects links and MUL/DIM immediate words. ! 442: */ ! 443: seg = tp->t_seg; ! 444: if (seg==SCODE || seg==SLINK ! 445: || (isvariant(VLARGE) ! 446: && ((seg==SPURE && notvariant(VRAM)) ! 447: || (seg==SSTRN && isvariant(VROM))))) { ! 448: *modep &= ~A_PREFX; ! 449: *modep |= A_CS; ! 450: } ! 451: break; ! 452: ! 453: case REG: ! 454: if ((*modep&A_AMOD)!=A_DIR || s!=0) ! 455: return (0); ! 456: switch (tp->t_reg) { ! 457: case DSBX: ! 458: case BX: ! 459: *modep = A_XBX; ! 460: break; ! 461: case ESBX: ! 462: *modep = A_ES|A_XBX; ! 463: break; ! 464: case SSBP: ! 465: case BP: ! 466: *modep = A_XBP; ! 467: break; ! 468: case DSSI: ! 469: case SI: ! 470: *modep = A_XSI; ! 471: break; ! 472: case ESSI: ! 473: *modep = A_ES|A_XSI; ! 474: break; ! 475: case DSDI: ! 476: case DI: ! 477: *modep = A_XDI; ! 478: break; ! 479: case ESDI: ! 480: *modep = A_ES|A_XDI; ! 481: break; ! 482: default: ! 483: return (0); ! 484: } ! 485: break; ! 486: ! 487: default: ! 488: return (0); ! 489: } ! 490: return (1); ! 491: } ! 492: ! 493: /* ! 494: * Output an instruction that takes ! 495: * a single register as an operand. ! 496: */ ! 497: genr(op, r) ! 498: { ! 499: bput(CODE); ! 500: bput(op); ! 501: iput(r); ! 502: } ! 503: ! 504: /* ! 505: * Output an instruction that takes ! 506: * two registers as operands. ! 507: */ ! 508: genrr(op, r1, r2) ! 509: { ! 510: bput(CODE); ! 511: bput(op); ! 512: iput(r1); ! 513: iput(r2); ! 514: } ! 515: ! 516: /* ! 517: * Output an instruction that takes ! 518: * a register and an immediate constant value. ! 519: */ ! 520: genri(op, r, i) ! 521: { ! 522: bput(CODE); ! 523: bput(op); ! 524: iput(r); ! 525: iput(A_OFFS|A_IMM); ! 526: iput(i); ! 527: } ! 528: ! 529: /* ! 530: * Output an instruction with a single ! 531: * local label parameter. ! 532: */ ! 533: genl(op, l) ! 534: { ! 535: bput(CODE); ! 536: bput(op); ! 537: iput(A_LID|A_DIR); ! 538: iput(l); ! 539: } ! 540: ! 541: /* ! 542: * Output an instruction that takes ! 543: * a single global identifier as an operand. ! 544: */ ! 545: geng(op, g) ! 546: char *g; ! 547: { ! 548: bput(CODE); ! 549: bput(op); ! 550: iput(A_GID|A_DIR); ! 551: sput(g); ! 552: } ! 553: ! 554: /* ! 555: * Output an instruction that takes an immediate constant value. ! 556: */ ! 557: geni(op, i) ! 558: { ! 559: bput(CODE); ! 560: bput(op); ! 561: iput(A_OFFS|A_IMM); ! 562: iput(i); ! 563: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.