scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <assert.h>
  2#include <stdlib.h>
  3
  4#include <scc/scc.h>
  5#include "cc1.h"
  6
  7
  8unsigned long long
  9ones(int nbytes)
 10{
 11	return (nbytes == 8) ? -1 : ~(-1ull << nbytes * 8);
 12}
 13
 14static int
 15addi(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
 32static int
 33addf(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
 50static int
 51subi(long long l, long long r, Type *tp)
 52{
 53	return addi(l, -r, tp);
 54}
 55
 56static int
 57subf(double l, double r, Type *tp)
 58{
 59	return addf(l, -r, tp);
 60}
 61
 62static int
 63muli(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
 80static int
 81mulf(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
 98static int
 99divi(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
110static int
111divf(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
125static int
126lshi(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
135static int
136rshi(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
145static int
146foldint(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
196static int
197folduint(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
231sign:
232	res->u.i = i;
233
234	DBG("FOLD sui %llu %d %llu = %llu", l, op, r, i);
235	return 1;
236}
237
238static int
239foldldouble(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
275comparison:
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
282static int
283folddouble(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
319comparison:
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
326static int
327foldfloat(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
363comparison:
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
371static Node *
372foldconst(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
419static Node *
420foldcast(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
495static Node *
496foldunary(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
568static Node *
569fold(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
624static void
625commutative(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
654static Node *
655identity(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
750free_right:
751	DBG("FOLD identity %d", np->op);
752	np->left = NULL;
753	freetree(np);
754	return lp;
755
756free_left:
757	DBG("FOLD identity %d", np->op);
758	np->right = NULL;
759	freetree(np);
760	return rp;
761
762change_to_comma:
763	DBG("FOLD identity %d", np->op);
764	np->op = OCOMMA;
765	return np;
766}
767
768static Node *
769foldternary(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
791static Node *xsimplify(Node *);
792
793static void
794reduce(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
828static void
829associative(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 */
854static Node *
855xxsimplify(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
863repeat:
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
913static Node *
914xsimplify(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
928Node *
929simplify(Node *np)
930{
931	DBG("SIMPLIFY");
932	return xsimplify(np);
933	DBG("SIMPLIFY DONE");
934}