|
|
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.