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