|
|
1.1 ! root 1: /* ! 2: * n0/fold.c ! 3: * Constant expression folder for the C compiler parser. ! 4: * More of this is done in the code generator. ! 5: * This one exists only to allow constant expressions in case labels, ! 6: * in array bounds, and in initializers. ! 7: */ ! 8: ! 9: #ifdef vax ! 10: #include "INC$LIB:cc0.h" ! 11: #else ! 12: #include "cc0.h" ! 13: #endif ! 14: ! 15: extern lval_t grablval(); ! 16: ! 17: #if FOLD_DOUBLES ! 18: /* ! 19: * The double folding code below assumes that the compiler host and target fp ! 20: * representations are identical, ! 21: * an assumption the compiler source carefully avoids making everywhere else. ! 22: * If host fp == target fp, ! 23: * ordinary C fp operations (+, -, *, / etc.) can be used in folding. ! 24: * If host fp != target fp, folding requires format translation or emulation. ! 25: * A compiler produced with this option uses fp, ! 26: * so in particular the verison of fp it uses must run on all target systems; ! 27: * e.g., if you compile the compiler -VNDP then the target will need ! 28: * either an NDP or NDP emulation. ! 29: */ ! 30: extern TREE *foldd(); ! 31: extern double grabdval(); ! 32: #endif ! 33: ! 34: /* ! 35: * Try to fold constants. ! 36: * The given op must be appropriate for folding, ! 37: * the left subtree must be a constant (ICON/LCON/ZCON/DCON), and ! 38: * the right subtree (if any) must be a constant (ICON/LCON/ZCON/DCON) ! 39: * for folding to work. ! 40: * Return pointer to a constant tree node, ! 41: * or NULL if folding is impossible. ! 42: * This code is very casual about lval_t/ulval_t bit equivalence. ! 43: * Folds double constants if FOLD_DOUBLES. ! 44: */ ! 45: TREE * ! 46: fold0(op, lp, rp) int op; TREE *lp, *rp; ! 47: { ! 48: register TREE *tp; ! 49: register lval_t lv, rv; ! 50: int bool; ! 51: register int lt, rt, gt, uflag, zflag, lflag; ! 52: ! 53: /* Check op dope table to make sure op has a chance of folding. */ ! 54: if ((opdope[op - MIOBASE] & FOLD) == 0) ! 55: return NULL; ! 56: ! 57: /* Check for constant left subtree. */ ! 58: if (!isconst(lp)) ! 59: return NULL; ! 60: lt = lp->t_type; ! 61: ! 62: /* Handle ?: without further ado. */ ! 63: if (op == QUEST) { ! 64: if (rp->t_op != COLON) ! 65: return NULL; /* parsing must be fubar */ ! 66: return (grablval(lp, 0)) ? rp->t_lp : rp->t_rp; ! 67: } ! 68: ! 69: /* Handle ',' with constant on lhs without further ado. */ ! 70: if (op == COMMA) ! 71: return rp; ! 72: ! 73: if (rp != NULL) { ! 74: /* Check for constant right subtree. */ ! 75: if (!isconst(rp)) ! 76: return NULL; ! 77: rt = rp->t_type; ! 78: } else ! 79: rt = lt; /* Unary ops: no right subtree */ ! 80: ! 81: /* ! 82: * Find the goal type in the conversion dope table. ! 83: * Watch out for shifts, right type implicitly T_INT. ! 84: */ ! 85: if (op == SHL || op == SHR) ! 86: rt = T_INT; ! 87: gt = cvdope[13 * (lt - T_CHAR) + (rt - T_CHAR)] & GOAL; ! 88: ! 89: /* Set unsigned, long, ZCON flags based on goal type. */ ! 90: uflag = (gt == T_UINT || gt == T_ULONG); ! 91: lflag = (gt == T_LONG || gt == T_ULONG); ! 92: zflag = (lp->t_op == ZCON || (rp != NULL && rp->t_op == ZCON)); ! 93: ! 94: #if FOLD_DOUBLES ! 95: /* Fold as doubles if goal type is double. */ ! 96: if (gt == T_DOUBLE) { ! 97: if (opdope[op - MIOBASE] & NFLT) ! 98: return NULL; /* op is illegal in any case */ ! 99: return foldd(op, lp, rp); ! 100: } ! 101: #endif ! 102: ! 103: /* Grab the left and right values as [u]lval_t. */ ! 104: lv = grablval(lp, uflag); ! 105: if (rp != NULL) ! 106: rv = grablval(rp, uflag); ! 107: ! 108: /* Perform the folding, computing result in lv or in bool (0 or 1). */ ! 109: bool = -1; ! 110: switch (op) { ! 111: ! 112: case COM: lv = ~lv; break; ! 113: case NEG: lv = -lv; break; ! 114: case ADD: lv += rv; break; ! 115: case SUB: lv -= rv; break; ! 116: case MUL: lv *= rv; break; ! 117: case AND: lv &= rv; break; ! 118: case OR: lv |= rv; break; ! 119: case XOR: lv ^= rv; break; ! 120: case SHL: lv <<= rv; break; ! 121: ! 122: /* Ops /, % and >> are different for signed and unsigned cases. */ ! 123: case DIV: ! 124: if (rv == 0) { ! 125: cwarn("divide by zero"); ! 126: return NULL; ! 127: } ! 128: if (uflag) ! 129: lv = ((ulval_t)lv / (ulval_t)rv); ! 130: else ! 131: lv /= rv; ! 132: break; ! 133: ! 134: case REM: ! 135: if (rv == 0) { ! 136: cwarn("zero modulus"); ! 137: return NULL; ! 138: } ! 139: if (uflag) ! 140: lv = ((ulval_t)lv % (ulval_t)rv); ! 141: else ! 142: lv %= rv; ! 143: break; ! 144: ! 145: case SHR: ! 146: if (uflag) ! 147: lv = ((ulval_t)lv >> (ulval_t)rv); ! 148: else ! 149: lv >>= rv; ! 150: break; ! 151: ! 152: /* Relations and conditionals return T_INT result in bool. */ ! 153: case NOT: bool = !lv; break; ! 154: case EQ: bool = lv == rv; break; ! 155: case NE: bool = lv != rv; break; ! 156: case ANDAND: bool = (lv && rv); break; ! 157: case OROR: bool = (lv || rv); break; ! 158: /* Nonequality relations are different for signed and unsigned cases. */ ! 159: case LT: ! 160: bool = (uflag) ? ((ulval_t)lv < (ulval_t)rv) : (lv < rv); ! 161: break; ! 162: case LE: ! 163: bool = (uflag) ? ((ulval_t)lv <= (ulval_t)rv) : (lv <= rv); ! 164: break; ! 165: case GT: ! 166: bool = (uflag) ? ((ulval_t)lv > (ulval_t)rv) : (lv > rv); ! 167: break; ! 168: case GE: ! 169: bool = (uflag) ? ((ulval_t)lv >= (ulval_t)rv) : (lv >= rv); ! 170: break; ! 171: ! 172: default: /* shouldn't happen if opdope is right */ ! 173: return NULL; ! 174: } ! 175: ! 176: /* Allocate a TREE for the result, store result, return it. */ ! 177: tp = talloc(); ! 178: if (bool != -1) { /* boolean result */ ! 179: tp->t_op = ICON; ! 180: tp->t_type = T_INT; ! 181: tp->t_ival = bool; ! 182: } else if (lflag) { /* [u]long result */ ! 183: tp->t_op = LCON; ! 184: tp->t_type = (uflag) ? T_ULONG : T_LONG; ! 185: tp->t_lval = lv; ! 186: } else if (zflag) { /* size_t result */ ! 187: tp->t_op = ZCON; ! 188: tp->t_type = T_UINT; ! 189: tp->t_zval = lv; ! 190: } else { /* [u]int result */ ! 191: tp->t_op = ICON; ! 192: tp->t_type = (uflag) ? T_UINT : T_INT; ! 193: tp->t_ival = lv; ! 194: } ! 195: return tp; ! 196: } ! 197: ! 198: /* ! 199: * Return true if tp represents a constant (ICON, LCON, ZCON, DCON). ! 200: */ ! 201: int ! 202: isconst(tp) register TREE *tp; ! 203: { ! 204: register int op; ! 205: ! 206: return (tp->t_dp == NULL ! 207: && ((op = tp->t_op) == ICON ! 208: || op == LCON ! 209: || op == ZCON ! 210: #if FOLD_DOUBLES ! 211: || op == DCON ! 212: #endif ! 213: )); ! 214: } ! 215: ! 216: /* ! 217: * Grab the value of a constant as an lval_t (or ulval_t, really). ! 218: * Zero extend if the goal type is unsigned. ! 219: */ ! 220: lval_t ! 221: grablval(tp, uflag) register TREE *tp; int uflag; ! 222: { ! 223: switch (tp->t_op) { ! 224: case ICON: ! 225: return (uflag) ? (ulval_t)(uival_t)tp->t_ival : tp->t_ival; ! 226: case ZCON: ! 227: return (ulval_t)tp->t_zval; ! 228: case LCON: ! 229: return tp->t_lval; ! 230: #if FOLD_DOUBLES ! 231: case DCON: ! 232: return dval_to_d(tp); ! 233: #endif ! 234: } ! 235: cbotch("grablval"); ! 236: } ! 237: ! 238: #if FOLD_DOUBLES ! 239: ! 240: /* ! 241: * Fold double constants. ! 242: */ ! 243: TREE * ! 244: foldd(op, lp, rp) int op; TREE *lp, *rp; ! 245: { ! 246: register TREE *tp; ! 247: int bool; ! 248: double lv, rv; ! 249: ! 250: lv = grabdval(lp); ! 251: if (rp != NULL) ! 252: rv = grabdval(rp); ! 253: ! 254: ! 255: /* Perform the folding, leaving result in lv or in bool (0 or 1). */ ! 256: bool = -1; ! 257: switch(op) { ! 258: ! 259: case NEG: lv = -lv; break; ! 260: case ADD: lv += rv; break; ! 261: case SUB: lv -= rv; break; ! 262: case MUL: lv *= rv; break; ! 263: case DIV: lv /= rv; break; ! 264: ! 265: /* Relations and conditionals return T_INT result in bool. */ ! 266: case NOT: bool = !lv; break; ! 267: case EQ: bool = lv == rv; break; ! 268: case NE: bool = lv != rv; break; ! 269: case LT: bool = lv < rv; break; ! 270: case LE: bool = lv <= rv; break; ! 271: case GT: bool = lv > rv; break; ! 272: case GE: bool = lv >= rv; break; ! 273: case ANDAND: bool = (lv && rv); break; ! 274: case OROR: bool = (lv || rv); break; ! 275: ! 276: default: /* shouldn't happen if opdope is right */ ! 277: return NULL; ! 278: } ! 279: ! 280: /* Allocate a TREE for the result and store the result. */ ! 281: tp = talloc(); ! 282: if (bool != -1) { /* boolean result */ ! 283: tp->t_op = ICON; ! 284: tp->t_type = T_INT; ! 285: tp->t_ival = bool; ! 286: } else { /* double result */ ! 287: tp->t_op = DCON; ! 288: tp->t_type = T_DOUBLE; ! 289: d_to_dval(tp, lv); ! 290: } ! 291: return tp; ! 292: } ! 293: ! 294: /* ! 295: * Grab the value of a constant as a double. ! 296: */ ! 297: double ! 298: grabdval(tp) register TREE *tp; ! 299: { ! 300: register int t; ! 301: ! 302: switch (tp->t_op) { ! 303: case ICON: ! 304: return ((t = tp->t_type) == T_UINT || t == T_ULONG) ! 305: ? (uival_t)tp->t_ival : tp->t_ival; ! 306: case ZCON: ! 307: return (uival_t)tp->t_zval; ! 308: case LCON: ! 309: return ((t = tp->t_type) == T_UINT || t == T_ULONG) ! 310: ? (ulval_t)tp->t_lval : tp->t_lval; ! 311: case DCON: ! 312: return dval_to_d(tp); ! 313: } ! 314: cbotch("grabdval"); ! 315: } ! 316: ! 317: #endif ! 318: ! 319: /* end of n0/fold.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.