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