fold.c - scc - simple c99 compiler
HTML git clone git://git.simple-cc.org/scc
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
fold.c (17623B)
---
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include <scc/scc.h>
5 #include "cc1.h"
6
7
8 unsigned long long
9 ones(int nbytes)
10 {
11 return (nbytes == 8) ? -1 : ~(-1ull << nbytes * 8);
12 }
13
14 static int
15 addi(long long l, long long r, Type *tp)
16 {
17 struct limits *lim = getlimits(tp);
18 long long max = lim->max.i, min = lim->min.i;
19
20 if (l < 0 && r < 0 && l >= min - r ||
21 l == 0 ||
22 r == 0 ||
23 l < 0 && r > 0 ||
24 l > 0 && r < 0 ||
25 l > 0 && r > 0 && l <= max - r) {
26 return 1;
27 }
28 warn("overflow in constant expression");
29 return 0;
30 }
31
32 static int
33 addf(double l, double r, Type *tp)
34 {
35 struct limits *lim = getlimits(tp);
36 double max = lim->max.f, min = lim->min.f;
37
38 if (l < 0 && r < 0 && l >= min - r ||
39 l == 0 ||
40 r == 0 ||
41 l < 0 && r > 0 ||
42 l > 0 && r < 0 ||
43 l > 0 && r > 0 && l <= max - r) {
44 return 1;
45 }
46 warn("overflow in constant expression");
47 return 0;
48 }
49
50 static int
51 subi(long long l, long long r, Type *tp)
52 {
53 return addi(l, -r, tp);
54 }
55
56 static int
57 subf(double l, double r, Type *tp)
58 {
59 return addf(l, -r, tp);
60 }
61
62 static int
63 muli(long long l, long long r, Type *tp)
64 {
65 struct limits *lim = getlimits(tp);
66 long long max = lim->max.i, min = lim->min.i;
67
68 if (l > -1 && l <= 1 ||
69 r > -1 && r <= 1 ||
70 l < 0 && r < 0 && -l <= max/-r ||
71 l < 0 && r > 0 && l >= min/r ||
72 l > 0 && r < 0 && r >= min/l ||
73 l > 0 && r > 0 && l <= max/r) {
74 return 1;
75 }
76 warn("overflow in constant expression");
77 return 0;
78 }
79
80 static int
81 mulf(double l, double r, Type *tp)
82 {
83 struct limits *lim = getlimits(tp);
84 double max = lim->max.f, min = lim->min.f;
85
86 if (l > -1 && l <= 1 ||
87 r > -1 && r <= 1 ||
88 l < 0 && r < 0 && -l <= max/-r ||
89 l < 0 && r > 0 && l >= min/r ||
90 l > 0 && r < 0 && r >= min/l ||
91 l > 0 && r > 0 && l <= max/r) {
92 return 1;
93 }
94 warn("overflow in constant expression");
95 return 0;
96 }
97
98 static int
99 divi(long long l, long long r, Type *tp)
100 {
101 struct limits *lim = getlimits(tp);
102
103 if (r == 0 || l == -lim->min.i && r == -1) {
104 warn("overflow in constant expression");
105 return 0;
106 }
107 return 1;
108 }
109
110 static int
111 divf(double l, double r, Type *tp)
112 {
113 struct limits *lim = getlimits(tp);
114
115 if (l < 0) l = -l;
116 if (r < 0) r = -r;
117
118 if (r == 0.0 || r < 1.0 && l > lim->max.f * r) {
119 warn("overflow in constant expression");
120 return 0;
121 }
122 return 1;
123 }
124
125 static int
126 lshi(long long l, long long r, Type *tp)
127 {
128 if (r < 0 || r >= tp->size * 8) {
129 warn("shifting %d bits is undefined", r);
130 return 0;
131 }
132 return muli(l, 1 << r, tp);
133 }
134
135 static int
136 rshi(long long l, long long r, Type *tp)
137 {
138 if (r < 0 || r >= tp->size * 8) {
139 warn("shifting %d bits is undefined", r);
140 return 0;
141 }
142 return 1;
143 }
144
145 static int
146 foldint(int op, Symbol *res, long long l, long long r)
147 {
148 long long i;
149 Type *tp = res->type;
150 int (*validate)(long long, long long, Type *tp);
151
152 switch (op) {
153 case OADD: validate = addi; break;
154 case OSUB: validate = subi; break;
155 case OMUL: validate = muli; break;
156 case ODIV: validate = divi; break;
157 case OSHL: validate = lshi; break;
158 case OSHR: validate = rshi; break;
159 case OMOD: validate = divi; break;
160 default: validate = NULL; break;
161 }
162
163 if (validate && !(*validate)(l, r, tp))
164 return 0;
165
166 switch (op) {
167 case OADD: i = l + r; break;
168 case OSUB: i = l - r; break;
169 case OMUL: i = l * r; break;
170 case ODIV: i = l / r; break;
171 case OMOD: i = l % r; break;
172 case OSHL: i = l << r; break;
173 case OSHR: i = l >> r; break;
174 case OBAND: i = l & r; break;
175 case OBXOR: i = l ^ r; break;
176 case OBOR: i = l | r; break;
177 case OAND: i = l && r; break;
178 case OOR: i = l || r; break;
179 case OLT: i = l < r; break;
180 case OGT: i = l > r; break;
181 case OGE: i = l >= r; break;
182 case OLE: i = l <= r; break;
183 case OEQ: i = l == r; break;
184 case ONE: i = l != r; break;
185 case ONEG: i = !l; break;
186 case OSNEG: i = -l; break;
187 case OCPL: i = ~l; break;
188 default: return 0;
189 }
190 res->u.i = i;
191
192 DBG("FOLD i l=%lld %d r=%lld = %lld", l, op, r, i);
193 return 1;
194 }
195
196 static int
197 folduint(int op, Symbol *res, unsigned long long l, unsigned long long r)
198 {
199 long long i;
200 unsigned long long u;
201
202 switch (op) {
203 case OADD: u = l + r; break;
204 case OSUB: u = l - r; break;
205 case OMUL: u = l * r; break;
206 case ODIV: u = l / r; break;
207 case OMOD: u = l % r; break;
208 case OSHL: u = l << r; break;
209 case OSHR: u = l >> r; break;
210 case OBAND: u = l & r; break;
211 case OBXOR: u = l ^ r; break;
212 case OBOR: u = l | r; break;
213 case ONEG: u = !l; break;
214 case OSNEG: u = -l; break;
215 case OCPL: u = ~l; break;
216 case OAND: i = l && r; goto sign;
217 case OOR: i = l || r; goto sign;
218 case OLT: i = l < r; goto sign;
219 case OGT: i = l > r; goto sign;
220 case OGE: i = l >= r; goto sign;
221 case OLE: i = l <= r; goto sign;
222 case OEQ: i = l == r; goto sign;
223 case ONE: i = l != r; goto sign;
224 default: return 0;
225 }
226 res->u.u = u & ones(res->type->size);
227
228 DBG("FOLD ui l=%llu %d r=%llu = %llu", l, op, r, u);
229 return 1;
230
231 sign:
232 res->u.i = i;
233
234 DBG("FOLD sui %llu %d %llu = %llu", l, op, r, i);
235 return 1;
236 }
237
238 static int
239 foldldouble(int op, Symbol *res, long double l, long double r)
240 {
241 long double f;
242 long long i;
243 int (*validate)(double, double, Type *tp);
244
245 switch (op) {
246 case OADD: validate = addf; break;
247 case OSUB: validate = subf; break;
248 case OMUL: validate = mulf; break;
249 case ODIV: validate = divf; break;
250 default: validate = NULL; break;
251 }
252
253 if (validate && !(*validate)(l, r, res->type))
254 return 0;
255
256 switch (op) {
257 case OADD: f = l + r; break;
258 case OSUB: f = l - r; break;
259 case OMUL: f = l * r; break;
260 case ODIV: f = l / r; break;
261 case OSNEG: f = -l; break;
262 case OLT: i = l < r; goto comparison;
263 case OGT: i = l > r; goto comparison;
264 case OGE: i = l >= r; goto comparison;
265 case OLE: i = l <= r; goto comparison;
266 case OEQ: i = l == r; goto comparison;
267 case ONE: i = l != r; goto comparison;
268 default: return 0;
269 }
270 res->u.ld = f;
271
272 DBG("FOLD f l=%llf %d r=%llf = %llf", l, op, r, f);
273 return 1;
274
275 comparison:
276 res->u.i = i;
277
278 DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
279 return 1;
280 }
281
282 static int
283 folddouble(int op, Symbol *res, double l, double r)
284 {
285 double f;
286 long long i;
287 int (*validate)(double, double, Type *tp);
288
289 switch (op) {
290 case OADD: validate = addf; break;
291 case OSUB: validate = subf; break;
292 case OMUL: validate = mulf; break;
293 case ODIV: validate = divf; break;
294 default: validate = NULL; break;
295 }
296
297 if (validate && !(*validate)(l, r, res->type))
298 return 0;
299
300 switch (op) {
301 case OADD: f = l + r; break;
302 case OSUB: f = l - r; break;
303 case OMUL: f = l * r; break;
304 case ODIV: f = l / r; break;
305 case OSNEG: f = -l; break;
306 case OLT: i = l < r; goto comparison;
307 case OGT: i = l > r; goto comparison;
308 case OGE: i = l >= r; goto comparison;
309 case OLE: i = l <= r; goto comparison;
310 case OEQ: i = l == r; goto comparison;
311 case ONE: i = l != r; goto comparison;
312 default: return 0;
313 }
314 res->u.d = f;
315
316 DBG("FOLD f l=%lf %d r=%lf = %lf", l, op, r, f);
317 return 1;
318
319 comparison:
320 res->u.i = i;
321
322 DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
323 return 1;
324 }
325
326 static int
327 foldfloat(int op, Symbol *res, float l, float r)
328 {
329 float f;
330 long long i;
331 int (*validate)(double, double, Type *tp);
332
333 switch (op) {
334 case OADD: validate = addf; break;
335 case OSUB: validate = subf; break;
336 case OMUL: validate = mulf; break;
337 case ODIV: validate = divf; break;
338 default: validate = NULL; break;
339 }
340
341 if (validate && !(*validate)(l, r, res->type))
342 return 0;
343
344 switch (op) {
345 case OADD: f = l + r; break;
346 case OSUB: f = l - r; break;
347 case OMUL: f = l * r; break;
348 case ODIV: f = l / r; break;
349 case OSNEG: f = -l; break;
350 case OLT: i = l < r; goto comparison;
351 case OGT: i = l > r; goto comparison;
352 case OGE: i = l >= r; goto comparison;
353 case OLE: i = l <= r; goto comparison;
354 case OEQ: i = l == r; goto comparison;
355 case ONE: i = l != r; goto comparison;
356 default: return 0;
357 }
358 res->u.f = f;
359
360 DBG("FOLD f l=%f %d r=%f = %f", l, op, r, f);
361 return 1;
362
363 comparison:
364 res->u.i = i;
365
366 DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
367 return 1;
368 }
369
370
371 static Node *
372 foldconst(int type, int op, Type *tp, Symbol *ls, Symbol *rs)
373 {
374 Symbol *sym, aux;
375 long long i;
376 unsigned long long u;
377 float f;
378 double d;
379 long double ld;
380
381 aux.type = tp;
382 switch (type) {
383 case INT:
384 i = (rs) ? rs->u.i : 0;
385 if (!foldint(op, &aux, ls->u.i, i))
386 return NULL;
387 break;
388 case PTR:
389 case UNSIGNED:
390 u = (rs) ? rs->u.u : 0u;
391 if (!folduint(op, &aux, ls->u.u, u))
392 return NULL;
393 break;
394 case FLOAT:
395 if (tp == floattype) {
396 f = (rs) ? rs->u.f : 0.0;
397 if (!foldfloat(op, &aux, ls->u.f, f))
398 return NULL;
399 } else if (tp == doubletype) {
400 d = (rs) ? rs->u.d : 0.0;
401 if (!folddouble(op, &aux, ls->u.d, d))
402 return NULL;
403 } else {
404 ld = (rs) ? rs->u.ld : 0.0;
405 if (!foldldouble(op, &aux, ls->u.ld, ld))
406 return NULL;
407 }
408 break;
409 default:
410 abort();
411 }
412 sym = newsym(NS_IDEN, NULL);
413 sym->flags |= SCONSTANT;
414 sym->type = tp;
415 sym->u = aux.u;
416 return constnode(sym);
417 }
418
419 static Node *
420 foldcast(Node *np, Node *l)
421 {
422 long double ld;
423 unsigned long long negmask, mask, u;
424 Type *newtp = np->type, *oldtp = l->type;
425 Symbol aux, *sym, *osym = l->sym;
426
427 if ((l->flags & NCONST) == 0 || !osym)
428 return np;
429
430 switch (newtp->op) {
431 case PTR:
432 case INT:
433 case ENUM:
434 switch (oldtp->op) {
435 case PTR:
436 case INT:
437 case ENUM:
438 u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
439 break;
440 case FLOAT:
441 oldtp = newtp;
442 u = osym->u.f;
443 break;
444 default:
445 return np;
446 }
447 mask = ones(newtp->size);
448 if (newtp->prop & TSIGNED) {
449 negmask = ~mask;
450 if (u & (negmask >> 1) & mask)
451 u |= negmask;
452 aux.u.i = u;
453 } else {
454 aux.u.u = u & mask;
455 }
456 break;
457 case FLOAT:
458 if (oldtp->op != FLOAT) {
459 if (oldtp->prop & TSIGNED)
460 ld = osym->u.i;
461 else
462 ld = osym->u.u;
463 } else if (oldtp == floattype) {
464 ld = osym->u.f;
465 } else if (oldtp == doubletype) {
466 ld = osym->u.d;
467 } else if (oldtp == ldoubletype) {
468 ld = osym->u.ld;
469 } else {
470 return np;
471 }
472
473 if (newtp == floattype)
474 aux.u.f = ld;
475 else if (newtp == doubletype)
476 aux.u.d = ld;
477 else if (newtp == ldoubletype)
478 aux.u.ld = ld;
479 else
480 abort();
481 break;
482 default:
483 return np;
484 }
485
486 DBG("FOLD cast %c->%c", oldtp->letter, newtp->letter);
487 freetree(np);
488 sym = newsym(NS_IDEN, NULL);
489 sym->flags |= SCONSTANT;
490 sym->type = newtp;
491 sym->u = aux.u;
492 return constnode(sym);
493 }
494
495 static Node *
496 foldunary(Node *np)
497 {
498 Node *l = np->left;
499 Node *aux;
500 Symbol *sym;
501 int op = l->op;
502
503 switch (np->op) {
504 case ONEG:
505 if (l->op == ONEG)
506 break;
507 return np;
508 case OADD:
509 DBG("FOLD unary delete %d", np->op);
510 np->left = NULL;
511 freetree(np);
512 return l;
513 case OCAST:
514 return foldcast(np, l);
515 case OSNEG:
516 case OCPL:
517 if (op != np->op)
518 return np;
519 break;
520 case OPTR:
521 if (op != OADDR || np->type != l->left->type)
522 return np;
523 break;
524 case OADDR:
525 /* &(*s).f -> s + offsetof(typeof(*s), f) */
526 if (op == OFIELD && l->left->op == OPTR) {
527 DBG("FOLD collapse '&(*s).f' %d", np->op);
528 aux = node(OADD,
529 np->type,
530 l->left->left,
531 offsetnode(l->right->sym, np->type));
532
533 if (aux->left->flags & NCONST)
534 aux->flags |= NCONST;
535 l->left->left = NULL;
536 freetree(np);
537 return aux;
538 }
539
540 /* &s.f -> &s + offsetof(typeof(s), f) */
541 if (op == OFIELD) {
542 DBG("FOLD collapse '&s.f' %d", np->op);
543 aux = node(OADD,
544 np->type,
545 node(OADDR, np->type, l->left, NULL),
546 offsetnode(l->right->sym, np->type));
547
548 if (np->flags & NCONST)
549 aux->flags |= NCONST;
550 l->left = NULL;
551 freetree(np);
552 return aux;
553 }
554
555 if (op != OPTR)
556 return np;
557 break;
558 default:
559 return np;
560 }
561 DBG("FOLD unary cancel %d", np->op);
562 aux = l->left;
563 l->left = NULL;
564 freetree(np);
565 return aux;
566 }
567
568 static Node *
569 fold(Node *np)
570 {
571 Symbol *rs, *ls;
572 Type *optype;
573 int type;
574 int op = np->op;
575 Node *p, *lp = np->left, *rp = np->right;
576 Type *tp = np->type;
577
578 if (!lp && !rp)
579 return np;
580
581 if ((op == ODIV || op == OMOD) && cmpnode(rp, 0)) {
582 warn("division by 0");
583 return np;
584 }
585 /*
586 * Return if any of the children is no constant,
587 * or it is a constant generated when
588 * the address of a static variable is taken
589 * (when we don't know the physical address so
590 * we cannot fold it)
591 */
592 if (!rp) {
593 rs = NULL;
594 } else {
595 if (!(rp->flags & NCONST) || !rp->sym)
596 return np;
597 rs = rp->sym;
598 }
599
600 if ((lp->flags & NCONST) == 0 || !lp->sym)
601 return np;
602 optype = lp->type;
603 ls = lp->sym;
604
605 type = optype->op;
606 switch (type) {
607 case ENUM:
608 case INT:
609 if (!(optype->prop & TSIGNED))
610 type = UNSIGNED;
611 case PTR:
612 case FLOAT:
613 if ((p = foldconst(type, op, tp, ls, rs)) == NULL) {
614 np->flags &= ~NCONST;
615 return np;
616 }
617 freetree(np);
618 return p;
619 default:
620 return np;
621 }
622 }
623
624 static void
625 commutative(Node *np)
626 {
627 int op = np->op;
628 Node *l = np->left, *r = np->right;
629
630 if (r == NULL || r->flags&NCONST || !(l->flags&NCONST))
631 return;
632
633 switch (op) {
634 case OLT:
635 case OGT:
636 case OGE:
637 case OLE:
638 DBG("FOLD neg commutative %d", np->op);
639 np->op = negop(op);
640 case OEQ:
641 case ONE:
642 case OADD:
643 case OMUL:
644 case OBAND:
645 case OBXOR:
646 case OBOR:
647 DBG("FOLD commutative %d", np->op);
648 np->left = r;
649 np->right = l;
650 break;
651 }
652 }
653
654 static Node *
655 identity(Node *np)
656 {
657 int iszeror, isoner;
658 int iszerol, isonel;
659 Node *lp = np->left, *rp = np->right;
660
661 if (!rp)
662 return np;
663
664 iszeror = cmpnode(rp, 0);
665 isoner = cmpnode(rp, 1),
666 iszerol = cmpnode(lp, 0);
667 isonel = cmpnode(lp, 1);
668
669 switch (np->op) {
670 case OOR:
671 /*
672 * 1 || i => 1 (free right)
673 * i || 0 => i (free right)
674 * 0 || i => i (free left)
675 * i || 1 => i,1 (comma)
676 */
677 if (isonel | iszeror)
678 goto free_right;
679 if (iszerol)
680 goto free_left;
681 if (isoner)
682 goto change_to_comma;
683 return np;
684 case OAND:
685 /*
686 * 0 && i => 0 (free right)
687 * i && 1 => i (free right)
688 * 1 && i => i (free left)
689 * i && 0 => i,0 (comma)
690 */
691 if (iszerol | isoner)
692 goto free_right;
693 if (isonel)
694 goto free_left;
695 if (iszeror)
696 goto change_to_comma;
697 return np;
698 case OSHL:
699 case OSHR:
700 /*
701 * i >> 0 => i (free right)
702 * i << 0 => i (free right)
703 * 0 >> i => 0 (free right)
704 * 0 << i => 0 (free right)
705 */
706 if (iszeror | iszerol)
707 goto free_right;
708 return np;
709 case OBXOR:
710 case OADD:
711 case OBOR:
712 case OSUB:
713 /*
714 * i + 0 => i
715 * i - 0 => i
716 * i | 0 => i
717 * i ^ 0 => i
718 */
719 if (iszeror)
720 goto free_right;
721 return np;
722 case OMUL:
723 /*
724 * i * 0 => i,0 (comma)
725 * i * 1 => i (free right)
726 */
727 if (iszeror)
728 goto change_to_comma;
729 if (isoner)
730 goto free_right;
731 return np;
732 case ODIV:
733 /* i / 1 => i */
734 if (isoner)
735 goto free_right;
736 return np;
737 case OBAND:
738 /* i & ~0 => i */
739 if (cmpnode(rp, -1))
740 goto free_right;
741 return np;
742 case OMOD:
743 /* i % 1 => i,1 */
744 if (isoner)
745 goto change_to_comma;
746 default:
747 return np;
748 }
749
750 free_right:
751 DBG("FOLD identity %d", np->op);
752 np->left = NULL;
753 freetree(np);
754 return lp;
755
756 free_left:
757 DBG("FOLD identity %d", np->op);
758 np->right = NULL;
759 freetree(np);
760 return rp;
761
762 change_to_comma:
763 DBG("FOLD identity %d", np->op);
764 np->op = OCOMMA;
765 return np;
766 }
767
768 static Node *
769 foldternary(Node *np)
770 {
771 Node *cond = np->left, *body = np->right;
772
773 if ((cond->flags & NCONST) == 0)
774 return np;
775 if (cmpnode(cond, 0)) {
776 np = body->right;
777 freetree(body->left);
778 } else {
779 np = body->left;
780 freetree(body->right);
781 }
782
783 DBG("FOLD ternary");
784 body->left = NULL;
785 body->right = NULL;
786 freetree(cond);
787 free(body);
788 return np;
789 }
790
791 static Node *xsimplify(Node *);
792
793 static void
794 reduce(Node *np)
795 {
796 Node *lp = np->left, *rp = np->right;
797 Node *aux, *aux2;
798 int log, op = np->op;
799
800 if (np->type->prop & TSIGNED)
801 return;
802 if (!power2node(rp, &log))
803 return;
804
805 switch (op) {
806 case OMUL:
807 /* i * 2^n => i << n */
808 np->op = OSHL;
809 rp->sym->u.u = log;
810 break;
811 case ODIV:
812 /* i / 2^n => i >> n */
813 np->op = OSHR;
814 rp->sym->u.u = log;
815 break;
816 case OMOD:
817 /* i % 2^n => i & n-1 */
818 np->op = OBAND;
819 rp->sym->u.u--;
820 break;
821 default:
822 return;
823 }
824
825 DBG("FOLD reduce %d->%d", op, np->op);
826 }
827
828 static void
829 associative(Node *np)
830 {
831 Node *l = np->left, *r = np->right;
832
833 switch (np->op) {
834 case OADD:
835 case OMUL:
836 case OBAND:
837 case OBXOR:
838 case OBOR:
839 if (np->op != l->op
840 || l->right->op != OSYM
841 || !(l->right->sym->flags&SCONSTANT)) {
842 return;
843 }
844
845 DBG("FOLD associative %d", np->op);
846 np->left = l->left;
847 l->left = r;
848 np->right = fold(l);
849 break;
850 }
851 }
852
853 /* TODO: fold OCOMMA */
854 static Node *
855 xxsimplify(Node *np)
856 {
857 int op;
858 int isfloat = np->type->op == FLOAT;
859
860 np->left = xsimplify(np->left);
861 np->right = xsimplify(np->right);
862
863 repeat:
864 switch (op = np->op) {
865 case OASK:
866 np = foldternary(np);
867 break;
868 case OCALL:
869 case OPAR:
870 case OSYM:
871 case OASSIGN:
872 case OA_MUL:
873 case OA_DIV:
874 case OA_MOD:
875 case OA_ADD:
876 case OA_SUB:
877 case OA_SHL:
878 case OA_SHR:
879 case OA_AND:
880 case OA_XOR:
881 case OA_OR:
882 break;
883 case OSNEG:
884 case OCPL:
885 case OADDR:
886 case OPTR:
887 case INC:
888 case DEC:
889 case OCAST:
890 case ONEG:
891 assert(!np->right);
892 np = foldunary(np);
893 np = fold(np);
894 break;
895 default:
896 if (!isfloat) {
897 commutative(np);
898 associative(np);
899 }
900 np = fold(np);
901 if (!isfloat) {
902 np = identity(np);
903 reduce(np);
904 }
905 break;
906 }
907
908 if (op != np->op)
909 goto repeat;
910 return np;
911 }
912
913 static Node *
914 xsimplify(Node *np)
915 {
916 if (!np)
917 return NULL;
918
919 if (enadebug)
920 prtree("simplify before", np);
921 np = xxsimplify(np);
922 if (enadebug)
923 prtree("simplify after", np);
924
925 return np;
926 }
927
928 Node *
929 simplify(Node *np)
930 {
931 DBG("SIMPLIFY");
932 return xsimplify(np);
933 DBG("SIMPLIFY DONE");
934 }