utah rcsid 1.4 87/03/20 05:10:31: More work on sconv(). For sign extension
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
CommitLineData
f2b49199 1#ifndef lint
26ab1ae0 2static char sccsid[] = "@(#)local2.c 1.13 (Berkeley) %G%";
f2b49199
SL
3#endif
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
19where(c){
20 fprintf( stderr, "%s, line %d: ", filename, lineno );
21 }
22# endif
23
24lineid( l, fn ) char *fn; {
25 /* identify line l and file fn */
26 printf( "# line %d, file %s\n", l, fn );
27 }
28
29int ent_mask;
30
31eobl2(){
32 register OFFSZ spoff; /* offset from stack pointer */
33#ifndef FORT
34 extern int ftlab1, ftlab2;
35#endif
36
37 spoff = maxoff;
38 spoff /= SZCHAR;
39 SETOFF(spoff,4);
40#ifdef FORT
41#ifndef FLEXNAMES
42 printf( " .set .F%d,%d\n", ftnno, spoff );
43#else
44 /* SHOULD BE L%d ... ftnno but must change pc/f77 */
45 printf( " .set LF%d,%d\n", ftnno, spoff );
46#endif
47 printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
48#else
49 printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
50 printf( "L%d:\n", ftlab1);
51 if( maxoff > AUTOINIT )
52 printf( " subl3 $%d,fp,sp\n", spoff);
53 printf( " jbr L%d\n", ftlab2);
54#endif
55 ent_mask = 0;
56 maxargs = -1;
57 }
58
59struct hoptab { int opmask; char * opstring; } ioptab[] = {
60
61 PLUS, "add",
62 MINUS, "sub",
63 MUL, "mul",
64 DIV, "div",
65 MOD, "div",
66 OR, "or",
67 ER, "xor",
68 AND, "and",
69 -1, "" };
70
71hopcode( f, o ){
72 /* output the appropriate string from the above table */
73
74 register struct hoptab *q;
75
76 if(asgop(o))
77 o = NOASG o;
78 for( q = ioptab; q->opmask>=0; ++q ){
79 if( q->opmask == o ){
80 if(f == 'E')
81 printf( "e%s", q->opstring);
82 else
83 printf( "%s%c", q->opstring, tolower(f));
84 return;
85 }
86 }
87 cerror( "no hoptab for %s", opst[o] );
88 }
89
90char *
91rnames[] = { /* keyed to register number tokens */
92
93 "r0", "r1",
94 "r2", "r3", "r4", "r5",
95 "r6", "r7", "r8", "r9", "r10", "r11",
96 "r12", "fp", "sp", "pc",
97 };
98
99/* output register name and update entry mask */
100char *
101rname(r)
102 register int r;
103{
104
105 ent_mask |= 1<<r;
106 return(rnames[r]);
107}
108
109int rstatus[] = {
110 SAREG|STAREG, SAREG|STAREG,
111 SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
112 SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
113 SAREG, SAREG, SAREG, SAREG,
114 };
115
116tlen(p) NODE *p;
117{
118 switch(p->in.type) {
119 case CHAR:
120 case UCHAR:
121 return(1);
122
123 case SHORT:
124 case USHORT:
125 return(2);
126
127 case DOUBLE:
128 return(8);
129
130 default:
131 return(4);
132 }
133}
134
f1824a4b
SL
135anyfloat(p, q)
136 NODE *p, *q;
137{
138 register TWORD tp, tq;
139
140 tp = p->in.type;
141 tq = q->in.type;
142 return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
143}
144
f2b49199
SL
145prtype(n) NODE *n;
146{
147 switch (n->in.type)
148 {
149
150 case DOUBLE:
895241c8 151 putchar('d');
f2b49199
SL
152 return;
153
154 case FLOAT:
895241c8 155 putchar('f');
f2b49199
SL
156 return;
157
158 case INT:
159 case UNSIGNED:
895241c8 160 putchar('l');
f2b49199
SL
161 return;
162
163 case SHORT:
164 case USHORT:
895241c8 165 putchar('w');
f2b49199
SL
166 return;
167
168 case CHAR:
169 case UCHAR:
895241c8 170 putchar('b');
f2b49199
SL
171 return;
172
173 default:
174 if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
175 else {
895241c8 176 putchar('l');
f2b49199
SL
177 return;
178 }
179 }
180}
181
182zzzcode( p, c ) register NODE *p; {
183 register int m;
184 int val;
185 switch( c ){
186
187 case 'N': /* logical ops, turned into 0-1 */
188 /* use register given by register 1 */
189 cbgen( 0, m=getlab(), 'I' );
190 deflab( p->bn.label );
191 printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) );
192 deflab( m );
193 return;
194
195 case 'P':
196 cbgen( p->in.op, p->bn.label, c );
197 return;
198
199 case 'A': /* assignment and load (integer only) */
200 {
201 register NODE *l, *r;
202
203 if (xdebug) eprint(p, 0, &val, &val);
204 r = getlr(p, 'R');
205 if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) {
206 l = resc;
207 l->in.type = INT;
208 } else
209 l = getlr(p, 'L');
210 if(r->in.type==FLOAT || r->in.type==DOUBLE
211 || l->in.type==FLOAT || l->in.type==DOUBLE)
212 cerror("float in ZA");
213 if (r->in.op == ICON)
214 if(r->in.name[0] == '\0') {
215 if (r->tn.lval == 0) {
895241c8 216 putstr("clr");
f2b49199 217 prtype(l);
895241c8 218 putchar('\t');
f2b49199
SL
219 adrput(l);
220 return;
221 }
222 if (r->tn.lval < 0 && r->tn.lval >= -63) {
895241c8 223 putstr("mneg");
f2b49199
SL
224 prtype(l);
225 r->tn.lval = -r->tn.lval;
226 goto ops;
227 }
228#ifdef MOVAFASTER
229 } else {
895241c8 230 putstr("movab\t");
f2b49199 231 acon(r);
895241c8 232 putchar(',');
f2b49199
SL
233 adrput(l);
234 return;
235#endif MOVAFASTER
236 }
237
238 if (l->in.op == REG) {
239 if( tlen(l) < tlen(r) ) {
895241c8
SL
240 putstr(!ISUNSIGNED(l->in.type)?
241 "cvt": "movz");
f2b49199 242 prtype(l);
895241c8 243 putchar('l');
f2b49199
SL
244 goto ops;
245 } else
246 l->in.type = INT;
247 }
248 if (tlen(l) == tlen(r)) {
895241c8 249 putstr("mov");
f2b49199
SL
250 prtype(l);
251 goto ops;
252 } else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type))
895241c8 253 putstr("movz");
f2b49199 254 else
895241c8 255 putstr("cvt");
f2b49199
SL
256 prtype(r);
257 prtype(l);
258 ops:
895241c8 259 putchar('\t');
f2b49199 260 adrput(r);
895241c8 261 putchar(',');
f2b49199
SL
262 adrput(l);
263 return;
264 }
265
266 case 'B': /* get oreg value in temp register for shift */
267 {
268 register NODE *r;
269 if (xdebug) eprint(p, 0, &val, &val);
270 r = p->in.right;
271 if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
895241c8 272 putstr("movl");
f2b49199 273 else {
895241c8 274 putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
f2b49199 275 prtype(r);
895241c8 276 putchar('l');
f2b49199
SL
277 }
278 return;
279 }
280
281 case 'C': /* num bytes pushed on arg stack */
282 {
283 extern int gc_numbytes;
284 extern int xdebug;
285
286 if (xdebug) printf("->%d<-",gc_numbytes);
287
288 printf("call%c $%d",
289 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
290 gc_numbytes+4);
291 /* dont change to double (here's the only place to catch it) */
292 if(p->in.type == FLOAT)
293 rtyflg = 1;
294 return;
295 }
296
297 case 'D': /* INCR and DECR */
298 zzzcode(p->in.left, 'A');
895241c8 299 putstr("\n ");
f2b49199
SL
300
301 case 'E': /* INCR and DECR, FOREFF */
302 if (p->in.right->tn.lval == 1)
303 {
895241c8 304 putstr(p->in.op == INCR ? "inc" : "dec");
f2b49199 305 prtype(p->in.left);
895241c8 306 putchar('\t');
f2b49199
SL
307 adrput(p->in.left);
308 return;
309 }
895241c8 310 putstr(p->in.op == INCR ? "add" : "sub");
f2b49199 311 prtype(p->in.left);
895241c8 312 putstr("2 ");
f2b49199 313 adrput(p->in.right);
895241c8 314 putchar(',');
f2b49199
SL
315 adrput(p->in.left);
316 return;
317
318 case 'F': /* masked constant for fields */
7412b41b 319 printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
f2b49199
SL
320 return;
321
322 case 'H': /* opcode for shift */
323 if(p->in.op == LS || p->in.op == ASG LS)
895241c8 324 putstr("shll");
f2b49199 325 else if(ISUNSIGNED(p->in.left->in.type))
895241c8 326 putstr("shrl");
f2b49199 327 else
895241c8 328 putstr("shar");
f2b49199
SL
329 return;
330
331 case 'L': /* type of left operand */
332 case 'R': /* type of right operand */
333 {
334 register NODE *n;
335 extern int xdebug;
336
337 n = getlr ( p, c);
338 if (xdebug) printf("->%d<-", n->in.type);
339
340 prtype(n);
341 return;
342 }
343
f1824a4b 344 case 'M': { /* initiate ediv for mod and unsigned div */
f2b49199
SL
345 register char *r;
346 m = getlr(p, '1')->tn.rval;
347 r = rname(m);
348 printf("\tclrl\t%s\n\tmovl\t", r);
349 adrput(p->in.left);
350 printf(",%s\n", rname(m+1));
351 if(!ISUNSIGNED(p->in.type)) { /* should be MOD */
352 m = getlab();
353 printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
354 deflab(m);
355 }
f2b49199 356 return;
f1824a4b 357 }
f2b49199 358
f1824a4b
SL
359 case 'T': { /* rounded structure length for arguments */
360 int size = p->stn.stsize;
f2b49199
SL
361 SETOFF( size, 4);
362 printf("movab -%d(sp),sp", size);
363 return;
f1824a4b 364 }
f2b49199
SL
365
366 case 'S': /* structure assignment */
1d43595d
SL
367 stasg(p);
368 break;
f2b49199 369
73fe5b3f
SL
370 case 'X': /* multiplication for short and char */
371 if (ISUNSIGNED(p->in.left->in.type))
372 printf("\tmovz");
373 else
374 printf("\tcvt");
375 zzzcode(p, 'L');
376 printf("l\t");
377 adrput(p->in.left);
378 printf(",");
379 adrput(&resc[0]);
380 printf("\n");
381 if (ISUNSIGNED(p->in.right->in.type))
382 printf("\tmovz");
383 else
384 printf("\tcvt");
385 zzzcode(p, 'R');
386 printf("l\t");
387 adrput(p->in.right);
388 printf(",");
389 adrput(&resc[1]);
390 printf("\n");
391 return;
392
f1824a4b
SL
393 case 'U': /* SCONV */
394 case 'V': /* SCONV with FORCC */
395 sconv(p, c == 'V');
396 break;
397
398 case 'Z':
399 p = p->in.right;
400 switch (p->in.type) {
401 case SHORT: {
402 short w = p->tn.lval;
403 p->tn.lval = w;
404 break;
405 }
406 case CHAR: {
407 char c = p->tn.lval;
408 p->tn.lval = c;
409 break;
410 }
411 }
412 printf("$%d", p->tn.lval);
413 break;
414
1d43595d
SL
415 default:
416 cerror( "illegal zzzcode" );
1d43595d 417 }
f1824a4b 418}
f2b49199 419
1d43595d 420#define MOVB(dst, src, off) { \
895241c8 421 putstr("\tmovb\t"); upput(src, off); putchar(','); \
1d43595d
SL
422 upput(dst, off); putchar('\n'); \
423}
424#define MOVW(dst, src, off) { \
895241c8 425 putstr("\tmovw\t"); upput(src, off); putchar(','); \
1d43595d
SL
426 upput(dst, off); putchar('\n'); \
427}
428#define MOVL(dst, src, off) { \
895241c8 429 putstr("\tmovl\t"); upput(src, off); putchar(','); \
1d43595d
SL
430 upput(dst, off); putchar('\n'); \
431}
432/*
433 * Generate code for a structure assignment.
434 */
435stasg(p)
436 register NODE *p;
437{
438 register NODE *l, *r;
439 register int size;
440
441 switch (p->in.op) {
442 case STASG: /* regular assignment */
443 l = p->in.left;
444 r = p->in.right;
445 break;
446 case STARG: /* place arg on the stack */
447 l = getlr(p, '3');
448 r = p->in.left;
449 break;
450 default:
451 cerror("STASG bad");
452 /*NOTREACHED*/
453 }
454 /*
455 * Pun source for use in code generation.
456 */
457 switch (r->in.op) {
458 case ICON:
459 r->in.op = NAME;
460 break;
461 case REG:
462 r->in.op = OREG;
463 break;
464 default:
465 cerror( "STASG-r" );
466 /*NOTREACHED*/
467 }
468 size = p->stn.stsize;
469 if (size <= 0 || size > 65535)
470 cerror("structure size out of range");
471 /*
472 * Generate optimized code based on structure size
473 * and alignment properties....
474 */
475 switch (size) {
476
477 case 1:
895241c8 478 putstr("\tmovb\t");
1d43595d
SL
479 optimized:
480 adrput(r);
895241c8 481 putchar(',');
1d43595d 482 adrput(l);
895241c8 483 putchar('\n');
1d43595d
SL
484 break;
485
486 case 2:
487 if (p->stn.stalign != 2) {
488 MOVB(l, r, SZCHAR);
895241c8 489 putstr("\tmovb\t");
1d43595d 490 } else
895241c8 491 putstr("\tmovw\t");
1d43595d
SL
492 goto optimized;
493
494 case 4:
495 if (p->stn.stalign != 4) {
496 if (p->stn.stalign != 2) {
497 MOVB(l, r, 3*SZCHAR);
498 MOVB(l, r, 2*SZCHAR);
499 MOVB(l, r, 1*SZCHAR);
895241c8 500 putstr("\tmovb\t");
1d43595d
SL
501 } else {
502 MOVW(l, r, SZSHORT);
895241c8 503 putstr("\tmovw\t");
f2b49199 504 }
1d43595d 505 } else
895241c8 506 putstr("\tmovl\t");
1d43595d
SL
507 goto optimized;
508
509 case 6:
510 if (p->stn.stalign != 2)
511 goto movblk;
512 MOVW(l, r, 2*SZSHORT);
513 MOVW(l, r, 1*SZSHORT);
895241c8 514 putstr("\tmovw\t");
1d43595d
SL
515 goto optimized;
516
517 case 8:
518 if (p->stn.stalign == 4) {
519 MOVL(l, r, SZLONG);
895241c8 520 putstr("\tmovl\t");
1d43595d
SL
521 goto optimized;
522 }
523 /* fall thru...*/
f2b49199 524
1d43595d
SL
525 default:
526 movblk:
527 /*
528 * Can we ever get a register conflict with R1 here?
529 */
895241c8 530 putstr("\tmovab\t");
1d43595d 531 adrput(l);
895241c8 532 putstr(",r1\n\tmovab\t");
1d43595d
SL
533 adrput(r);
534 printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
535 rname(R2);
f2b49199 536 break;
1d43595d
SL
537 }
538 /*
539 * Reverse above pun for reclaim.
540 */
541 if (r->in.op == NAME)
542 r->in.op = ICON;
543 else if (r->in.op == OREG)
544 r->in.op = REG;
545}
f2b49199 546
1d43595d
SL
547/*
548 * Output the address of the second item in the
549 * pair pointed to by p.
550 */
551upput(p, size)
552 register NODE *p;
553{
554 CONSZ save;
555
556 if (p->in.op == FLD)
557 p = p->in.left;
558 switch (p->in.op) {
559
560 case NAME:
561 case OREG:
562 save = p->tn.lval;
563 p->tn.lval += size/SZCHAR;
564 adrput(p);
565 p->tn.lval = save;
566 break;
567
568 case REG:
569 if (size == SZLONG) {
895241c8 570 putstr(rname(p->tn.rval+1));
1d43595d 571 break;
f2b49199 572 }
1d43595d
SL
573 /* fall thru... */
574
575 default:
576 cerror("illegal upper address op %s size %d",
577 opst[p->tn.op], size);
578 /*NOTREACHED*/
f2b49199 579 }
1d43595d 580}
f2b49199 581
26ab1ae0
DS
582/*
583 * Prlen() is a cheap prtype()...
584 */
585static char convtab[SZINT/SZCHAR + 1] = {
586 '?', 'b', 'w', '?', 'l'
587};
588#define prlen(len) putchar(convtab[len])
589
590
52b983f1
DS
591/*
592 * Generate code for integral scalar conversions.
26ab1ae0
DS
593 * Some of this code is designed to work around a tahoe misfeature
594 * that causes sign- and zero- extension to be defeated in
595 * certain circumstances.
596 * Basically if the source operand of a CVT or MOVZ instruction is
597 * shorter than the destination, and the source is a register
598 * or an immediate constant, sign- and zero- extension are
599 * ignored and the high bits of the source are copied. (Note
600 * that zero-extension is not a problem for immediate
601 * constants.)
52b983f1
DS
602 */
603sconv(p, forcc)
604 NODE *p;
605 int forcc;
606{
607 register NODE *src, *dst;
608 register NODE *tmp;
609 register int srclen, dstlen;
610 int srctype, dsttype;
611 int val;
612
613 if (p->in.op == ASSIGN) {
614 src = getlr(p, 'R');
615 dst = getlr(p, 'L');
616 dstlen = tlen(dst);
617 dsttype = dst->in.type;
618 } else /* if (p->in.op == SCONV || optype(p->in.op) == LTYPE) */ {
619 src = getlr(p, 'L');
620 dst = getlr(p, '1');
621 dstlen = tlen(p);
622 dsttype = p->in.type;
623 }
624
26ab1ae0
DS
625 if (src->in.op == REG) {
626 srclen = SZINT/SZCHAR;
627 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
628 } else {
629 srclen = tlen(src);
630 srctype = src->in.type;
631 }
632
633 if (src->in.op == ICON) {
634 if (src->tn.lval == 0) {
635 putstr("clr");
636 prtype(dst);
637 putchar('\t');
638 adrput(dst);
639 return;
640 }
641 if (dstlen < srclen) {
642 switch (dsttype) {
643 case CHAR:
644 src->tn.lval = (char) src->tn.lval;
645 break;
646 case UCHAR:
647 src->tn.lval = (unsigned char) src->tn.lval;
648 break;
649 case SHORT:
650 src->tn.lval = (short) src->tn.lval;
651 break;
652 case USHORT:
653 src->tn.lval = (unsigned short) src->tn.lval;
654 break;
655 }
656 }
657 if (dst->in.op == REG) {
658 dsttype = INT;
659 dstlen = SZINT/SZCHAR;
660 }
661 srctype = dsttype;
662 srclen = dstlen;
663 }
52b983f1
DS
664
665 if (srclen < dstlen) {
666 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
667 /* (unsigned short) c; => sign extend to 16 bits */
c3446016 668 putstr("cvtbl\t");
52b983f1
DS
669 adrput(src);
670 putstr(",-(sp)\n\tmovzwl\t2(sp),");
671 adrput(dst);
672 putstr("\n\tmovab\t4(sp),sp");
673 if (forcc) {
674 /* inverted test */
675 putstr("\n\tcmpl\t$0,");
676 adrput(dst);
677 }
678 return;
679 }
680 genconv(ISUNSIGNED(srctype),
681 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
682 src, dst);
683 return;
684 }
685
686 if (srclen > dstlen && dst->in.op == REG) {
26ab1ae0 687 /* if dst is a register, the result must look like an int */
52b983f1
DS
688 if (src->in.op == REG) {
689 if (ISUNSIGNED(dsttype)) {
690 val = (1 << dstlen * SZCHAR) - 1;
691 if (src->tn.rval == dst->tn.rval)
692 /* conversion in place */
c3446016 693 printf("andl2\t$%#x,", val);
52b983f1 694 else {
c3446016 695 printf("andl3\t$%#x,", val);
52b983f1
DS
696 adrput(src);
697 putchar(',');
698 }
699 adrput(dst);
700 return;
701 }
26ab1ae0
DS
702 /*
703 * Sign extension in register can also be
704 * accomplished by shifts, but unfortunately
705 * shifts are extremely slow, due to the lack
706 * of a barrel shifter.
707 */
708 putstr("pushl\t");
52b983f1 709 adrput(src);
26ab1ae0
DS
710 putstr("\n\tcvt");
711 prlen(dstlen);
712 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
52b983f1 713 adrput(dst);
26ab1ae0
DS
714 putstr("\n\tmovab\t4(sp),sp");
715 if (forcc) {
716 /* inverted test */
717 putstr("\n\tcmpl\t$0,");
718 adrput(dst);
719 }
52b983f1
DS
720 return;
721 }
722 tmp = talloc();
723 if ((src->in.op == UNARY MUL &&
724 ((src->in.left->in.op == NAME ||
725 (src->in.left->in.op == ICON)))) ||
726 (src->in.op == OREG && !R2TEST(src->tn.rval))) {
727 /* we can increment src's address & pun it */
728 *tmp = *src;
729 tmp->tn.lval += srclen - dstlen;
730 } else {
731 /* we must store src's address */
732 *tmp = *dst;
26ab1ae0
DS
733 putstr("mova");
734 prlen(srclen);
735 putchar('\t');
52b983f1
DS
736 adrput(src);
737 putchar(',');
738 adrput(tmp);
c3446016 739 putstr("\n\t");
52b983f1
DS
740 tmp->tn.op = OREG;
741 tmp->tn.lval = srclen - dstlen;
742 }
743 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
744 tmp->in.op = FREE;
745 return;
746 }
747
748 genconv(ISUNSIGNED(dsttype),
749 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
750 src, dst);
751}
752
753genconv(usrc, srclen, dstlen, src, dst)
26ab1ae0
DS
754 int usrc;
755 register int srclen, dstlen;
52b983f1
DS
756 NODE *src, *dst;
757{
52b983f1
DS
758 if (srclen != dstlen) {
759 if (usrc && srclen < dstlen)
c3446016 760 putstr("movz");
52b983f1 761 else
c3446016 762 putstr("cvt");
26ab1ae0 763 prlen(srclen);
52b983f1 764 } else
c3446016 765 putstr("mov");
26ab1ae0 766 prlen(dstlen);
52b983f1
DS
767 putchar('\t');
768 adrput(src);
769 putchar(',');
770 adrput(dst);
771}
f1824a4b 772
f2b49199
SL
773rmove( rt, rs, t ) TWORD t;{
774 printf( " movl %s,%s\n", rname(rs), rname(rt) );
775 if(t==DOUBLE)
776 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
777 }
778
779struct respref
780respref[] = {
781 INTAREG|INTBREG, INTAREG|INTBREG,
782 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
783 INTEMP, INTEMP,
784 FORARG, FORARG,
785 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
786 0, 0 };
787
788setregs(){ /* set up temporary registers */
789 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
790 }
791
ebdd0416 792#ifndef szty
f2b49199
SL
793szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
794 return(t==DOUBLE ? 2 : 1 );
795 }
ebdd0416 796#endif
f2b49199
SL
797
798rewfld( p ) NODE *p; {
799 return(1);
800 }
801
802callreg(p) NODE *p; {
803 return( R0 );
804 }
805
806base( p ) register NODE *p; {
807 register int o = p->in.op;
808
809 if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
810 if( o==REG ) return( p->tn.rval );
811 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
812 return( p->in.left->tn.rval );
813 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
814 return( p->tn.rval + 0200*1 );
815 return( -1 );
816 }
817
818offset( p, tyl ) register NODE *p; int tyl; {
819
820 if(tyl > 8) return( -1 );
821 if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
822 if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
823 (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
824 && (1<<p->in.right->tn.lval)==tyl))
825 return( p->in.left->tn.rval );
826 return( -1 );
827 }
828
829makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
830 register NODE *t;
831 register int i;
832 NODE *f;
833
834 p->in.op = OREG;
835 f = p->in.left; /* have to free this subtree later */
836
837 /* init base */
838 switch (q->in.op) {
839 case ICON:
840 case REG:
841 case OREG:
842 t = q;
843 break;
844
845 case MINUS:
846 q->in.right->tn.lval = -q->in.right->tn.lval;
847 case PLUS:
848 t = q->in.right;
849 break;
850
851 case UNARY MUL:
852 t = q->in.left->in.left;
853 break;
854
855 default:
856 cerror("illegal makeor2");
857 }
858
859 p->tn.lval = t->tn.lval;
860#ifndef FLEXNAMES
861 for(i=0; i<NCHNAM; ++i)
862 p->in.name[i] = t->in.name[i];
863#else
864 p->in.name = t->in.name;
865#endif
866
867 /* init offset */
868 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
869
870 tfree(f);
871 return;
872 }
873
874canaddr( p ) NODE *p; {
875 register int o = p->in.op;
876
877 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
878 return(0);
879 }
880
ebdd0416 881#ifndef shltype
f2b49199
SL
882shltype( o, p ) register NODE *p; {
883 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
884 }
ebdd0416 885#endif
f2b49199
SL
886
887flshape( p ) NODE *p; {
888 register int o = p->in.op;
889
890 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
891 return(0);
892 }
893
894shtemp( p ) register NODE *p; {
895 if( p->in.op == STARG ) p = p->in.left;
896 return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
897 }
898
899shumul( p ) register NODE *p; {
900 register int o;
901 extern int xdebug;
902
903 if (xdebug) {
904 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
905 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
906 }
907
908 o = p->in.op;
909 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
910 && p->in.type != PTR+DOUBLE)
911 return( STARNM );
912
913 return( 0 );
914 }
915
916special( p, shape ) register NODE *p; {
917 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
918 else return(0);
919}
920
921adrcon( val ) CONSZ val; {
7412b41b 922 printf(ACONFMT, val);
f2b49199
SL
923 }
924
925conput( p ) register NODE *p; {
926 switch( p->in.op ){
927
928 case ICON:
929 acon( p );
930 return;
931
932 case REG:
895241c8 933 putstr(rname(p->tn.rval));
f2b49199
SL
934 return;
935
936 default:
937 cerror( "illegal conput" );
938 }
939 }
940
941insput( p ) NODE *p; {
942 cerror( "insput" );
943 }
944
f2b49199
SL
945adrput( p ) register NODE *p; {
946 register int r;
947 /* output an address, with offsets, from p */
948
949 if( p->in.op == FLD ){
950 p = p->in.left;
951 }
952 switch( p->in.op ){
953
954 case NAME:
955 acon( p );
956 return;
957
958 case ICON:
959 /* addressable value of the constant */
895241c8 960 putchar('$');
f2b49199
SL
961 acon( p );
962 return;
963
964 case REG:
895241c8 965 putstr(rname(p->tn.rval));
f2b49199
SL
966 if(p->in.type == DOUBLE) /* for entry mask */
967 (void) rname(p->tn.rval+1);
968 return;
969
970 case OREG:
971 r = p->tn.rval;
972 if( R2TEST(r) ){ /* double indexing */
973 register int flags;
974
975 flags = R2UPK3(r);
895241c8 976 if( flags & 1 ) putchar('*');
f2b49199
SL
977 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
978 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
979 printf( "[%s]", rname(R2UPK2(r)) );
980 return;
981 }
982 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
983 if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
984 printf( CONFMT, p->tn.lval );
895241c8 985 putstr( "(fp)" );
f2b49199
SL
986 return;
987 }
988 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
989 printf( "(%s)", rname(p->tn.rval) );
990 return;
991
992 case UNARY MUL:
993 /* STARNM or STARREG found */
994 if( tshape(p, STARNM) ) {
895241c8 995 putchar( '*' );
f2b49199
SL
996 adrput( p->in.left);
997 }
998 return;
999
1000 default:
1001 cerror( "illegal address" );
1002 return;
1003
1004 }
1005
1006 }
1007
1008acon( p ) register NODE *p; { /* print out a constant */
1009
1010 if( p->in.name[0] == '\0' ){
1011 printf( CONFMT, p->tn.lval);
895241c8
SL
1012 return;
1013 } else {
f2b49199
SL
1014#ifndef FLEXNAMES
1015 printf( "%.8s", p->in.name );
1016#else
895241c8 1017 putstr(p->in.name);
f2b49199 1018#endif
895241c8
SL
1019 if (p->tn.lval != 0) {
1020 putchar('+');
1021 printf(CONFMT, p->tn.lval);
f2b49199 1022 }
895241c8 1023 }
f2b49199
SL
1024 }
1025
1026genscall( p, cookie ) register NODE *p; {
1027 /* structure valued call */
1028 return( gencall( p, cookie ) );
1029 }
1030
1031genfcall( p, cookie ) register NODE *p; {
1032 register NODE *p1;
1033 register int m;
1034 static char *funcops[6] = {
1035 "sin", "cos", "sqrt", "exp", "log", "atan"
1036 };
1037
1038 /* generate function opcodes */
1039 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1040 (p1 = p->in.left)->in.op==ICON &&
1041 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1042#ifdef FLEXNAMES
1043 p1->in.name++;
1044#else
1045 strcpy(p1->in.name, p1->in.name[1]);
1046#endif
1047 for(m=0; m<6; m++)
1048 if(!strcmp(p1->in.name, funcops[m]))
1049 break;
1050 if(m >= 6)
1051 uerror("no opcode for fortarn function %s", p1->in.name);
1052 } else
1053 uerror("illegal type of fortarn function");
1054 p1 = p->in.right;
1055 p->in.op = FORTCALL;
1056 if(!canaddr(p1))
1057 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1058 m = match( p, INTAREG|INTBREG );
1059 return(m != MDONE);
1060}
1061
1062/* tbl */
1063int gc_numbytes;
1064/* tbl */
1065
1066gencall( p, cookie ) register NODE *p; {
1067 /* generate the call given by p */
1068 register NODE *p1, *ptemp;
1069 register int temp, temp1;
1070 register int m;
1071
1072 if( p->in.right ) temp = argsize( p->in.right );
1073 else temp = 0;
1074
1075 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1076 /* set aside room for structure return */
1077
1078 if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1079 else temp1 = temp;
1080 }
1081
1082 if( temp > maxargs ) maxargs = temp;
1083 SETOFF(temp1,4);
1084
1085 if( p->in.right ){ /* make temp node, put offset in, and generate args */
1086 ptemp = talloc();
1087 ptemp->in.op = OREG;
1088 ptemp->tn.lval = -1;
1089 ptemp->tn.rval = SP;
1090#ifndef FLEXNAMES
1091 ptemp->in.name[0] = '\0';
1092#else
1093 ptemp->in.name = "";
1094#endif
1095 ptemp->in.rall = NOPREF;
1096 ptemp->in.su = 0;
1097 genargs( p->in.right, ptemp );
1098 ptemp->in.op = FREE;
1099 }
1100
1101 p1 = p->in.left;
1102 if( p1->in.op != ICON ){
1103 if( p1->in.op != REG ){
1104 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1105 if( p1->in.op != NAME ){
1106 order( p1, INAREG );
1107 }
1108 }
1109 }
1110 }
1111
1112/* tbl
1113 setup gc_numbytes so reference to ZC works */
1114
1115 gc_numbytes = temp&(0x3ff);
1116
1117 p->in.op = UNARY CALL;
1118 m = match( p, INTAREG|INTBREG );
1119
1120 return(m != MDONE);
1121 }
1122
1123/* tbl */
1124char *
1125ccbranches[] = {
1126 "eql",
1127 "neq",
1128 "leq",
1129 "lss",
1130 "geq",
1131 "gtr",
1132 "lequ",
1133 "lssu",
1134 "gequ",
1135 "gtru",
1136 };
1137/* tbl */
1138
1139cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
1140
1141 if(o != 0 && (o < EQ || o > UGT ))
1142 cerror( "bad conditional branch: %s", opst[o] );
1143 printf( " j%s L%d\n",
1144 o == 0 ? "br" : ccbranches[o-EQ], lab );
1145 }
1146
1147nextcook( p, cookie ) NODE *p; {
1148 /* we have failed to match p with cookie; try another */
1149 if( cookie == FORREW ) return( 0 ); /* hopeless! */
1150 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1151 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1152 return( FORREW );
1153 }
1154
1155lastchance( p, cook ) NODE *p; {
1156 /* forget it! */
1157 return(0);
1158 }
1159
1160optim2( p ) register NODE *p; {
1161# ifdef ONEPASS
1162 /* do local tree transformations and optimizations */
1163# define RV(p) p->in.right->tn.lval
ebdd0416 1164# define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0)
f1824a4b
SL
1165 register int o, i;
1166 register NODE *l, *r;
f2b49199 1167
f1824a4b
SL
1168 switch (o = p->in.op) {
1169
1170 case DIV: case ASG DIV:
1171 case MOD: case ASG MOD:
1172 /*
1173 * Change unsigned mods and divs to
1174 * logicals (mul is done in mip & c2)
1175 */
1176 if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1177 (i = ispow2(RV(p))) >= 0) {
1178 if (o == DIV || o == ASG DIV) {
1179 p->in.op = RS;
1180 RV(p) = i;
1181 } else {
1182 p->in.op = AND;
1183 RV(p)--;
1184 }
1185 if (asgop(o))
1186 p->in.op = ASG p->in.op;
1187 }
1188 return;
1189
1190 case SCONV:
1191 l = p->in.left;
1192 /* clobber conversions w/o side effects */
1193 if (!anyfloat(p, l) && l->in.op != PCONV &&
1194 tlen(p) == tlen(l)) {
1195 if (l->in.op != FLD)
1196 l->in.type = p->in.type;
1197 ncopy(p, l);
1198 l->in.op = FREE;
1199 }
1200 return;
1201
1202 case ASSIGN:
1203 /*
1204 * Try to zap storage conversions of non-float items.
1205 */
1206 r = p->in.right;
1207 if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
1208 int wdest, wconv, wsrc;
1209 wdest = tlen(p->in.left);
1210 wconv = tlen(r);
1211 /*
1212 * If size doesn't change across assignment or
1213 * conversion expands src before shrinking again
1214 * due to the assignment, delete conversion so
1215 * code generator can create optimal code.
1216 */
1217 if (wdest == wconv ||
1218 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1219 p->in.right = r->in.left;
1220 r->in.op = FREE;
1221 }
f2b49199 1222 }
f1824a4b 1223 return;
f2b49199
SL
1224 }
1225# endif
1226}
1227
1228struct functbl {
1229 int fop;
1230 char *func;
1231} opfunc[] = {
1232 DIV, "udiv",
1233 ASG DIV, "udiv",
1234 0
1235};
1236
1237hardops(p) register NODE *p; {
1238 /* change hard to do operators into function calls. */
1239 register NODE *q;
1240 register struct functbl *f;
1241 register int o;
1242 register TWORD t, t1, t2;
1243
1244 o = p->in.op;
1245
1246 for( f=opfunc; f->fop; f++ ) {
1247 if( o==f->fop ) goto convert;
1248 }
1249 return;
1250
1251 convert:
1252 t = p->in.type;
1253 t1 = p->in.left->in.type;
1254 t2 = p->in.right->in.type;
73fe5b3f
SL
1255
1256 if (!((ISUNSIGNED(t1) && !(ISUNSIGNED(t2))) ||
1257 ( t2 == UNSIGNED))) return;
f2b49199
SL
1258
1259 /* need to rewrite tree for ASG OP */
1260 /* must change ASG OP to a simple OP */
1261 if( asgop( o ) ) {
1262 q = talloc();
1263 q->in.op = NOASG ( o );
1264 q->in.rall = NOPREF;
1265 q->in.type = p->in.type;
1266 q->in.left = tcopy(p->in.left);
1267 q->in.right = p->in.right;
1268 p->in.op = ASSIGN;
1269 p->in.right = q;
1270 zappost(q->in.left); /* remove post-INCR(DECR) from new node */
1271 fixpre(q->in.left); /* change pre-INCR(DECR) to +/- */
1272 p = q;
1273
1274 }
1275 /* turn logicals to compare 0 */
1276 else if( logop( o ) ) {
1277 ncopy(q = talloc(), p);
1278 p->in.left = q;
1279 p->in.right = q = talloc();
1280 q->in.op = ICON;
1281 q->in.type = INT;
1282#ifndef FLEXNAMES
1283 q->in.name[0] = '\0';
1284#else
1285 q->in.name = "";
1286#endif
1287 q->tn.lval = 0;
1288 q->tn.rval = 0;
1289 p = p->in.left;
1290 }
1291
1292 /* build comma op for args to function */
1293 t1 = p->in.left->in.type;
1294 t2 = 0;
1295 if ( optype(p->in.op) == BITYPE) {
1296 q = talloc();
1297 q->in.op = CM;
1298 q->in.rall = NOPREF;
1299 q->in.type = INT;
1300 q->in.left = p->in.left;
1301 q->in.right = p->in.right;
1302 t2 = p->in.right->in.type;
1303 } else
1304 q = p->in.left;
1305
1306 p->in.op = CALL;
1307 p->in.right = q;
1308
1309 /* put function name in left node of call */
1310 p->in.left = q = talloc();
1311 q->in.op = ICON;
1312 q->in.rall = NOPREF;
1313 q->in.type = INCREF( FTN + p->in.type );
1314#ifndef FLEXNAMES
1315 strcpy( q->in.name, f->func );
1316#else
1317 q->in.name = f->func;
1318#endif
1319 q->tn.lval = 0;
1320 q->tn.rval = 0;
1321
1322 }
1323
1324zappost(p) NODE *p; {
1325 /* look for ++ and -- operators and remove them */
1326
1327 register int o, ty;
1328 register NODE *q;
1329 o = p->in.op;
1330 ty = optype( o );
1331
1332 switch( o ){
1333
1334 case INCR:
1335 case DECR:
1336 q = p->in.left;
1337 p->in.right->in.op = FREE; /* zap constant */
1338 ncopy( p, q );
1339 q->in.op = FREE;
1340 return;
1341
1342 }
1343
1344 if( ty == BITYPE ) zappost( p->in.right );
1345 if( ty != LTYPE ) zappost( p->in.left );
1346}
1347
1348fixpre(p) NODE *p; {
1349
1350 register int o, ty;
1351 o = p->in.op;
1352 ty = optype( o );
1353
1354 switch( o ){
1355
1356 case ASG PLUS:
1357 p->in.op = PLUS;
1358 break;
1359 case ASG MINUS:
1360 p->in.op = MINUS;
1361 break;
1362 }
1363
1364 if( ty == BITYPE ) fixpre( p->in.right );
1365 if( ty != LTYPE ) fixpre( p->in.left );
1366}
1367
1368NODE * addroreg(l) NODE *l;
1369 /* OREG was built in clocal()
1370 * for an auto or formal parameter
1371 * now its address is being taken
1372 * local code must unwind it
1373 * back to PLUS/MINUS REG ICON
1374 * according to local conventions
1375 */
1376{
1377 cerror("address of OREG taken");
1378}
1379
1380# ifndef ONEPASS
1381main( argc, argv ) char *argv[]; {
1382 return( mainp2( argc, argv ) );
1383 }
1384# endif
1385
f1824a4b
SL
1386strip(p) register NODE *p; {
1387 NODE *q;
1388
1389 /* strip nodes off the top when no side effects occur */
1390 for( ; ; ) {
1391 switch( p->in.op ) {
1392 case SCONV: /* remove lint tidbits */
1393 q = p->in.left;
1394 ncopy( p, q );
1395 q->in.op = FREE;
1396 break;
1397 /* could probably add a few more here */
1398 default:
1399 return;
1400 }
1401 }
1402 }
1403
f2b49199 1404myreader(p) register NODE *p; {
f1824a4b 1405 strip( p ); /* strip off operations with no side effects */
f2b49199
SL
1406 walkf( p, hardops ); /* convert ops to function calls */
1407 canon( p ); /* expands r-vals for fileds */
1408 walkf( p, optim2 );
1409 }