xref: /inferno-os/utils/cc/scon.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
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