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