Finish installing vax fix for float/double increments.
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
CommitLineData
ac77a290 1#ifndef lint
57be5b96 2static char sccsid[] = "@(#)local2.c 1.30 (Berkeley) %G%";
ac77a290 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.)
baaad82c
DS
750 * Another problem -- condition codes for a conversion with a
751 * register source reflect the source rather than the destination.
52b983f1
DS
752 */
753sconv(p, forcc)
754 NODE *p;
755 int forcc;
756{
757 register NODE *src, *dst;
758 register NODE *tmp;
759 register int srclen, dstlen;
760 int srctype, dsttype;
761 int val;
a1eb6a2f 762 int neg = 0;
52b983f1
DS
763
764 if (p->in.op == ASSIGN) {
7999919c
DS
765 src = p->in.right;
766 dst = p->in.left;
52b983f1
DS
767 dstlen = tlen(dst);
768 dsttype = dst->in.type;
7999919c
DS
769 } else if (p->in.op == SCONV) {
770 src = p->in.left;
771 dst = resc;
52b983f1
DS
772 dstlen = tlen(p);
773 dsttype = p->in.type;
7999919c
DS
774 } else /* if (p->in.op == OPLEAF) */ {
775 src = p;
776 dst = resc;
777 dstlen = SZINT/SZCHAR;
778 dsttype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
52b983f1
DS
779 }
780
26ab1ae0
DS
781 if (src->in.op == REG) {
782 srclen = SZINT/SZCHAR;
783 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
784 } else {
785 srclen = tlen(src);
786 srctype = src->in.type;
787 }
788
a1eb6a2f 789 if (src->in.op == ICON && src->tn.name[0] == '\0') {
26ab1ae0
DS
790 if (src->tn.lval == 0) {
791 putstr("clr");
792 prtype(dst);
793 putchar('\t');
794 adrput(dst);
795 return;
796 }
797 if (dstlen < srclen) {
798 switch (dsttype) {
799 case CHAR:
800 src->tn.lval = (char) src->tn.lval;
801 break;
802 case UCHAR:
803 src->tn.lval = (unsigned char) src->tn.lval;
804 break;
805 case SHORT:
806 src->tn.lval = (short) src->tn.lval;
807 break;
808 case USHORT:
809 src->tn.lval = (unsigned short) src->tn.lval;
810 break;
811 }
812 }
813 if (dst->in.op == REG) {
814 dsttype = INT;
815 dstlen = SZINT/SZCHAR;
816 }
817 srctype = dsttype;
818 srclen = dstlen;
c45469ab
DS
819 val = -src->tn.lval & ((1 << dstlen * SZCHAR) - 1);
820 if ((unsigned) val < 64) {
821 src->tn.lval = val;
a1eb6a2f
DS
822 ++neg; /* MNEGx may be shorter */
823 }
26ab1ae0 824 }
52b983f1
DS
825
826 if (srclen < dstlen) {
827 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
828 /* (unsigned short) c; => sign extend to 16 bits */
c3446016 829 putstr("cvtbl\t");
52b983f1
DS
830 adrput(src);
831 putstr(",-(sp)\n\tmovzwl\t2(sp),");
832 adrput(dst);
833 putstr("\n\tmovab\t4(sp),sp");
834 if (forcc) {
835 /* inverted test */
836 putstr("\n\tcmpl\t$0,");
837 adrput(dst);
838 }
839 return;
840 }
841 genconv(ISUNSIGNED(srctype),
842 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
baaad82c 843 src, dst, forcc);
52b983f1
DS
844 return;
845 }
846
847 if (srclen > dstlen && dst->in.op == REG) {
26ab1ae0 848 /* if dst is a register, the result must look like an int */
52b983f1
DS
849 if (src->in.op == REG) {
850 if (ISUNSIGNED(dsttype)) {
851 val = (1 << dstlen * SZCHAR) - 1;
852 if (src->tn.rval == dst->tn.rval)
853 /* conversion in place */
c45469ab 854 printf("andl2\t$%ld,", val);
52b983f1 855 else {
c45469ab 856 printf("andl3\t$%ld,", val);
52b983f1
DS
857 adrput(src);
858 putchar(',');
859 }
860 adrput(dst);
861 return;
862 }
26ab1ae0
DS
863 /*
864 * Sign extension in register can also be
865 * accomplished by shifts, but unfortunately
866 * shifts are extremely slow, due to the lack
867 * of a barrel shifter.
868 */
869 putstr("pushl\t");
52b983f1 870 adrput(src);
26ab1ae0
DS
871 putstr("\n\tcvt");
872 prlen(dstlen);
873 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
52b983f1 874 adrput(dst);
26ab1ae0
DS
875 putstr("\n\tmovab\t4(sp),sp");
876 if (forcc) {
877 /* inverted test */
878 putstr("\n\tcmpl\t$0,");
879 adrput(dst);
880 }
52b983f1
DS
881 return;
882 }
883 tmp = talloc();
c45469ab
DS
884 if ((src->in.op == NAME) ||
885 (src->in.op == UNARY MUL && src->in.left->in.op == ICON) ||
52b983f1
DS
886 (src->in.op == OREG && !R2TEST(src->tn.rval))) {
887 /* we can increment src's address & pun it */
888 *tmp = *src;
889 tmp->tn.lval += srclen - dstlen;
890 } else {
891 /* we must store src's address */
892 *tmp = *dst;
26ab1ae0
DS
893 putstr("mova");
894 prlen(srclen);
895 putchar('\t');
52b983f1
DS
896 adrput(src);
897 putchar(',');
898 adrput(tmp);
c3446016 899 putstr("\n\t");
52b983f1
DS
900 tmp->tn.op = OREG;
901 tmp->tn.lval = srclen - dstlen;
902 }
baaad82c 903 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst, forcc);
52b983f1
DS
904 tmp->in.op = FREE;
905 return;
906 }
907
a1eb6a2f 908 genconv(neg ? -1 : ISUNSIGNED(dsttype),
52b983f1 909 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
baaad82c 910 src, dst, forcc);
52b983f1
DS
911}
912
baaad82c 913genconv(srcflag, srclen, dstlen, src, dst, forcc)
a1eb6a2f 914 int srcflag;
26ab1ae0 915 register int srclen, dstlen;
52b983f1 916 NODE *src, *dst;
baaad82c 917 int forcc;
52b983f1 918{
52b983f1 919 if (srclen != dstlen) {
a1eb6a2f 920 if (srcflag > 0 && srclen < dstlen)
c3446016 921 putstr("movz");
52b983f1 922 else
c3446016 923 putstr("cvt");
26ab1ae0 924 prlen(srclen);
a1eb6a2f
DS
925 } else if (srcflag < 0)
926 putstr("mneg");
927 else
c3446016 928 putstr("mov");
26ab1ae0 929 prlen(dstlen);
52b983f1
DS
930 putchar('\t');
931 adrput(src);
932 putchar(',');
933 adrput(dst);
baaad82c
DS
934
935 /*
936 * This hack is made necessary by architecture problems
937 * described above
938 */
939 if (forcc && src->in.op == REG && srclen > dstlen) {
940 putstr("\n\ttst");
941 prlen(dstlen);
942 putchar('\t');
943 adrput(dst);
944 }
52b983f1 945}
f1824a4b 946
55f818e1 947rmove( rt, rs, t ) TWORD t; {
f2b49199
SL
948 printf( " movl %s,%s\n", rname(rs), rname(rt) );
949 if(t==DOUBLE)
950 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
951 }
952
953struct respref
954respref[] = {
955 INTAREG|INTBREG, INTAREG|INTBREG,
956 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
957 INTEMP, INTEMP,
958 FORARG, FORARG,
959 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
960 0, 0 };
961
962setregs(){ /* set up temporary registers */
963 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
964 }
965
ebdd0416 966#ifndef szty
f2b49199
SL
967szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
968 return(t==DOUBLE ? 2 : 1 );
969 }
ebdd0416 970#endif
f2b49199 971
55f818e1 972/*ARGSUSED*/
f2b49199
SL
973rewfld( p ) NODE *p; {
974 return(1);
975 }
976
55f818e1 977/*ARGSUSED*/
f2b49199
SL
978callreg(p) NODE *p; {
979 return( R0 );
980 }
981
982base( p ) register NODE *p; {
983 register int o = p->in.op;
984
c45469ab 985 if( o==ICON && p->in.name[0] != '\0' ) return( 100 ); /* ie no base reg */
f2b49199
SL
986 if( o==REG ) return( p->tn.rval );
987 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
988 return( p->in.left->tn.rval );
989 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
990 return( p->tn.rval + 0200*1 );
c45469ab 991 if( o==NAME ) return( 100 + 0200*1 );
f2b49199
SL
992 return( -1 );
993 }
994
995offset( p, tyl ) register NODE *p; int tyl; {
996
55f818e1
DS
997 if( tyl==1 &&
998 p->in.op==REG &&
999 (p->in.type==INT || p->in.type==UNSIGNED) )
1000 return( p->tn.rval );
1001 if( p->in.op==LS &&
1002 p->in.left->in.op==REG &&
1003 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
1004 p->in.right->in.op==ICON &&
1005 p->in.right->in.name[0]=='\0' &&
1006 (1<<p->in.right->tn.lval)==tyl)
1007 return( p->in.left->tn.rval );
1008 if( tyl==2 &&
1009 p->in.op==PLUS &&
1010 (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
1011 p->in.left->in.op==REG &&
1012 p->in.right->in.op==REG &&
1013 p->in.left->tn.rval==p->in.right->tn.rval )
f2b49199
SL
1014 return( p->in.left->tn.rval );
1015 return( -1 );
1016 }
1017
1018makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
1019 register NODE *t;
f2b49199
SL
1020 NODE *f;
1021
1022 p->in.op = OREG;
1023 f = p->in.left; /* have to free this subtree later */
1024
1025 /* init base */
1026 switch (q->in.op) {
1027 case ICON:
1028 case REG:
1029 case OREG:
c45469ab 1030 case NAME:
f2b49199
SL
1031 t = q;
1032 break;
1033
1034 case MINUS:
1035 q->in.right->tn.lval = -q->in.right->tn.lval;
1036 case PLUS:
1037 t = q->in.right;
1038 break;
1039
1040 case UNARY MUL:
1041 t = q->in.left->in.left;
1042 break;
1043
1044 default:
1045 cerror("illegal makeor2");
1046 }
1047
1048 p->tn.lval = t->tn.lval;
1049#ifndef FLEXNAMES
55f818e1
DS
1050 {
1051 register int i;
1052 for(i=0; i<NCHNAM; ++i)
1053 p->in.name[i] = t->in.name[i];
1054 }
f2b49199
SL
1055#else
1056 p->in.name = t->in.name;
1057#endif
1058
1059 /* init offset */
1060 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
1061
1062 tfree(f);
1063 return;
1064 }
1065
1066canaddr( p ) NODE *p; {
1067 register int o = p->in.op;
1068
1069 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1070 return(0);
1071 }
1072
ebdd0416 1073#ifndef shltype
f2b49199
SL
1074shltype( o, p ) register NODE *p; {
1075 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
1076 }
ebdd0416 1077#endif
f2b49199
SL
1078
1079flshape( p ) NODE *p; {
1080 register int o = p->in.op;
1081
1082 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
1083 return(0);
1084 }
1085
55f818e1 1086/* INTEMP shapes must not contain any temporary registers */
f2b49199 1087shtemp( p ) register NODE *p; {
55f818e1
DS
1088 int r;
1089
f2b49199 1090 if( p->in.op == STARG ) p = p->in.left;
55f818e1
DS
1091
1092 switch (p->in.op) {
1093 case REG:
1094 return( !istreg(p->tn.rval) );
1095 case OREG:
1096 r = p->tn.rval;
1097 if( R2TEST(r) ) {
1098 if( istreg(R2UPK1(r)) )
1099 return(0);
1100 r = R2UPK2(r);
1101 }
1102 return( !istreg(r) );
1103 case UNARY MUL:
1104 p = p->in.left;
1105 return( p->in.op != UNARY MUL && shtemp(p) );
1106 }
1107
1108 if( optype( p->in.op ) != LTYPE ) return(0);
1109 return(1);
f2b49199
SL
1110 }
1111
1112shumul( p ) register NODE *p; {
1113 register int o;
1114 extern int xdebug;
1115
1116 if (xdebug) {
1117 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
1118 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
1119 }
1120
1121 o = p->in.op;
1122 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
1123 && p->in.type != PTR+DOUBLE)
1124 return( STARNM );
1125
1126 return( 0 );
1127 }
1128
c45469ab
DS
1129special( p, shape ) register NODE *p; {
1130 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
1131 else return(0);
1132}
1133
f2b49199 1134adrcon( val ) CONSZ val; {
7412b41b 1135 printf(ACONFMT, val);
f2b49199
SL
1136 }
1137
1138conput( p ) register NODE *p; {
1139 switch( p->in.op ){
1140
1141 case ICON:
1142 acon( p );
1143 return;
1144
1145 case REG:
895241c8 1146 putstr(rname(p->tn.rval));
f2b49199
SL
1147 return;
1148
1149 default:
1150 cerror( "illegal conput" );
1151 }
1152 }
1153
55f818e1 1154/*ARGSUSED*/
f2b49199
SL
1155insput( p ) NODE *p; {
1156 cerror( "insput" );
1157 }
1158
55f818e1
DS
1159/*
1160 * Output the address of the second item in the
1161 * pair pointed to by p.
1162 */
1163upput(p, size)
1164 register NODE *p;
1165{
1166 CONSZ save;
1167
1168 if (p->in.op == FLD)
1169 p = p->in.left;
1170 switch (p->in.op) {
1171
1172 case NAME:
1173 case OREG:
1174 save = p->tn.lval;
1175 p->tn.lval += size/SZCHAR;
1176 adrput(p);
1177 p->tn.lval = save;
1178 break;
1179
1180 case REG:
1181 if (size == SZLONG) {
1182 putstr(rname(p->tn.rval+1));
1183 break;
1184 }
1185 /* fall thru... */
1186
1187 default:
1188 cerror("illegal upper address op %s size %d",
1189 opst[p->tn.op], size);
1190 /*NOTREACHED*/
1191 }
1192}
1193
f2b49199
SL
1194adrput( p ) register NODE *p; {
1195 register int r;
1196 /* output an address, with offsets, from p */
1197
1198 if( p->in.op == FLD ){
1199 p = p->in.left;
1200 }
1201 switch( p->in.op ){
1202
1203 case NAME:
1204 acon( p );
1205 return;
1206
1207 case ICON:
1208 /* addressable value of the constant */
895241c8 1209 putchar('$');
f2b49199
SL
1210 acon( p );
1211 return;
1212
1213 case REG:
895241c8 1214 putstr(rname(p->tn.rval));
f2b49199
SL
1215 if(p->in.type == DOUBLE) /* for entry mask */
1216 (void) rname(p->tn.rval+1);
1217 return;
1218
1219 case OREG:
1220 r = p->tn.rval;
1221 if( R2TEST(r) ){ /* double indexing */
1222 register int flags;
1223
1224 flags = R2UPK3(r);
895241c8 1225 if( flags & 1 ) putchar('*');
f2b49199
SL
1226 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1227 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1228 printf( "[%s]", rname(R2UPK2(r)) );
1229 return;
1230 }
1231 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
1232 if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1233 printf( CONFMT, p->tn.lval );
895241c8 1234 putstr( "(fp)" );
f2b49199
SL
1235 return;
1236 }
1237 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1238 printf( "(%s)", rname(p->tn.rval) );
1239 return;
1240
1241 case UNARY MUL:
1242 /* STARNM or STARREG found */
1243 if( tshape(p, STARNM) ) {
895241c8 1244 putchar( '*' );
f2b49199
SL
1245 adrput( p->in.left);
1246 }
1247 return;
1248
1249 default:
1250 cerror( "illegal address" );
1251 return;
1252
1253 }
1254
1255 }
1256
1257acon( p ) register NODE *p; { /* print out a constant */
1258
55f818e1 1259 if( p->in.name[0] == '\0' )
f2b49199 1260 printf( CONFMT, p->tn.lval);
55f818e1 1261 else {
f2b49199
SL
1262#ifndef FLEXNAMES
1263 printf( "%.8s", p->in.name );
1264#else
55f818e1 1265 putstr( p->in.name );
f2b49199 1266#endif
55f818e1
DS
1267 if( p->tn.lval != 0 ) {
1268 putchar( '+' );
1269 printf( CONFMT, p->tn.lval );
1270 }
f2b49199 1271 }
895241c8 1272 }
f2b49199
SL
1273
1274genscall( p, cookie ) register NODE *p; {
1275 /* structure valued call */
1276 return( gencall( p, cookie ) );
1277 }
1278
1279genfcall( p, cookie ) register NODE *p; {
1280 register NODE *p1;
1281 register int m;
1282 static char *funcops[6] = {
1283 "sin", "cos", "sqrt", "exp", "log", "atan"
1284 };
1285
1286 /* generate function opcodes */
1287 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1288 (p1 = p->in.left)->in.op==ICON &&
1289 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1290#ifdef FLEXNAMES
1291 p1->in.name++;
1292#else
1293 strcpy(p1->in.name, p1->in.name[1]);
1294#endif
1295 for(m=0; m<6; m++)
1296 if(!strcmp(p1->in.name, funcops[m]))
1297 break;
1298 if(m >= 6)
1299 uerror("no opcode for fortarn function %s", p1->in.name);
1300 } else
1301 uerror("illegal type of fortarn function");
1302 p1 = p->in.right;
1303 p->in.op = FORTCALL;
1304 if(!canaddr(p1))
1305 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1306 m = match( p, INTAREG|INTBREG );
1307 return(m != MDONE);
1308}
1309
1310/* tbl */
1311int gc_numbytes;
1312/* tbl */
1313
55f818e1 1314/*ARGSUSED*/
f2b49199
SL
1315gencall( p, cookie ) register NODE *p; {
1316 /* generate the call given by p */
1317 register NODE *p1, *ptemp;
1318 register int temp, temp1;
1319 register int m;
1320
1321 if( p->in.right ) temp = argsize( p->in.right );
1322 else temp = 0;
1323
1324 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1325 /* set aside room for structure return */
1326
1327 if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1328 else temp1 = temp;
1329 }
1330
1331 if( temp > maxargs ) maxargs = temp;
1332 SETOFF(temp1,4);
1333
1334 if( p->in.right ){ /* make temp node, put offset in, and generate args */
1335 ptemp = talloc();
1336 ptemp->in.op = OREG;
1337 ptemp->tn.lval = -1;
1338 ptemp->tn.rval = SP;
1339#ifndef FLEXNAMES
1340 ptemp->in.name[0] = '\0';
1341#else
1342 ptemp->in.name = "";
1343#endif
1344 ptemp->in.rall = NOPREF;
1345 ptemp->in.su = 0;
1346 genargs( p->in.right, ptemp );
1347 ptemp->in.op = FREE;
1348 }
1349
1350 p1 = p->in.left;
1351 if( p1->in.op != ICON ){
1352 if( p1->in.op != REG ){
1353 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1354 if( p1->in.op != NAME ){
1355 order( p1, INAREG );
1356 }
1357 }
1358 }
1359 }
1360
1361/* tbl
1362 setup gc_numbytes so reference to ZC works */
1363
1364 gc_numbytes = temp&(0x3ff);
1365
1366 p->in.op = UNARY CALL;
1367 m = match( p, INTAREG|INTBREG );
1368
1369 return(m != MDONE);
1370 }
1371
1372/* tbl */
1373char *
1374ccbranches[] = {
1375 "eql",
1376 "neq",
1377 "leq",
1378 "lss",
1379 "geq",
1380 "gtr",
1381 "lequ",
1382 "lssu",
1383 "gequ",
1384 "gtru",
1385 };
1386/* tbl */
1387
55f818e1 1388/*ARGSUSED*/
f2b49199
SL
1389cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
1390
55f818e1
DS
1391 if( o != 0 && ( o < EQ || o > UGT ) )
1392 cerror( "bad conditional branch: %s", opst[o] );
1393 printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab );
f2b49199
SL
1394 }
1395
1396nextcook( p, cookie ) NODE *p; {
1397 /* we have failed to match p with cookie; try another */
1398 if( cookie == FORREW ) return( 0 ); /* hopeless! */
1399 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1400 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1401 return( FORREW );
1402 }
1403
55f818e1 1404/*ARGSUSED*/
f2b49199
SL
1405lastchance( p, cook ) NODE *p; {
1406 /* forget it! */
1407 return(0);
1408 }
1409
1410optim2( p ) register NODE *p; {
f2b49199 1411 /* do local tree transformations and optimizations */
55f818e1
DS
1412
1413 int o;
1414 int i, mask;
f1824a4b 1415 register NODE *l, *r;
f2b49199 1416
55f818e1 1417 switch( o = p->in.op ) {
f1824a4b 1418
c45469ab
DS
1419 case ASG PLUS:
1420 case ASG MINUS:
1421 case ASG MUL:
1422 case ASG OR:
1423 /* simple ASG OPSIMP -- reduce range of constant rhs */
1424 l = p->in.left;
1425 r = p->in.right;
1426 if( tlen(l) < SZINT/SZCHAR &&
1427 r->in.op==ICON && r->in.name[0]==0 ){
1428 mask = (1 << tlen(l) * SZCHAR) - 1;
1429 if( r->tn.lval & (mask & ~(mask >> 1)) )
1430 r->tn.lval |= ~mask;
1431 else
1432 r->tn.lval &= mask;
1433 }
1434 break;
1435
55f818e1
DS
1436 case AND:
1437 case ASG AND:
1438 r = p->in.right;
1439 if( r->in.op==ICON && r->in.name[0]==0 ) {
1440 /* check for degenerate operations */
1441 l = p->in.left;
1442 mask = (1 << tlen(l) * SZCHAR) - 1;
c45469ab
DS
1443 if( o == ASG AND || ISUNSIGNED(r->in.type) ) {
1444 i = r->tn.lval & mask;
55f818e1 1445 if( i == mask ) {
c45469ab 1446 /* redundant mask */
55f818e1
DS
1447 r->in.op = FREE;
1448 ncopy(p, l);
1449 l->in.op = FREE;
1450 break;
1451 }
1452 else if( i == 0 )
c45469ab 1453 /* all bits masked off */
55f818e1 1454 goto zero;
c45469ab
DS
1455 r->tn.lval = i;
1456 if( tlen(l) < SZINT/SZCHAR ){
1457 /* sign extend */
1458 if( r->tn.lval & (mask & ~(mask >> 1)) )
1459 r->tn.lval |= ~mask;
1460 else
1461 r->tn.lval &= mask;
1462 }
55f818e1
DS
1463 }
1464 else if( r->tn.lval == mask &&
1465 tlen(l) < SZINT/SZCHAR ) {
c45469ab 1466 /* use movz instead of and */
55f818e1
DS
1467 r->in.op = SCONV;
1468 r->in.left = l;
1469 r->in.right = 0;
1470 r->in.type = ENUNSIGN(l->in.type);
1471 r->in.su = l->in.su > 1 ? l->in.su : 1;
1472 ncopy(p, r);
1473 p->in.left = r;
1474 p->in.type = INT;
1475 }
f1824a4b 1476 }
55f818e1 1477 break;
f1824a4b
SL
1478
1479 case SCONV:
1480 l = p->in.left;
55f818e1
DS
1481 if( p->in.type == FLOAT || p->in.type == DOUBLE ||
1482 l->in.type == FLOAT || l->in.type == DOUBLE )
1483 return;
c45469ab
DS
1484 if( l->in.op == PCONV )
1485 return;
1486 if( (l->in.op == CALL || l->in.op == UNARY CALL) &&
1487 l->in.type != INT && l->in.type != UNSIGNED )
55f818e1 1488 return;
7999919c 1489
55f818e1
DS
1490 /* Only trust it to get it right if the size is the same */
1491 if( tlen(p) != tlen(l) )
1492 return;
1493
1494 /* clobber conversion */
1495 if( l->in.op != FLD )
1496 l->in.type = p->in.type;
1497 ncopy( p, l );
1498 l->in.op = FREE;
1499
1500 break;
f1824a4b
SL
1501
1502 case ASSIGN:
1503 /*
55f818e1
DS
1504 * Conversions are equivalent to assignments;
1505 * when the two operations are combined,
1506 * we can sometimes zap the conversion.
f1824a4b
SL
1507 */
1508 r = p->in.right;
55f818e1
DS
1509 l = p->in.left;
1510 if ( r->in.op == SCONV &&
1511 !mixtypes(l, r) &&
1512 l->in.op != FLD &&
1513 tlen(l) == tlen(r) ) {
f1824a4b
SL
1514 p->in.right = r->in.left;
1515 r->in.op = FREE;
1516 }
55f818e1 1517 break;
b45bedd3
DS
1518
1519 case ULE:
1520 case ULT:
1521 case UGE:
1522 case UGT:
55f818e1
DS
1523 p->in.op -= (UGE-GE);
1524 if( degenerate(p) )
1525 break;
1526 p->in.op += (UGE-GE);
1527 break;
1528
b45bedd3
DS
1529 case EQ:
1530 case NE:
1531 case LE:
1532 case LT:
1533 case GE:
1534 case GT:
c45469ab
DS
1535 if( p->in.left->in.op == SCONV &&
1536 p->in.right->in.op == SCONV ) {
1537 l = p->in.left;
1538 r = p->in.right;
1539 if( l->in.type == DOUBLE &&
1540 l->in.left->in.type == FLOAT &&
1541 r->in.left->in.type == FLOAT ) {
1542 /* nuke the conversions */
1543 p->in.left = l->in.left;
1544 p->in.right = r->in.left;
1545 l->in.op = FREE;
1546 r->in.op = FREE;
1547 }
1548 /* more? */
1549 }
55f818e1
DS
1550 (void) degenerate(p);
1551 break;
1552
1553 case DIV:
1554 if( p->in.right->in.op == ICON &&
1555 p->in.right->tn.name[0] == '\0' &&
1556 ISUNSIGNED(p->in.right->in.type) &&
1557 (unsigned) p->in.right->tn.lval >= 0x80000000 ) {
1558 /* easy to do here, harder to do in zzzcode() */
1559 p->in.op = UGE;
1560 break;
1561 }
1562 case MOD:
1563 case ASG DIV:
1564 case ASG MOD:
b45bedd3 1565 /*
55f818e1
DS
1566 * optimize DIV and MOD
1567 *
1568 * basically we spot UCHAR and USHORT and try to do them
1569 * as signed ints... this may need tuning for the tahoe.
b45bedd3 1570 */
55f818e1 1571 if( degenerate(p) )
b45bedd3 1572 break;
55f818e1
DS
1573 l = p->in.left;
1574 r = p->in.right;
1575 if( !ISUNSIGNED(r->in.type) ||
1576 tlen(l) >= SZINT/SZCHAR ||
1577 !(tlen(r) < SZINT/SZCHAR ||
1578 (r->in.op == ICON && r->tn.name[0] == '\0')) )
b45bedd3 1579 break;
55f818e1
DS
1580 if( r->in.op == ICON )
1581 r->tn.type = INT;
1582 else {
1583 NODE *t = talloc();
1584 t->in.left = r;
1585 r = t;
1586 r->in.op = SCONV;
1587 r->in.type = INT;
1588 r->in.right = 0;
1589 p->in.right = r;
1590 }
1591 if( o == DIV || o == MOD ) {
1592 NODE *t = talloc();
1593 t->in.left = l;
1594 l = t;
1595 l->in.op = SCONV;
1596 l->in.type = INT;
1597 l->in.right = 0;
1598 p->in.left = l;
1599 }
1600 /* handle asgops in table */
1601 break;
1602
1603 case RS:
1604 case ASG RS:
1605 case LS:
1606 case ASG LS:
1607 /* pick up degenerate shifts */
1608 l = p->in.left;
1609 r = p->in.right;
1610 if( !(r->in.op == ICON && r->tn.name[0] == '\0') )
b45bedd3 1611 break;
b45bedd3 1612 i = r->tn.lval;
55f818e1
DS
1613 if( i < 0 )
1614 /* front end 'fixes' this? */
1615 if( o == LS || o == ASG LS )
1616 o += (RS-LS);
1617 else
1618 o += (LS-RS);
1619 if( (o == RS || o == ASG RS) &&
1620 !ISUNSIGNED(l->in.type) )
1621 /* can't optimize signed right shifts */
b45bedd3 1622 break;
55f818e1
DS
1623 if( o == LS ) {
1624 if( i < SZINT )
1625 break;
1626 }
1627 else {
1628 if( i < tlen(l) * SZCHAR )
1629 break;
1630 }
1631 zero:
1632 if( !asgop( o ) )
1633 if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1634 /* no side effects */
1635 tfree(l);
1636 ncopy(p, r);
1637 r->in.op = FREE;
1638 p->tn.lval = 0;
1639 }
1640 else {
1641 p->in.op = COMOP;
1642 r->tn.lval = 0;
1643 }
1644 else {
1645 p->in.op = ASSIGN;
1646 r->tn.lval = 0;
1647 }
1648 break;
b45bedd3 1649 }
55f818e1 1650 }
b45bedd3 1651
55f818e1
DS
1652degenerate(p) register NODE *p; {
1653 int o;
1654 int result, i;
1655 int lower, upper;
1656 register NODE *l, *r;
1657
1658 /*
1659 * try to keep degenerate comparisons with constants
1660 * out of the table.
1661 */
1662 r = p->in.right;
1663 l = p->in.left;
1664 if( r->in.op != ICON ||
1665 r->tn.name[0] != '\0' ||
1666 tlen(l) >= tlen(r) )
1667 return (0);
1668 switch( l->in.type ) {
1669 case CHAR:
1670 lower = -(1 << SZCHAR - 1);
1671 upper = (1 << SZCHAR - 1) - 1;
1672 break;
1673 case UCHAR:
1674 lower = 0;
1675 upper = (1 << SZCHAR) - 1;
1676 break;
1677 case SHORT:
1678 lower = -(1 << SZSHORT - 1);
1679 upper = (1 << SZSHORT - 1) - 1;
1680 break;
1681 case USHORT:
1682 lower = 0;
1683 upper = (1 << SZSHORT) - 1;
1684 break;
1685 default:
1686 cerror("unsupported type in degenerate()");
1687 }
1688 i = r->tn.lval;
1689 switch( o = p->in.op ) {
1690 case DIV:
1691 case ASG DIV:
1692 case MOD:
1693 case ASG MOD:
1694 /* DIV and MOD work like EQ */
1695 case EQ:
1696 case NE:
1697 if( lower == 0 && (unsigned) i > upper )
1698 result = o == NE;
1699 else if( i < lower || i > upper )
1700 result = o == NE;
1701 else
1702 return (0);
1703 break;
1704 case LT:
1705 case GE:
1706 if( lower == 0 && (unsigned) i > upper )
1707 result = o == LT;
1708 else if( i <= lower )
1709 result = o != LT;
1710 else if( i > upper )
1711 result = o == LT;
1712 else
1713 return (0);
1714 break;
1715 case LE:
1716 case GT:
1717 if( lower == 0 && (unsigned) i >= upper )
1718 result = o == LE;
1719 else if( i < lower )
1720 result = o != LE;
1721 else if( i >= upper )
1722 result = o == LE;
1723 else
1724 return (0);
1725 break;
1726 default:
1727 cerror("unknown op in degenerate()");
1728 }
1729
1730 if( o == MOD || o == ASG MOD ) {
1731 r->in.op = FREE;
1732 ncopy(p, l);
1733 l->in.op = FREE;
1734 }
1735 else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) {
1736 /* no side effects */
1737 tfree(l);
1738 ncopy(p, r);
1739 r->in.op = FREE;
1740 p->tn.lval = result;
1741 }
1742 else {
1743 if( o == ASG DIV )
1744 p->in.op = ASSIGN;
1745 else {
b45bedd3 1746 p->in.op = COMOP;
b45bedd3 1747 r->tn.type = INT;
55f818e1
DS
1748 }
1749 r->tn.lval = result;
b45bedd3 1750 }
55f818e1
DS
1751 if( logop(o) )
1752 p->in.type = INT;
1753
1754 return (1);
f2b49199 1755 }
f2b49199
SL
1756
1757struct functbl {
1758 int fop;
20018a56 1759 TWORD ftype;
f2b49199 1760 char *func;
20018a56
DS
1761 } opfunc[] = {
1762 DIV, TANY, "udiv",
1763 MOD, TANY, "urem",
1764 ASG DIV, TANY, "audiv",
1765 ASG MOD, TANY, "aurem",
1766 0, 0, 0 };
f2b49199
SL
1767
1768hardops(p) register NODE *p; {
1769 /* change hard to do operators into function calls. */
1770 register NODE *q;
1771 register struct functbl *f;
20018a56
DS
1772 register o;
1773 NODE *old,*temp;
f2b49199
SL
1774
1775 o = p->in.op;
20018a56
DS
1776 if( ! (optype(o)==BITYPE &&
1777 (ISUNSIGNED(p->in.left->in.type) ||
1778 ISUNSIGNED(p->in.right->in.type))) )
1779 return;
f2b49199
SL
1780
1781 for( f=opfunc; f->fop; f++ ) {
1782 if( o==f->fop ) goto convert;
20018a56 1783 }
f2b49199
SL
1784 return;
1785
1786 convert:
55f818e1
DS
1787 if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' )
1788 /* 'J' in zzzcode() -- assumes DIV or MOD operations */
1789 /* save a subroutine call -- use at most 5 instructions */
1790 return;
1791 if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR )
1792 /* optim2() will modify the op into an ordinary int op */
1793 return;
f2b49199 1794 if( asgop( o ) ) {
20018a56
DS
1795 old = NIL;
1796 switch( p->in.left->in.op ){
1797 case FLD:
1798 q = p->in.left->in.left;
1799 /*
1800 * rewrite (lval.fld /= rval); as
1801 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1802 * else the compiler will evaluate lval twice.
1803 */
1804 if( q->in.op == UNARY MUL ){
1805 /* first allocate a temp storage */
1806 temp = talloc();
1807 temp->in.op = OREG;
1808 temp->tn.rval = TMPREG;
1809 temp->tn.lval = BITOOR(freetemp(1));
1810 temp->in.type = INCREF(p->in.type);
1811#ifdef FLEXNAMES
1812 temp->in.name = "";
1813#else
1814 temp->in.name[0] = '\0';
1815#endif
1816 old = q->in.left;
1817 q->in.left = temp;
1818 }
1819 /* fall thru ... */
f2b49199 1820
20018a56
DS
1821 case REG:
1822 case NAME:
1823 case OREG:
1824 /* change ASG OP to a simple OP */
1825 q = talloc();
1826 q->in.op = NOASG p->in.op;
1827 q->in.rall = NOPREF;
1828 q->in.type = p->in.type;
1829 q->in.left = tcopy(p->in.left);
1830 q->in.right = p->in.right;
1831 p->in.op = ASSIGN;
1832 p->in.right = q;
1833 p = q;
1834 f -= 2; /* Note: this depends on the table order */
1835 /* on the right side only - replace *temp with
1836 *(temp = &lval), build the assignment node */
1837 if( old ){
1838 temp = q->in.left->in.left; /* the "*" node */
1839 q = talloc();
1840 q->in.op = ASSIGN;
1841 q->in.left = temp->in.left;
1842 q->in.right = old;
1843 q->in.type = old->in.type;
1844#ifdef FLEXNAMES
1845 q->in.name = "";
f2b49199 1846#else
20018a56 1847 q->in.name[0] = '\0';
f2b49199 1848#endif
20018a56
DS
1849 temp->in.left = q;
1850 }
1851 break;
f2b49199 1852
20018a56
DS
1853 case UNARY MUL:
1854 /* avoid doing side effects twice */
1855 q = p->in.left;
1856 p->in.left = q->in.left;
1857 q->in.op = FREE;
1858 break;
1859
1860 default:
1861 cerror( "hardops: can't compute & LHS" );
1862 }
1863 }
f2b49199 1864
20018a56
DS
1865 /* build comma op for args to function */
1866 q = talloc();
1867 q->in.op = CM;
1868 q->in.rall = NOPREF;
1869 q->in.type = INT;
1870 q->in.left = p->in.left;
1871 q->in.right = p->in.right;
f2b49199
SL
1872 p->in.op = CALL;
1873 p->in.right = q;
1874
1875 /* put function name in left node of call */
1876 p->in.left = q = talloc();
1877 q->in.op = ICON;
1878 q->in.rall = NOPREF;
1879 q->in.type = INCREF( FTN + p->in.type );
1880#ifndef FLEXNAMES
20018a56 1881 strcpy( q->in.name, f->func );
f2b49199 1882#else
20018a56 1883 q->in.name = f->func;
f2b49199
SL
1884#endif
1885 q->tn.lval = 0;
1886 q->tn.rval = 0;
1887
1888 }
1889
1890zappost(p) NODE *p; {
1891 /* look for ++ and -- operators and remove them */
1892
1893 register int o, ty;
1894 register NODE *q;
1895 o = p->in.op;
1896 ty = optype( o );
1897
1898 switch( o ){
1899
1900 case INCR:
1901 case DECR:
1902 q = p->in.left;
1903 p->in.right->in.op = FREE; /* zap constant */
1904 ncopy( p, q );
1905 q->in.op = FREE;
1906 return;
1907
1908 }
1909
1910 if( ty == BITYPE ) zappost( p->in.right );
1911 if( ty != LTYPE ) zappost( p->in.left );
1912}
1913
1914fixpre(p) NODE *p; {
1915
1916 register int o, ty;
1917 o = p->in.op;
1918 ty = optype( o );
1919
1920 switch( o ){
1921
1922 case ASG PLUS:
1923 p->in.op = PLUS;
1924 break;
1925 case ASG MINUS:
1926 p->in.op = MINUS;
1927 break;
1928 }
1929
1930 if( ty == BITYPE ) fixpre( p->in.right );
1931 if( ty != LTYPE ) fixpre( p->in.left );
1932}
1933
55f818e1 1934/*ARGSUSED*/
f2b49199
SL
1935NODE * addroreg(l) NODE *l;
1936 /* OREG was built in clocal()
1937 * for an auto or formal parameter
1938 * now its address is being taken
1939 * local code must unwind it
1940 * back to PLUS/MINUS REG ICON
1941 * according to local conventions
1942 */
1943{
1944 cerror("address of OREG taken");
55f818e1 1945 /*NOTREACHED*/
f2b49199
SL
1946}
1947
1948# ifndef ONEPASS
1949main( argc, argv ) char *argv[]; {
1950 return( mainp2( argc, argv ) );
1951 }
1952# endif
1953
f1824a4b
SL
1954strip(p) register NODE *p; {
1955 NODE *q;
1956
1957 /* strip nodes off the top when no side effects occur */
1958 for( ; ; ) {
1959 switch( p->in.op ) {
1960 case SCONV: /* remove lint tidbits */
1961 q = p->in.left;
1962 ncopy( p, q );
1963 q->in.op = FREE;
1964 break;
1965 /* could probably add a few more here */
1966 default:
1967 return;
1968 }
1969 }
1970 }
1971
f2b49199 1972myreader(p) register NODE *p; {
f1824a4b 1973 strip( p ); /* strip off operations with no side effects */
55f818e1 1974 canon( p ); /* expands r-vals for fields */
f2b49199 1975 walkf( p, hardops ); /* convert ops to function calls */
f2b49199
SL
1976 walkf( p, optim2 );
1977 }