Commit | Line | Data |
---|---|---|
f2b49199 | 1 | #ifndef lint |
1d43595d | 2 | static char sccsid[] = "@(#)local2.c 1.3 (Berkeley) %G%"; |
f2b49199 SL |
3 | #endif |
4 | ||
5 | # include "mfile2" | |
6 | # include "ctype.h" | |
7 | # ifdef FORT | |
8 | int ftlab1, ftlab2; | |
9 | # endif | |
10 | /* a lot of the machine dependent parts of the second pass */ | |
11 | ||
12 | # define BITMASK(n) ((1L<<n)-1) | |
13 | ||
14 | # ifndef ONEPASS | |
15 | where(c){ | |
16 | fprintf( stderr, "%s, line %d: ", filename, lineno ); | |
17 | } | |
18 | # endif | |
19 | ||
20 | lineid( l, fn ) char *fn; { | |
21 | /* identify line l and file fn */ | |
22 | printf( "# line %d, file %s\n", l, fn ); | |
23 | } | |
24 | ||
25 | int ent_mask; | |
26 | ||
27 | eobl2(){ | |
28 | register OFFSZ spoff; /* offset from stack pointer */ | |
29 | #ifndef FORT | |
30 | extern int ftlab1, ftlab2; | |
31 | #endif | |
32 | ||
33 | spoff = maxoff; | |
34 | spoff /= SZCHAR; | |
35 | SETOFF(spoff,4); | |
36 | #ifdef FORT | |
37 | #ifndef FLEXNAMES | |
38 | printf( " .set .F%d,%d\n", ftnno, spoff ); | |
39 | #else | |
40 | /* SHOULD BE L%d ... ftnno but must change pc/f77 */ | |
41 | printf( " .set LF%d,%d\n", ftnno, spoff ); | |
42 | #endif | |
43 | printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000); | |
44 | #else | |
45 | printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc); | |
46 | printf( "L%d:\n", ftlab1); | |
47 | if( maxoff > AUTOINIT ) | |
48 | printf( " subl3 $%d,fp,sp\n", spoff); | |
49 | printf( " jbr L%d\n", ftlab2); | |
50 | #endif | |
51 | ent_mask = 0; | |
52 | maxargs = -1; | |
53 | } | |
54 | ||
55 | struct hoptab { int opmask; char * opstring; } ioptab[] = { | |
56 | ||
57 | PLUS, "add", | |
58 | MINUS, "sub", | |
59 | MUL, "mul", | |
60 | DIV, "div", | |
61 | MOD, "div", | |
62 | OR, "or", | |
63 | ER, "xor", | |
64 | AND, "and", | |
65 | -1, "" }; | |
66 | ||
67 | hopcode( f, o ){ | |
68 | /* output the appropriate string from the above table */ | |
69 | ||
70 | register struct hoptab *q; | |
71 | ||
72 | if(asgop(o)) | |
73 | o = NOASG o; | |
74 | for( q = ioptab; q->opmask>=0; ++q ){ | |
75 | if( q->opmask == o ){ | |
76 | if(f == 'E') | |
77 | printf( "e%s", q->opstring); | |
78 | else | |
79 | printf( "%s%c", q->opstring, tolower(f)); | |
80 | return; | |
81 | } | |
82 | } | |
83 | cerror( "no hoptab for %s", opst[o] ); | |
84 | } | |
85 | ||
86 | char * | |
87 | rnames[] = { /* keyed to register number tokens */ | |
88 | ||
89 | "r0", "r1", | |
90 | "r2", "r3", "r4", "r5", | |
91 | "r6", "r7", "r8", "r9", "r10", "r11", | |
92 | "r12", "fp", "sp", "pc", | |
93 | }; | |
94 | ||
95 | /* output register name and update entry mask */ | |
96 | char * | |
97 | rname(r) | |
98 | register int r; | |
99 | { | |
100 | ||
101 | ent_mask |= 1<<r; | |
102 | return(rnames[r]); | |
103 | } | |
104 | ||
105 | int rstatus[] = { | |
106 | SAREG|STAREG, SAREG|STAREG, | |
107 | SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, | |
108 | SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, | |
109 | SAREG, SAREG, SAREG, SAREG, | |
110 | }; | |
111 | ||
112 | tlen(p) NODE *p; | |
113 | { | |
114 | switch(p->in.type) { | |
115 | case CHAR: | |
116 | case UCHAR: | |
117 | return(1); | |
118 | ||
119 | case SHORT: | |
120 | case USHORT: | |
121 | return(2); | |
122 | ||
123 | case DOUBLE: | |
124 | return(8); | |
125 | ||
126 | default: | |
127 | return(4); | |
128 | } | |
129 | } | |
130 | ||
131 | prtype(n) NODE *n; | |
132 | { | |
133 | switch (n->in.type) | |
134 | { | |
135 | ||
136 | case DOUBLE: | |
137 | printf("d"); | |
138 | return; | |
139 | ||
140 | case FLOAT: | |
141 | printf("f"); | |
142 | return; | |
143 | ||
144 | case INT: | |
145 | case UNSIGNED: | |
146 | printf("l"); | |
147 | return; | |
148 | ||
149 | case SHORT: | |
150 | case USHORT: | |
151 | printf("w"); | |
152 | return; | |
153 | ||
154 | case CHAR: | |
155 | case UCHAR: | |
156 | printf("b"); | |
157 | return; | |
158 | ||
159 | default: | |
160 | if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type"); | |
161 | else { | |
162 | printf("l"); | |
163 | return; | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | zzzcode( p, c ) register NODE *p; { | |
169 | register int m; | |
170 | int val; | |
171 | switch( c ){ | |
172 | ||
173 | case 'N': /* logical ops, turned into 0-1 */ | |
174 | /* use register given by register 1 */ | |
175 | cbgen( 0, m=getlab(), 'I' ); | |
176 | deflab( p->bn.label ); | |
177 | printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) ); | |
178 | deflab( m ); | |
179 | return; | |
180 | ||
181 | case 'P': | |
182 | cbgen( p->in.op, p->bn.label, c ); | |
183 | return; | |
184 | ||
185 | case 'A': /* assignment and load (integer only) */ | |
186 | { | |
187 | register NODE *l, *r; | |
188 | ||
189 | if (xdebug) eprint(p, 0, &val, &val); | |
190 | r = getlr(p, 'R'); | |
191 | if (optype(p->in.op) == LTYPE || p->in.op == UNARY MUL) { | |
192 | l = resc; | |
193 | l->in.type = INT; | |
194 | } else | |
195 | l = getlr(p, 'L'); | |
196 | if(r->in.type==FLOAT || r->in.type==DOUBLE | |
197 | || l->in.type==FLOAT || l->in.type==DOUBLE) | |
198 | cerror("float in ZA"); | |
199 | if (r->in.op == ICON) | |
200 | if(r->in.name[0] == '\0') { | |
201 | if (r->tn.lval == 0) { | |
202 | printf("clr"); | |
203 | prtype(l); | |
204 | printf(" "); | |
205 | adrput(l); | |
206 | return; | |
207 | } | |
208 | if (r->tn.lval < 0 && r->tn.lval >= -63) { | |
209 | printf("mneg"); | |
210 | prtype(l); | |
211 | r->tn.lval = -r->tn.lval; | |
212 | goto ops; | |
213 | } | |
214 | #ifdef MOVAFASTER | |
215 | } else { | |
216 | printf("movab"); | |
217 | printf(" "); | |
218 | acon(r); | |
219 | printf(","); | |
220 | adrput(l); | |
221 | return; | |
222 | #endif MOVAFASTER | |
223 | } | |
224 | ||
225 | if (l->in.op == REG) { | |
226 | if( tlen(l) < tlen(r) ) { | |
227 | !ISUNSIGNED(l->in.type)? | |
228 | printf("cvt"): | |
229 | printf("movz"); | |
230 | prtype(l); | |
231 | printf("l"); | |
232 | goto ops; | |
233 | } else | |
234 | l->in.type = INT; | |
235 | } | |
236 | if (tlen(l) == tlen(r)) { | |
237 | printf("mov"); | |
238 | prtype(l); | |
239 | goto ops; | |
240 | } else if (tlen(l) > tlen(r) && ISUNSIGNED(r->in.type)) | |
241 | printf("movz"); | |
242 | else | |
243 | printf("cvt"); | |
244 | prtype(r); | |
245 | prtype(l); | |
246 | ops: | |
247 | printf(" "); | |
248 | adrput(r); | |
249 | printf(","); | |
250 | adrput(l); | |
251 | return; | |
252 | } | |
253 | ||
254 | case 'B': /* get oreg value in temp register for shift */ | |
255 | { | |
256 | register NODE *r; | |
257 | if (xdebug) eprint(p, 0, &val, &val); | |
258 | r = p->in.right; | |
259 | if( tlen(r) == sizeof(int) && r->in.type != FLOAT ) | |
260 | printf("movl"); | |
261 | else { | |
262 | printf(ISUNSIGNED(r->in.type) ? "movz" : "cvt"); | |
263 | prtype(r); | |
264 | printf("l"); | |
265 | } | |
266 | return; | |
267 | } | |
268 | ||
269 | case 'C': /* num bytes pushed on arg stack */ | |
270 | { | |
271 | extern int gc_numbytes; | |
272 | extern int xdebug; | |
273 | ||
274 | if (xdebug) printf("->%d<-",gc_numbytes); | |
275 | ||
276 | printf("call%c $%d", | |
277 | (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s', | |
278 | gc_numbytes+4); | |
279 | /* dont change to double (here's the only place to catch it) */ | |
280 | if(p->in.type == FLOAT) | |
281 | rtyflg = 1; | |
282 | return; | |
283 | } | |
284 | ||
285 | case 'D': /* INCR and DECR */ | |
286 | zzzcode(p->in.left, 'A'); | |
287 | printf("\n "); | |
288 | ||
289 | case 'E': /* INCR and DECR, FOREFF */ | |
290 | if (p->in.right->tn.lval == 1) | |
291 | { | |
292 | printf("%s", (p->in.op == INCR ? "inc" : "dec") ); | |
293 | prtype(p->in.left); | |
294 | printf(" "); | |
295 | adrput(p->in.left); | |
296 | return; | |
297 | } | |
298 | printf("%s", (p->in.op == INCR ? "add" : "sub") ); | |
299 | prtype(p->in.left); | |
300 | printf("2 "); | |
301 | adrput(p->in.right); | |
302 | printf(","); | |
303 | adrput(p->in.left); | |
304 | return; | |
305 | ||
306 | case 'F': /* masked constant for fields */ | |
7412b41b | 307 | printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf); |
f2b49199 SL |
308 | return; |
309 | ||
310 | case 'H': /* opcode for shift */ | |
311 | if(p->in.op == LS || p->in.op == ASG LS) | |
312 | printf("shll"); | |
313 | else if(ISUNSIGNED(p->in.left->in.type)) | |
314 | printf("shrl"); | |
315 | else | |
316 | printf("shar"); | |
317 | return; | |
318 | ||
319 | case 'L': /* type of left operand */ | |
320 | case 'R': /* type of right operand */ | |
321 | { | |
322 | register NODE *n; | |
323 | extern int xdebug; | |
324 | ||
325 | n = getlr ( p, c); | |
326 | if (xdebug) printf("->%d<-", n->in.type); | |
327 | ||
328 | prtype(n); | |
329 | return; | |
330 | } | |
331 | ||
332 | case 'M': /* initiate ediv for mod and unsigned div */ | |
333 | { | |
334 | register char *r; | |
335 | m = getlr(p, '1')->tn.rval; | |
336 | r = rname(m); | |
337 | printf("\tclrl\t%s\n\tmovl\t", r); | |
338 | adrput(p->in.left); | |
339 | printf(",%s\n", rname(m+1)); | |
340 | if(!ISUNSIGNED(p->in.type)) { /* should be MOD */ | |
341 | m = getlab(); | |
342 | printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r); | |
343 | deflab(m); | |
344 | } | |
345 | } | |
346 | return; | |
347 | ||
348 | case 'U': | |
349 | /* Truncate int for type conversions: | |
350 | LONG|ULONG -> CHAR|UCHAR|SHORT|USHORT | |
351 | SHORT|USHORT -> CHAR|UCHAR | |
352 | increment offset to correct byte */ | |
353 | { | |
354 | register NODE *p1; | |
355 | int dif; | |
356 | ||
357 | p1 = p->in.left; | |
358 | switch( p1->in.op ){ | |
359 | case NAME: | |
360 | case OREG: | |
361 | dif = tlen(p1)-tlen(p); | |
362 | p1->tn.lval += dif; | |
363 | adrput(p1); | |
364 | p1->tn.lval -= dif; | |
365 | return; | |
366 | default: | |
367 | cerror( "Illegal ZU type conversion" ); | |
368 | return; | |
369 | } | |
370 | } | |
371 | ||
372 | case 'T': /* rounded structure length for arguments */ | |
373 | { | |
374 | int size; | |
375 | ||
376 | size = p->stn.stsize; | |
377 | SETOFF( size, 4); | |
378 | printf("movab -%d(sp),sp", size); | |
379 | return; | |
380 | } | |
381 | ||
382 | case 'S': /* structure assignment */ | |
1d43595d SL |
383 | stasg(p); |
384 | break; | |
f2b49199 | 385 | |
1d43595d SL |
386 | default: |
387 | cerror( "illegal zzzcode" ); | |
388 | } | |
389 | } | |
f2b49199 | 390 | |
1d43595d SL |
391 | #define MOVB(dst, src, off) { \ |
392 | printf("\tmovb\t"); upput(src, off); putchar(','); \ | |
393 | upput(dst, off); putchar('\n'); \ | |
394 | } | |
395 | #define MOVW(dst, src, off) { \ | |
396 | printf("\tmovw\t"); upput(src, off); putchar(','); \ | |
397 | upput(dst, off); putchar('\n'); \ | |
398 | } | |
399 | #define MOVL(dst, src, off) { \ | |
400 | printf("\tmovl\t"); upput(src, off); putchar(','); \ | |
401 | upput(dst, off); putchar('\n'); \ | |
402 | } | |
403 | /* | |
404 | * Generate code for a structure assignment. | |
405 | */ | |
406 | stasg(p) | |
407 | register NODE *p; | |
408 | { | |
409 | register NODE *l, *r; | |
410 | register int size; | |
411 | ||
412 | switch (p->in.op) { | |
413 | case STASG: /* regular assignment */ | |
414 | l = p->in.left; | |
415 | r = p->in.right; | |
416 | break; | |
417 | case STARG: /* place arg on the stack */ | |
418 | l = getlr(p, '3'); | |
419 | r = p->in.left; | |
420 | break; | |
421 | default: | |
422 | cerror("STASG bad"); | |
423 | /*NOTREACHED*/ | |
424 | } | |
425 | /* | |
426 | * Pun source for use in code generation. | |
427 | */ | |
428 | switch (r->in.op) { | |
429 | case ICON: | |
430 | r->in.op = NAME; | |
431 | break; | |
432 | case REG: | |
433 | r->in.op = OREG; | |
434 | break; | |
435 | default: | |
436 | cerror( "STASG-r" ); | |
437 | /*NOTREACHED*/ | |
438 | } | |
439 | size = p->stn.stsize; | |
440 | if (size <= 0 || size > 65535) | |
441 | cerror("structure size out of range"); | |
442 | /* | |
443 | * Generate optimized code based on structure size | |
444 | * and alignment properties.... | |
445 | */ | |
446 | switch (size) { | |
447 | ||
448 | case 1: | |
449 | printf("\tmovb\t"); | |
450 | optimized: | |
451 | adrput(r); | |
452 | printf(","); | |
453 | adrput(l); | |
454 | printf("\n"); | |
455 | werror("optimized structure assignment (size %d alignment %d)", size, p->stn.stalign); | |
456 | break; | |
457 | ||
458 | case 2: | |
459 | if (p->stn.stalign != 2) { | |
460 | MOVB(l, r, SZCHAR); | |
461 | printf("\tmovb\t"); | |
462 | } else | |
463 | printf("\tmovw\t"); | |
464 | goto optimized; | |
465 | ||
466 | case 4: | |
467 | if (p->stn.stalign != 4) { | |
468 | if (p->stn.stalign != 2) { | |
469 | MOVB(l, r, 3*SZCHAR); | |
470 | MOVB(l, r, 2*SZCHAR); | |
471 | MOVB(l, r, 1*SZCHAR); | |
7412b41b | 472 | printf("\tmovb\t"); |
1d43595d SL |
473 | } else { |
474 | MOVW(l, r, SZSHORT); | |
475 | printf("\tmovw\t"); | |
f2b49199 | 476 | } |
1d43595d SL |
477 | } else |
478 | printf("\tmovl\t"); | |
479 | goto optimized; | |
480 | ||
481 | case 6: | |
482 | if (p->stn.stalign != 2) | |
483 | goto movblk; | |
484 | MOVW(l, r, 2*SZSHORT); | |
485 | MOVW(l, r, 1*SZSHORT); | |
486 | printf("\tmovw\t"); | |
487 | goto optimized; | |
488 | ||
489 | case 8: | |
490 | if (p->stn.stalign == 4) { | |
491 | MOVL(l, r, SZLONG); | |
492 | printf("\tmovl\t"); | |
493 | goto optimized; | |
494 | } | |
495 | /* fall thru...*/ | |
f2b49199 | 496 | |
1d43595d SL |
497 | default: |
498 | movblk: | |
499 | /* | |
500 | * Can we ever get a register conflict with R1 here? | |
501 | */ | |
502 | printf("\tmovab\t"); | |
503 | adrput(l); | |
504 | printf(",r1\n\tmovab\t"); | |
505 | adrput(r); | |
506 | printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size); | |
507 | rname(R2); | |
f2b49199 | 508 | break; |
1d43595d SL |
509 | } |
510 | /* | |
511 | * Reverse above pun for reclaim. | |
512 | */ | |
513 | if (r->in.op == NAME) | |
514 | r->in.op = ICON; | |
515 | else if (r->in.op == OREG) | |
516 | r->in.op = REG; | |
517 | } | |
f2b49199 | 518 | |
1d43595d SL |
519 | /* |
520 | * Output the address of the second item in the | |
521 | * pair pointed to by p. | |
522 | */ | |
523 | upput(p, size) | |
524 | register NODE *p; | |
525 | { | |
526 | CONSZ save; | |
527 | ||
528 | if (p->in.op == FLD) | |
529 | p = p->in.left; | |
530 | switch (p->in.op) { | |
531 | ||
532 | case NAME: | |
533 | case OREG: | |
534 | save = p->tn.lval; | |
535 | p->tn.lval += size/SZCHAR; | |
536 | adrput(p); | |
537 | p->tn.lval = save; | |
538 | break; | |
539 | ||
540 | case REG: | |
541 | if (size == SZLONG) { | |
542 | printf("%s", rname(p->tn.rval+1)); | |
543 | break; | |
f2b49199 | 544 | } |
1d43595d SL |
545 | /* fall thru... */ |
546 | ||
547 | default: | |
548 | cerror("illegal upper address op %s size %d", | |
549 | opst[p->tn.op], size); | |
550 | /*NOTREACHED*/ | |
f2b49199 | 551 | } |
1d43595d | 552 | } |
f2b49199 SL |
553 | |
554 | rmove( rt, rs, t ) TWORD t;{ | |
555 | printf( " movl %s,%s\n", rname(rs), rname(rt) ); | |
556 | if(t==DOUBLE) | |
557 | printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) ); | |
558 | } | |
559 | ||
560 | struct respref | |
561 | respref[] = { | |
562 | INTAREG|INTBREG, INTAREG|INTBREG, | |
563 | INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, | |
564 | INTEMP, INTEMP, | |
565 | FORARG, FORARG, | |
566 | INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, | |
567 | 0, 0 }; | |
568 | ||
569 | setregs(){ /* set up temporary registers */ | |
570 | fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */ | |
571 | } | |
572 | ||
573 | szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */ | |
574 | return(t==DOUBLE ? 2 : 1 ); | |
575 | } | |
576 | ||
577 | rewfld( p ) NODE *p; { | |
578 | return(1); | |
579 | } | |
580 | ||
581 | callreg(p) NODE *p; { | |
582 | return( R0 ); | |
583 | } | |
584 | ||
585 | base( p ) register NODE *p; { | |
586 | register int o = p->in.op; | |
587 | ||
588 | if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */ | |
589 | if( o==REG ) return( p->tn.rval ); | |
590 | if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON) | |
591 | return( p->in.left->tn.rval ); | |
592 | if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) ) | |
593 | return( p->tn.rval + 0200*1 ); | |
594 | return( -1 ); | |
595 | } | |
596 | ||
597 | offset( p, tyl ) register NODE *p; int tyl; { | |
598 | ||
599 | if(tyl > 8) return( -1 ); | |
600 | if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval ); | |
601 | if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) && | |
602 | (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0') | |
603 | && (1<<p->in.right->tn.lval)==tyl)) | |
604 | return( p->in.left->tn.rval ); | |
605 | return( -1 ); | |
606 | } | |
607 | ||
608 | makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { | |
609 | register NODE *t; | |
610 | register int i; | |
611 | NODE *f; | |
612 | ||
613 | p->in.op = OREG; | |
614 | f = p->in.left; /* have to free this subtree later */ | |
615 | ||
616 | /* init base */ | |
617 | switch (q->in.op) { | |
618 | case ICON: | |
619 | case REG: | |
620 | case OREG: | |
621 | t = q; | |
622 | break; | |
623 | ||
624 | case MINUS: | |
625 | q->in.right->tn.lval = -q->in.right->tn.lval; | |
626 | case PLUS: | |
627 | t = q->in.right; | |
628 | break; | |
629 | ||
630 | case UNARY MUL: | |
631 | t = q->in.left->in.left; | |
632 | break; | |
633 | ||
634 | default: | |
635 | cerror("illegal makeor2"); | |
636 | } | |
637 | ||
638 | p->tn.lval = t->tn.lval; | |
639 | #ifndef FLEXNAMES | |
640 | for(i=0; i<NCHNAM; ++i) | |
641 | p->in.name[i] = t->in.name[i]; | |
642 | #else | |
643 | p->in.name = t->in.name; | |
644 | #endif | |
645 | ||
646 | /* init offset */ | |
647 | p->tn.rval = R2PACK( (b & 0177), o, (b>>7) ); | |
648 | ||
649 | tfree(f); | |
650 | return; | |
651 | } | |
652 | ||
653 | canaddr( p ) NODE *p; { | |
654 | register int o = p->in.op; | |
655 | ||
656 | if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); | |
657 | return(0); | |
658 | } | |
659 | ||
660 | shltype( o, p ) register NODE *p; { | |
661 | return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) ); | |
662 | } | |
663 | ||
664 | flshape( p ) NODE *p; { | |
665 | register int o = p->in.op; | |
666 | ||
667 | if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1); | |
668 | return(0); | |
669 | } | |
670 | ||
671 | shtemp( p ) register NODE *p; { | |
672 | if( p->in.op == STARG ) p = p->in.left; | |
673 | return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) ); | |
674 | } | |
675 | ||
676 | shumul( p ) register NODE *p; { | |
677 | register int o; | |
678 | extern int xdebug; | |
679 | ||
680 | if (xdebug) { | |
681 | printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op); | |
682 | printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval); | |
683 | } | |
684 | ||
685 | o = p->in.op; | |
686 | if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON ) | |
687 | && p->in.type != PTR+DOUBLE) | |
688 | return( STARNM ); | |
689 | ||
690 | return( 0 ); | |
691 | } | |
692 | ||
693 | special( p, shape ) register NODE *p; { | |
694 | if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1); | |
695 | else return(0); | |
696 | } | |
697 | ||
698 | adrcon( val ) CONSZ val; { | |
7412b41b | 699 | printf(ACONFMT, val); |
f2b49199 SL |
700 | } |
701 | ||
702 | conput( p ) register NODE *p; { | |
703 | switch( p->in.op ){ | |
704 | ||
705 | case ICON: | |
706 | acon( p ); | |
707 | return; | |
708 | ||
709 | case REG: | |
710 | printf( "%s", rname(p->tn.rval) ); | |
711 | return; | |
712 | ||
713 | default: | |
714 | cerror( "illegal conput" ); | |
715 | } | |
716 | } | |
717 | ||
718 | insput( p ) NODE *p; { | |
719 | cerror( "insput" ); | |
720 | } | |
721 | ||
f2b49199 SL |
722 | adrput( p ) register NODE *p; { |
723 | register int r; | |
724 | /* output an address, with offsets, from p */ | |
725 | ||
726 | if( p->in.op == FLD ){ | |
727 | p = p->in.left; | |
728 | } | |
729 | switch( p->in.op ){ | |
730 | ||
731 | case NAME: | |
732 | acon( p ); | |
733 | return; | |
734 | ||
735 | case ICON: | |
736 | /* addressable value of the constant */ | |
737 | printf( "$" ); | |
738 | acon( p ); | |
739 | return; | |
740 | ||
741 | case REG: | |
742 | printf( "%s", rname(p->tn.rval) ); | |
743 | if(p->in.type == DOUBLE) /* for entry mask */ | |
744 | (void) rname(p->tn.rval+1); | |
745 | return; | |
746 | ||
747 | case OREG: | |
748 | r = p->tn.rval; | |
749 | if( R2TEST(r) ){ /* double indexing */ | |
750 | register int flags; | |
751 | ||
752 | flags = R2UPK3(r); | |
753 | if( flags & 1 ) printf("*"); | |
754 | if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p); | |
755 | if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) ); | |
756 | printf( "[%s]", rname(R2UPK2(r)) ); | |
757 | return; | |
758 | } | |
759 | if( r == FP && p->tn.lval > 0 ){ /* in the argument region */ | |
760 | if( p->in.name[0] != '\0' ) werror( "bad arg temp" ); | |
761 | printf( CONFMT, p->tn.lval ); | |
762 | printf( "(fp)" ); | |
763 | return; | |
764 | } | |
765 | if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p ); | |
766 | printf( "(%s)", rname(p->tn.rval) ); | |
767 | return; | |
768 | ||
769 | case UNARY MUL: | |
770 | /* STARNM or STARREG found */ | |
771 | if( tshape(p, STARNM) ) { | |
772 | printf( "*" ); | |
773 | adrput( p->in.left); | |
774 | } | |
775 | return; | |
776 | ||
777 | default: | |
778 | cerror( "illegal address" ); | |
779 | return; | |
780 | ||
781 | } | |
782 | ||
783 | } | |
784 | ||
785 | acon( p ) register NODE *p; { /* print out a constant */ | |
786 | ||
787 | if( p->in.name[0] == '\0' ){ | |
788 | printf( CONFMT, p->tn.lval); | |
789 | } | |
790 | else if( p->tn.lval == 0 ) { | |
791 | #ifndef FLEXNAMES | |
792 | printf( "%.8s", p->in.name ); | |
793 | #else | |
794 | printf( "%s", p->in.name ); | |
795 | #endif | |
796 | } | |
797 | else { | |
798 | #ifndef FLEXNAMES | |
799 | printf( "%.8s+", p->in.name ); | |
800 | #else | |
801 | printf( "%s+", p->in.name ); | |
802 | #endif | |
803 | printf( CONFMT, p->tn.lval ); | |
804 | } | |
805 | } | |
806 | ||
807 | genscall( p, cookie ) register NODE *p; { | |
808 | /* structure valued call */ | |
809 | return( gencall( p, cookie ) ); | |
810 | } | |
811 | ||
812 | genfcall( p, cookie ) register NODE *p; { | |
813 | register NODE *p1; | |
814 | register int m; | |
815 | static char *funcops[6] = { | |
816 | "sin", "cos", "sqrt", "exp", "log", "atan" | |
817 | }; | |
818 | ||
819 | /* generate function opcodes */ | |
820 | if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT && | |
821 | (p1 = p->in.left)->in.op==ICON && | |
822 | p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) { | |
823 | #ifdef FLEXNAMES | |
824 | p1->in.name++; | |
825 | #else | |
826 | strcpy(p1->in.name, p1->in.name[1]); | |
827 | #endif | |
828 | for(m=0; m<6; m++) | |
829 | if(!strcmp(p1->in.name, funcops[m])) | |
830 | break; | |
831 | if(m >= 6) | |
832 | uerror("no opcode for fortarn function %s", p1->in.name); | |
833 | } else | |
834 | uerror("illegal type of fortarn function"); | |
835 | p1 = p->in.right; | |
836 | p->in.op = FORTCALL; | |
837 | if(!canaddr(p1)) | |
838 | order( p1, INAREG|INBREG|SOREG|STARREG|STARNM ); | |
839 | m = match( p, INTAREG|INTBREG ); | |
840 | return(m != MDONE); | |
841 | } | |
842 | ||
843 | /* tbl */ | |
844 | int gc_numbytes; | |
845 | /* tbl */ | |
846 | ||
847 | gencall( p, cookie ) register NODE *p; { | |
848 | /* generate the call given by p */ | |
849 | register NODE *p1, *ptemp; | |
850 | register int temp, temp1; | |
851 | register int m; | |
852 | ||
853 | if( p->in.right ) temp = argsize( p->in.right ); | |
854 | else temp = 0; | |
855 | ||
856 | if( p->in.op == STCALL || p->in.op == UNARY STCALL ){ | |
857 | /* set aside room for structure return */ | |
858 | ||
859 | if( p->stn.stsize > temp ) temp1 = p->stn.stsize; | |
860 | else temp1 = temp; | |
861 | } | |
862 | ||
863 | if( temp > maxargs ) maxargs = temp; | |
864 | SETOFF(temp1,4); | |
865 | ||
866 | if( p->in.right ){ /* make temp node, put offset in, and generate args */ | |
867 | ptemp = talloc(); | |
868 | ptemp->in.op = OREG; | |
869 | ptemp->tn.lval = -1; | |
870 | ptemp->tn.rval = SP; | |
871 | #ifndef FLEXNAMES | |
872 | ptemp->in.name[0] = '\0'; | |
873 | #else | |
874 | ptemp->in.name = ""; | |
875 | #endif | |
876 | ptemp->in.rall = NOPREF; | |
877 | ptemp->in.su = 0; | |
878 | genargs( p->in.right, ptemp ); | |
879 | ptemp->in.op = FREE; | |
880 | } | |
881 | ||
882 | p1 = p->in.left; | |
883 | if( p1->in.op != ICON ){ | |
884 | if( p1->in.op != REG ){ | |
885 | if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){ | |
886 | if( p1->in.op != NAME ){ | |
887 | order( p1, INAREG ); | |
888 | } | |
889 | } | |
890 | } | |
891 | } | |
892 | ||
893 | /* tbl | |
894 | setup gc_numbytes so reference to ZC works */ | |
895 | ||
896 | gc_numbytes = temp&(0x3ff); | |
897 | ||
898 | p->in.op = UNARY CALL; | |
899 | m = match( p, INTAREG|INTBREG ); | |
900 | ||
901 | return(m != MDONE); | |
902 | } | |
903 | ||
904 | /* tbl */ | |
905 | char * | |
906 | ccbranches[] = { | |
907 | "eql", | |
908 | "neq", | |
909 | "leq", | |
910 | "lss", | |
911 | "geq", | |
912 | "gtr", | |
913 | "lequ", | |
914 | "lssu", | |
915 | "gequ", | |
916 | "gtru", | |
917 | }; | |
918 | /* tbl */ | |
919 | ||
920 | cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ | |
921 | ||
922 | if(o != 0 && (o < EQ || o > UGT )) | |
923 | cerror( "bad conditional branch: %s", opst[o] ); | |
924 | printf( " j%s L%d\n", | |
925 | o == 0 ? "br" : ccbranches[o-EQ], lab ); | |
926 | } | |
927 | ||
928 | nextcook( p, cookie ) NODE *p; { | |
929 | /* we have failed to match p with cookie; try another */ | |
930 | if( cookie == FORREW ) return( 0 ); /* hopeless! */ | |
931 | if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); | |
932 | if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); | |
933 | return( FORREW ); | |
934 | } | |
935 | ||
936 | lastchance( p, cook ) NODE *p; { | |
937 | /* forget it! */ | |
938 | return(0); | |
939 | } | |
940 | ||
941 | optim2( p ) register NODE *p; { | |
942 | # ifdef ONEPASS | |
943 | /* do local tree transformations and optimizations */ | |
944 | # define RV(p) p->in.right->tn.lval | |
945 | register int o = p->in.op; | |
946 | register int i; | |
947 | ||
948 | /* change unsigned mods and divs to logicals (mul is done in mip & c2) */ | |
949 | if(optype(o) == BITYPE && ISUNSIGNED(p->in.left->in.type) | |
950 | && nncon(p->in.right) && (i=ispow2(RV(p)))>=0){ | |
951 | switch(o) { | |
952 | case DIV: | |
953 | case ASG DIV: | |
954 | p->in.op = RS; | |
955 | RV(p) = i; | |
956 | break; | |
957 | case MOD: | |
958 | case ASG MOD: | |
959 | p->in.op = AND; | |
960 | RV(p)--; | |
961 | break; | |
962 | default: | |
963 | return; | |
964 | } | |
965 | if(asgop(o)) | |
966 | p->in.op = ASG p->in.op; | |
967 | } | |
968 | # endif | |
969 | } | |
970 | ||
971 | struct functbl { | |
972 | int fop; | |
973 | char *func; | |
974 | } opfunc[] = { | |
975 | DIV, "udiv", | |
976 | ASG DIV, "udiv", | |
977 | 0 | |
978 | }; | |
979 | ||
980 | hardops(p) register NODE *p; { | |
981 | /* change hard to do operators into function calls. */ | |
982 | register NODE *q; | |
983 | register struct functbl *f; | |
984 | register int o; | |
985 | register TWORD t, t1, t2; | |
986 | ||
987 | o = p->in.op; | |
988 | ||
989 | for( f=opfunc; f->fop; f++ ) { | |
990 | if( o==f->fop ) goto convert; | |
991 | } | |
992 | return; | |
993 | ||
994 | convert: | |
995 | t = p->in.type; | |
996 | t1 = p->in.left->in.type; | |
997 | t2 = p->in.right->in.type; | |
998 | if ( t1 != UNSIGNED && (t2 != UNSIGNED)) return; | |
999 | ||
1000 | /* need to rewrite tree for ASG OP */ | |
1001 | /* must change ASG OP to a simple OP */ | |
1002 | if( asgop( o ) ) { | |
1003 | q = talloc(); | |
1004 | q->in.op = NOASG ( o ); | |
1005 | q->in.rall = NOPREF; | |
1006 | q->in.type = p->in.type; | |
1007 | q->in.left = tcopy(p->in.left); | |
1008 | q->in.right = p->in.right; | |
1009 | p->in.op = ASSIGN; | |
1010 | p->in.right = q; | |
1011 | zappost(q->in.left); /* remove post-INCR(DECR) from new node */ | |
1012 | fixpre(q->in.left); /* change pre-INCR(DECR) to +/- */ | |
1013 | p = q; | |
1014 | ||
1015 | } | |
1016 | /* turn logicals to compare 0 */ | |
1017 | else if( logop( o ) ) { | |
1018 | ncopy(q = talloc(), p); | |
1019 | p->in.left = q; | |
1020 | p->in.right = q = talloc(); | |
1021 | q->in.op = ICON; | |
1022 | q->in.type = INT; | |
1023 | #ifndef FLEXNAMES | |
1024 | q->in.name[0] = '\0'; | |
1025 | #else | |
1026 | q->in.name = ""; | |
1027 | #endif | |
1028 | q->tn.lval = 0; | |
1029 | q->tn.rval = 0; | |
1030 | p = p->in.left; | |
1031 | } | |
1032 | ||
1033 | /* build comma op for args to function */ | |
1034 | t1 = p->in.left->in.type; | |
1035 | t2 = 0; | |
1036 | if ( optype(p->in.op) == BITYPE) { | |
1037 | q = talloc(); | |
1038 | q->in.op = CM; | |
1039 | q->in.rall = NOPREF; | |
1040 | q->in.type = INT; | |
1041 | q->in.left = p->in.left; | |
1042 | q->in.right = p->in.right; | |
1043 | t2 = p->in.right->in.type; | |
1044 | } else | |
1045 | q = p->in.left; | |
1046 | ||
1047 | p->in.op = CALL; | |
1048 | p->in.right = q; | |
1049 | ||
1050 | /* put function name in left node of call */ | |
1051 | p->in.left = q = talloc(); | |
1052 | q->in.op = ICON; | |
1053 | q->in.rall = NOPREF; | |
1054 | q->in.type = INCREF( FTN + p->in.type ); | |
1055 | #ifndef FLEXNAMES | |
1056 | strcpy( q->in.name, f->func ); | |
1057 | #else | |
1058 | q->in.name = f->func; | |
1059 | #endif | |
1060 | q->tn.lval = 0; | |
1061 | q->tn.rval = 0; | |
1062 | ||
1063 | } | |
1064 | ||
1065 | zappost(p) NODE *p; { | |
1066 | /* look for ++ and -- operators and remove them */ | |
1067 | ||
1068 | register int o, ty; | |
1069 | register NODE *q; | |
1070 | o = p->in.op; | |
1071 | ty = optype( o ); | |
1072 | ||
1073 | switch( o ){ | |
1074 | ||
1075 | case INCR: | |
1076 | case DECR: | |
1077 | q = p->in.left; | |
1078 | p->in.right->in.op = FREE; /* zap constant */ | |
1079 | ncopy( p, q ); | |
1080 | q->in.op = FREE; | |
1081 | return; | |
1082 | ||
1083 | } | |
1084 | ||
1085 | if( ty == BITYPE ) zappost( p->in.right ); | |
1086 | if( ty != LTYPE ) zappost( p->in.left ); | |
1087 | } | |
1088 | ||
1089 | fixpre(p) NODE *p; { | |
1090 | ||
1091 | register int o, ty; | |
1092 | o = p->in.op; | |
1093 | ty = optype( o ); | |
1094 | ||
1095 | switch( o ){ | |
1096 | ||
1097 | case ASG PLUS: | |
1098 | p->in.op = PLUS; | |
1099 | break; | |
1100 | case ASG MINUS: | |
1101 | p->in.op = MINUS; | |
1102 | break; | |
1103 | } | |
1104 | ||
1105 | if( ty == BITYPE ) fixpre( p->in.right ); | |
1106 | if( ty != LTYPE ) fixpre( p->in.left ); | |
1107 | } | |
1108 | ||
1109 | NODE * addroreg(l) NODE *l; | |
1110 | /* OREG was built in clocal() | |
1111 | * for an auto or formal parameter | |
1112 | * now its address is being taken | |
1113 | * local code must unwind it | |
1114 | * back to PLUS/MINUS REG ICON | |
1115 | * according to local conventions | |
1116 | */ | |
1117 | { | |
1118 | cerror("address of OREG taken"); | |
1119 | } | |
1120 | ||
1121 | # ifndef ONEPASS | |
1122 | main( argc, argv ) char *argv[]; { | |
1123 | return( mainp2( argc, argv ) ); | |
1124 | } | |
1125 | # endif | |
1126 | ||
1127 | myreader(p) register NODE *p; { | |
1128 | walkf( p, hardops ); /* convert ops to function calls */ | |
1129 | canon( p ); /* expands r-vals for fileds */ | |
1130 | walkf( p, optim2 ); | |
1131 | } |