utah rcsid 1.15 87/07/19 22:46:18: First attack at integrating recent VAX
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
CommitLineData
55f818e1
DS
1# ifndef lint
2static char sccsid[] = "@(#)local2.c 1.24 (Berkeley) %G%";
3# endif
f2b49199 4
ebdd0416
SL
5# include "pass2.h"
6# include <ctype.h>
895241c8
SL
7
8# define putstr(s) fputs((s), stdout)
73fe5b3f 9# define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR)
895241c8 10
f2b49199
SL
11# ifdef FORT
12int ftlab1, ftlab2;
13# endif
14/* a lot of the machine dependent parts of the second pass */
15
16# define BITMASK(n) ((1L<<n)-1)
17
18# ifndef ONEPASS
55f818e1 19/*ARGSUSED*/
f2b49199
SL
20where(c){
21 fprintf( stderr, "%s, line %d: ", filename, lineno );
22 }
23# endif
24
25lineid( l, fn ) char *fn; {
26 /* identify line l and file fn */
27 printf( "# line %d, file %s\n", l, fn );
28 }
29
30int ent_mask;
31
32eobl2(){
33 register OFFSZ spoff; /* offset from stack pointer */
34#ifndef FORT
35 extern int ftlab1, ftlab2;
36#endif
37
38 spoff = maxoff;
39 spoff /= SZCHAR;
40 SETOFF(spoff,4);
41#ifdef FORT
42#ifndef FLEXNAMES
55f818e1 43 printf( " .set .F%d,%ld\n", ftnno, spoff );
f2b49199
SL
44#else
45 /* SHOULD BE L%d ... ftnno but must change pc/f77 */
55f818e1 46 printf( " .set LF%d,%ld\n", ftnno, spoff );
f2b49199
SL
47#endif
48 printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
49#else
50 printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
51 printf( "L%d:\n", ftlab1);
52 if( maxoff > AUTOINIT )
55f818e1 53 printf( " subl3 $%ld,fp,sp\n", spoff);
f2b49199
SL
54 printf( " jbr L%d\n", ftlab2);
55#endif
56 ent_mask = 0;
57 maxargs = -1;
58 }
59
60struct hoptab { int opmask; char * opstring; } ioptab[] = {
61
62 PLUS, "add",
63 MINUS, "sub",
64 MUL, "mul",
65 DIV, "div",
66 MOD, "div",
67 OR, "or",
68 ER, "xor",
69 AND, "and",
70 -1, "" };
71
72hopcode( f, o ){
73 /* output the appropriate string from the above table */
74
75 register struct hoptab *q;
76
77 if(asgop(o))
78 o = NOASG o;
79 for( q = ioptab; q->opmask>=0; ++q ){
80 if( q->opmask == o ){
81 if(f == 'E')
82 printf( "e%s", q->opstring);
83 else
84 printf( "%s%c", q->opstring, tolower(f));
85 return;
86 }
87 }
88 cerror( "no hoptab for %s", opst[o] );
89 }
90
91char *
92rnames[] = { /* keyed to register number tokens */
93
94 "r0", "r1",
95 "r2", "r3", "r4", "r5",
96 "r6", "r7", "r8", "r9", "r10", "r11",
97 "r12", "fp", "sp", "pc",
98 };
99
100/* output register name and update entry mask */
101char *
102rname(r)
103 register int r;
104{
105
106 ent_mask |= 1<<r;
107 return(rnames[r]);
108}
109
110int rstatus[] = {
111 SAREG|STAREG, SAREG|STAREG,
112 SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
113 SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
114 SAREG, SAREG, SAREG, SAREG,
115 };
116
117tlen(p) NODE *p;
118{
119 switch(p->in.type) {
120 case CHAR:
121 case UCHAR:
122 return(1);
123
124 case SHORT:
125 case USHORT:
55f818e1 126 return(SZSHORT/SZCHAR);
f2b49199
SL
127
128 case DOUBLE:
55f818e1 129 return(SZDOUBLE/SZCHAR);
f2b49199
SL
130
131 default:
55f818e1 132 return(SZINT/SZCHAR);
f2b49199
SL
133 }
134}
135
55f818e1 136mixtypes(p, q) NODE *p, *q;
f1824a4b
SL
137{
138 register TWORD tp, tq;
139
140 tp = p->in.type;
141 tq = q->in.type;
55f818e1
DS
142
143 return( (tp==FLOAT || tp==DOUBLE) !=
144 (tq==FLOAT || tq==DOUBLE) );
f1824a4b
SL
145}
146
f2b49199
SL
147prtype(n) NODE *n;
148{
149 switch (n->in.type)
150 {
151
152 case DOUBLE:
895241c8 153 putchar('d');
f2b49199
SL
154 return;
155
156 case FLOAT:
895241c8 157 putchar('f');
f2b49199
SL
158 return;
159
55f818e1
DS
160 case LONG:
161 case ULONG:
f2b49199
SL
162 case INT:
163 case UNSIGNED:
895241c8 164 putchar('l');
f2b49199
SL
165 return;
166
167 case SHORT:
168 case USHORT:
895241c8 169 putchar('w');
f2b49199
SL
170 return;
171
172 case CHAR:
173 case UCHAR:
895241c8 174 putchar('b');
f2b49199
SL
175 return;
176
177 default:
178 if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
179 else {
895241c8 180 putchar('l');
f2b49199
SL
181 return;
182 }
183 }
184}
185
186zzzcode( p, c ) register NODE *p; {
187 register int m;
188 int val;
189 switch( c ){
190
191 case 'N': /* logical ops, turned into 0-1 */
192 /* use register given by register 1 */
193 cbgen( 0, m=getlab(), 'I' );
194 deflab( p->bn.label );
195 printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) );
196 deflab( m );
197 return;
198
199 case 'P':
200 cbgen( p->in.op, p->bn.label, c );
201 return;
202
8acf7c89 203 case 'G': /* i *= f; asgops with int lhs and float rhs */
f2b49199 204 {
8acf7c89
DS
205 register NODE *l, *r, *s;
206 int lt, rt;
f2b49199 207
8acf7c89
DS
208 l = p->in.left;
209 r = p->in.right;
210 s = talloc();
211 rt = r->in.type;
212 lt = l->in.type;
213
214 if (lt != INT && lt != UNSIGNED) {
215 s->in.op = SCONV;
216 s->in.left = l;
217 s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
218 zzzcode(s, 'U');
219 putstr("\n\t");
220 }
f2b49199 221
8acf7c89
DS
222 if (ISUNSIGNED(lt)) {
223 s->in.op = SCONV;
224 s->in.left = lt == UNSIGNED ? l : resc;
225 s->in.type = rt;
226 unsigned_to_float(s);
227 } else {
228 putstr("cvl");
229 prtype(r);
230 putchar('\t');
231 adrput(lt == INT ? l : resc);
f2b49199 232 }
8acf7c89
DS
233 putstr("\n\t");
234
235 hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
895241c8 236 putchar('\t');
f2b49199 237 adrput(r);
8acf7c89
DS
238
239 if (ISUNSIGNED(lt)) {
240 putstr("\n\t");
241 s->in.op = SCONV;
242 s->in.left = r; /* we need only the type */
243 s->in.type = UNSIGNED;
244 float_to_unsigned(s);
245 } else {
246 putstr("\n\tcv");
247 prtype(r);
248 putstr("l\t");
249 if (lt == INT)
250 adrput(l);
251 else
252 adrput(resc);
253 }
254 if (lt != INT) {
255 putstr("\n\t");
256 s->in.op = ASSIGN;
257 s->in.left = l;
258 s->in.right = resc;
259 s->in.type = lt;
260 zzzcode(s, 'U');
261 }
262
263 s->in.op = FREE;
f2b49199
SL
264 return;
265 }
266
55f818e1
DS
267 case 'J': /* unsigned DIV/MOD with constant divisors */
268 {
269 register int ck = INAREG;
270 int label1, label2;
271
272 /* case constant <= 1 is handled by optim() in pass 1 */
273 /* case constant < 0x80000000 is handled in table */
274 switch( p->in.op ) {
275 /* case DIV: handled in hardops() */
276 case MOD:
277 if( p->in.left->in.op == REG &&
278 p->in.left->tn.rval == resc->tn.rval )
279 goto asgmod;
280 label1 = getlab();
281 expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n");
282 printf("\tjlssu\tL%d\n", label1);
283 expand(p, ck, "\tsubl2\tAR,A1\n");
284 printf("L%d:", label1);
285 break;
286 case ASG DIV:
287 label1 = getlab();
288 label2 = getlab();
289 expand(p, ck, "cmpl\tAL,AR\n");
290 printf("\tjgequ\tL%d\n", label1);
291 expand(p, ck, "\tmovl\t$1,AL\n");
292 printf("\tjbr\tL%d\nL%d:\n", label2, label1);
293 expand(p, ck, "\tclrl\tAL\n");
294 printf("L%d:", label2);
295 break;
296 case ASG MOD:
297 asgmod:
298 label1 = getlab();
299 expand(p, ck, "cmpl\tAL,AR\n");
300 printf("\tjlssu\tL%d\n", label1);
301 expand(p, ck, "\tsubl2\tAR,AL\n");
302 printf("L%d:", label1);
303 break;
304 }
305 return;
306 }
307
f2b49199
SL
308 case 'B': /* get oreg value in temp register for shift */
309 {
310 register NODE *r;
311 if (xdebug) eprint(p, 0, &val, &val);
312 r = p->in.right;
55f818e1 313 if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT )
895241c8 314 putstr("movl");
f2b49199 315 else {
895241c8 316 putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
f2b49199 317 prtype(r);
895241c8 318 putchar('l');
f2b49199
SL
319 }
320 return;
321 }
322
55f818e1 323 case 'C': /* generate 'call[fs] $bytes' */
f2b49199
SL
324 {
325 extern int gc_numbytes;
326 extern int xdebug;
327
328 if (xdebug) printf("->%d<-",gc_numbytes);
329
330 printf("call%c $%d",
331 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
332 gc_numbytes+4);
55f818e1 333 /* don't change to double (here's the only place to catch it) */
f2b49199
SL
334 if(p->in.type == FLOAT)
335 rtyflg = 1;
336 return;
337 }
338
339 case 'D': /* INCR and DECR */
8acf7c89 340 zzzcode(p->in.left, 'U');
895241c8 341 putstr("\n ");
f2b49199
SL
342
343 case 'E': /* INCR and DECR, FOREFF */
344 if (p->in.right->tn.lval == 1)
345 {
895241c8 346 putstr(p->in.op == INCR ? "inc" : "dec");
f2b49199 347 prtype(p->in.left);
895241c8 348 putchar('\t');
f2b49199
SL
349 adrput(p->in.left);
350 return;
351 }
895241c8 352 putstr(p->in.op == INCR ? "add" : "sub");
f2b49199 353 prtype(p->in.left);
895241c8 354 putstr("2 ");
f2b49199 355 adrput(p->in.right);
895241c8 356 putchar(',');
f2b49199
SL
357 adrput(p->in.left);
358 return;
359
360 case 'F': /* masked constant for fields */
7412b41b 361 printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
f2b49199
SL
362 return;
363
2ff1cc5a
DS
364 case 'I': /* produce value of bitfield assignment */
365 /* avoid shifts -- shifts are SLOW on this machine */
366 {
55f818e1
DS
367 register NODE *r = p->in.right;
368 if(r->in.op == ICON && r->tn.name[0] == '\0') {
369 putstr("movl\t");
370 printf(ACONFMT, r->tn.lval & ((1<<fldsz)-1));
371 }
372 else {
373 putstr("andl3\t");
374 printf(ACONFMT, (1 << fldsz) - 1);
2ff1cc5a 375 putchar(',');
55f818e1 376 adrput(r);
2ff1cc5a 377 }
55f818e1
DS
378 putchar(',');
379 adrput(resc);
380 break;
381 }
2ff1cc5a 382
f2b49199
SL
383 case 'H': /* opcode for shift */
384 if(p->in.op == LS || p->in.op == ASG LS)
895241c8 385 putstr("shll");
f2b49199 386 else if(ISUNSIGNED(p->in.left->in.type))
895241c8 387 putstr("shrl");
f2b49199 388 else
895241c8 389 putstr("shar");
f2b49199
SL
390 return;
391
392 case 'L': /* type of left operand */
393 case 'R': /* type of right operand */
394 {
395 register NODE *n;
396 extern int xdebug;
397
398 n = getlr ( p, c);
399 if (xdebug) printf("->%d<-", n->in.type);
400
401 prtype(n);
402 return;
403 }
404
f1824a4b 405 case 'M': { /* initiate ediv for mod and unsigned div */
f2b49199
SL
406 register char *r;
407 m = getlr(p, '1')->tn.rval;
408 r = rname(m);
409 printf("\tclrl\t%s\n\tmovl\t", r);
410 adrput(p->in.left);
411 printf(",%s\n", rname(m+1));
412 if(!ISUNSIGNED(p->in.type)) { /* should be MOD */
413 m = getlab();
414 printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
415 deflab(m);
416 }
f2b49199 417 return;
f1824a4b 418 }
f2b49199 419
f1824a4b
SL
420 case 'T': { /* rounded structure length for arguments */
421 int size = p->stn.stsize;
f2b49199
SL
422 SETOFF( size, 4);
423 printf("movab -%d(sp),sp", size);
424 return;
f1824a4b 425 }
f2b49199
SL
426
427 case 'S': /* structure assignment */
1d43595d
SL
428 stasg(p);
429 break;
f2b49199 430
55f818e1 431#ifdef I_don_t_understand_this
73fe5b3f
SL
432 case 'X': /* multiplication for short and char */
433 if (ISUNSIGNED(p->in.left->in.type))
434 printf("\tmovz");
435 else
436 printf("\tcvt");
437 zzzcode(p, 'L');
438 printf("l\t");
439 adrput(p->in.left);
440 printf(",");
441 adrput(&resc[0]);
442 printf("\n");
443 if (ISUNSIGNED(p->in.right->in.type))
444 printf("\tmovz");
445 else
446 printf("\tcvt");
447 zzzcode(p, 'R');
448 printf("l\t");
449 adrput(p->in.right);
450 printf(",");
451 adrput(&resc[1]);
452 printf("\n");
453 return;
55f818e1 454#endif
73fe5b3f 455
f1824a4b
SL
456 case 'U': /* SCONV */
457 case 'V': /* SCONV with FORCC */
458 sconv(p, c == 'V');
459 break;
460
7999919c
DS
461 case 'W': { /* SCONV or ASSIGN float/double => unsigned */
462 NODE *src = p->in.op == SCONV ? p->in.left : p->in.right;
463
8acf7c89 464 putstr("ld");
7999919c 465 prtype(src);
8acf7c89 466 putchar('\t');
7999919c 467 adrput(src);
8acf7c89
DS
468 putstr("\n\t");
469 float_to_unsigned(p);
470 break;
7999919c 471 }
8acf7c89 472
7999919c 473 case 'Y': /* SCONV or ASSIGN unsigned => float/double */
8acf7c89
DS
474 unsigned_to_float(p); /* stores into accumulator */
475 putstr("\n\tst");
476 prtype(p);
477 putchar('\t');
7999919c
DS
478 if (p->in.op == SCONV)
479 adrput(resc);
480 else
481 adrput(p->in.left);
482 rtyflg = 1;
8acf7c89
DS
483 break;
484
55f818e1 485#ifdef I_don_t_understand_this
f1824a4b
SL
486 case 'Z':
487 p = p->in.right;
488 switch (p->in.type) {
489 case SHORT: {
490 short w = p->tn.lval;
491 p->tn.lval = w;
492 break;
493 }
494 case CHAR: {
495 char c = p->tn.lval;
496 p->tn.lval = c;
497 break;
498 }
499 }
500 printf("$%d", p->tn.lval);
501 break;
55f818e1 502#endif
f1824a4b 503
1d43595d
SL
504 default:
505 cerror( "illegal zzzcode" );
1d43595d 506 }
f1824a4b 507}
f2b49199 508
1d43595d 509#define MOVB(dst, src, off) { \
895241c8 510 putstr("\tmovb\t"); upput(src, off); putchar(','); \
1d43595d
SL
511 upput(dst, off); putchar('\n'); \
512}
513#define MOVW(dst, src, off) { \
895241c8 514 putstr("\tmovw\t"); upput(src, off); putchar(','); \
1d43595d
SL
515 upput(dst, off); putchar('\n'); \
516}
517#define MOVL(dst, src, off) { \
895241c8 518 putstr("\tmovl\t"); upput(src, off); putchar(','); \
1d43595d
SL
519 upput(dst, off); putchar('\n'); \
520}
521/*
522 * Generate code for a structure assignment.
523 */
524stasg(p)
525 register NODE *p;
526{
527 register NODE *l, *r;
528 register int size;
529
530 switch (p->in.op) {
531 case STASG: /* regular assignment */
532 l = p->in.left;
533 r = p->in.right;
534 break;
535 case STARG: /* place arg on the stack */
536 l = getlr(p, '3');
537 r = p->in.left;
538 break;
539 default:
540 cerror("STASG bad");
541 /*NOTREACHED*/
542 }
543 /*
544 * Pun source for use in code generation.
545 */
546 switch (r->in.op) {
547 case ICON:
548 r->in.op = NAME;
549 break;
550 case REG:
551 r->in.op = OREG;
552 break;
553 default:
554 cerror( "STASG-r" );
555 /*NOTREACHED*/
556 }
557 size = p->stn.stsize;
558 if (size <= 0 || size > 65535)
559 cerror("structure size out of range");
560 /*
561 * Generate optimized code based on structure size
562 * and alignment properties....
563 */
564 switch (size) {
565
566 case 1:
895241c8 567 putstr("\tmovb\t");
1d43595d
SL
568 optimized:
569 adrput(r);
895241c8 570 putchar(',');
1d43595d 571 adrput(l);
895241c8 572 putchar('\n');
1d43595d
SL
573 break;
574
575 case 2:
576 if (p->stn.stalign != 2) {
577 MOVB(l, r, SZCHAR);
895241c8 578 putstr("\tmovb\t");
1d43595d 579 } else
895241c8 580 putstr("\tmovw\t");
1d43595d
SL
581 goto optimized;
582
583 case 4:
584 if (p->stn.stalign != 4) {
585 if (p->stn.stalign != 2) {
586 MOVB(l, r, 3*SZCHAR);
587 MOVB(l, r, 2*SZCHAR);
588 MOVB(l, r, 1*SZCHAR);
895241c8 589 putstr("\tmovb\t");
1d43595d
SL
590 } else {
591 MOVW(l, r, SZSHORT);
895241c8 592 putstr("\tmovw\t");
f2b49199 593 }
1d43595d 594 } else
895241c8 595 putstr("\tmovl\t");
1d43595d
SL
596 goto optimized;
597
598 case 6:
599 if (p->stn.stalign != 2)
600 goto movblk;
601 MOVW(l, r, 2*SZSHORT);
602 MOVW(l, r, 1*SZSHORT);
895241c8 603 putstr("\tmovw\t");
1d43595d
SL
604 goto optimized;
605
606 case 8:
607 if (p->stn.stalign == 4) {
608 MOVL(l, r, SZLONG);
895241c8 609 putstr("\tmovl\t");
1d43595d
SL
610 goto optimized;
611 }
612 /* fall thru...*/
f2b49199 613
1d43595d
SL
614 default:
615 movblk:
616 /*
617 * Can we ever get a register conflict with R1 here?
618 */
895241c8 619 putstr("\tmovab\t");
1d43595d 620 adrput(l);
895241c8 621 putstr(",r1\n\tmovab\t");
1d43595d
SL
622 adrput(r);
623 printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
624 rname(R2);
f2b49199 625 break;
1d43595d
SL
626 }
627 /*
628 * Reverse above pun for reclaim.
629 */
630 if (r->in.op == NAME)
631 r->in.op = ICON;
632 else if (r->in.op == OREG)
633 r->in.op = REG;
634}
f2b49199 635
8acf7c89
DS
636/*
637 * Convert a float or double in the accumulator into an unsigned int.
638 * Unlike the vax, the tahoe stores 0 into the destination
639 * on a conversion of > 2 ** 31, so we compensate.
640 */
641float_to_unsigned(p)
642 NODE *p;
643{
644 register NODE *l = p->in.left;
645 int label1 = getlab();
646 int label2 = getlab();
647 int label3 = getlab();
7999919c
DS
648 NODE *src, *dst;
649
650 if (p->in.op == SCONV) {
651 src = p->in.left;
652 dst = resc;
653 } else {
654 src = p->in.right;
655 dst = p->in.left;
656 }
8acf7c89
DS
657
658 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
7999919c
DS
659 if (src->in.type == DOUBLE)
660 putstr(", 0x00000000 # .double");
661 else
662 putstr(" # .float");
663 putstr(" 2147483648\n\t.text\n\tcmp");
664 prtype(src);
8acf7c89 665 printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
7999919c 666 prtype(src);
8acf7c89 667 printf("\tL%d\n\tcv", label1);
7999919c 668 prtype(src);
8acf7c89 669 putstr("l\t");
7999919c 670 adrput(dst);
8acf7c89 671 putstr("\n\taddl2\t$-2147483648,");
7999919c 672 adrput(dst);
8acf7c89 673 printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
7999919c 674 prtype(src);
8acf7c89 675 putstr("l\t");
7999919c 676 adrput(dst);
8acf7c89
DS
677 printf("\nL%d:", label3);
678}
679
680/*
681 * Convert an unsigned int into a float or double, leaving the result
682 * in the accumulator.
683 */
684unsigned_to_float(p)
685 register NODE *p;
686{
687 int label1 = getlab();
688 int label2 = getlab();
7999919c
DS
689 NODE *src, *dst;
690
691 if (p->in.op == SCONV) {
692 src = p->in.left;
693 dst = resc;
694 } else {
695 src = p->in.right;
696 dst = p->in.left;
697 }
8acf7c89
DS
698
699 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
700 if (p->in.type == DOUBLE)
7999919c
DS
701 putstr(", 0x00000000 # .double");
702 else
703 putstr(" # .float");
704 putstr(" 4294967296\n\t.text\n\tmovl\t");
705 adrput(src);
8acf7c89 706 putchar(',');
7999919c 707 adrput(dst);
8acf7c89
DS
708 putstr("\n\tcvl");
709 prtype(p);
710 putchar('\t');
7999919c
DS
711 adrput(dst);
712 printf("\n\tjgeq\tL%d\n\tadd", label1);
713 prtype(p);
714 printf("\tL%d\nL%d:", label2, label1);
8acf7c89
DS
715}
716
26ab1ae0
DS
717/*
718 * Prlen() is a cheap prtype()...
719 */
720static char convtab[SZINT/SZCHAR + 1] = {
721 '?', 'b', 'w', '?', 'l'
722};
723#define prlen(len) putchar(convtab[len])
724
725
52b983f1
DS
726/*
727 * Generate code for integral scalar conversions.
26ab1ae0
DS
728 * Some of this code is designed to work around a tahoe misfeature
729 * that causes sign- and zero- extension to be defeated in
730 * certain circumstances.
731 * Basically if the source operand of a CVT or MOVZ instruction is
732 * shorter than the destination, and the source is a register
733 * or an immediate constant, sign- and zero- extension are
734 * ignored and the high bits of the source are copied. (Note
735 * that zero-extension is not a problem for immediate
736 * constants.)
52b983f1
DS
737 */
738sconv(p, forcc)
739 NODE *p;
740 int forcc;
741{
742 register NODE *src, *dst;
743 register NODE *tmp;
744 register int srclen, dstlen;
745 int srctype, dsttype;
746 int val;
a1eb6a2f 747 int neg = 0;
52b983f1
DS
748
749 if (p->in.op == ASSIGN) {
7999919c
DS
750 src = p->in.right;
751 dst = p->in.left;
52b983f1
DS
752 dstlen = tlen(dst);
753 dsttype = dst->in.type;
7999919c
DS
754 } else if (p->in.op == SCONV) {
755 src = p->in.left;
756 dst = resc;
52b983f1
DS
757 dstlen = tlen(p);
758 dsttype = p->in.type;
7999919c
DS
759 } else /* if (p->in.op == OPLEAF) */ {
760 src = p;
761 dst = resc;
762 dstlen = SZINT/SZCHAR;
763 dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
52b983f1
DS
764 }
765
26ab1ae0
DS
766 if (src->in.op == REG) {
767 srclen = SZINT/SZCHAR;
768 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
769 } else {
770 srclen = tlen(src);
771 srctype = src->in.type;
772 }
773
a1eb6a2f 774 if (src->in.op == ICON && src->tn.name[0] == '\0') {
26ab1ae0
DS
775 if (src->tn.lval == 0) {
776 putstr("clr");
777 prtype(dst);
778 putchar('\t');
779 adrput(dst);
780 return;
781 }
782 if (dstlen < srclen) {
783 switch (dsttype) {
784 case CHAR:
785 src->tn.lval = (char) src->tn.lval;
786 break;
787 case UCHAR:
788 src->tn.lval = (unsigned char) src->tn.lval;
789 break;
790 case SHORT:
791 src->tn.lval = (short) src->tn.lval;
792 break;
793 case USHORT:
794 src->tn.lval = (unsigned short) src->tn.lval;
795 break;
796 }
797 }
798 if (dst->in.op == REG) {
799 dsttype = INT;
800 dstlen = SZINT/SZCHAR;
801 }
802 srctype = dsttype;
803 srclen = dstlen;
a1eb6a2f
DS
804 if ((val = src->tn.lval) & 1 << dstlen * SZCHAR - 1) {
805 src->tn.lval = -(val | ~((1 << dstlen * SZCHAR) - 1));
806 ++neg; /* MNEGx may be shorter */
807 }
26ab1ae0 808 }
52b983f1
DS
809
810 if (srclen < dstlen) {
811 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
812 /* (unsigned short) c; => sign extend to 16 bits */
c3446016 813 putstr("cvtbl\t");
52b983f1
DS
814 adrput(src);
815 putstr(",-(sp)\n\tmovzwl\t2(sp),");
816 adrput(dst);
817 putstr("\n\tmovab\t4(sp),sp");
818 if (forcc) {
819 /* inverted test */
820 putstr("\n\tcmpl\t$0,");
821 adrput(dst);
822 }
823 return;
824 }
825 genconv(ISUNSIGNED(srctype),
826 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
827 src, dst);
828 return;
829 }
830
831 if (srclen > dstlen && dst->in.op == REG) {
26ab1ae0 832 /* if dst is a register, the result must look like an int */
52b983f1
DS
833 if (src->in.op == REG) {
834 if (ISUNSIGNED(dsttype)) {
835 val = (1 << dstlen * SZCHAR) - 1;
836 if (src->tn.rval == dst->tn.rval)
837 /* conversion in place */
c3446016 838 printf("andl2\t$%#x,", val);
52b983f1 839 else {
c3446016 840 printf("andl3\t$%#x,", val);
52b983f1
DS
841 adrput(src);
842 putchar(',');
843 }
844 adrput(dst);
845 return;
846 }
26ab1ae0
DS
847 /*
848 * Sign extension in register can also be
849 * accomplished by shifts, but unfortunately
850 * shifts are extremely slow, due to the lack
851 * of a barrel shifter.
852 */
853 putstr("pushl\t");
52b983f1 854 adrput(src);
26ab1ae0
DS
855 putstr("\n\tcvt");
856 prlen(dstlen);
857 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
52b983f1 858 adrput(dst);
26ab1ae0
DS
859 putstr("\n\tmovab\t4(sp),sp");
860 if (forcc) {
861 /* inverted test */
862 putstr("\n\tcmpl\t$0,");
863 adrput(dst);
864 }
52b983f1
DS
865 return;
866 }
867 tmp = talloc();
868 if ((src->in.op == UNARY MUL &&
869 ((src->in.left->in.op == NAME ||
870 (src->in.left->in.op == ICON)))) ||
871 (src->in.op == OREG && !R2TEST(src->tn.rval))) {
872 /* we can increment src's address & pun it */
873 *tmp = *src;
874 tmp->tn.lval += srclen - dstlen;
875 } else {
876 /* we must store src's address */
877 *tmp = *dst;
26ab1ae0
DS
878 putstr("mova");
879 prlen(srclen);
880 putchar('\t');
52b983f1
DS
881 adrput(src);
882 putchar(',');
883 adrput(tmp);
c3446016 884 putstr("\n\t");
52b983f1
DS
885 tmp->tn.op = OREG;
886 tmp->tn.lval = srclen - dstlen;
887 }
888 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
889 tmp->in.op = FREE;
890 return;
891 }
892
a1eb6a2f 893 genconv(neg ? -1 : ISUNSIGNED(dsttype),
52b983f1
DS
894 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
895 src, dst);
896}
897
a1eb6a2f
DS
898genconv(srcflag, srclen, dstlen, src, dst)
899 int srcflag;
26ab1ae0 900 register int srclen, dstlen;
52b983f1
DS
901 NODE *src, *dst;
902{
52b983f1 903 if (srclen != dstlen) {
a1eb6a2f 904 if (srcflag > 0 && srclen < dstlen)
c3446016 905 putstr("movz");
52b983f1 906 else
c3446016 907 putstr("cvt");
26ab1ae0 908 prlen(srclen);
a1eb6a2f
DS
909 } else if (srcflag < 0)
910 putstr("mneg");
911 else
c3446016 912 putstr("mov");
26ab1ae0 913 prlen(dstlen);
52b983f1
DS
914 putchar('\t');
915 adrput(src);
916 putchar(',');
917 adrput(dst);
918}
f1824a4b 919
55f818e1 920rmove( rt, rs, t ) TWORD t; {
f2b49199
SL
921 printf( " movl %s,%s\n", rname(rs), rname(rt) );
922 if(t==DOUBLE)
923 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
924 }
925
926struct respref
927respref[] = {
928 INTAREG|INTBREG, INTAREG|INTBREG,
929 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
930 INTEMP, INTEMP,
931 FORARG, FORARG,
932 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
933 0, 0 };
934
935setregs(){ /* set up temporary registers */
936 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
937 }
938
ebdd0416 939#ifndef szty
f2b49199
SL
940szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
941 return(t==DOUBLE ? 2 : 1 );
942 }
ebdd0416 943#endif
f2b49199 944
55f818e1 945/*ARGSUSED*/
f2b49199
SL
946rewfld( p ) NODE *p; {
947 return(1);
948 }
949
55f818e1 950/*ARGSUSED*/
f2b49199
SL
951callreg(p) NODE *p; {
952 return( R0 );
953 }
954
955base( p ) register NODE *p; {
956 register int o = p->in.op;
957
958 if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
959 if( o==REG ) return( p->tn.rval );
960 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
961 return( p->in.left->tn.rval );
962 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
963 return( p->tn.rval + 0200*1 );
964 return( -1 );
965 }
966
967offset( p, tyl ) register NODE *p; int tyl; {
968
55f818e1
DS
969 if( tyl==1 &&
970 p->in.op==REG &&
971 (p->in.type==INT || p->in.type==UNSIGNED) )
972 return( p->tn.rval );
973 if( p->in.op==LS &&
974 p->in.left->in.op==REG &&
975 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
976 p->in.right->in.op==ICON &&
977 p->in.right->in.name[0]=='\0' &&
978 (1<<p->in.right->tn.lval)==tyl)
979 return( p->in.left->tn.rval );
980 if( tyl==2 &&
981 p->in.op==PLUS &&
982 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
983 p->in.left->in.op==REG &&
984 p->in.right->in.op==REG &&
985 p->in.left->tn.rval==p->in.right->tn.rval )
f2b49199
SL
986 return( p->in.left->tn.rval );
987 return( -1 );
988 }
989
990makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
991 register NODE *t;
f2b49199
SL
992 NODE *f;
993
994 p->in.op = OREG;
995 f = p->in.left; /* have to free this subtree later */
996
997 /* init base */
998 switch (q->in.op) {
999 case ICON:
1000 case REG:
1001 case OREG:
1002 t = q;
1003 break;
1004
1005 case MINUS:
1006 q->in.right->tn.lval = -q->in.right->tn.lval;
1007 case PLUS:
1008 t = q->in.right;
1009 break;
1010
1011 case UNARY MUL:
1012 t = q->in.left->in.left;
1013 break;
1014
1015 default:
1016 cerror("illegal makeor2");
1017 }
1018
1019 p->tn.lval = t->tn.lval;
1020#ifndef FLEXNAMES
55f818e1
DS
1021 {
1022 register int i;
1023 for(i=0; i<NCHNAM; ++i)
1024 p->in.name[i] = t->in.name[i];
1025 }
f2b49199
SL
1026#else
1027 p->in.name = t->in.name;
1028#endif
1029
1030 /* init offset */
1031 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
1032
1033 tfree(f);
1034 return;
1035 }
1036
1037canaddr( p ) NODE *p; {
1038 register int o = p->in.op;
1039
1040 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1041 return(0);
1042 }
1043
ebdd0416 1044#ifndef shltype
f2b49199
SL
1045shltype( o, p ) register NODE *p; {
1046 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
1047 }
ebdd0416 1048#endif
f2b49199
SL
1049
1050flshape( p ) NODE *p; {
1051 register int o = p->in.op;
1052
1053 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1054 return(0);
1055 }
1056
55f818e1 1057/* INTEMP shapes must not contain any temporary registers */
f2b49199 1058shtemp( p ) register NODE *p; {
55f818e1
DS
1059 int r;
1060
f2b49199 1061 if( p->in.op == STARG ) p = p->in.left;
55f818e1
DS
1062
1063 switch (p->in.op) {
1064 case REG:
1065 return( !istreg(p->tn.rval) );
1066 case OREG:
1067 r = p->tn.rval;
1068 if( R2TEST(r) ) {
1069 if( istreg(R2UPK1(r)) )
1070 return(0);
1071 r = R2UPK2(r);
1072 }
1073 return( !istreg(r) );
1074 case UNARY MUL:
1075 p = p->in.left;
1076 return( p->in.op != UNARY MUL && shtemp(p) );
1077 }
1078
1079 if( optype( p->in.op ) != LTYPE ) return(0);
1080 return(1);
f2b49199
SL
1081 }
1082
1083shumul( p ) register NODE *p; {
1084 register int o;
1085 extern int xdebug;
1086
1087 if (xdebug) {
1088 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1089 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1090 }
1091
1092 o = p->in.op;
1093 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1094 && p->in.type != PTR+DOUBLE)
1095 return( STARNM );
1096
1097 return( 0 );
1098 }
1099
f2b49199 1100adrcon( val ) CONSZ val; {
7412b41b 1101 printf(ACONFMT, val);
f2b49199
SL
1102 }
1103
1104conput( p ) register NODE *p; {
1105 switch( p->in.op ){
1106
1107 case ICON:
1108 acon( p );
1109 return;
1110
1111 case REG:
895241c8 1112 putstr(rname(p->tn.rval));
f2b49199
SL
1113 return;
1114
1115 default:
1116 cerror( "illegal conput" );
1117 }
1118 }
1119
55f818e1 1120/*ARGSUSED*/
f2b49199
SL
1121insput( p ) NODE *p; {
1122 cerror( "insput" );
1123 }
1124
55f818e1
DS
1125/*
1126 * Output the address of the second item in the
1127 * pair pointed to by p.
1128 */
1129upput(p, size)
1130 register NODE *p;
1131{
1132 CONSZ save;
1133
1134 if (p->in.op == FLD)
1135 p = p->in.left;
1136 switch (p->in.op) {
1137
1138 case NAME:
1139 case OREG:
1140 save = p->tn.lval;
1141 p->tn.lval += size/SZCHAR;
1142 adrput(p);
1143 p->tn.lval = save;
1144 break;
1145
1146 case REG:
1147 if (size == SZLONG) {
1148 putstr(rname(p->tn.rval+1));
1149 break;
1150 }
1151 /* fall thru... */
1152
1153 default:
1154 cerror("illegal upper address op %s size %d",
1155 opst[p->tn.op], size);
1156 /*NOTREACHED*/
1157 }
1158}
1159
f2b49199
SL
1160adrput( p ) register NODE *p; {
1161 register int r;
1162 /* output an address, with offsets, from p */
1163
1164 if( p->in.op == FLD ){
1165 p = p->in.left;
1166 }
1167 switch( p->in.op ){
1168
1169 case NAME:
1170 acon( p );
1171 return;
1172
1173 case ICON:
1174 /* addressable value of the constant */
895241c8 1175 putchar('$');
f2b49199
SL
1176 acon( p );
1177 return;
1178
1179 case REG:
895241c8 1180 putstr(rname(p->tn.rval));
f2b49199
SL
1181 if(p->in.type == DOUBLE) /* for entry mask */
1182 (void) rname(p->tn.rval+1);
1183 return;
1184
1185 case OREG:
1186 r = p->tn.rval;
1187 if( R2TEST(r) ){ /* double indexing */
1188 register int flags;
1189
1190 flags = R2UPK3(r);
895241c8 1191 if( flags & 1 ) putchar('*');
f2b49199
SL
1192 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1193 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1194 printf( "[%s]", rname(R2UPK2(r)) );
1195 return;
1196 }
1197 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
1198 if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1199 printf( CONFMT, p->tn.lval );
895241c8 1200 putstr( "(fp)" );
f2b49199
SL
1201 return;
1202 }
1203 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1204 printf( "(%s)", rname(p->tn.rval) );
1205 return;
1206
1207 case UNARY MUL:
1208 /* STARNM or STARREG found */
1209 if( tshape(p, STARNM) ) {
895241c8 1210 putchar( '*' );
f2b49199
SL
1211 adrput( p->in.left);
1212 }
1213 return;
1214
1215 default:
1216 cerror( "illegal address" );
1217 return;
1218
1219 }
1220
1221 }
1222
1223acon( p ) register NODE *p; { /* print out a constant */
1224
55f818e1 1225 if( p->in.name[0] == '\0' )
f2b49199 1226 printf( CONFMT, p->tn.lval);
55f818e1 1227 else {
f2b49199
SL
1228#ifndef FLEXNAMES
1229 printf( "%.8s", p->in.name );
1230#else
55f818e1 1231 putstr( p->in.name );
f2b49199 1232#endif
55f818e1
DS
1233 if( p->tn.lval != 0 ) {
1234 putchar( '+' );
1235 printf( CONFMT, p->tn.lval );
1236 }
f2b49199 1237 }
895241c8 1238 }
f2b49199
SL
1239
1240genscall( p, cookie ) register NODE *p; {
1241 /* structure valued call */
1242 return( gencall( p, cookie ) );
1243 }
1244
1245genfcall( p, cookie ) register NODE *p; {
1246 register NODE *p1;
1247 register int m;
1248 static char *funcops[6] = {
1249 "sin", "cos", "sqrt", "exp", "log", "atan"
1250 };
1251
1252 /* generate function opcodes */
1253 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1254 (p1 = p->in.left)->in.op==ICON &&
1255 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1256#ifdef FLEXNAMES
1257 p1->in.name++;
1258#else
1259 strcpy(p1->in.name, p1->in.name[1]);
1260#endif
1261 for(m=0; m<6; m++)
1262 if(!strcmp(p1->in.name, funcops[m]))
1263 break;
1264 if(m >= 6)
1265 uerror("no opcode for fortarn function %s", p1->in.name);
1266 } else
1267 uerror("illegal type of fortarn function");
1268 p1 = p->in.right;
1269 p->in.op = FORTCALL;
1270 if(!canaddr(p1))
1271 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1272 m = match( p, INTAREG|INTBREG );
1273 return(m != MDONE);
1274}
1275
1276/* tbl */
1277int gc_numbytes;
1278/* tbl */
1279
55f818e1 1280/*ARGSUSED*/
f2b49199
SL
1281gencall( p, cookie ) register NODE *p; {
1282 /* generate the call given by p */
1283 register NODE *p1, *ptemp;
1284 register int temp, temp1;
1285 register int m;
1286
1287 if( p->in.right ) temp = argsize( p->in.right );
1288 else temp = 0;
1289
1290 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1291 /* set aside room for structure return */
1292
1293 if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1294 else temp1 = temp;
1295 }
1296
1297 if( temp > maxargs ) maxargs = temp;
1298 SETOFF(temp1,4);
1299
1300 if( p->in.right ){ /* make temp node, put offset in, and generate args */
1301 ptemp = talloc();
1302 ptemp->in.op = OREG;
1303 ptemp->tn.lval = -1;
1304 ptemp->tn.rval = SP;
1305#ifndef FLEXNAMES
1306 ptemp->in.name[0] = '\0';
1307#else
1308 ptemp->in.name = "";
1309#endif
1310 ptemp->in.rall = NOPREF;
1311 ptemp->in.su = 0;
1312 genargs( p->in.right, ptemp );
1313 ptemp->in.op = FREE;
1314 }
1315
1316 p1 = p->in.left;
1317 if( p1->in.op != ICON ){
1318 if( p1->in.op != REG ){
1319 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1320 if( p1->in.op != NAME ){
1321 order( p1, INAREG );
1322 }
1323 }
1324 }
1325 }
1326
1327/* tbl
1328 setup gc_numbytes so reference to ZC works */
1329
1330 gc_numbytes = temp&(0x3ff);
1331
1332 p->in.op = UNARY CALL;
1333 m = match( p, INTAREG|INTBREG );
1334
1335 return(m != MDONE);
1336 }
1337
1338/* tbl */
1339char *
1340ccbranches[] = {
1341 "eql",
1342 "neq",
1343 "leq",
1344 "lss",
1345 "geq",
1346 "gtr",
1347 "lequ",
1348 "lssu",
1349 "gequ",
1350 "gtru",
1351 };
1352/* tbl */
1353
55f818e1 1354/*ARGSUSED*/
f2b49199
SL
1355cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
1356
55f818e1
DS
1357 if( o != 0 && ( o < EQ || o > UGT ) )
1358 cerror( "bad conditional branch: %s", opst[o] );
1359 printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
f2b49199
SL
1360 }
1361
1362nextcook( p, cookie ) NODE *p; {
1363 /* we have failed to match p with cookie; try another */
1364 if( cookie == FORREW ) return( 0 ); /* hopeless! */
1365 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1366 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1367 return( FORREW );
1368 }
1369
55f818e1 1370/*ARGSUSED*/
f2b49199
SL
1371lastchance( p, cook ) NODE *p; {
1372 /* forget it! */
1373 return(0);
1374 }
1375
1376optim2( p ) register NODE *p; {
f2b49199 1377 /* do local tree transformations and optimizations */
55f818e1
DS
1378
1379 int o;
1380 int i, mask;
f1824a4b 1381 register NODE *l, *r;
f2b49199 1382
55f818e1 1383 switch( o = p->in.op ) {
f1824a4b 1384
55f818e1
DS
1385 case AND:
1386 case ASG AND:
1387 r = p->in.right;
1388 if( r->in.op==ICON && r->in.name[0]==0 ) {
1389 /* check for degenerate operations */
1390 l = p->in.left;
1391 mask = (1 << tlen(l) * SZCHAR) - 1;
1392 if( ISUNSIGNED(r->in.type) ) {
1393 i = (r->tn.lval & mask);
1394 if( i == mask ) {
1395 r->in.op = FREE;
1396 ncopy(p, l);
1397 l->in.op = FREE;
1398 break;
1399 }
1400 else if( i == 0 )
1401 goto zero;
1402 else
1403 r->tn.lval = i;
1404 }
1405 else if( r->tn.lval == mask &&
1406 tlen(l) < SZINT/SZCHAR ) {
1407 r->in.op = SCONV;
1408 r->in.left = l;
1409 r->in.right = 0;
1410 r->in.type = ENUNSIGN(l->in.type);
1411 r->in.su = l->in.su > 1 ? l->in.su : 1;
1412 ncopy(p, r);
1413 p->in.left = r;
1414 p->in.type = INT;
1415 }
f1824a4b 1416 }
55f818e1 1417 break;
f1824a4b
SL
1418
1419 case SCONV:
1420 l = p->in.left;
55f818e1
DS
1421 if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1422 l->in.type == FLOAT || l->in.type == DOUBLE )
1423 return;
1424 if( l->in.op == PCONV || l->in.op == CALL || l->in.op == UNARY CALL )
1425 return;
7999919c 1426
55f818e1
DS
1427 /* Only trust it to get it right if the size is the same */
1428 if( tlen(p) != tlen(l) )
1429 return;
1430
1431 /* clobber conversion */
1432 if( l->in.op != FLD )
1433 l->in.type = p->in.type;
1434 ncopy( p, l );
1435 l->in.op = FREE;
1436
1437 break;
f1824a4b
SL
1438
1439 case ASSIGN:
1440 /*
55f818e1
DS
1441 * Conversions are equivalent to assignments;
1442 * when the two operations are combined,
1443 * we can sometimes zap the conversion.
f1824a4b
SL
1444 */
1445 r = p->in.right;
55f818e1
DS
1446 l = p->in.left;
1447 if ( r->in.op == SCONV &&
1448 !mixtypes(l, r) &&
1449 l->in.op != FLD &&
1450 tlen(l) == tlen(r) ) {
f1824a4b
SL
1451 p->in.right = r->in.left;
1452 r->in.op = FREE;
1453 }
55f818e1 1454 break;
b45bedd3
DS
1455
1456 case ULE:
1457 case ULT:
1458 case UGE:
1459 case UGT:
55f818e1
DS
1460 p->in.op -= (UGE-GE);
1461 if( degenerate(p) )
1462 break;
1463 p->in.op += (UGE-GE);
1464 break;
1465
b45bedd3
DS
1466 case EQ:
1467 case NE:
1468 case LE:
1469 case LT:
1470 case GE:
1471 case GT:
55f818e1
DS
1472 (void) degenerate(p);
1473 break;
1474
1475 case DIV:
1476 if( p->in.right->in.op == ICON &&
1477 p->in.right->tn.name[0] == '\0' &&
1478 ISUNSIGNED(p->in.right->in.type) &&
1479 (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1480 /* easy to do here, harder to do in zzzcode() */
1481 p->in.op = UGE;
1482 break;
1483 }
1484 case MOD:
1485 case ASG DIV:
1486 case ASG MOD:
b45bedd3 1487 /*
55f818e1
DS
1488 * optimize DIV and MOD
1489 *
1490 * basically we spot UCHAR and USHORT and try to do them
1491 * as signed ints... this may need tuning for the tahoe.
b45bedd3 1492 */
55f818e1 1493 if( degenerate(p) )
b45bedd3 1494 break;
55f818e1
DS
1495 l = p->in.left;
1496 r = p->in.right;
1497 if( !ISUNSIGNED(r->in.type) ||
1498 tlen(l) >= SZINT/SZCHAR ||
1499 !(tlen(r) < SZINT/SZCHAR ||
1500 (r->in.op == ICON && r->tn.name[0] == '\0')) )
b45bedd3 1501 break;
55f818e1
DS
1502 if( r->in.op == ICON )
1503 r->tn.type = INT;
1504 else {
1505 NODE *t = talloc();
1506 t->in.left = r;
1507 r = t;
1508 r->in.op = SCONV;
1509 r->in.type = INT;
1510 r->in.right = 0;
1511 p->in.right = r;
1512 }
1513 if( o == DIV || o == MOD ) {
1514 NODE *t = talloc();
1515 t->in.left = l;
1516 l = t;
1517 l->in.op = SCONV;
1518 l->in.type = INT;
1519 l->in.right = 0;
1520 p->in.left = l;
1521 }
1522 /* handle asgops in table */
1523 break;
1524
1525 case RS:
1526 case ASG RS:
1527 case LS:
1528 case ASG LS:
1529 /* pick up degenerate shifts */
1530 l = p->in.left;
1531 r = p->in.right;
1532 if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
b45bedd3 1533 break;
b45bedd3 1534 i = r->tn.lval;
55f818e1
DS
1535 if( i < 0 )
1536 /* front end 'fixes' this? */
1537 if( o == LS || o == ASG LS )
1538 o += (RS-LS);
1539 else
1540 o += (LS-RS);
1541 if( (o == RS || o == ASG RS) &&
1542 !ISUNSIGNED(l->in.type) )
1543 /* can't optimize signed right shifts */
b45bedd3 1544 break;
55f818e1
DS
1545 if( o == LS ) {
1546 if( i < SZINT )
1547 break;
1548 }
1549 else {
1550 if( i < tlen(l) * SZCHAR )
1551 break;
1552 }
1553 zero:
1554 if( !asgop( o ) )
1555 if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1556 /* no side effects */
1557 tfree(l);
1558 ncopy(p, r);
1559 r->in.op = FREE;
1560 p->tn.lval = 0;
1561 }
1562 else {
1563 p->in.op = COMOP;
1564 r->tn.lval = 0;
1565 }
1566 else {
1567 p->in.op = ASSIGN;
1568 r->tn.lval = 0;
1569 }
1570 break;
b45bedd3 1571 }
55f818e1 1572 }
b45bedd3 1573
55f818e1
DS
1574degenerate(p) register NODE *p; {
1575 int o;
1576 int result, i;
1577 int lower, upper;
1578 register NODE *l, *r;
1579
1580 /*
1581 * try to keep degenerate comparisons with constants
1582 * out of the table.
1583 */
1584 r = p->in.right;
1585 l = p->in.left;
1586 if( r->in.op != ICON ||
1587 r->tn.name[0] != '\0' ||
1588 tlen(l) >= tlen(r) )
1589 return (0);
1590 switch( l->in.type ) {
1591 case CHAR:
1592 lower = -(1 << SZCHAR - 1);
1593 upper = (1 << SZCHAR - 1) - 1;
1594 break;
1595 case UCHAR:
1596 lower = 0;
1597 upper = (1 << SZCHAR) - 1;
1598 break;
1599 case SHORT:
1600 lower = -(1 << SZSHORT - 1);
1601 upper = (1 << SZSHORT - 1) - 1;
1602 break;
1603 case USHORT:
1604 lower = 0;
1605 upper = (1 << SZSHORT) - 1;
1606 break;
1607 default:
1608 cerror("unsupported type in degenerate()");
1609 }
1610 i = r->tn.lval;
1611 switch( o = p->in.op ) {
1612 case DIV:
1613 case ASG DIV:
1614 case MOD:
1615 case ASG MOD:
1616 /* DIV and MOD work like EQ */
1617 case EQ:
1618 case NE:
1619 if( lower == 0 && (unsigned) i > upper )
1620 result = o == NE;
1621 else if( i < lower || i > upper )
1622 result = o == NE;
1623 else
1624 return (0);
1625 break;
1626 case LT:
1627 case GE:
1628 if( lower == 0 && (unsigned) i > upper )
1629 result = o == LT;
1630 else if( i <= lower )
1631 result = o != LT;
1632 else if( i > upper )
1633 result = o == LT;
1634 else
1635 return (0);
1636 break;
1637 case LE:
1638 case GT:
1639 if( lower == 0 && (unsigned) i >= upper )
1640 result = o == LE;
1641 else if( i < lower )
1642 result = o != LE;
1643 else if( i >= upper )
1644 result = o == LE;
1645 else
1646 return (0);
1647 break;
1648 default:
1649 cerror("unknown op in degenerate()");
1650 }
1651
1652 if( o == MOD || o == ASG MOD ) {
1653 r->in.op = FREE;
1654 ncopy(p, l);
1655 l->in.op = FREE;
1656 }
1657 else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1658 /* no side effects */
1659 tfree(l);
1660 ncopy(p, r);
1661 r->in.op = FREE;
1662 p->tn.lval = result;
1663 }
1664 else {
1665 if( o == ASG DIV )
1666 p->in.op = ASSIGN;
1667 else {
b45bedd3 1668 p->in.op = COMOP;
b45bedd3 1669 r->tn.type = INT;
55f818e1
DS
1670 }
1671 r->tn.lval = result;
b45bedd3 1672 }
55f818e1
DS
1673 if( logop(o) )
1674 p->in.type = INT;
1675
1676 return (1);
f2b49199 1677 }
f2b49199
SL
1678
1679struct functbl {
1680 int fop;
20018a56 1681 TWORD ftype;
f2b49199 1682 char *func;
20018a56
DS
1683 } opfunc[] = {
1684 DIV, TANY, "udiv",
1685 MOD, TANY, "urem",
1686 ASG DIV, TANY, "audiv",
1687 ASG MOD, TANY, "aurem",
1688 0, 0, 0 };
f2b49199
SL
1689
1690hardops(p) register NODE *p; {
1691 /* change hard to do operators into function calls. */
1692 register NODE *q;
1693 register struct functbl *f;
20018a56
DS
1694 register o;
1695 NODE *old,*temp;
f2b49199
SL
1696
1697 o = p->in.op;
20018a56
DS
1698 if( ! (optype(o)==BITYPE &&
1699 (ISUNSIGNED(p->in.left->in.type) ||
1700 ISUNSIGNED(p->in.right->in.type))) )
1701 return;
f2b49199
SL
1702
1703 for( f=opfunc; f->fop; f++ ) {
1704 if( o==f->fop ) goto convert;
20018a56 1705 }
f2b49199
SL
1706 return;
1707
1708 convert:
55f818e1
DS
1709 if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1710 /* 'J' in zzzcode() -- assumes DIV or MOD operations */
1711 /* save a subroutine call -- use at most 5 instructions */
1712 return;
1713 if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1714 /* optim2() will modify the op into an ordinary int op */
1715 return;
f2b49199 1716 if( asgop( o ) ) {
20018a56
DS
1717 old = NIL;
1718 switch( p->in.left->in.op ){
1719 case FLD:
1720 q = p->in.left->in.left;
1721 /*
1722 * rewrite (lval.fld /= rval); as
1723 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1724 * else the compiler will evaluate lval twice.
1725 */
1726 if( q->in.op == UNARY MUL ){
1727 /* first allocate a temp storage */
1728 temp = talloc();
1729 temp->in.op = OREG;
1730 temp->tn.rval = TMPREG;
1731 temp->tn.lval = BITOOR(freetemp(1));
1732 temp->in.type = INCREF(p->in.type);
1733#ifdef FLEXNAMES
1734 temp->in.name = "";
1735#else
1736 temp->in.name[0] = '\0';
1737#endif
1738 old = q->in.left;
1739 q->in.left = temp;
1740 }
1741 /* fall thru ... */
f2b49199 1742
20018a56
DS
1743 case REG:
1744 case NAME:
1745 case OREG:
1746 /* change ASG OP to a simple OP */
1747 q = talloc();
1748 q->in.op = NOASG p->in.op;
1749 q->in.rall = NOPREF;
1750 q->in.type = p->in.type;
1751 q->in.left = tcopy(p->in.left);
1752 q->in.right = p->in.right;
1753 p->in.op = ASSIGN;
1754 p->in.right = q;
1755 p = q;
1756 f -= 2; /* Note: this depends on the table order */
1757 /* on the right side only - replace *temp with
1758 *(temp = &lval), build the assignment node */
1759 if( old ){
1760 temp = q->in.left->in.left; /* the "*" node */
1761 q = talloc();
1762 q->in.op = ASSIGN;
1763 q->in.left = temp->in.left;
1764 q->in.right = old;
1765 q->in.type = old->in.type;
1766#ifdef FLEXNAMES
1767 q->in.name = "";
f2b49199 1768#else
20018a56 1769 q->in.name[0] = '\0';
f2b49199 1770#endif
20018a56
DS
1771 temp->in.left = q;
1772 }
1773 break;
f2b49199 1774
20018a56
DS
1775 case UNARY MUL:
1776 /* avoid doing side effects twice */
1777 q = p->in.left;
1778 p->in.left = q->in.left;
1779 q->in.op = FREE;
1780 break;
1781
1782 default:
1783 cerror( "hardops: can't compute & LHS" );
1784 }
1785 }
f2b49199 1786
20018a56
DS
1787 /* build comma op for args to function */
1788 q = talloc();
1789 q->in.op = CM;
1790 q->in.rall = NOPREF;
1791 q->in.type = INT;
1792 q->in.left = p->in.left;
1793 q->in.right = p->in.right;
f2b49199
SL
1794 p->in.op = CALL;
1795 p->in.right = q;
1796
1797 /* put function name in left node of call */
1798 p->in.left = q = talloc();
1799 q->in.op = ICON;
1800 q->in.rall = NOPREF;
1801 q->in.type = INCREF( FTN + p->in.type );
1802#ifndef FLEXNAMES
20018a56 1803 strcpy( q->in.name, f->func );
f2b49199 1804#else
20018a56 1805 q->in.name = f->func;
f2b49199
SL
1806#endif
1807 q->tn.lval = 0;
1808 q->tn.rval = 0;
1809
1810 }
1811
1812zappost(p) NODE *p; {
1813 /* look for ++ and -- operators and remove them */
1814
1815 register int o, ty;
1816 register NODE *q;
1817 o = p->in.op;
1818 ty = optype( o );
1819
1820 switch( o ){
1821
1822 case INCR:
1823 case DECR:
1824 q = p->in.left;
1825 p->in.right->in.op = FREE; /* zap constant */
1826 ncopy( p, q );
1827 q->in.op = FREE;
1828 return;
1829
1830 }
1831
1832 if( ty == BITYPE ) zappost( p->in.right );
1833 if( ty != LTYPE ) zappost( p->in.left );
1834}
1835
1836fixpre(p) NODE *p; {
1837
1838 register int o, ty;
1839 o = p->in.op;
1840 ty = optype( o );
1841
1842 switch( o ){
1843
1844 case ASG PLUS:
1845 p->in.op = PLUS;
1846 break;
1847 case ASG MINUS:
1848 p->in.op = MINUS;
1849 break;
1850 }
1851
1852 if( ty == BITYPE ) fixpre( p->in.right );
1853 if( ty != LTYPE ) fixpre( p->in.left );
1854}
1855
55f818e1 1856/*ARGSUSED*/
f2b49199
SL
1857NODE * addroreg(l) NODE *l;
1858 /* OREG was built in clocal()
1859 * for an auto or formal parameter
1860 * now its address is being taken
1861 * local code must unwind it
1862 * back to PLUS/MINUS REG ICON
1863 * according to local conventions
1864 */
1865{
1866 cerror("address of OREG taken");
55f818e1 1867 /*NOTREACHED*/
f2b49199
SL
1868}
1869
1870# ifndef ONEPASS
1871main( argc, argv ) char *argv[]; {
1872 return( mainp2( argc, argv ) );
1873 }
1874# endif
1875
f1824a4b
SL
1876strip(p) register NODE *p; {
1877 NODE *q;
1878
1879 /* strip nodes off the top when no side effects occur */
1880 for( ; ; ) {
1881 switch( p->in.op ) {
1882 case SCONV: /* remove lint tidbits */
1883 q = p->in.left;
1884 ncopy( p, q );
1885 q->in.op = FREE;
1886 break;
1887 /* could probably add a few more here */
1888 default:
1889 return;
1890 }
1891 }
1892 }
1893
f2b49199 1894myreader(p) register NODE *p; {
f1824a4b 1895 strip( p ); /* strip off operations with no side effects */
55f818e1 1896 canon( p ); /* expands r-vals for fields */
f2b49199 1897 walkf( p, hardops ); /* convert ops to function calls */
f2b49199
SL
1898 walkf( p, optim2 );
1899 }