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