xref: /inferno-os/utils/cc/scon.c (revision 50b0dbb170df61467e42c7ea4deb0b5692d15f4c)
1  #include "cc.h"
2  
3  static Node*
4  acast(Type *t, Node *n)
5  {
6  	if(n->type->etype != t->etype || n->op == OBIT) {
7  		n = new1(OCAST, n, Z);
8  		if(nocast(n->left->type, t))
9  			*n = *n->left;
10  		n->type = t;
11  	}
12  	return n;
13  }
14  
15  
16  void
17  evconst(Node *n)
18  {
19  	Node *l, *r;
20  	int et, isf;
21  	vlong v;
22  	double d;
23  
24  	if(n == Z || n->type == T)
25  		return;
26  
27  	et = n->type->etype;
28  	isf = typefd[et];
29  
30  	l = n->left;
31  	r = n->right;
32  
33  	d = 0;
34  	v = 0;
35  
36  	switch(n->op) {
37  	default:
38  		return;
39  
40  	case ONEG:
41  		if(isf)
42  			d = -l->fconst;
43  		else
44  			v = -l->vconst;
45  		break;
46  
47  	case OCOM:
48  		v = ~l->vconst;
49  		break;
50  
51  	case OCAST:
52  		if(et == TVOID)
53  			return;
54  		et = l->type->etype;
55  		if(isf) {
56  			if(typefd[et])
57  				d = l->fconst;
58  			else
59  				d = l->vconst;
60  		} else {
61  			if(typefd[et])
62  				v = l->fconst;
63  			else
64  				v = convvtox(l->vconst, n->type->etype);
65  		}
66  		break;
67  
68  	case OCONST:
69  		break;
70  
71  	case OADD:
72  		if(isf)
73  			d = l->fconst + r->fconst;
74  		else {
75  			v = l->vconst + r->vconst;
76  		}
77  		break;
78  
79  	case OSUB:
80  		if(isf)
81  			d = l->fconst - r->fconst;
82  		else
83  			v = l->vconst - r->vconst;
84  		break;
85  
86  	case OMUL:
87  		if(isf)
88  			d = l->fconst * r->fconst;
89  		else {
90  			v = l->vconst * r->vconst;
91  		}
92  		break;
93  
94  	case OLMUL:
95  		v = (uvlong)l->vconst * (uvlong)r->vconst;
96  		break;
97  
98  
99  	case ODIV:
100  		if(vconst(r) == 0) {
101  			warn(n, "divide by zero");
102  			return;
103  		}
104  		if(isf)
105  			d = l->fconst / r->fconst;
106  		else
107  			v = l->vconst / r->vconst;
108  		break;
109  
110  	case OLDIV:
111  		if(vconst(r) == 0) {
112  			warn(n, "divide by zero");
113  			return;
114  		}
115  		v = (uvlong)l->vconst / (uvlong)r->vconst;
116  		break;
117  
118  	case OMOD:
119  		if(vconst(r) == 0) {
120  			warn(n, "modulo by zero");
121  			return;
122  		}
123  		v = l->vconst % r->vconst;
124  		break;
125  
126  	case OLMOD:
127  		if(vconst(r) == 0) {
128  			warn(n, "modulo by zero");
129  			return;
130  		}
131  		v = (uvlong)l->vconst % (uvlong)r->vconst;
132  		break;
133  
134  	case OAND:
135  		v = l->vconst & r->vconst;
136  		break;
137  
138  	case OOR:
139  		v = l->vconst | r->vconst;
140  		break;
141  
142  	case OXOR:
143  		v = l->vconst ^ r->vconst;
144  		break;
145  
146  	case OLSHR:
147  		v = (uvlong)l->vconst >> r->vconst;
148  		break;
149  
150  	case OASHR:
151  		v = l->vconst >> r->vconst;
152  		break;
153  
154  	case OASHL:
155  		v = l->vconst << r->vconst;
156  		break;
157  
158  	case OLO:
159  		v = (uvlong)l->vconst < (uvlong)r->vconst;
160  		break;
161  
162  	case OLT:
163  		if(typefd[l->type->etype])
164  			v = l->fconst < r->fconst;
165  		else
166  			v = l->vconst < r->vconst;
167  		break;
168  
169  	case OHI:
170  		v = (uvlong)l->vconst > (uvlong)r->vconst;
171  		break;
172  
173  	case OGT:
174  		if(typefd[l->type->etype])
175  			v = l->fconst > r->fconst;
176  		else
177  			v = l->vconst > r->vconst;
178  		break;
179  
180  	case OLS:
181  		v = (uvlong)l->vconst <= (uvlong)r->vconst;
182  		break;
183  
184  	case OLE:
185  		if(typefd[l->type->etype])
186  			v = l->fconst <= r->fconst;
187  		else
188  			v = l->vconst <= r->vconst;
189  		break;
190  
191  	case OHS:
192  		v = (uvlong)l->vconst >= (uvlong)r->vconst;
193  		break;
194  
195  	case OGE:
196  		if(typefd[l->type->etype])
197  			v = l->fconst >= r->fconst;
198  		else
199  			v = l->vconst >= r->vconst;
200  		break;
201  
202  	case OEQ:
203  		if(typefd[l->type->etype])
204  			v = l->fconst == r->fconst;
205  		else
206  			v = l->vconst == r->vconst;
207  		break;
208  
209  	case ONE:
210  		if(typefd[l->type->etype])
211  			v = l->fconst != r->fconst;
212  		else
213  			v = l->vconst != r->vconst;
214  		break;
215  
216  	case ONOT:
217  		if(typefd[l->type->etype])
218  			v = !l->fconst;
219  		else
220  			v = !l->vconst;
221  		break;
222  
223  	case OANDAND:
224  		if(typefd[l->type->etype])
225  			v = l->fconst && r->fconst;
226  		else
227  			v = l->vconst && r->vconst;
228  		break;
229  
230  	case OOROR:
231  		if(typefd[l->type->etype])
232  			v = l->fconst || r->fconst;
233  		else
234  			v = l->vconst || r->vconst;
235  		break;
236  	}
237  	if(isf) {
238  		n->fconst = d;
239  	} else {
240  		n->vconst = convvtox(v, n->type->etype);
241  	}
242  	n->oldop = n->op;
243  	n->op = OCONST;
244  }
245  
246  void
247  acom(Node *n)
248  {
249  	Type *t;
250  	Node *l, *r;
251  	int i;
252  
253  	switch(n->op)
254  	{
255  
256  	case ONAME:
257  	case OCONST:
258  	case OSTRING:
259  	case OINDREG:
260  	case OREGISTER:
261  		return;
262  
263  	case ONEG:
264  		l = n->left;
265  		if(addo(n) && addo(l))
266  			break;
267  		acom(l);
268  		return;
269  
270  	case OADD:
271  	case OSUB:
272  	case OMUL:
273  		l = n->left;
274  		r = n->right;
275  		if(addo(n)) {
276  			if(addo(r))
277  				break;
278  			if(addo(l))
279  				break;
280  		}
281  		acom(l);
282  		acom(r);
283  		return;
284  
285  	default:
286  		l = n->left;
287  		r = n->right;
288  		if(l != Z)
289  			acom(l);
290  		if(r != Z)
291  			acom(r);
292  		return;
293  	}
294  
295  	/* bust terms out */
296  	t = n->type;
297  	term[0].mult = 0;
298  	term[0].node = Z;
299  	nterm = 1;
300  	acom1(1, n);
301  	if(debug['m'])
302  	for(i=0; i<nterm; i++) {
303  		print("%d %3lld ", i, term[i].mult);
304  		prtree1(term[i].node, 1, 0);
305  	}
306  	if(nterm < NTERM)
307  		acom2(n, t);
308  	n->type = t;
309  }
310  
311  int
312  acomcmp1(void *a1, void *a2)
313  {
314  	vlong c1, c2;
315  	Term *t1, *t2;
316  
317  	t1 = (Term*)a1;
318  	t2 = (Term*)a2;
319  	c1 = t1->mult;
320  	if(c1 < 0)
321  		c1 = -c1;
322  	c2 = t2->mult;
323  	if(c2 < 0)
324  		c2 = -c2;
325  	if(c1 > c2)
326  		return 1;
327  	if(c1 < c2)
328  		return -1;
329  	c1 = 1;
330  	if(t1->mult < 0)
331  		c1 = 0;
332  	c2 = 1;
333  	if(t2->mult < 0)
334  		c2 = 0;
335  	if(c2 -= c1)
336  		return c2;
337  	if(t2 > t1)
338  		return 1;
339  	return -1;
340  }
341  
342  int
343  acomcmp2(void *a1, void *a2)
344  {
345  	vlong c1, c2;
346  	Term *t1, *t2;
347  
348  	t1 = (Term*)a1;
349  	t2 = (Term*)a2;
350  	c1 = t1->mult;
351  	c2 = t2->mult;
352  	if(c1 > c2)
353  		return 1;
354  	if(c1 < c2)
355  		return -1;
356  	if(t2 > t1)
357  		return 1;
358  	return -1;
359  }
360  
361  void
362  acom2(Node *n, Type *t)
363  {
364  	Node *l, *r;
365  	Term trm[NTERM];
366  	int et, nt, i, j;
367  	vlong c1, c2;
368  
369  	/*
370  	 * copy into automatic
371  	 */
372  	c2 = 0;
373  	nt = nterm;
374  	for(i=0; i<nt; i++)
375  		trm[i] = term[i];
376  	/*
377  	 * recur on subtrees
378  	 */
379  	j = 0;
380  	for(i=1; i<nt; i++) {
381  		c1 = trm[i].mult;
382  		if(c1 == 0)
383  			continue;
384  		l = trm[i].node;
385  		if(l != Z) {
386  			j = 1;
387  			acom(l);
388  		}
389  	}
390  	c1 = trm[0].mult;
391  	if(j == 0) {
392  		n->oldop = n->op;
393  		n->op = OCONST;
394  		n->vconst = c1;
395  		return;
396  	}
397  	et = t->etype;
398  
399  	/*
400  	 * prepare constant term,
401  	 * combine it with an addressing term
402  	 */
403  	if(c1 != 0) {
404  		l = new1(OCONST, Z, Z);
405  		l->type = t;
406  		l->vconst = c1;
407  		trm[0].mult = 1;
408  		for(i=1; i<nt; i++) {
409  			if(trm[i].mult != 1)
410  				continue;
411  			r = trm[i].node;
412  			if(r->op != OADDR)
413  				continue;
414  			r->type = t;
415  			l = new1(OADD, r, l);
416  			l->type = t;
417  			trm[i].mult = 0;
418  			break;
419  		}
420  		trm[0].node = l;
421  	}
422  	/*
423  	 * look for factorable terms
424  	 * c1*i + c1*c2*j -> c1*(i + c2*j)
425  	 */
426  	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
427  	for(i=nt-1; i>=0; i--) {
428  		c1 = trm[i].mult;
429  		if(c1 < 0)
430  			c1 = -c1;
431  		if(c1 <= 1)
432  			continue;
433  		for(j=i+1; j<nt; j++) {
434  			c2 = trm[j].mult;
435  			if(c2 < 0)
436  				c2 = -c2;
437  			if(c2 <= 1)
438  				continue;
439  			if(c2 % c1)
440  				continue;
441  			r = trm[j].node;
442  			if(r->type->etype != et)
443  				r = acast(t, r);
444  			c2 = trm[j].mult/trm[i].mult;
445  			if(c2 != 1 && c2 != -1) {
446  				r = new1(OMUL, r, new(OCONST, Z, Z));
447  				r->type = t;
448  				r->right->type = t;
449  				r->right->vconst = c2;
450  			}
451  			l = trm[i].node;
452  			if(l->type->etype != et)
453  				l = acast(t, l);
454  			r = new1(OADD, l, r);
455  			r->type = t;
456  			if(c2 == -1)
457  				r->op = OSUB;
458  			trm[i].node = r;
459  			trm[j].mult = 0;
460  		}
461  	}
462  	if(debug['m']) {
463  		print("\n");
464  		for(i=0; i<nt; i++) {
465  			print("%d %3lld ", i, trm[i].mult);
466  			prtree1(trm[i].node, 1, 0);
467  		}
468  	}
469  
470  	/*
471  	 * put it all back together
472  	 */
473  	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
474  	l = Z;
475  	for(i=nt-1; i>=0; i--) {
476  		c1 = trm[i].mult;
477  		if(c1 == 0)
478  			continue;
479  		r = trm[i].node;
480  		if(r->type->etype != et || r->op == OBIT)
481  			r = acast(t, r);
482  		if(c1 != 1 && c1 != -1) {
483  			r = new1(OMUL, r, new(OCONST, Z, Z));
484  			r->type = t;
485  			r->right->type = t;
486  			if(c1 < 0) {
487  				r->right->vconst = -c1;
488  				c1 = -1;
489  			} else {
490  				r->right->vconst = c1;
491  				c1 = 1;
492  			}
493  		}
494  		if(l == Z) {
495  			l = r;
496  			c2 = c1;
497  			continue;
498  		}
499  		if(c1 < 0)
500  			if(c2 < 0)
501  				l = new1(OADD, l, r);
502  			else
503  				l = new1(OSUB, l, r);
504  		else
505  			if(c2 < 0) {
506  				l = new1(OSUB, r, l);
507  				c2 = 1;
508  			} else
509  				l = new1(OADD, l, r);
510  		l->type = t;
511  	}
512  	if(c2 < 0) {
513  		r = new1(OCONST, 0, 0);
514  		r->vconst = 0;
515  		r->type = t;
516  		l = new1(OSUB, r, l);
517  		l->type = t;
518  	}
519  	*n = *l;
520  }
521  
522  void
523  acom1(vlong v, Node *n)
524  {
525  	Node *l, *r;
526  
527  	if(v == 0 || nterm >= NTERM)
528  		return;
529  	if(!addo(n)) {
530  		if(n->op == OCONST)
531  		if(!typefd[n->type->etype]) {
532  			term[0].mult += v*n->vconst;
533  			return;
534  		}
535  		term[nterm].mult = v;
536  		term[nterm].node = n;
537  		nterm++;
538  		return;
539  	}
540  	switch(n->op) {
541  
542  	case OCAST:
543  		acom1(v, n->left);
544  		break;
545  
546  	case ONEG:
547  		acom1(-v, n->left);
548  		break;
549  
550  	case OADD:
551  		acom1(v, n->left);
552  		acom1(v, n->right);
553  		break;
554  
555  	case OSUB:
556  		acom1(v, n->left);
557  		acom1(-v, n->right);
558  		break;
559  
560  	case OMUL:
561  		l = n->left;
562  		r = n->right;
563  		if(l->op == OCONST)
564  		if(!typefd[n->type->etype]) {
565  			acom1(v*l->vconst, r);
566  			break;
567  		}
568  		if(r->op == OCONST)
569  		if(!typefd[n->type->etype]) {
570  			acom1(v*r->vconst, l);
571  			break;
572  		}
573  		break;
574  
575  	default:
576  		diag(n, "not addo");
577  	}
578  }
579  
580  int
581  addo(Node *n)
582  {
583  
584  	if(n != Z)
585  	if(!typefd[n->type->etype])
586  	if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
587  	switch(n->op) {
588  
589  	case OCAST:
590  		if(nilcast(n->left->type, n->type))
591  			return 1;
592  		break;
593  
594  	case ONEG:
595  	case OADD:
596  	case OSUB:
597  		return 1;
598  
599  	case OMUL:
600  		if(n->left->op == OCONST)
601  			return 1;
602  		if(n->right->op == OCONST)
603  			return 1;
604  	}
605  	return 0;
606  }
607