fold.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
fold.c (14428B)
---
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include <scc/scc.h>
5 #include "cc1.h"
6
7
8 TUINT
9 ones(int nbytes)
10 {
11 return (nbytes == 8) ? -1 : ~(-1ull << nbytes * 8);
12 }
13
14 static int
15 addi(TINT l, TINT r, Type *tp)
16 {
17 struct limits *lim = getlimits(tp);
18 TINT 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(TFLOAT l, TFLOAT r, Type *tp)
34 {
35 struct limits *lim = getlimits(tp);
36 TFLOAT 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(TINT l, TINT r, Type *tp)
52 {
53 return addi(l, -r, tp);
54 }
55
56 static int
57 subf(TFLOAT l, TFLOAT r, Type *tp)
58 {
59 return addf(l, -r, tp);
60 }
61
62 static int
63 muli(TINT l, TINT r, Type *tp)
64 {
65 struct limits *lim = getlimits(tp);
66 TINT 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(TFLOAT l, TFLOAT r, Type *tp)
82 {
83 struct limits *lim = getlimits(tp);
84 TFLOAT 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(TINT l, TINT 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(TFLOAT l, TFLOAT 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(TINT l, TINT 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(TINT l, TINT 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, TINT l, TINT r)
147 {
148 TINT i;
149 Type *tp = res->type;
150 int (*validate)(TINT, TINT, 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, TUINT l, TUINT r)
198 {
199 TINT i;
200 TUINT 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 foldfloat(int op, Symbol *res, TFLOAT l, TFLOAT r)
240 {
241 TFLOAT f;
242 TINT i;
243 int (*validate)(TFLOAT, TFLOAT, 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 OLT: i = l < r; goto comparison;
262 case OGT: i = l > r; goto comparison;
263 case OGE: i = l >= r; goto comparison;
264 case OLE: i = l <= r; goto comparison;
265 case OEQ: i = l == r; goto comparison;
266 case ONE: i = l != r; goto comparison;
267 default: return 0;
268 }
269 res->u.f = f;
270
271 DBG("FOLD f l=%lf %d r=%lf = %lf", l, op, r, f);
272 return 1;
273
274 comparison:
275 res->u.i = i;
276
277 DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
278 return 1;
279 }
280
281 static Node *
282 foldconst(int type, int op, Type *tp, Symbol *ls, Symbol *rs)
283 {
284 Symbol *sym, aux;
285 TINT i;
286 TUINT u;
287 TFLOAT f;
288
289 aux.type = tp;
290 switch (type) {
291 case INT:
292 i = (rs) ? rs->u.i : 0;
293 if (!foldint(op, &aux, ls->u.i, i))
294 return NULL;
295 break;
296 case PTR:
297 case UNSIGNED:
298 u = (rs) ? rs->u.u : 0u;
299 if (!folduint(op, &aux, ls->u.u, u))
300 return NULL;
301 break;
302 case FLOAT:
303 f = (rs) ? rs->u.f : 0.0;
304 if (!foldfloat(op, &aux, ls->u.f, f))
305 return NULL;
306 break;
307 default:
308 abort();
309 }
310 sym = newsym(NS_IDEN, NULL);
311 sym->flags |= SCONSTANT;
312 sym->type = tp;
313 sym->u = aux.u;
314 return constnode(sym);
315 }
316
317 static Node *
318 foldcast(Node *np, Node *l)
319 {
320 TUINT negmask, mask, u;
321 Type *newtp = np->type, *oldtp = l->type;
322 Symbol aux, *sym, *osym = l->sym;
323
324 if ((l->flags & NCONST) == 0 || !osym)
325 return np;
326
327 switch (newtp->op) {
328 case PTR:
329 case INT:
330 case ENUM:
331 switch (oldtp->op) {
332 case PTR:
333 case INT:
334 case ENUM:
335 u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
336 break;
337 case FLOAT:
338 oldtp = newtp;
339 u = osym->u.f;
340 break;
341 default:
342 return np;
343 }
344 mask = ones(newtp->size);
345 if (newtp->prop & TSIGNED) {
346 negmask = ~mask;
347 if (u & (negmask >> 1) & mask)
348 u |= negmask;
349 aux.u.i = u;
350 } else {
351 aux.u.u = u & mask;
352 }
353 break;
354 case FLOAT:
355 /* FIXME: The cast can be from another float type */
356 aux.u.f = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
357 break;
358 default:
359 return np;
360 }
361
362 DBG("FOLD cast %c->%c", oldtp->letter, newtp->letter);
363 freetree(np);
364 sym = newsym(NS_IDEN, NULL);
365 sym->flags |= SCONSTANT;
366 sym->type = newtp;
367 sym->u = aux.u;
368 return constnode(sym);
369 }
370
371 static Node *
372 foldunary(Node *np)
373 {
374 Node *l = np->left;
375 Node *aux;
376 Symbol *sym;
377 int op = l->op;
378
379 switch (np->op) {
380 case ONEG:
381 if (l->op == ONEG)
382 break;
383 return np;
384 case OADD:
385 DBG("FOLD unary delete %d", np->op);
386 np->left = NULL;
387 freetree(np);
388 return l;
389 case OCAST:
390 return foldcast(np, l);
391 case OSNEG:
392 case OCPL:
393 if (op != np->op)
394 return np;
395 break;
396 case OPTR:
397 if (op != OADDR || np->type != l->left->type)
398 return np;
399 break;
400 case OADDR:
401 /* &(*s).f -> s + offsetof(typeof(*s), f) */
402 if (op == OFIELD && l->left->op == OPTR) {
403 DBG("FOLD collapse '&(*s).f' %d", np->op);
404 aux = node(OADD,
405 np->type,
406 l->left->left,
407 offsetnode(l->right->sym, np->type));
408
409 if (aux->left->flags & NCONST)
410 aux->flags |= NCONST;
411 l->left->left = NULL;
412 freetree(np);
413 return aux;
414 }
415
416 /* &s.f -> &s + offsetof(typeof(s), f) */
417 if (op == OFIELD) {
418 DBG("FOLD collapse '&s.f' %d", np->op);
419 aux = node(OADD,
420 np->type,
421 node(OADDR, np->type, l->left, NULL),
422 offsetnode(l->right->sym, np->type));
423
424 if (np->flags & NCONST)
425 aux->flags |= NCONST;
426 l->left = NULL;
427 freetree(np);
428 return aux;
429 }
430
431 if (op != OPTR)
432 return np;
433 break;
434 default:
435 return np;
436 }
437 DBG("FOLD unary cancel %d", np->op);
438 aux = l->left;
439 l->left = NULL;
440 freetree(np);
441 return aux;
442 }
443
444 static Node *
445 fold(Node *np)
446 {
447 Symbol *rs, *ls;
448 Type *optype;
449 int type;
450 int op = np->op;
451 Node *p, *lp = np->left, *rp = np->right;
452 Type *tp = np->type;
453
454 if (!lp && !rp)
455 return np;
456
457 if ((op == ODIV || op == OMOD) && cmpnode(rp, 0)) {
458 warn("division by 0");
459 return np;
460 }
461 /*
462 * Return if any of the children is no constant,
463 * or it is a constant generated when
464 * the address of a static variable is taken
465 * (when we don't know the physical address so
466 * we cannot fold it)
467 */
468 if (!rp) {
469 rs = NULL;
470 } else {
471 if (!(rp->flags & NCONST) || !rp->sym)
472 return np;
473 rs = rp->sym;
474 }
475
476 if ((lp->flags & NCONST) == 0 || !lp->sym)
477 return np;
478 optype = lp->type;
479 ls = lp->sym;
480
481 type = optype->op;
482 switch (type) {
483 case ENUM:
484 case INT:
485 if (!(optype->prop & TSIGNED))
486 type = UNSIGNED;
487 case PTR:
488 case FLOAT:
489 if ((p = foldconst(type, op, tp, ls, rs)) == NULL) {
490 np->flags &= ~NCONST;
491 return np;
492 }
493 freetree(np);
494 return p;
495 default:
496 return np;
497 }
498 }
499
500 static void
501 commutative(Node *np)
502 {
503 int op = np->op;
504 Node *l = np->left, *r = np->right;
505
506 if (r == NULL || r->flags&NCONST || !(l->flags&NCONST))
507 return;
508
509 switch (op) {
510 case OLT:
511 case OGT:
512 case OGE:
513 case OLE:
514 DBG("FOLD neg commutative %d", np->op);
515 np->op = negop(op);
516 case OEQ:
517 case ONE:
518 case OADD:
519 case OMUL:
520 case OBAND:
521 case OBXOR:
522 case OBOR:
523 DBG("FOLD commutative %d", np->op);
524 np->left = r;
525 np->right = l;
526 break;
527 }
528 }
529
530 static Node *
531 identity(Node *np)
532 {
533 int iszeror, isoner;
534 int iszerol, isonel;
535 Node *lp = np->left, *rp = np->right;
536
537 if (!rp)
538 return np;
539
540 iszeror = cmpnode(rp, 0);
541 isoner = cmpnode(rp, 1),
542 iszerol = cmpnode(lp, 0);
543 isonel = cmpnode(lp, 1);
544
545 switch (np->op) {
546 case OOR:
547 /*
548 * 1 || i => 1 (free right)
549 * i || 0 => i (free right)
550 * 0 || i => i (free left)
551 * i || 1 => i,1 (comma)
552 */
553 if (isonel | iszeror)
554 goto free_right;
555 if (iszerol)
556 goto free_left;
557 if (isoner)
558 goto change_to_comma;
559 return np;
560 case OAND:
561 /*
562 * 0 && i => 0 (free right)
563 * i && 1 => i (free right)
564 * 1 && i => i (free left)
565 * i && 0 => i,0 (comma)
566 */
567 if (iszerol | isoner)
568 goto free_right;
569 if (isonel)
570 goto free_left;
571 if (iszeror)
572 goto change_to_comma;
573 return np;
574 case OSHL:
575 case OSHR:
576 /*
577 * i >> 0 => i (free right)
578 * i << 0 => i (free right)
579 * 0 >> i => 0 (free right)
580 * 0 << i => 0 (free right)
581 */
582 if (iszeror | iszerol)
583 goto free_right;
584 return np;
585 case OBXOR:
586 case OADD:
587 case OBOR:
588 case OSUB:
589 /*
590 * i + 0 => i
591 * i - 0 => i
592 * i | 0 => i
593 * i ^ 0 => i
594 */
595 if (iszeror)
596 goto free_right;
597 return np;
598 case OMUL:
599 /*
600 * i * 0 => i,0 (comma)
601 * i * 1 => i (free right)
602 */
603 if (iszeror)
604 goto change_to_comma;
605 if (isoner)
606 goto free_right;
607 return np;
608 case ODIV:
609 /* i / 1 => i */
610 if (isoner)
611 goto free_right;
612 return np;
613 case OBAND:
614 /* i & ~0 => i */
615 if (cmpnode(rp, -1))
616 goto free_right;
617 return np;
618 case OMOD:
619 /* i % 1 => i,1 */
620 if (isoner)
621 goto change_to_comma;
622 default:
623 return np;
624 }
625
626 free_right:
627 DBG("FOLD identity %d", np->op);
628 np->left = NULL;
629 freetree(np);
630 return lp;
631
632 free_left:
633 DBG("FOLD identity %d", np->op);
634 np->right = NULL;
635 freetree(np);
636 return rp;
637
638 change_to_comma:
639 DBG("FOLD identity %d", np->op);
640 np->op = OCOMMA;
641 return np;
642 }
643
644 static Node *
645 foldternary(Node *np)
646 {
647 Node *cond = np->left, *body = np->right;
648
649 if ((cond->flags & NCONST) == 0)
650 return np;
651 if (cmpnode(cond, 0)) {
652 np = body->right;
653 freetree(body->left);
654 } else {
655 np = body->left;
656 freetree(body->right);
657 }
658
659 DBG("FOLD ternary");
660 body->left = NULL;
661 body->right = NULL;
662 freetree(cond);
663 free(body);
664 return np;
665 }
666
667 static Node *xsimplify(Node *);
668
669 static void
670 reduce(Node *np)
671 {
672 Node *lp = np->left, *rp = np->right;
673 Node *aux, *aux2;
674 int op = np->op;
675
676 switch (op) {
677 case OMOD:
678 /* i % 2^n => i & n-1 */
679 if (power2node(rp, NULL)) {
680 np->op = OBAND;
681 rp->sym->u.u--;
682 break;
683 }
684 return;
685 default:
686 return;
687 }
688
689 DBG("FOLD reduce %d->%d", op, np->op);
690 }
691
692 static void
693 associative(Node *np)
694 {
695 Node *l = np->left, *r = np->right;
696
697 switch (np->op) {
698 case OADD:
699 case OMUL:
700 case OBAND:
701 case OBXOR:
702 case OBOR:
703 if (np->op != l->op
704 || l->right->op != OSYM
705 || !(l->right->sym->flags&SCONSTANT)) {
706 return;
707 }
708
709 DBG("FOLD associative %d", np->op);
710 np->left = l->left;
711 l->left = r;
712 np->right = fold(l);
713 break;
714 }
715 }
716
717 /* TODO: fold OCOMMA */
718 static Node *
719 xxsimplify(Node *np)
720 {
721 int op;
722
723 np->left = xsimplify(np->left);
724 np->right = xsimplify(np->right);
725
726 repeat:
727 switch (op = np->op) {
728 case OASK:
729 np = foldternary(np);
730 break;
731 case OCALL:
732 case OPAR:
733 case OSYM:
734 case OASSIGN:
735 case OA_MUL:
736 case OA_DIV:
737 case OA_MOD:
738 case OA_ADD:
739 case OA_SUB:
740 case OA_SHL:
741 case OA_SHR:
742 case OA_AND:
743 case OA_XOR:
744 case OA_OR:
745 break;
746 case OSNEG:
747 case OCPL:
748 case OADDR:
749 case OPTR:
750 case INC:
751 case DEC:
752 case OCAST:
753 case ONEG:
754 assert(!np->right);
755 np = foldunary(np);
756 np = fold(np);
757 break;
758 default:
759 commutative(np);
760 associative(np);
761 np = fold(np);
762 np = identity(np);
763 reduce(np);
764 break;
765 }
766
767 if (op != np->op)
768 goto repeat;
769 return np;
770 }
771
772 static Node *
773 xsimplify(Node *np)
774 {
775 if (!np)
776 return NULL;
777
778 if (enadebug)
779 prtree("simplify before", np);
780 np = xxsimplify(np);
781 if (enadebug)
782 prtree("simplify after", np);
783
784 return np;
785 }
786
787 Node *
788 simplify(Node *np)
789 {
790 DBG("SIMPLIFY");
791 return xsimplify(np);
792 DBG("SIMPLIFY DONE");
793 }