Commit | Line | Data |
---|---|---|
262eaf56 | 1 | # ifndef lint |
6eafb37d | 2 | static char *sccsid ="@(#)local2.c 1.32 (Berkeley) %G%"; |
262eaf56 RC |
3 | # endif |
4 | ||
0ec67d08 | 5 | # include "pass2.h" |
74789784 DS |
6 | # include <ctype.h> |
7 | ||
8 | # define putstr(s) fputs((s), stdout) | |
9 | ||
439a068b ML |
10 | # ifdef FORT |
11 | int ftlab1, ftlab2; | |
12 | # endif | |
13 | /* a lot of the machine dependent parts of the second pass */ | |
14 | ||
15 | # define BITMASK(n) ((1L<<n)-1) | |
16 | ||
6dc2c6c8 | 17 | /*ARGSUSED*/ |
439a068b ML |
18 | where(c){ |
19 | fprintf( stderr, "%s, line %d: ", filename, lineno ); | |
20 | } | |
21 | ||
22 | lineid( l, fn ) char *fn; { | |
23 | /* identify line l and file fn */ | |
24 | printf( "# line %d, file %s\n", l, fn ); | |
25 | } | |
26 | ||
27 | ||
28 | eobl2(){ | |
74789784 DS |
29 | register OFFSZ spoff; /* offset from stack pointer */ |
30 | #ifndef FORT | |
31 | extern int ftlab1, ftlab2; | |
32 | #endif | |
33 | ||
439a068b ML |
34 | spoff = maxoff; |
35 | if( spoff >= AUTOINIT ) spoff -= AUTOINIT; | |
36 | spoff /= SZCHAR; | |
37 | SETOFF(spoff,4); | |
74789784 | 38 | #ifdef FORT |
439a068b ML |
39 | #ifndef FLEXNAMES |
40 | printf( " .set .F%d,%ld\n", ftnno, spoff ); | |
41 | #else | |
42 | /* SHOULD BE L%d ... ftnno but must change pc/f77 */ | |
43 | printf( " .set LF%d,%ld\n", ftnno, spoff ); | |
44 | #endif | |
45 | #else | |
439a068b ML |
46 | printf( "L%d:\n", ftlab1); |
47 | if( spoff!=0 ) | |
48 | if( spoff < 64 ) | |
49 | printf( " subl2 $%ld,sp\n", spoff); | |
50 | else | |
51 | printf( " movab -%ld(sp),sp\n", spoff); | |
52 | printf( " jbr L%d\n", ftlab2); | |
53 | #endif | |
54 | maxargs = -1; | |
55 | } | |
56 | ||
57 | struct hoptab { int opmask; char * opstring; } ioptab[] = { | |
58 | ||
439a068b ML |
59 | PLUS, "add", |
60 | MINUS, "sub", | |
61 | MUL, "mul", | |
62 | DIV, "div", | |
63 | OR, "bis", | |
64 | ER, "xor", | |
65 | AND, "bic", | |
66 | -1, "" }; | |
67 | ||
68 | hopcode( f, o ){ | |
69 | /* output the appropriate string from the above table */ | |
70 | ||
71 | register struct hoptab *q; | |
72 | ||
74789784 DS |
73 | if(asgop(o)) |
74 | o = NOASG o; | |
439a068b ML |
75 | for( q = ioptab; q->opmask>=0; ++q ){ |
76 | if( q->opmask == o ){ | |
74789784 | 77 | printf( "%s%c", q->opstring, tolower(f)); |
439a068b ML |
78 | return; |
79 | } | |
80 | } | |
81 | cerror( "no hoptab for %s", opst[o] ); | |
82 | } | |
83 | ||
84 | char * | |
85 | rnames[] = { /* keyed to register number tokens */ | |
86 | ||
87 | "r0", "r1", | |
88 | "r2", "r3", "r4", "r5", | |
89 | "r6", "r7", "r8", "r9", "r10", "r11", | |
90 | "ap", "fp", "sp", "pc", | |
439a068b ML |
91 | }; |
92 | ||
93 | int rstatus[] = { | |
94 | SAREG|STAREG, SAREG|STAREG, | |
95 | SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, | |
96 | SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, | |
97 | SAREG, SAREG, SAREG, SAREG, | |
439a068b ML |
98 | }; |
99 | ||
100 | tlen(p) NODE *p; | |
101 | { | |
102 | switch(p->in.type) { | |
103 | case CHAR: | |
104 | case UCHAR: | |
105 | return(1); | |
106 | ||
107 | case SHORT: | |
108 | case USHORT: | |
3f494137 | 109 | return(SZSHORT/SZCHAR); |
439a068b ML |
110 | |
111 | case DOUBLE: | |
3f494137 | 112 | return(SZDOUBLE/SZCHAR); |
439a068b ML |
113 | |
114 | default: | |
3f494137 | 115 | return(SZINT/SZCHAR); |
439a068b ML |
116 | } |
117 | } | |
118 | ||
119 | mixtypes(p, q) NODE *p, *q; | |
120 | { | |
472582a4 | 121 | register TWORD tp, tq; |
439a068b ML |
122 | |
123 | tp = p->in.type; | |
124 | tq = q->in.type; | |
125 | ||
126 | return( (tp==FLOAT || tp==DOUBLE) != | |
127 | (tq==FLOAT || tq==DOUBLE) ); | |
128 | } | |
129 | ||
130 | prtype(n) NODE *n; | |
131 | { | |
132 | switch (n->in.type) | |
133 | { | |
74789784 | 134 | |
439a068b | 135 | case DOUBLE: |
88bb0c9f | 136 | putchar('d'); |
439a068b ML |
137 | return; |
138 | ||
139 | case FLOAT: | |
88bb0c9f | 140 | putchar('f'); |
439a068b ML |
141 | return; |
142 | ||
143 | case LONG: | |
144 | case ULONG: | |
145 | case INT: | |
146 | case UNSIGNED: | |
88bb0c9f | 147 | putchar('l'); |
439a068b ML |
148 | return; |
149 | ||
150 | case SHORT: | |
151 | case USHORT: | |
88bb0c9f | 152 | putchar('w'); |
439a068b ML |
153 | return; |
154 | ||
155 | case CHAR: | |
156 | case UCHAR: | |
88bb0c9f | 157 | putchar('b'); |
439a068b ML |
158 | return; |
159 | ||
160 | default: | |
161 | if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); | |
162 | else { | |
88bb0c9f | 163 | putchar('l'); |
439a068b ML |
164 | return; |
165 | } | |
166 | } | |
167 | } | |
168 | ||
169 | zzzcode( p, c ) register NODE *p; { | |
74789784 | 170 | register int m; |
6dc2c6c8 | 171 | int val; |
439a068b ML |
172 | switch( c ){ |
173 | ||
174 | case 'N': /* logical ops, turned into 0-1 */ | |
175 | /* use register given by register 1 */ | |
176 | cbgen( 0, m=getlab(), 'I' ); | |
177 | deflab( p->bn.label ); | |
178 | printf( " clrl %s\n", rnames[getlr( p, '1' )->tn.rval] ); | |
179 | deflab( m ); | |
180 | return; | |
181 | ||
439a068b ML |
182 | case 'P': |
183 | cbgen( p->in.op, p->bn.label, c ); | |
184 | return; | |
185 | ||
186 | case 'A': | |
74789784 DS |
187 | case 'V': |
188 | sconv( p, c == 'V' ); | |
439a068b | 189 | return; |
439a068b | 190 | |
4bcc0eaf DS |
191 | case 'G': /* i *= f; asgops with int lhs and float rhs */ |
192 | { | |
193 | register NODE *l, *r, *s; | |
194 | int rt; | |
195 | ||
196 | l = p->in.left; | |
197 | r = p->in.right; | |
198 | s = talloc(); | |
199 | rt = r->in.type; | |
200 | ||
201 | s->in.op = SCONV; | |
202 | s->in.left = l; | |
203 | s->in.type = rt; | |
204 | zzzcode(s, 'A'); | |
205 | putstr("\n\t"); | |
206 | ||
207 | hopcode(rt == FLOAT ? 'F' : 'D', p->in.op); | |
208 | putstr("2\t"); | |
209 | adrput(r); | |
210 | putchar(','); | |
211 | adrput(resc); | |
212 | putstr("\n\t"); | |
213 | ||
214 | s->in.op = ASSIGN; | |
215 | s->in.left = l; | |
216 | s->in.right = resc; | |
217 | s->in.type = l->in.type; | |
218 | zzzcode(s, 'A'); | |
219 | ||
220 | s->in.op = FREE; | |
221 | return; | |
222 | } | |
223 | ||
70f59a26 DS |
224 | case 'J': /* unsigned DIV/MOD with constant divisors */ |
225 | { | |
226 | register int ck = INAREG; | |
227 | int label1, label2; | |
228 | ||
229 | /* case constant <= 1 is handled by optim() in pass 1 */ | |
230 | /* case constant < 0x80000000 is handled in table */ | |
231 | switch( p->in.op ) { | |
6eafb37d | 232 | /* case DIV: handled in optim2() */ |
70f59a26 DS |
233 | case MOD: |
234 | if( p->in.left->in.op == REG && | |
235 | p->in.left->tn.rval == resc->tn.rval ) | |
236 | goto asgmod; | |
237 | label1 = getlab(); | |
238 | expand(p, ck, "movl\tAL,A1\n\tcmpl\tA1,AR\n"); | |
239 | printf("\tjlssu\tL%d\n", label1); | |
240 | expand(p, ck, "\tsubl2\tAR,A1\n"); | |
241 | printf("L%d:", label1); | |
242 | break; | |
243 | case ASG DIV: | |
244 | label1 = getlab(); | |
245 | label2 = getlab(); | |
246 | expand(p, ck, "cmpl\tAL,AR\n"); | |
247 | printf("\tjgequ\tL%d\n", label1); | |
248 | expand(p, ck, "\tmovl\t$1,AL\n"); | |
249 | printf("\tjbr\tL%d\nL%d:\n", label2, label1); | |
250 | expand(p, ck, "\tclrl\tAL\n"); | |
251 | printf("L%d:", label2); | |
252 | break; | |
253 | case ASG MOD: | |
254 | asgmod: | |
255 | label1 = getlab(); | |
256 | expand(p, ck, "cmpl\tAL,AR\n"); | |
257 | printf("\tjlssu\tL%d\n", label1); | |
258 | expand(p, ck, "\tsubl2\tAR,AL\n"); | |
259 | printf("L%d:", label1); | |
260 | break; | |
261 | } | |
262 | return; | |
263 | } | |
264 | ||
439a068b ML |
265 | case 'B': /* get oreg value in temp register for left shift */ |
266 | { | |
267 | register NODE *r; | |
268 | if (xdebug) eprint(p, 0, &val, &val); | |
269 | r = p->in.right; | |
3f494137 | 270 | if( tlen(r) == SZINT/SZCHAR && r->in.type != FLOAT ) |
88bb0c9f | 271 | putstr("movl"); |
439a068b | 272 | else { |
74789784 | 273 | putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); |
439a068b | 274 | prtype(r); |
88bb0c9f | 275 | putchar('l'); |
439a068b ML |
276 | } |
277 | return; | |
278 | } | |
279 | ||
280 | case 'C': /* num words pushed on arg stack */ | |
281 | { | |
282 | extern int gc_numbytes; | |
283 | extern int xdebug; | |
284 | ||
285 | if (xdebug) printf("->%d<-",gc_numbytes); | |
286 | ||
287 | printf("$%d", gc_numbytes/(SZLONG/SZCHAR) ); | |
288 | return; | |
289 | } | |
290 | ||
291 | case 'D': /* INCR and DECR */ | |
292 | zzzcode(p->in.left, 'A'); | |
88bb0c9f KM |
293 | putchar('\n'); |
294 | putchar('\t'); | |
439a068b ML |
295 | |
296 | case 'E': /* INCR and DECR, FOREFF */ | |
ffc0e7a6 | 297 | if (p->in.right->in.op == ICON && p->in.right->tn.lval == 1) |
439a068b | 298 | { |
74789784 | 299 | putstr(p->in.op == INCR ? "inc" : "dec"); |
439a068b | 300 | prtype(p->in.left); |
88bb0c9f | 301 | putchar('\t'); |
439a068b ML |
302 | adrput(p->in.left); |
303 | return; | |
304 | } | |
74789784 | 305 | putstr(p->in.op == INCR ? "add" : "sub"); |
439a068b | 306 | prtype(p->in.left); |
88bb0c9f KM |
307 | putchar('2'); |
308 | putchar('\t'); | |
439a068b | 309 | adrput(p->in.right); |
88bb0c9f | 310 | putchar(','); |
439a068b ML |
311 | adrput(p->in.left); |
312 | return; | |
313 | ||
314 | case 'F': /* register type of right operand */ | |
315 | { | |
316 | register NODE *n; | |
317 | extern int xdebug; | |
318 | register int ty; | |
319 | ||
320 | n = getlr( p, 'R' ); | |
321 | ty = n->in.type; | |
322 | ||
323 | if (xdebug) printf("->%d<-", ty); | |
324 | ||
88bb0c9f KM |
325 | if ( ty==DOUBLE) putchar('d'); |
326 | else if ( ty==FLOAT ) putchar('f'); | |
327 | else putchar('l'); | |
439a068b ML |
328 | return; |
329 | } | |
330 | ||
331 | case 'L': /* type of left operand */ | |
332 | case 'R': /* type of right operand */ | |
333 | { | |
334 | register NODE *n; | |
335 | extern int xdebug; | |
336 | ||
472582a4 | 337 | n = getlr( p, c ); |
439a068b ML |
338 | if (xdebug) printf("->%d<-", n->in.type); |
339 | ||
340 | prtype(n); | |
341 | return; | |
342 | } | |
343 | ||
6eafb37d DS |
344 | case 'Z': /* AND for CC with ICON -- lval is complemented */ |
345 | { | |
346 | register NODE *l, *r; | |
347 | ||
348 | l = getlr( p, 'L' ); | |
349 | r = getlr( p, 'R' ); | |
350 | m = (1 << tlen(l) * SZCHAR) - 1; | |
351 | r->tn.lval = ~r->tn.lval; | |
352 | if( (l->in.type == CHAR || l->in.type == SHORT) && | |
353 | (r->tn.lval & ~m) ) { | |
354 | putstr("cvt"); | |
355 | prtype(l); | |
356 | putstr("l\t"); | |
357 | adrput(l); | |
358 | putchar(','); | |
359 | adrput(resc); | |
360 | putstr("\n\t"); | |
361 | resc->tn.type = INT; | |
362 | l = resc; | |
363 | } | |
364 | else if( l->in.type == UCHAR || l->in.type == USHORT ) | |
365 | /* remove trash left over from complementing */ | |
366 | r->tn.lval &= m; | |
367 | putstr("bit"); | |
368 | prtype(l); | |
369 | printf("\t$%ld", r->tn.lval); | |
370 | putchar(','); | |
371 | adrput(l); | |
439a068b | 372 | return; |
6eafb37d | 373 | } |
439a068b ML |
374 | |
375 | case 'U': /* 32 - n, for unsigned right shifts */ | |
376 | printf("$%d", 32 - p->in.right->tn.lval ); | |
377 | return; | |
378 | ||
379 | case 'T': /* rounded structure length for arguments */ | |
380 | { | |
381 | int size; | |
382 | ||
383 | size = p->stn.stsize; | |
384 | SETOFF( size, 4); | |
385 | printf("$%d", size); | |
386 | return; | |
387 | } | |
388 | ||
389 | case 'S': /* structure assignment */ | |
74789784 DS |
390 | stasg(p); |
391 | break; | |
439a068b | 392 | |
74789784 DS |
393 | default: |
394 | cerror( "illegal zzzcode" ); | |
395 | } | |
396 | } | |
439a068b | 397 | |
74789784 DS |
398 | stasg(p) |
399 | register NODE *p; | |
400 | { | |
401 | register NODE *l, *r; | |
402 | register size; | |
439a068b | 403 | |
74789784 DS |
404 | if( p->in.op == STASG ){ |
405 | l = p->in.left; | |
406 | r = p->in.right; | |
439a068b | 407 | |
74789784 DS |
408 | } |
409 | else if( p->in.op == STARG ){ /* store an arg into a temporary */ | |
410 | r = p->in.left; | |
411 | } | |
412 | else cerror( "STASG bad" ); | |
439a068b | 413 | |
74789784 DS |
414 | if( r->in.op == ICON ) r->in.op = NAME; |
415 | else if( r->in.op == REG ) r->in.op = OREG; | |
416 | else if( r->in.op != OREG ) cerror( "STASG-r" ); | |
439a068b | 417 | |
74789784 DS |
418 | size = p->stn.stsize; |
419 | ||
420 | if( size <= 0 || size > 65535 ) | |
421 | cerror("structure size <0=0 or >65535"); | |
422 | ||
423 | switch(size) { | |
424 | case 1: | |
425 | putstr(" movb "); | |
426 | break; | |
427 | case 2: | |
428 | putstr(" movw "); | |
429 | break; | |
430 | case 4: | |
431 | putstr(" movl "); | |
432 | break; | |
433 | case 8: | |
434 | putstr(" movq "); | |
435 | break; | |
436 | default: | |
437 | printf(" movc3 $%d,", size); | |
438 | break; | |
439 | } | |
440 | adrput(r); | |
441 | if( p->in.op == STASG ){ | |
442 | putchar(','); | |
443 | adrput(l); | |
444 | putchar('\n'); | |
445 | } | |
446 | else | |
447 | putstr(",(sp)\n"); | |
448 | ||
449 | if( r->in.op == NAME ) r->in.op = ICON; | |
450 | else if( r->in.op == OREG ) r->in.op = REG; | |
451 | } | |
452 | ||
453 | NODE *makearg( ty ) int ty; { | |
454 | register NODE *p, *q; | |
455 | ||
456 | /* build a -(sp) operand */ | |
457 | p = talloc(); | |
458 | p->in.op = REG; | |
459 | /* the type needn't be right, just consistent */ | |
460 | p->in.type = INCREF(ty); | |
461 | p->tn.rval = SP; | |
462 | p->tn.lval = 0; | |
463 | q = talloc(); | |
464 | q->in.op = ASG MINUS; | |
465 | q->in.type = INCREF(ty); | |
466 | q->in.left = p; | |
467 | p = talloc(); | |
468 | p->in.op = ICON; | |
469 | p->in.type = INT; | |
470 | p->tn.name = ""; | |
6eafb37d | 471 | p->tn.lval = szty(ty) * (SZINT/SZCHAR); |
74789784 DS |
472 | q->in.right = p; |
473 | p = talloc(); | |
474 | p->in.op = UNARY MUL; | |
475 | p->in.left = q; | |
476 | return( p ); | |
477 | } | |
478 | ||
479 | sconv( p, forarg ) register NODE *p; { | |
480 | register NODE *l, *r; | |
481 | int m, val; | |
482 | ||
483 | if (xdebug) eprint(p, 0, &val, &val); | |
484 | r = getlr(p, 'R'); | |
485 | if (p->in.op == ASSIGN) | |
486 | l = getlr(p, 'L'); | |
487 | else if (p->in.op == SCONV) { | |
488 | #if defined(FORT) || defined(SPRECC) | |
489 | m = r->in.type; | |
490 | #else | |
491 | m = r->in.type==FLOAT ? DOUBLE : r->in.type; | |
492 | #endif | |
493 | if (forarg) | |
494 | l = makearg( m ); | |
495 | else | |
496 | l = resc; | |
497 | l->in.type = m; | |
498 | r = getlr(p, 'L'); | |
499 | } | |
500 | else { /* OPLTYPE */ | |
501 | #if defined(FORT) || defined(SPRECC) | |
502 | m = (r->in.type==FLOAT || r->in.type==DOUBLE ? r->in.type : INT); | |
503 | #else | |
504 | m = (r->in.type==FLOAT || r->in.type==DOUBLE ? DOUBLE : INT); | |
505 | #endif | |
506 | if (forarg) | |
507 | l = makearg( m ); | |
508 | else | |
509 | l = resc; | |
510 | l->in.type = m; | |
511 | } | |
512 | if (r->in.op == ICON) | |
513 | if (r->in.name[0] == '\0') { | |
6eafb37d | 514 | if (r->tn.lval == 0 && !forarg) { |
74789784 DS |
515 | putstr("clr"); |
516 | prtype(l); | |
517 | putchar('\t'); | |
3add848c | 518 | adrput(l); |
74789784 DS |
519 | goto cleanup; |
520 | } | |
521 | if (r->tn.lval < 0 && r->tn.lval >= -63) { | |
522 | putstr("mneg"); | |
523 | prtype(l); | |
524 | r->tn.lval = -r->tn.lval; | |
525 | goto ops; | |
3add848c | 526 | } |
74789784 DS |
527 | if (r->tn.lval < 0) |
528 | r->in.type = r->tn.lval >= -128 ? CHAR | |
529 | : (r->tn.lval >= -32768 ? SHORT | |
530 | : INT); | |
531 | else if (l->in.type == FLOAT || | |
532 | l->in.type == DOUBLE) | |
533 | r->in.type = r->tn.lval <= 63 ? INT | |
534 | : (r->tn.lval <= 127 ? CHAR | |
535 | : (r->tn.lval <= 32767 ? SHORT | |
536 | : INT)); | |
3add848c | 537 | else |
74789784 DS |
538 | r->in.type = r->tn.lval <= 63 ? INT |
539 | : (r->tn.lval <= 127 ? CHAR | |
540 | : (r->tn.lval <= 255 ? UCHAR | |
541 | : (r->tn.lval <= 32767 ? SHORT | |
542 | : (r->tn.lval <= 65535 ? USHORT | |
543 | : INT)))); | |
6eafb37d DS |
544 | if (forarg && r->in.type == INT) { |
545 | putstr("pushl\t"); | |
546 | adrput(r); | |
547 | goto cleanup; | |
548 | } | |
74789784 DS |
549 | } |
550 | else { | |
6eafb37d DS |
551 | if (forarg && tlen(r) == SZINT/SZCHAR) { |
552 | putstr("pushl\t"); | |
553 | adrput(r); | |
554 | goto cleanup; | |
555 | } | |
556 | putstr("moval\t"); | |
74789784 DS |
557 | acon(r); |
558 | putchar(','); | |
559 | adrput(l); | |
560 | goto cleanup; | |
561 | } | |
439a068b | 562 | |
74789784 DS |
563 | if (p->in.op == SCONV && |
564 | !(l->in.type == FLOAT || l->in.type == DOUBLE) && | |
565 | !mixtypes(l, r)) { | |
566 | /* | |
567 | * Because registers must always contain objects | |
568 | * of the same width as INTs, we may have to | |
569 | * perform two conversions to get an INT. Can | |
570 | * the conversions be collapsed into one? | |
571 | */ | |
572 | if (m = collapsible(l, r)) | |
573 | r->in.type = m; | |
574 | else { | |
575 | /* | |
576 | * Two steps are required. | |
577 | */ | |
578 | NODE *x = &resc[1]; | |
439a068b | 579 | |
74789784 DS |
580 | *x = *l; |
581 | if (tlen(x) > tlen(r) && ISUNSIGNED(r->in.type)) | |
582 | putstr("movz"); | |
583 | else | |
584 | putstr("cvt"); | |
585 | prtype(r); | |
586 | prtype(x); | |
587 | putchar('\t'); | |
588 | adrput(r); | |
589 | putchar(','); | |
590 | adrput(x); | |
591 | putchar('\n'); | |
592 | putchar('\t'); | |
593 | r = x; | |
439a068b | 594 | } |
74789784 DS |
595 | l->in.type = (ISUNSIGNED(l->in.type) ? UNSIGNED : INT); |
596 | } | |
439a068b | 597 | |
74789784 DS |
598 | if ((r->in.type == UNSIGNED || r->in.type == ULONG) && |
599 | mixtypes(l, r)) { | |
600 | int label1, label2; | |
601 | ||
602 | label1 = getlab(); | |
603 | label2 = getlab(); | |
604 | ||
605 | putstr("movl\t"); | |
606 | adrput(r); | |
607 | putchar(','); | |
608 | adrput(l); | |
609 | putstr("\n\tjbsc\t$31,"); | |
610 | adrput(l); | |
611 | printf(",L%d\n\tcvtl", label1); | |
612 | prtype(l); | |
613 | putchar('\t'); | |
614 | adrput(l); | |
615 | putchar(','); | |
616 | adrput(l); | |
617 | printf("\n\tjbr\tL%d\nL%d:\n\tcvtl", label2, label1); | |
618 | prtype(l); | |
619 | putchar('\t'); | |
620 | adrput(l); | |
621 | putchar(','); | |
622 | adrput(l); | |
623 | putstr("\n\tadd"); | |
624 | prtype(l); | |
625 | putstr("2\t$0"); | |
626 | prtype(l); | |
627 | putstr("2.147483648e9,"); | |
628 | adrput(l); | |
629 | printf("\nL%d:", label2); | |
630 | ||
631 | goto cleanup; | |
439a068b | 632 | } |
74789784 DS |
633 | |
634 | if (!mixtypes(l,r)) { | |
635 | if (tlen(l) == tlen(r)) { | |
6eafb37d DS |
636 | if (forarg && tlen(l) == SZINT/SZCHAR) { |
637 | putstr("pushl\t"); | |
638 | adrput(r); | |
639 | goto cleanup; | |
640 | } | |
74789784 DS |
641 | putstr("mov"); |
642 | #ifdef FORT | |
643 | if (Oflag) | |
644 | prtype(l); | |
645 | else { | |
646 | if (l->in.type == DOUBLE) | |
647 | putchar('q'); | |
648 | else if(l->in.type == FLOAT) | |
649 | putchar('l'); | |
650 | else | |
651 | prtype(l); | |
652 | } | |
653 | #else | |
654 | prtype(l); | |
655 | #endif FORT | |
656 | goto ops; | |
657 | } | |
658 | else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type)) | |
659 | putstr("movz"); | |
660 | else | |
661 | putstr("cvt"); | |
662 | } | |
663 | else | |
664 | putstr("cvt"); | |
665 | prtype(r); | |
666 | prtype(l); | |
667 | ops: | |
668 | putchar('\t'); | |
669 | adrput(r); | |
670 | putchar(','); | |
671 | adrput(l); | |
672 | ||
673 | cleanup: | |
674 | if (forarg) | |
675 | tfree(l); | |
439a068b ML |
676 | } |
677 | ||
83d9f822 JB |
678 | /* |
679 | * collapsible(dest, src) -- if a conversion with a register destination | |
680 | * can be accomplished in one instruction, return the type of src | |
681 | * that will do the job correctly; otherwise return 0. Note that | |
682 | * a register must always end up having type INT or UNSIGNED. | |
683 | */ | |
684 | int | |
685 | collapsible(dest, src) | |
686 | NODE *dest, *src; | |
687 | { | |
688 | int st = src->in.type; | |
689 | int dt = dest->in.type; | |
690 | int newt = 0; | |
691 | ||
692 | /* | |
693 | * Are there side effects of evaluating src? | |
694 | * If the derived type will not be the same size as src, | |
88bb0c9f | 695 | * we may have to use two steps. |
83d9f822 | 696 | */ |
88bb0c9f KM |
697 | if (tlen(src) > tlen(dest)) { |
698 | if (tshape(src, STARREG)) | |
699 | return (0); | |
700 | if (src->in.op == OREG && R2TEST(src->tn.rval)) | |
701 | return (0); | |
702 | } | |
83d9f822 JB |
703 | |
704 | /* | |
705 | * Can we get an object of dest's type by punning src? | |
706 | * Praises be to great Cthulhu for little-endian machines... | |
707 | */ | |
708 | if (st == CHAR && dt == USHORT) | |
709 | /* | |
710 | * Special case -- we must sign-extend to 16 bits. | |
711 | */ | |
712 | return (0); | |
713 | ||
714 | if (tlen(src) < tlen(dest)) | |
715 | newt = st; | |
716 | else | |
717 | newt = dt; | |
718 | ||
719 | return (newt); | |
720 | } | |
721 | ||
262eaf56 | 722 | rmove( rt, rs, t ) TWORD t; { |
439a068b | 723 | printf( " %s %s,%s\n", |
262eaf56 RC |
724 | #ifdef FORT |
725 | !Oflag ? (t==DOUBLE ? "movq" : "movl") : | |
726 | #endif | |
439a068b ML |
727 | (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")), |
728 | rnames[rs], rnames[rt] ); | |
729 | } | |
730 | ||
731 | struct respref | |
732 | respref[] = { | |
733 | INTAREG|INTBREG, INTAREG|INTBREG, | |
734 | INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, | |
735 | INTEMP, INTEMP, | |
736 | FORARG, FORARG, | |
737 | INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, | |
738 | 0, 0 }; | |
739 | ||
740 | setregs(){ /* set up temporary registers */ | |
741 | fregs = 6; /* tbl- 6 free regs on VAX (0-5) */ | |
439a068b ML |
742 | } |
743 | ||
6dc2c6c8 | 744 | /*ARGSUSED*/ |
439a068b ML |
745 | rewfld( p ) NODE *p; { |
746 | return(1); | |
747 | } | |
748 | ||
6dc2c6c8 | 749 | /*ARGSUSED*/ |
439a068b ML |
750 | callreg(p) NODE *p; { |
751 | return( R0 ); | |
752 | } | |
753 | ||
754 | base( p ) register NODE *p; { | |
755 | register int o = p->in.op; | |
756 | ||
6eafb37d | 757 | if( o==ICON && p->tn.name[0] != '\0' ) return( 100 ); /* ie no base reg */ |
439a068b ML |
758 | if( o==REG ) return( p->tn.rval ); |
759 | if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) | |
760 | return( p->in.left->tn.rval ); | |
761 | if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) | |
762 | return( p->tn.rval + 0200*1 ); | |
763 | if( o==INCR && p->in.left->in.op==REG ) return( p->in.left->tn.rval + 0200*2 ); | |
764 | if( o==ASG MINUS && p->in.left->in.op==REG) return( p->in.left->tn.rval + 0200*4 ); | |
765 | if( o==UNARY MUL && p->in.left->in.op==INCR && p->in.left->in.left->in.op==REG | |
766 | && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) | |
767 | return( p->in.left->in.left->tn.rval + 0200*(1+2) ); | |
6eafb37d | 768 | if( o==NAME ) return( 100 + 0200*1 ); |
439a068b ML |
769 | return( -1 ); |
770 | } | |
771 | ||
772 | offset( p, tyl ) register NODE *p; int tyl; { | |
773 | ||
88bb0c9f KM |
774 | if( tyl==1 && |
775 | p->in.op==REG && | |
776 | (p->in.type==INT || p->in.type==UNSIGNED) ) | |
777 | return( p->tn.rval ); | |
778 | if( p->in.op==LS && | |
779 | p->in.left->in.op==REG && | |
780 | (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && | |
781 | p->in.right->in.op==ICON && | |
782 | p->in.right->in.name[0]=='\0' && | |
783 | (1<<p->in.right->tn.lval)==tyl) | |
784 | return( p->in.left->tn.rval ); | |
785 | if( tyl==2 && | |
786 | p->in.op==PLUS && | |
787 | (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && | |
788 | p->in.left->in.op==REG && | |
789 | p->in.right->in.op==REG && | |
790 | p->in.left->tn.rval==p->in.right->tn.rval ) | |
439a068b ML |
791 | return( p->in.left->tn.rval ); |
792 | return( -1 ); | |
793 | } | |
794 | ||
795 | makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { | |
796 | register NODE *t; | |
439a068b ML |
797 | NODE *f; |
798 | ||
799 | p->in.op = OREG; | |
800 | f = p->in.left; /* have to free this subtree later */ | |
801 | ||
802 | /* init base */ | |
803 | switch (q->in.op) { | |
804 | case ICON: | |
805 | case REG: | |
806 | case OREG: | |
6eafb37d | 807 | case NAME: |
439a068b ML |
808 | t = q; |
809 | break; | |
810 | ||
811 | case MINUS: | |
812 | q->in.right->tn.lval = -q->in.right->tn.lval; | |
813 | case PLUS: | |
814 | t = q->in.right; | |
815 | break; | |
816 | ||
817 | case INCR: | |
818 | case ASG MINUS: | |
819 | t = q->in.left; | |
820 | break; | |
821 | ||
822 | case UNARY MUL: | |
823 | t = q->in.left->in.left; | |
824 | break; | |
825 | ||
826 | default: | |
827 | cerror("illegal makeor2"); | |
828 | } | |
829 | ||
830 | p->tn.lval = t->tn.lval; | |
831 | #ifndef FLEXNAMES | |
6dc2c6c8 DS |
832 | { |
833 | register int i; | |
834 | for(i=0; i<NCHNAM; ++i) | |
835 | p->in.name[i] = t->in.name[i]; | |
836 | } | |
439a068b ML |
837 | #else |
838 | p->in.name = t->in.name; | |
839 | #endif | |
840 | ||
841 | /* init offset */ | |
842 | p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); | |
843 | ||
844 | tfree(f); | |
845 | return; | |
846 | } | |
847 | ||
848 | canaddr( p ) NODE *p; { | |
849 | register int o = p->in.op; | |
850 | ||
851 | if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); | |
852 | return(0); | |
853 | } | |
854 | ||
74789784 DS |
855 | flshape( p ) NODE *p; { |
856 | register int o = p->in.op; | |
857 | ||
858 | return( o == REG || o == NAME || o == ICON || | |
859 | (o == OREG && (!R2TEST(p->tn.rval) || tlen(p) == 1)) ); | |
439a068b ML |
860 | } |
861 | ||
10902f65 | 862 | /* INTEMP shapes must not contain any temporary registers */ |
439a068b | 863 | shtemp( p ) register NODE *p; { |
10902f65 DS |
864 | int r; |
865 | ||
439a068b | 866 | if( p->in.op == STARG ) p = p->in.left; |
10902f65 DS |
867 | |
868 | switch (p->in.op) { | |
869 | case REG: | |
870 | return( !istreg(p->tn.rval) ); | |
871 | case OREG: | |
872 | r = p->tn.rval; | |
873 | if( R2TEST(r) ) { | |
874 | if( istreg(R2UPK1(r)) ) | |
875 | return(0); | |
876 | r = R2UPK2(r); | |
877 | } | |
878 | return( !istreg(r) ); | |
10902f65 DS |
879 | case UNARY MUL: |
880 | p = p->in.left; | |
881 | return( p->in.op != UNARY MUL && shtemp(p) ); | |
10902f65 DS |
882 | } |
883 | ||
884 | if( optype( p->in.op ) != LTYPE ) return(0); | |
885 | return(1); | |
439a068b ML |
886 | } |
887 | ||
888 | shumul( p ) register NODE *p; { | |
74789784 | 889 | register int o; |
439a068b ML |
890 | extern int xdebug; |
891 | ||
892 | if (xdebug) { | |
f221fccf DS |
893 | int val; |
894 | printf("shumul:\n"); | |
895 | eprint(p, 0, &val, &val); | |
439a068b ML |
896 | } |
897 | ||
439a068b ML |
898 | o = p->in.op; |
899 | if( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) return( STARNM ); | |
900 | ||
901 | if( ( o == INCR || o == ASG MINUS ) && | |
902 | ( p->in.left->in.op == REG && p->in.right->in.op == ICON ) && | |
903 | p->in.right->in.name[0] == '\0' ) | |
904 | { | |
f83495a1 | 905 | switch (p->in.type) |
439a068b ML |
906 | { |
907 | case CHAR|PTR: | |
908 | case UCHAR|PTR: | |
909 | o = 1; | |
910 | break; | |
911 | ||
912 | case SHORT|PTR: | |
913 | case USHORT|PTR: | |
914 | o = 2; | |
915 | break; | |
916 | ||
917 | case INT|PTR: | |
918 | case UNSIGNED|PTR: | |
919 | case LONG|PTR: | |
920 | case ULONG|PTR: | |
921 | case FLOAT|PTR: | |
922 | o = 4; | |
923 | break; | |
924 | ||
925 | case DOUBLE|PTR: | |
926 | o = 8; | |
927 | break; | |
928 | ||
929 | default: | |
262eaf56 RC |
930 | if ( ISPTR(p->in.type) && |
931 | ISPTR(DECREF(p->in.type)) ) { | |
439a068b ML |
932 | o = 4; |
933 | break; | |
934 | } | |
935 | else return(0); | |
936 | } | |
937 | return( p->in.right->tn.lval == o ? STARREG : 0); | |
938 | } | |
939 | ||
940 | return( 0 ); | |
941 | } | |
942 | ||
943 | adrcon( val ) CONSZ val; { | |
88bb0c9f | 944 | putchar( '$' ); |
439a068b ML |
945 | printf( CONFMT, val ); |
946 | } | |
947 | ||
948 | conput( p ) register NODE *p; { | |
949 | switch( p->in.op ){ | |
950 | ||
951 | case ICON: | |
952 | acon( p ); | |
953 | return; | |
954 | ||
955 | case REG: | |
88bb0c9f | 956 | putstr( rnames[p->tn.rval] ); |
439a068b ML |
957 | return; |
958 | ||
959 | default: | |
960 | cerror( "illegal conput" ); | |
961 | } | |
962 | } | |
963 | ||
4ab1e9a8 | 964 | /*ARGSUSED*/ |
6dc2c6c8 | 965 | insput( p ) NODE *p; { |
439a068b ML |
966 | cerror( "insput" ); |
967 | } | |
968 | ||
70f59a26 DS |
969 | upput( p, size ) NODE *p; int size; { |
970 | if( size == SZLONG && p->in.op == REG ) { | |
971 | putstr( rnames[p->tn.rval + 1] ); | |
972 | return; | |
973 | } | |
439a068b ML |
974 | cerror( "upput" ); |
975 | } | |
976 | ||
977 | adrput( p ) register NODE *p; { | |
978 | register int r; | |
979 | /* output an address, with offsets, from p */ | |
980 | ||
981 | if( p->in.op == FLD ){ | |
982 | p = p->in.left; | |
983 | } | |
984 | switch( p->in.op ){ | |
985 | ||
986 | case NAME: | |
987 | acon( p ); | |
988 | return; | |
989 | ||
990 | case ICON: | |
991 | /* addressable value of the constant */ | |
88bb0c9f | 992 | putchar( '$' ); |
439a068b ML |
993 | acon( p ); |
994 | return; | |
995 | ||
996 | case REG: | |
88bb0c9f | 997 | putstr( rnames[p->tn.rval] ); |
439a068b ML |
998 | return; |
999 | ||
1000 | case OREG: | |
1001 | r = p->tn.rval; | |
1002 | if( R2TEST(r) ){ /* double indexing */ | |
1003 | register int flags; | |
1004 | ||
1005 | flags = R2UPK3(r); | |
88bb0c9f KM |
1006 | if( flags & 1 ) putchar('*'); |
1007 | if( flags & 4 ) putchar('-'); | |
439a068b ML |
1008 | if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); |
1009 | if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); | |
88bb0c9f | 1010 | if( flags & 2 ) putchar('+'); |
439a068b ML |
1011 | printf( "[%s]", rnames[R2UPK2(r)] ); |
1012 | return; | |
1013 | } | |
1014 | if( r == AP ){ /* in the argument region */ | |
237a345d | 1015 | if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); |
439a068b | 1016 | printf( CONFMT, p->tn.lval ); |
88bb0c9f | 1017 | putstr( "(ap)" ); |
439a068b ML |
1018 | return; |
1019 | } | |
1020 | if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); | |
1021 | printf( "(%s)", rnames[p->tn.rval] ); | |
1022 | return; | |
1023 | ||
1024 | case UNARY MUL: | |
1025 | /* STARNM or STARREG found */ | |
1026 | if( tshape(p, STARNM) ) { | |
88bb0c9f | 1027 | putchar( '*' ); |
439a068b ML |
1028 | adrput( p->in.left); |
1029 | } | |
1030 | else { /* STARREG - really auto inc or dec */ | |
1031 | register NODE *q; | |
1032 | ||
439a068b | 1033 | q = p->in.left; |
262eaf56 RC |
1034 | if( q->in.right->tn.lval != tlen(p) ) |
1035 | cerror("adrput: bad auto-increment/decrement"); | |
f83495a1 RC |
1036 | printf("%s(%s)%s", (q->in.op==INCR ? "" : "-"), |
1037 | rnames[q->in.left->tn.rval], | |
1038 | (q->in.op==INCR ? "+" : "") ); | |
1039 | p->in.op = OREG; | |
1040 | p->tn.rval = q->in.left->tn.rval; | |
1041 | p->tn.lval = (q->in.op == INCR ? -q->in.right->tn.lval : 0); | |
439a068b ML |
1042 | #ifndef FLEXNAMES |
1043 | p->in.name[0] = '\0'; | |
1044 | #else | |
1045 | p->in.name = ""; | |
1046 | #endif | |
1047 | tfree(q); | |
1048 | } | |
1049 | return; | |
1050 | ||
1051 | default: | |
1052 | cerror( "illegal address" ); | |
1053 | return; | |
1054 | ||
1055 | } | |
1056 | ||
1057 | } | |
1058 | ||
1059 | acon( p ) register NODE *p; { /* print out a constant */ | |
1060 | ||
74789784 | 1061 | if( p->in.name[0] == '\0' ) |
439a068b | 1062 | printf( CONFMT, p->tn.lval); |
74789784 | 1063 | else { |
439a068b ML |
1064 | #ifndef FLEXNAMES |
1065 | printf( "%.8s", p->in.name ); | |
1066 | #else | |
88bb0c9f | 1067 | putstr( p->in.name ); |
439a068b | 1068 | #endif |
74789784 DS |
1069 | if( p->tn.lval != 0 ) { |
1070 | putchar( '+' ); | |
1071 | printf( CONFMT, p->tn.lval ); | |
1072 | } | |
439a068b ML |
1073 | } |
1074 | } | |
439a068b ML |
1075 | |
1076 | genscall( p, cookie ) register NODE *p; { | |
1077 | /* structure valued call */ | |
1078 | return( gencall( p, cookie ) ); | |
1079 | } | |
1080 | ||
1081 | /* tbl */ | |
1082 | int gc_numbytes; | |
1083 | /* tbl */ | |
1084 | ||
6dc2c6c8 | 1085 | /*ARGSUSED*/ |
439a068b ML |
1086 | gencall( p, cookie ) register NODE *p; { |
1087 | /* generate the call given by p */ | |
3add848c | 1088 | register NODE *p1; |
74789784 DS |
1089 | register int temp, temp1; |
1090 | register int m; | |
439a068b ML |
1091 | |
1092 | if( p->in.right ) temp = argsize( p->in.right ); | |
1093 | else temp = 0; | |
1094 | ||
1095 | if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ | |
1096 | /* set aside room for structure return */ | |
1097 | ||
1098 | if( p->stn.stsize > temp ) temp1 = p->stn.stsize; | |
1099 | else temp1 = temp; | |
1100 | } | |
1101 | ||
1102 | if( temp > maxargs ) maxargs = temp; | |
1103 | SETOFF(temp1,4); | |
1104 | ||
1105 | if( p->in.right ){ /* make temp node, put offset in, and generate args */ | |
3add848c | 1106 | genargs( p->in.right ); |
439a068b ML |
1107 | } |
1108 | ||
1109 | p1 = p->in.left; | |
1110 | if( p1->in.op != ICON ){ | |
1111 | if( p1->in.op != REG ){ | |
1112 | if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ | |
1113 | if( p1->in.op != NAME ){ | |
1114 | order( p1, INAREG ); | |
1115 | } | |
1116 | } | |
1117 | } | |
1118 | } | |
1119 | ||
439a068b ML |
1120 | /* tbl |
1121 | setup gc_numbytes so reference to ZC works */ | |
1122 | ||
1123 | gc_numbytes = temp&(0x3ff); | |
1124 | /* tbl */ | |
1125 | ||
1126 | p->in.op = UNARY CALL; | |
1127 | m = match( p, INTAREG|INTBREG ); | |
1128 | ||
1129 | /* compensate for deficiency in 'ret' instruction ... wah,kre */ | |
1130 | /* (plus in assignment to gc_numbytes above, for neatness only) */ | |
1131 | if (temp >= 1024) | |
1132 | printf(" addl2 $%d,sp\n", (temp&(~0x3ff))); | |
1133 | ||
439a068b ML |
1134 | return(m != MDONE); |
1135 | } | |
1136 | ||
1137 | /* tbl */ | |
1138 | char * | |
1139 | ccbranches[] = { | |
74789784 DS |
1140 | "eql", |
1141 | "neq", | |
1142 | "leq", | |
1143 | "lss", | |
1144 | "geq", | |
1145 | "gtr", | |
1146 | "lequ", | |
1147 | "lssu", | |
1148 | "gequ", | |
1149 | "gtru", | |
439a068b ML |
1150 | }; |
1151 | /* tbl */ | |
1152 | ||
6dc2c6c8 | 1153 | /*ARGSUSED*/ |
439a068b ML |
1154 | cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ |
1155 | ||
74789784 DS |
1156 | if( o != 0 && ( o < EQ || o > UGT ) ) |
1157 | cerror( "bad conditional branch: %s", opst[o] ); | |
1158 | printf( " j%s L%d\n", o == 0 ? "br" : ccbranches[o-EQ], lab ); | |
439a068b ML |
1159 | } |
1160 | ||
1161 | nextcook( p, cookie ) NODE *p; { | |
1162 | /* we have failed to match p with cookie; try another */ | |
1163 | if( cookie == FORREW ) return( 0 ); /* hopeless! */ | |
1164 | if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); | |
1165 | if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); | |
1166 | return( FORREW ); | |
1167 | } | |
1168 | ||
6dc2c6c8 | 1169 | /*ARGSUSED*/ |
439a068b ML |
1170 | lastchance( p, cook ) NODE *p; { |
1171 | /* forget it! */ | |
1172 | return(0); | |
1173 | } | |
1174 | ||
1175 | optim2( p ) register NODE *p; { | |
1176 | /* do local tree transformations and optimizations */ | |
1177 | ||
71cac6bf | 1178 | int o; |
bcc20d15 | 1179 | int i, mask; |
472582a4 | 1180 | register NODE *l, *r; |
439a068b | 1181 | |
71cac6bf | 1182 | switch( o = p->in.op ) { |
439a068b ML |
1183 | |
1184 | case AND: | |
85696ba1 | 1185 | /* commute L and R to eliminate complements and constants */ |
472582a4 RC |
1186 | if( (l = p->in.left)->in.op == ICON && l->in.name[0] == 0 || |
1187 | l->in.op == COMPL ) { | |
439a068b | 1188 | p->in.left = p->in.right; |
472582a4 | 1189 | p->in.right = l; |
439a068b ML |
1190 | } |
1191 | case ASG AND: | |
1192 | /* change meaning of AND to ~R&L - bic on pdp11 */ | |
1193 | r = p->in.right; | |
89ccccb8 DS |
1194 | if( r->in.op==ICON && r->in.name[0]==0 ) { |
1195 | /* check for degenerate operations */ | |
1196 | l = p->in.left; | |
bcc20d15 DS |
1197 | mask = (1 << tlen(l) * SZCHAR) - 1; |
1198 | if( ISUNSIGNED(r->in.type) ) { | |
6eafb37d DS |
1199 | i = (~r->tn.lval & mask); |
1200 | if( i == 0 ) { | |
bcc20d15 DS |
1201 | r->in.op = FREE; |
1202 | ncopy(p, l); | |
1203 | l->in.op = FREE; | |
1204 | break; | |
1205 | } | |
6eafb37d | 1206 | else if( i == mask ) |
bcc20d15 DS |
1207 | goto zero; |
1208 | else | |
1209 | r->tn.lval = i; | |
6eafb37d | 1210 | break; |
bcc20d15 DS |
1211 | } |
1212 | else if( r->tn.lval == mask && | |
1213 | tlen(l) < SZINT/SZCHAR ) { | |
1214 | r->in.op = SCONV; | |
1215 | r->in.left = l; | |
1216 | r->in.right = 0; | |
1217 | r->in.type = ENUNSIGN(l->in.type); | |
1218 | r->in.su = l->in.su > 1 ? l->in.su : 1; | |
1219 | ncopy(p, r); | |
1220 | p->in.left = r; | |
1221 | p->in.type = INT; | |
89ccccb8 DS |
1222 | break; |
1223 | } | |
1224 | /* complement constant */ | |
439a068b ML |
1225 | r->tn.lval = ~r->tn.lval; |
1226 | } | |
1227 | else if( r->in.op==COMPL ) { /* ~~A => A */ | |
1228 | r->in.op = FREE; | |
1229 | p->in.right = r->in.left; | |
1230 | } | |
1231 | else { /* insert complement node */ | |
472582a4 RC |
1232 | p->in.right = l = talloc(); |
1233 | l->in.op = COMPL; | |
1234 | l->in.rall = NOPREF; | |
1235 | l->in.type = r->in.type; | |
1236 | l->in.left = r; | |
1237 | l->in.right = NULL; | |
439a068b ML |
1238 | } |
1239 | break; | |
1240 | ||
472582a4 | 1241 | case SCONV: |
85696ba1 | 1242 | l = p->in.left; |
6eafb37d DS |
1243 | if( (l->in.type == UCHAR || l->in.type == USHORT) && |
1244 | (p->in.type == DOUBLE || p->in.type == FLOAT) ) { | |
1245 | /* we can convert to INT without loss of significance */ | |
1246 | r = talloc(); | |
1247 | *r = *p; | |
1248 | r->in.type = INT; | |
1249 | p->in.left = r; | |
1250 | #if !defined(FORT) && !defined(SPRECC) | |
1251 | /* nothing to be 'gained' by a FLOAT conversion */ | |
1252 | p->in.type = DOUBLE; | |
1253 | #endif | |
1254 | return; | |
1255 | } | |
262eaf56 | 1256 | #if defined(FORT) || defined(SPRECC) |
7f12173b | 1257 | if( p->in.type == FLOAT || p->in.type == DOUBLE || |
85696ba1 KM |
1258 | l->in.type == FLOAT || l->in.type == DOUBLE ) |
1259 | return; | |
7f12173b | 1260 | #else |
85696ba1 | 1261 | if( mixtypes(p, l) ) return; |
7f12173b | 1262 | #endif |
6eafb37d DS |
1263 | if( l->in.op == PCONV ) |
1264 | return; | |
1265 | if( (l->in.op == CALL || l->in.op == UNARY CALL) && | |
1266 | l->in.type != INT && l->in.type != UNSIGNED ) | |
4bcc0eaf DS |
1267 | return; |
1268 | ||
85696ba1 KM |
1269 | /* Only trust it to get it right if the size is the same */ |
1270 | if( tlen(p) != tlen(l) ) | |
1271 | return; | |
472582a4 RC |
1272 | |
1273 | /* clobber conversion */ | |
85696ba1 | 1274 | if( l->in.op != FLD ) |
472582a4 RC |
1275 | l->in.type = p->in.type; |
1276 | ncopy( p, l ); | |
1277 | l->in.op = FREE; | |
85696ba1 | 1278 | |
472582a4 RC |
1279 | break; |
1280 | ||
88bb0c9f KM |
1281 | case ASSIGN: |
1282 | /* | |
1283 | * Conversions are equivalent to assignments; | |
1284 | * when the two operations are combined, | |
1285 | * we can sometimes zap the conversion. | |
1286 | */ | |
1287 | r = p->in.right; | |
1288 | l = p->in.left; | |
1289 | if ( r->in.op == SCONV && | |
1290 | !mixtypes(l, r) && | |
ef3be726 | 1291 | l->in.op != FLD && |
88bb0c9f KM |
1292 | tlen(l) == tlen(r) ) { |
1293 | p->in.right = r->in.left; | |
1294 | r->in.op = FREE; | |
1295 | } | |
6eafb37d DS |
1296 | else if( (r->in.type == UCHAR || r->in.type == USHORT) && |
1297 | (p->in.type == DOUBLE || p->in.type == FLOAT) ) { | |
1298 | /* we can convert to INT without loss of significance */ | |
1299 | l = talloc(); | |
1300 | l->in.op = SCONV; | |
1301 | l->in.rall = NOPREF; | |
1302 | l->in.left = r; | |
1303 | l->in.right = NULL; | |
1304 | l->in.type = INT; | |
1305 | p->in.right = r; | |
1306 | return; | |
1307 | } | |
88bb0c9f KM |
1308 | break; |
1309 | ||
71cac6bf DS |
1310 | case ULE: |
1311 | case ULT: | |
1312 | case UGE: | |
1313 | case UGT: | |
89ccccb8 DS |
1314 | p->in.op -= (UGE-GE); |
1315 | if( degenerate(p) ) | |
1316 | break; | |
1317 | p->in.op += (UGE-GE); | |
1318 | break; | |
1319 | ||
71cac6bf DS |
1320 | case EQ: |
1321 | case NE: | |
1322 | case LE: | |
1323 | case LT: | |
1324 | case GE: | |
1325 | case GT: | |
6eafb37d DS |
1326 | if( p->in.left->in.op == SCONV && |
1327 | p->in.right->in.op == SCONV ) { | |
1328 | l = p->in.left; | |
1329 | r = p->in.right; | |
1330 | if( l->in.type == DOUBLE && | |
1331 | l->in.left->in.type == FLOAT && | |
1332 | r->in.left->in.type == FLOAT ) { | |
1333 | /* nuke the conversions */ | |
1334 | p->in.left = l->in.left; | |
1335 | p->in.right = r->in.left; | |
1336 | l->in.op = FREE; | |
1337 | r->in.op = FREE; | |
1338 | } | |
1339 | /* more? */ | |
1340 | } | |
89ccccb8 DS |
1341 | (void) degenerate(p); |
1342 | break; | |
1343 | ||
1344 | case DIV: | |
1345 | if( p->in.right->in.op == ICON && | |
1346 | p->in.right->tn.name[0] == '\0' && | |
1347 | ISUNSIGNED(p->in.right->in.type) && | |
1348 | (unsigned) p->in.right->tn.lval >= 0x80000000 ) { | |
1349 | /* easy to do here, harder to do in zzzcode() */ | |
1350 | p->in.op = UGE; | |
71cac6bf | 1351 | break; |
89ccccb8 DS |
1352 | } |
1353 | case MOD: | |
1354 | case ASG DIV: | |
1355 | case ASG MOD: | |
1356 | /* | |
1357 | * optimize DIV and MOD | |
1358 | * | |
1359 | * basically we spot UCHAR and USHORT and try to do them | |
1360 | * as signed ints... apparently div+mul+sub is always | |
1361 | * faster than ediv for finding MOD on the VAX, when | |
1362 | * full unsigned MOD isn't needed. | |
1363 | * | |
1364 | * a curious fact: for MOD, cmp+sub and cmp+sub+cmp+sub | |
1365 | * are faster for unsigned dividend and a constant divisor | |
1366 | * in the right range (.5 to 1 of dividend's range for the | |
1367 | * first, .333+ to .5 for the second). full unsigned is | |
1368 | * already done cmp+sub in the appropriate case; the | |
1369 | * other cases are less common and require more ambition. | |
1370 | */ | |
1371 | if( degenerate(p) ) | |
71cac6bf | 1372 | break; |
89ccccb8 DS |
1373 | l = p->in.left; |
1374 | r = p->in.right; | |
1375 | if( !ISUNSIGNED(r->in.type) || | |
1376 | tlen(l) >= SZINT/SZCHAR || | |
1377 | !(tlen(r) < SZINT/SZCHAR || | |
1378 | (r->in.op == ICON && r->tn.name[0] == '\0')) ) | |
71cac6bf | 1379 | break; |
89ccccb8 DS |
1380 | if( r->in.op == ICON ) |
1381 | r->tn.type = INT; | |
1382 | else { | |
1383 | NODE *t = talloc(); | |
1384 | t->in.left = r; | |
1385 | r = t; | |
1386 | r->in.op = SCONV; | |
1387 | r->in.type = INT; | |
1388 | r->in.right = 0; | |
1389 | p->in.right = r; | |
71cac6bf | 1390 | } |
89ccccb8 DS |
1391 | if( o == DIV || o == MOD ) { |
1392 | NODE *t = talloc(); | |
1393 | t->in.left = l; | |
1394 | l = t; | |
1395 | l->in.op = SCONV; | |
1396 | l->in.type = INT; | |
1397 | l->in.right = 0; | |
1398 | p->in.left = l; | |
1399 | } | |
1400 | /* handle asgops in table */ | |
1401 | break; | |
1402 | ||
1403 | case RS: | |
1404 | case ASG RS: | |
1405 | case LS: | |
1406 | case ASG LS: | |
1407 | /* pick up degenerate shifts */ | |
1408 | l = p->in.left; | |
1409 | r = p->in.right; | |
1410 | if( !(r->in.op == ICON && r->tn.name[0] == '\0') ) | |
71cac6bf | 1411 | break; |
89ccccb8 DS |
1412 | i = r->tn.lval; |
1413 | if( i < 0 ) | |
1414 | /* front end 'fixes' this? */ | |
1415 | if( o == LS || o == ASG LS ) | |
1416 | o += (RS-LS); | |
1417 | else | |
1418 | o += (LS-RS); | |
1419 | if( (o == RS || o == ASG RS) && | |
1420 | !ISUNSIGNED(l->in.type) ) | |
1421 | /* can't optimize signed right shifts */ | |
71cac6bf | 1422 | break; |
74789784 DS |
1423 | if( o == LS ) { |
1424 | if( i < SZINT ) | |
1425 | break; | |
1426 | } | |
1427 | else { | |
1428 | if( i < tlen(l) * SZCHAR ) | |
1429 | break; | |
1430 | } | |
89ccccb8 DS |
1431 | zero: |
1432 | if( !asgop( o ) ) | |
1433 | if( tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { | |
1434 | /* no side effects */ | |
bcc20d15 | 1435 | tfree(l); |
89ccccb8 DS |
1436 | ncopy(p, r); |
1437 | r->in.op = FREE; | |
1438 | p->tn.lval = 0; | |
1439 | } | |
1440 | else { | |
1441 | p->in.op = COMOP; | |
bcc20d15 | 1442 | r->tn.lval = 0; |
89ccccb8 DS |
1443 | } |
1444 | else { | |
1445 | p->in.op = ASSIGN; | |
1446 | r->tn.lval = 0; | |
71cac6bf | 1447 | } |
89ccccb8 DS |
1448 | break; |
1449 | } | |
1450 | } | |
1451 | ||
1452 | degenerate(p) register NODE *p; { | |
1453 | int o; | |
1454 | int result, i; | |
1455 | int lower, upper; | |
1456 | register NODE *l, *r; | |
1457 | ||
1458 | /* | |
1459 | * try to keep degenerate comparisons with constants | |
1460 | * out of the table. | |
1461 | */ | |
1462 | r = p->in.right; | |
1463 | l = p->in.left; | |
1464 | if( r->in.op != ICON || | |
1465 | r->tn.name[0] != '\0' || | |
1466 | tlen(l) >= tlen(r) ) | |
1467 | return (0); | |
1468 | switch( l->in.type ) { | |
1469 | case CHAR: | |
1470 | lower = -(1 << SZCHAR - 1); | |
1471 | upper = (1 << SZCHAR - 1) - 1; | |
1472 | break; | |
1473 | case UCHAR: | |
1474 | lower = 0; | |
1475 | upper = (1 << SZCHAR) - 1; | |
1476 | break; | |
1477 | case SHORT: | |
1478 | lower = -(1 << SZSHORT - 1); | |
1479 | upper = (1 << SZSHORT - 1) - 1; | |
1480 | break; | |
1481 | case USHORT: | |
1482 | lower = 0; | |
1483 | upper = (1 << SZSHORT) - 1; | |
1484 | break; | |
1485 | default: | |
bcc20d15 | 1486 | cerror("unsupported type in degenerate()"); |
89ccccb8 DS |
1487 | } |
1488 | i = r->tn.lval; | |
1489 | switch( o = p->in.op ) { | |
1490 | case DIV: | |
1491 | case ASG DIV: | |
1492 | case MOD: | |
1493 | case ASG MOD: | |
1494 | /* DIV and MOD work like EQ */ | |
1495 | case EQ: | |
1496 | case NE: | |
1497 | if( lower == 0 && (unsigned) i > upper ) | |
1498 | result = o == NE; | |
1499 | else if( i < lower || i > upper ) | |
1500 | result = o == NE; | |
1501 | else | |
1502 | return (0); | |
1503 | break; | |
1504 | case LT: | |
1505 | case GE: | |
1506 | if( lower == 0 && (unsigned) i > upper ) | |
1507 | result = o == LT; | |
1508 | else if( i <= lower ) | |
1509 | result = o != LT; | |
1510 | else if( i > upper ) | |
1511 | result = o == LT; | |
1512 | else | |
1513 | return (0); | |
1514 | break; | |
1515 | case LE: | |
1516 | case GT: | |
1517 | if( lower == 0 && (unsigned) i >= upper ) | |
1518 | result = o == LE; | |
1519 | else if( i < lower ) | |
1520 | result = o != LE; | |
1521 | else if( i >= upper ) | |
1522 | result = o == LE; | |
1523 | else | |
1524 | return (0); | |
1525 | break; | |
1526 | default: | |
1527 | cerror("unknown op in degenerate()"); | |
1528 | } | |
1529 | ||
1530 | if( o == MOD || o == ASG MOD ) { | |
1531 | r->in.op = FREE; | |
1532 | ncopy(p, l); | |
1533 | l->in.op = FREE; | |
1534 | } | |
1535 | else if( o != ASG DIV && tshape(l, SAREG|SNAME|SCON|SOREG|STARNM) ) { | |
1536 | /* no side effects */ | |
bcc20d15 | 1537 | tfree(l); |
89ccccb8 DS |
1538 | ncopy(p, r); |
1539 | r->in.op = FREE; | |
1540 | p->tn.lval = result; | |
1541 | } | |
1542 | else { | |
1543 | if( o == ASG DIV ) | |
1544 | p->in.op = ASSIGN; | |
71cac6bf DS |
1545 | else { |
1546 | p->in.op = COMOP; | |
71cac6bf | 1547 | r->tn.type = INT; |
71cac6bf | 1548 | } |
89ccccb8 | 1549 | r->tn.lval = result; |
439a068b | 1550 | } |
89ccccb8 DS |
1551 | if( logop(o) ) |
1552 | p->in.type = INT; | |
1553 | ||
1554 | return (1); | |
439a068b ML |
1555 | } |
1556 | ||
439a068b ML |
1557 | /* added by jwf */ |
1558 | struct functbl { | |
1559 | int fop; | |
1560 | TWORD ftype; | |
1561 | char *func; | |
1562 | } opfunc[] = { | |
1563 | DIV, TANY, "udiv", | |
1564 | MOD, TANY, "urem", | |
28312bdc RC |
1565 | ASG DIV, TANY, "audiv", |
1566 | ASG MOD, TANY, "aurem", | |
439a068b ML |
1567 | 0, 0, 0 }; |
1568 | ||
1569 | hardops(p) register NODE *p; { | |
1570 | /* change hard to do operators into function calls. */ | |
1571 | register NODE *q; | |
1572 | register struct functbl *f; | |
1573 | register o; | |
262eaf56 | 1574 | NODE *old,*temp; |
439a068b ML |
1575 | |
1576 | o = p->in.op; | |
262eaf56 RC |
1577 | if( ! (optype(o)==BITYPE && |
1578 | (ISUNSIGNED(p->in.left->in.type) || | |
1579 | ISUNSIGNED(p->in.right->in.type))) ) | |
1580 | return; | |
439a068b ML |
1581 | |
1582 | for( f=opfunc; f->fop; f++ ) { | |
1583 | if( o==f->fop ) goto convert; | |
1584 | } | |
1585 | return; | |
1586 | ||
439a068b | 1587 | convert: |
89ccccb8 | 1588 | if( p->in.right->in.op == ICON && p->in.right->tn.name[0] == '\0' ) |
70f59a26 DS |
1589 | /* 'J', 'K' in zzzcode() -- assumes DIV or MOD operations */ |
1590 | /* save a subroutine call -- use at most 5 instructions */ | |
70f59a26 | 1591 | return; |
89ccccb8 DS |
1592 | if( tlen(p->in.left) < SZINT/SZCHAR && tlen(p->in.right) < SZINT/SZCHAR ) |
1593 | /* optim2() will modify the op into an ordinary int op */ | |
1594 | return; | |
439a068b | 1595 | if( asgop( o ) ) { |
262eaf56 | 1596 | old = NIL; |
28312bdc | 1597 | switch( p->in.left->in.op ){ |
262eaf56 RC |
1598 | case FLD: |
1599 | q = p->in.left->in.left; | |
1600 | /* | |
1601 | * rewrite (lval.fld /= rval); as | |
1602 | * ((*temp).fld = udiv((*(temp = &lval)).fld,rval)); | |
1603 | * else the compiler will evaluate lval twice. | |
1604 | */ | |
1605 | if( q->in.op == UNARY MUL ){ | |
1606 | /* first allocate a temp storage */ | |
1607 | temp = talloc(); | |
1608 | temp->in.op = OREG; | |
1609 | temp->tn.rval = TMPREG; | |
1610 | temp->tn.lval = BITOOR(freetemp(1)); | |
1611 | temp->in.type = INCREF(p->in.type); | |
1612 | #ifdef FLEXNAMES | |
1613 | temp->in.name = ""; | |
1614 | #else | |
1615 | temp->in.name[0] = '\0'; | |
1616 | #endif | |
1617 | old = q->in.left; | |
1618 | q->in.left = temp; | |
1619 | } | |
1620 | /* fall thru ... */ | |
1621 | ||
28312bdc RC |
1622 | case REG: |
1623 | case NAME: | |
1624 | case OREG: | |
1625 | /* change ASG OP to a simple OP */ | |
1626 | q = talloc(); | |
1627 | q->in.op = NOASG p->in.op; | |
1628 | q->in.rall = NOPREF; | |
1629 | q->in.type = p->in.type; | |
1630 | q->in.left = tcopy(p->in.left); | |
1631 | q->in.right = p->in.right; | |
1632 | p->in.op = ASSIGN; | |
1633 | p->in.right = q; | |
1634 | p = q; | |
1635 | f -= 2; /* Note: this depends on the table order */ | |
262eaf56 RC |
1636 | /* on the right side only - replace *temp with |
1637 | *(temp = &lval), build the assignment node */ | |
1638 | if( old ){ | |
1639 | temp = q->in.left->in.left; /* the "*" node */ | |
1640 | q = talloc(); | |
1641 | q->in.op = ASSIGN; | |
1642 | q->in.left = temp->in.left; | |
1643 | q->in.right = old; | |
1644 | q->in.type = old->in.type; | |
1645 | #ifdef FLEXNAMES | |
1646 | q->in.name = ""; | |
1647 | #else | |
1648 | q->in.name[0] = '\0'; | |
1649 | #endif | |
1650 | temp->in.left = q; | |
1651 | } | |
28312bdc RC |
1652 | break; |
1653 | ||
1654 | case UNARY MUL: | |
1655 | /* avoid doing side effects twice */ | |
1656 | q = p->in.left; | |
1657 | p->in.left = q->in.left; | |
1658 | q->in.op = FREE; | |
1659 | break; | |
1660 | ||
1661 | default: | |
1662 | cerror( "hardops: can't compute & LHS" ); | |
1663 | } | |
262eaf56 | 1664 | } |
439a068b ML |
1665 | |
1666 | /* build comma op for args to function */ | |
1667 | q = talloc(); | |
1668 | q->in.op = CM; | |
1669 | q->in.rall = NOPREF; | |
1670 | q->in.type = INT; | |
1671 | q->in.left = p->in.left; | |
1672 | q->in.right = p->in.right; | |
1673 | p->in.op = CALL; | |
1674 | p->in.right = q; | |
1675 | ||
1676 | /* put function name in left node of call */ | |
1677 | p->in.left = q = talloc(); | |
1678 | q->in.op = ICON; | |
1679 | q->in.rall = NOPREF; | |
1680 | q->in.type = INCREF( FTN + p->in.type ); | |
1681 | #ifndef FLEXNAMES | |
1682 | strcpy( q->in.name, f->func ); | |
1683 | #else | |
1684 | q->in.name = f->func; | |
1685 | #endif | |
1686 | q->tn.lval = 0; | |
1687 | q->tn.rval = 0; | |
1688 | ||
439a068b ML |
1689 | } |
1690 | ||
262eaf56 RC |
1691 | zappost(p) NODE *p; { |
1692 | /* look for ++ and -- operators and remove them */ | |
1693 | ||
74789784 | 1694 | register int o, ty; |
262eaf56 RC |
1695 | register NODE *q; |
1696 | o = p->in.op; | |
1697 | ty = optype( o ); | |
1698 | ||
1699 | switch( o ){ | |
1700 | ||
1701 | case INCR: | |
1702 | case DECR: | |
1703 | q = p->in.left; | |
1704 | p->in.right->in.op = FREE; /* zap constant */ | |
1705 | ncopy( p, q ); | |
1706 | q->in.op = FREE; | |
1707 | return; | |
1708 | ||
1709 | } | |
1710 | ||
1711 | if( ty == BITYPE ) zappost( p->in.right ); | |
1712 | if( ty != LTYPE ) zappost( p->in.left ); | |
1713 | } | |
1714 | ||
1715 | fixpre(p) NODE *p; { | |
1716 | ||
74789784 | 1717 | register int o, ty; |
262eaf56 RC |
1718 | o = p->in.op; |
1719 | ty = optype( o ); | |
1720 | ||
1721 | switch( o ){ | |
1722 | ||
1723 | case ASG PLUS: | |
1724 | p->in.op = PLUS; | |
1725 | break; | |
1726 | case ASG MINUS: | |
1727 | p->in.op = MINUS; | |
1728 | break; | |
1729 | } | |
1730 | ||
1731 | if( ty == BITYPE ) fixpre( p->in.right ); | |
1732 | if( ty != LTYPE ) fixpre( p->in.left ); | |
1733 | } | |
1734 | ||
74789784 DS |
1735 | /*ARGSUSED*/ |
1736 | NODE * addroreg(l) NODE *l; | |
1737 | /* OREG was built in clocal() | |
1738 | * for an auto or formal parameter | |
1739 | * now its address is being taken | |
1740 | * local code must unwind it | |
1741 | * back to PLUS/MINUS REG ICON | |
1742 | * according to local conventions | |
1743 | */ | |
1744 | { | |
1745 | cerror("address of OREG taken"); | |
1746 | /*NOTREACHED*/ | |
1747 | } | |
1748 | ||
1749 | ||
1750 | ||
1751 | # ifndef ONEPASS | |
1752 | main( argc, argv ) char *argv[]; { | |
1753 | return( mainp2( argc, argv ) ); | |
1754 | } | |
1755 | # endif | |
1756 | ||
88bb0c9f KM |
1757 | strip(p) register NODE *p; { |
1758 | NODE *q; | |
1759 | ||
1760 | /* strip nodes off the top when no side effects occur */ | |
1761 | for( ; ; ) { | |
1762 | switch( p->in.op ) { | |
1763 | case SCONV: /* remove lint tidbits */ | |
1764 | q = p->in.left; | |
1765 | ncopy( p, q ); | |
1766 | q->in.op = FREE; | |
1767 | break; | |
1768 | /* could probably add a few more here */ | |
1769 | default: | |
1770 | return; | |
1771 | } | |
1772 | } | |
1773 | } | |
1774 | ||
439a068b | 1775 | myreader(p) register NODE *p; { |
88bb0c9f | 1776 | strip( p ); /* strip off operations with no side effects */ |
262eaf56 | 1777 | canon( p ); /* expands r-vals for fields */ |
439a068b | 1778 | walkf( p, hardops ); /* convert ops to function calls */ |
439a068b | 1779 | walkf( p, optim2 ); |
439a068b | 1780 | } |