Commit | Line | Data |
---|---|---|
3c5d933b SJ |
1 | # include "mfile2" |
2 | /* a lot of the machine dependent parts of the second pass */ | |
3 | ||
4 | # define BITMASK(n) ((1L<<n)-1) | |
5 | ||
6 | lineid( l, fn ) char *fn; { | |
7 | /* identify line l and file fn */ | |
8 | printf( "/ line %d, file %s\n", l, fn ); | |
9 | } | |
10 | ||
11 | eobl2(){ | |
12 | OFFSZ spoff; /* offset from stack pointer */ | |
13 | ||
14 | spoff = maxoff; | |
15 | if( spoff >= AUTOINIT ) spoff -= AUTOINIT; | |
16 | spoff /= SZCHAR; | |
17 | SETOFF(spoff,2); | |
18 | printf( " .F%d = %Ld.\n", ftnno, spoff ); | |
19 | if( fltused ) { | |
20 | fltused = 0; | |
21 | printf( " .globl fltused\n" ); | |
22 | } | |
23 | } | |
24 | ||
25 | struct hoptab { int opmask; char * opstring; } ioptab[]= { | |
26 | ||
27 | ASG PLUS, "add", | |
28 | ASG MINUS, "sub", | |
29 | ASG OR, "bis", | |
30 | ASG AND, "bic", | |
31 | ASG ER, "xor", | |
32 | ASG MUL, "mul", | |
33 | ASG DIV, "div", | |
34 | ASG MOD, "div", | |
35 | ASG LS, "asl", | |
36 | ASG RS, "asr", | |
37 | ||
38 | -1, "" }; | |
39 | ||
40 | hopcode( f, o ){ | |
41 | /* output the appropriate string from the above table */ | |
42 | ||
43 | register struct hoptab *q; | |
44 | ||
45 | for( q = ioptab; q->opmask>=0; ++q ){ | |
46 | if( q->opmask == o ){ | |
47 | printf( "%s", q->opstring ); | |
48 | if( f == 'F' ) printf( "f" ); | |
49 | return; | |
50 | } | |
51 | } | |
52 | cerror( "no hoptab for %s", opst[o] ); | |
53 | } | |
54 | ||
55 | char * | |
56 | rnames[]= { /* keyed to register number tokens */ | |
57 | ||
58 | "r0", "r1", | |
59 | "r2", "r3", "r4", | |
60 | "r5", "sp", "pc", | |
61 | ||
62 | "fr0", "fr1", "fr2", "fr3", | |
63 | "fr4", "fr5", /* not accumulators - used for temps */ | |
64 | }; | |
65 | ||
66 | int rstatus[] = { | |
67 | SAREG|STAREG, SAREG|STAREG, | |
68 | SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, /* use as scratch if not reg var */ | |
69 | SAREG, SAREG, SAREG, | |
70 | ||
71 | SBREG|STBREG, SBREG|STBREG, SBREG|STBREG, SBREG|STBREG, | |
72 | SBREG, SBREG, | |
73 | }; | |
74 | ||
75 | NODE *brnode; | |
76 | int brcase; | |
77 | ||
78 | int toff = 0; /* number of stack locations used for args */ | |
79 | ||
80 | zzzcode( p, c ) NODE *p; { | |
81 | register m; | |
82 | switch( c ){ | |
83 | ||
84 | case 'B': /* output b if type is byte */ | |
85 | if( p->type == CHAR || p->type == UCHAR ) printf( "b" ); | |
86 | return; | |
87 | ||
88 | case 'N': /* logical ops, turned into 0-1 */ | |
89 | /* use register given by register 1 */ | |
90 | cbgen( 0, m=getlab(), 'I' ); | |
91 | deflab( p->label ); | |
92 | printf( " clr %s\n", rnames[getlr( p, '1' )->rval] ); | |
93 | if( p->type == LONG || p->type == ULONG ) | |
94 | printf( " clr %s\n", rnames[getlr( p, '1' )->rval + 1] ); | |
95 | deflab( m ); | |
96 | return; | |
97 | ||
98 | case 'I': | |
99 | case 'F': | |
100 | cbgen( p->op, p->label, c ); | |
101 | return; | |
102 | ||
103 | case 'A': | |
104 | case 'C': | |
105 | /* logical operators for longs | |
106 | defer comparisons until branch occurs */ | |
107 | ||
108 | brnode = tcopy( p ); | |
109 | brcase = c; | |
110 | return; | |
111 | ||
112 | case 'H': /* fix up unsigned shifts */ | |
113 | { register NODE *q; | |
114 | register r, l; | |
115 | TWORD t; | |
116 | ||
117 | if( p->op == ASG LS ) return; | |
118 | if( p->op != ASG RS ) cerror( "ZH bad" ); | |
119 | if( p->left->op != REG ) cerror( "SH left bad" ); | |
120 | ||
121 | r = p->left->rval; | |
122 | t = p->left->type; | |
123 | l = (t==LONG || t == ULONG ); | |
124 | ||
125 | if( t != UNSIGNED && t != UCHAR && t != ULONG ) return; /* signed is ok */ | |
126 | ||
127 | /* there are three cases: right side is a constant, | |
128 | and has the shift value; right side is | |
129 | a temporary reg, and has the - shift value, | |
130 | and right side is something else: A1 has the | |
131 | - shift value then */ | |
132 | ||
133 | /* in the case where the value is known (rhs a constant), | |
134 | the mask is just computed and put out... */ | |
135 | ||
136 | if( p->right->op == ICON ){ | |
137 | int s; | |
138 | s = p->right->lval; | |
139 | if( l ){ | |
140 | if( s >= 16 ){ | |
141 | printf( " clr r%d\n", r ); | |
142 | s -= 16; | |
143 | ++r; | |
144 | } | |
145 | } | |
146 | if( s >= 16 ) printf( " clr r%d\n", r ); | |
147 | else { | |
148 | m = 0100000; | |
149 | m >>= s; /* sign extends... */ | |
150 | m <<= 1; | |
151 | printf( " bic $%o,r%d\n", m, r ); | |
152 | } | |
153 | return; | |
154 | } | |
155 | ||
156 | /* general case */ | |
157 | ||
158 | if( istnode( p->right ) ) q = p->right; | |
159 | else q = getlr( p, '1' ); /* where -shift is stored */ | |
160 | ||
161 | /* first, we store the shifted value on the stack */ | |
162 | printf( " mov r%d,-(sp)\n", r ); | |
163 | if( l ) printf( " mov r%d,-(sp)\n", r+1 ); | |
164 | ||
165 | /* now, make a mask */ | |
166 | ||
167 | printf( " mov $100000,r%d\n", r ); | |
168 | if( l ) printf( " clr r%d\n", r+1 ); | |
169 | ||
170 | /* shift (arithmetically ) */ | |
171 | if( l ) expand( q, RNOP, " ashc AR" ); | |
172 | else expand( q, RNOP, " ash AR" ); | |
173 | printf( ",r%d\n", r ); | |
174 | ||
175 | if( l ) printf( " ashc $1,r%d\n", r ); | |
176 | else printf( " asl r%d\n", r ); | |
177 | ||
178 | /* now, we have a mask: use it to clear sp, and reload */ | |
179 | ||
180 | if( l ){ | |
181 | printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r+1, r+1 ); | |
182 | } | |
183 | printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r, r ); | |
184 | /* whew! */ | |
185 | return; | |
186 | } | |
187 | ||
188 | case 'V': | |
189 | /* sign extend or not -- register is one less than the | |
190 | left descendent */ | |
191 | ||
192 | m = p->left->rval - 1; | |
193 | ||
194 | if( ISUNSIGNED(p->type) ){ | |
195 | printf( " clr r%d\n", m ); | |
196 | } | |
197 | else { | |
198 | printf( " sxt r%d\n", m ); | |
199 | } | |
200 | return; | |
201 | ||
202 | /* stack management macros */ | |
203 | case '-': | |
204 | if( toff ++ ) printf( "-" ); | |
205 | printf( "(sp)" ); | |
206 | return; | |
207 | ||
208 | case '4': | |
209 | if( toff == 0 ) ++toff; /* can't push doubles that way */ | |
210 | printf( "-(sp)" ); | |
211 | toff += 4; | |
212 | return; | |
213 | ||
214 | case '~': | |
215 | /* complimented CR */ | |
216 | p->right->lval = ~p->right->lval; | |
217 | conput( getlr( p, 'R' ) ); | |
218 | p->right->lval = ~p->right->lval; | |
219 | return; | |
220 | ||
221 | case 'M': | |
222 | /* negated CR */ | |
223 | p->right->lval = -p->right->lval; | |
224 | conput( getlr( p, 'R' ) ); | |
225 | p->right->lval = -p->right->lval; | |
226 | return; | |
227 | ||
228 | case 'L': /* INIT for long constants */ | |
229 | { | |
230 | unsigned hi, lo; | |
231 | lo = p->left->lval & BITMASK(SZINT); | |
232 | hi = ( p->left->lval >> SZINT ) & BITMASK(SZINT); | |
233 | printf( " %o; %o\n", hi, lo ); | |
234 | return; | |
235 | } | |
236 | ||
237 | case 'T': | |
238 | /* Truncate longs for type conversions: | |
239 | LONG|ULONG -> CHAR|UCHAR|INT|UNSIGNED | |
240 | increment offset to second word */ | |
241 | ||
242 | m = p->type; | |
243 | p = p->left; | |
244 | switch( p->op ){ | |
245 | case NAME: | |
246 | case OREG: | |
247 | p->lval += SZINT/SZCHAR; | |
248 | return; | |
249 | case REG: | |
250 | rfree( p->rval, p->type ); | |
251 | p->rval += 1; | |
252 | p->type = m; | |
253 | rbusy( p->rval, p->type ); | |
254 | return; | |
255 | default: | |
256 | cerror( "Illegal ZT type conversion" ); | |
257 | return; | |
258 | ||
259 | } | |
260 | ||
261 | case 'U': | |
262 | /* same as AL for exp under U* */ | |
263 | if( p->left->op == UNARY MUL ) { | |
264 | adrput( getlr( p->left, 'L' ) ); | |
265 | return; | |
266 | } | |
267 | cerror( "Illegal ZU" ); | |
268 | /* NO RETURN */ | |
269 | ||
270 | case 'W': /* structure size */ | |
271 | if( p->op == STASG ) | |
272 | printf( "%d", p->stsize); | |
273 | else cerror( "Not a structure" ); | |
274 | return; | |
275 | ||
276 | case 'S': /* structure assignment */ | |
277 | { | |
278 | register NODE *l, *r; | |
279 | register size, count; | |
280 | ||
281 | if( p->op == STASG ){ | |
282 | l = p->left; | |
283 | r = p->right; | |
284 | } | |
285 | else if( p->op == STARG ){ /* store an arg onto the stack */ | |
286 | r = p->left; | |
287 | } | |
288 | else cerror( "STASG bad" ); | |
289 | ||
290 | if( r->op == ICON ) r->op = NAME; | |
291 | else if( r->op == REG ) r->op = OREG; | |
292 | else if( r->op != OREG ) cerror( "STASG-r" ); | |
293 | ||
294 | size = p->stsize; | |
295 | count = size / 2; | |
296 | ||
297 | r->lval += size; | |
298 | if( p->op == STASG ) l->lval += size; | |
299 | ||
300 | while( count-- ){ /* simple load/store loop */ | |
301 | r->lval -= 2; | |
302 | expand( r, FOREFF, " mov AR," ); | |
303 | if( p->op == STASG ){ | |
304 | l->lval -= 2; | |
305 | expand( l, FOREFF, "AR\n" ); | |
306 | } | |
307 | else { | |
308 | printf( "-(sp)\n" ); | |
309 | } | |
310 | ||
311 | } | |
312 | ||
313 | if( r->op == NAME ) r->op = ICON; | |
314 | else if( r->op == OREG ) r->op = REG; | |
315 | ||
316 | } | |
317 | break; | |
318 | ||
319 | default: | |
320 | cerror( "illegal zzzcode" ); | |
321 | } | |
322 | } | |
323 | ||
324 | rmove( rt, rs, t ) TWORD t; { | |
325 | printf( " %s %s,%s\n", (t==FLOAT||t==DOUBLE)?"movf":"mov", rnames[rs], rnames[rt] ); | |
326 | } | |
327 | ||
328 | struct respref | |
329 | respref[] = { | |
330 | INTAREG|INTBREG, INTAREG|INTBREG, | |
331 | INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|SNAME|STARNM|SCON, | |
332 | INTEMP, INTEMP, | |
333 | FORARG, FORARG, | |
334 | INTAREG, SOREG|SNAME, | |
335 | 0, 0 }; | |
336 | ||
337 | setregs(){ /* set up temporary registers */ | |
338 | register i; | |
339 | ||
340 | /* use any unused variable registers as scratch registers */ | |
341 | fregs = maxtreg>=MINRVAR ? maxtreg + 1 : MINRVAR; | |
342 | if( xdebug ){ | |
343 | /* -x changes number of free regs to 2, -xx to 3, etc. */ | |
344 | if( (xdebug+1) < fregs ) fregs = xdebug+1; | |
345 | } | |
346 | /* NOTE: for pdp11 fregs <= 4 for float regs */ | |
347 | if( fregs > 4 ) fregs = 4; | |
348 | for( i=MINRVAR; i<=MAXRVAR; i++ ) | |
349 | rstatus[i] = i<fregs ? SAREG|STAREG : SAREG; | |
350 | } | |
351 | ||
352 | szty(t) TWORD t; { /* size, in words, needed to hold thing of type t */ | |
353 | /* really is the number of registers to hold type t */ | |
354 | switch( t ) { | |
355 | ||
356 | case LONG: | |
357 | case ULONG: | |
358 | return( SZLONG/SZINT ); | |
359 | ||
360 | default: | |
361 | return(1); | |
362 | ||
363 | } | |
364 | } | |
365 | ||
366 | rewfld( p ) NODE *p; { | |
367 | return(1); | |
368 | } | |
369 | ||
370 | callreg(p) NODE *p; { | |
371 | return( (p->type==DOUBLE||p->type==FLOAT) ? FR0 : R0 ); | |
372 | } | |
373 | ||
374 | shltype( o, p ) NODE *p; { | |
375 | if( o == NAME|| o==REG || o == ICON || o == OREG ) return( 1 ); | |
376 | return( o==UNARY MUL && shumul(p->left) ); | |
377 | } | |
378 | ||
379 | flshape( p ) register NODE *p; { | |
380 | register o = p->op; | |
381 | if( o==NAME || o==REG || o==ICON || o==OREG ) return( 1 ); | |
382 | return( o==UNARY MUL && shumul(p->left)==STARNM ); | |
383 | } | |
384 | ||
385 | shtemp( p ) register NODE *p; { | |
386 | if( p->op == UNARY MUL ) p = p->left; | |
387 | if( p->op == REG || p->op == OREG ) return( !istreg( p->rval ) ); | |
388 | return( p->op == NAME || p->op == ICON ); | |
389 | } | |
390 | ||
391 | spsz( t, v ) TWORD t; CONSZ v; { | |
392 | ||
393 | /* is v the size to increment something of type t */ | |
394 | ||
395 | if( !ISPTR(t) ) return( 0 ); | |
396 | t = DECREF(t); | |
397 | ||
398 | if( ISPTR(t) ) return( v == 2 ); | |
399 | ||
400 | switch( t ){ | |
401 | ||
402 | case UCHAR: | |
403 | case CHAR: | |
404 | return( v == 1 ); | |
405 | ||
406 | case INT: | |
407 | case UNSIGNED: | |
408 | return( v == 2 ); | |
409 | ||
410 | case FLOAT: | |
411 | return( v == 4 ); | |
412 | ||
413 | case DOUBLE: | |
414 | return( v == 8 ); | |
415 | } | |
416 | ||
417 | return( 0 ); | |
418 | } | |
419 | ||
420 | shumul( p ) register NODE *p; { | |
421 | register o; | |
422 | ||
423 | o = p->op; | |
424 | if( o == NAME || o == OREG || o == ICON ) return( STARNM ); | |
425 | ||
426 | if( ( o == INCR || o == ASG MINUS ) && | |
427 | ( p->left->op == REG && p->right->op == ICON ) && | |
428 | p->right->name[0] == '\0' && | |
429 | spsz( p->left->type, p->right->lval ) ) | |
430 | return( STARREG ); | |
431 | ||
432 | return( 0 ); | |
433 | } | |
434 | ||
435 | adrcon( val ) CONSZ val; { | |
436 | printf( CONFMT, val ); | |
437 | } | |
438 | ||
439 | conput( p ) register NODE *p; { | |
440 | switch( p->op ){ | |
441 | ||
442 | case ICON: | |
443 | acon( p ); | |
444 | return; | |
445 | ||
446 | case REG: | |
447 | printf( "%s", rnames[p->rval] ); | |
448 | return; | |
449 | ||
450 | default: | |
451 | cerror( "illegal conput" ); | |
452 | } | |
453 | } | |
454 | ||
455 | insput( p ) NODE *p; { | |
456 | cerror( "insput" ); | |
457 | } | |
458 | ||
459 | upput( p ) NODE *p; { | |
460 | /* output the address of the second word in the | |
461 | pair pointed to by p (for LONGs)*/ | |
462 | CONSZ save; | |
463 | ||
464 | if( p->op == FLD ){ | |
465 | p = p->left; | |
466 | } | |
467 | ||
468 | save = p->lval; | |
469 | switch( p->op ){ | |
470 | ||
471 | case NAME: | |
472 | p->lval += SZINT/SZCHAR; | |
473 | acon( p ); | |
474 | break; | |
475 | ||
476 | case ICON: | |
477 | /* addressable value of the constant */ | |
478 | p->lval &= BITMASK(SZINT); | |
479 | printf( "$" ); | |
480 | acon( p ); | |
481 | break; | |
482 | ||
483 | case REG: | |
484 | printf( "%s", rnames[p->rval+1] ); | |
485 | break; | |
486 | ||
487 | case OREG: | |
488 | p->lval += SZINT/SZCHAR; | |
489 | if( p->rval == R5 ){ /* in the argument region */ | |
490 | if( p->name[0] != '\0' ) werror( "bad arg temp" ); | |
491 | } | |
492 | if( p->lval != 0 || p->name[0] != '\0' ) acon( p ); | |
493 | printf( "(%s)", rnames[p->rval] ); | |
494 | break; | |
495 | ||
496 | default: | |
497 | cerror( "illegal upper address" ); | |
498 | break; | |
499 | ||
500 | } | |
501 | p->lval = save; | |
502 | ||
503 | } | |
504 | ||
505 | adrput( p ) register NODE *p; { | |
506 | /* output an address, with offsets, from p */ | |
507 | ||
508 | if( p->op == FLD ){ | |
509 | p = p->left; | |
510 | } | |
511 | switch( p->op ){ | |
512 | ||
513 | case NAME: | |
514 | acon( p ); | |
515 | return; | |
516 | ||
517 | case ICON: | |
518 | /* addressable value of the constant */ | |
519 | if( szty( p->type ) == 2 ) { | |
520 | /* print the high order value */ | |
521 | CONSZ save; | |
522 | save = p->lval; | |
523 | p->lval = ( p->lval >> SZINT ) & BITMASK(SZINT); | |
524 | printf( "$" ); | |
525 | acon( p ); | |
526 | p->lval = save; | |
527 | return; | |
528 | } | |
529 | printf( "$" ); | |
530 | acon( p ); | |
531 | return; | |
532 | ||
533 | case REG: | |
534 | printf( "%s", rnames[p->rval] ); | |
535 | return; | |
536 | ||
537 | case OREG: | |
538 | if( p->rval == R5 ){ /* in the argument region */ | |
539 | if( p->name[0] != '\0' ) werror( "bad arg temp" ); | |
540 | printf( CONFMT, p->lval ); | |
541 | printf( ".(r5)" ); | |
542 | return; | |
543 | } | |
544 | if( p->lval != 0 || p->name[0] != '\0' ) acon( p ); | |
545 | printf( "(%s)", rnames[p->rval] ); | |
546 | return; | |
547 | ||
548 | case UNARY MUL: | |
549 | /* STARNM or STARREG found */ | |
550 | if( tshape(p, STARNM) ) { | |
551 | printf( "*" ); | |
552 | adrput( p->left); | |
553 | } | |
554 | else { /* STARREG - really auto inc or dec */ | |
555 | /* turn into OREG so replacement node will | |
556 | reflect the value of the expression */ | |
557 | register i; | |
558 | register NODE *q, *l; | |
559 | ||
560 | l = p->left; | |
561 | q = l->left; | |
562 | p->op = OREG; | |
563 | p->rall = q->rall; | |
564 | p->lval = q->lval; | |
565 | p->rval = q->rval; | |
566 | for( i=0; i<NCHNAM; i++ ) | |
567 | p->name[i] = q->name[i]; | |
568 | if( l->op == INCR ) { | |
569 | adrput( p ); | |
570 | printf( "+" ); | |
571 | p->lval -= l->right->lval; | |
572 | } | |
573 | else { /* l->op == ASG MINUS */ | |
574 | printf( "-" ); | |
575 | adrput( p ); | |
576 | } | |
577 | tfree( l ); | |
578 | } | |
579 | return; | |
580 | ||
581 | default: | |
582 | cerror( "illegal address" ); | |
583 | return; | |
584 | ||
585 | } | |
586 | ||
587 | } | |
588 | ||
589 | acon( p ) register NODE *p; { /* print out a constant */ | |
590 | ||
591 | if( p->name[0] == '\0' ){ /* constant only */ | |
592 | printf( CONFMT, p->lval); | |
593 | printf( "." ); | |
594 | } | |
595 | else if( p->lval == 0 ) { /* name only */ | |
596 | printf( "%.8s", p->name ); | |
597 | } | |
598 | else { /* name + offset */ | |
599 | printf( "%.8s+", p->name ); | |
600 | printf( CONFMT, p->lval ); | |
601 | printf( "." ); | |
602 | } | |
603 | } | |
604 | ||
605 | genscall( p, cookie ) register NODE *p; { | |
606 | /* structure valued call */ | |
607 | return( gencall( p, cookie ) ); | |
608 | } | |
609 | ||
610 | gencall( p, cookie ) register NODE *p; { | |
611 | /* generate the call given by p */ | |
612 | register temp; | |
613 | register m; | |
614 | ||
615 | if( p->right ) temp = argsize( p->right ); | |
616 | else temp = 0; | |
617 | ||
618 | if( p->right ){ /* generate args */ | |
619 | genargs( p->right ); | |
620 | } | |
621 | ||
622 | if( !shltype( p->left->op, p->left ) ) { | |
623 | order( p->left, INAREG|SOREG ); | |
624 | } | |
625 | ||
626 | p->op = UNARY CALL; | |
627 | m = match( p, INTAREG|INTBREG ); | |
628 | popargs( temp ); | |
629 | return(m != MDONE); | |
630 | } | |
631 | ||
632 | popargs( size ) register size; { | |
633 | /* pop arguments from stack */ | |
634 | ||
635 | toff -= size/2; | |
636 | if( toff == 0 && size >= 2 ) size -= 2; | |
637 | switch( size ) { | |
638 | case 0: | |
639 | break; | |
640 | case 2: | |
641 | printf( " tst (sp)+\n" ); | |
642 | break; | |
643 | case 4: | |
644 | printf( " cmp (sp)+,(sp)+\n" ); | |
645 | break; | |
646 | default: | |
647 | printf( " add $%d.,sp\n", size); | |
648 | } | |
649 | } | |
650 | ||
651 | char * | |
652 | ccbranches[] = { | |
653 | " jeq L%d\n", | |
654 | " jne L%d\n", | |
655 | " jle L%d\n", | |
656 | " jlt L%d\n", | |
657 | " jge L%d\n", | |
658 | " jgt L%d\n", | |
659 | " jlos L%d\n", | |
660 | " jlo L%d\n", | |
661 | " jhis L%d\n", | |
662 | " jhi L%d\n", | |
663 | }; | |
664 | ||
665 | /* long branch table | |
666 | ||
667 | This table, when indexed by a logical operator, | |
668 | selects a set of three logical conditions required | |
669 | to generate long comparisons and branches. A zero | |
670 | entry indicates that no branch is required. | |
671 | E.G.: The <= operator would generate: | |
672 | cmp AL,AR | |
673 | jlt lable / 1st entry LT -> lable | |
674 | jgt 1f / 2nd entry GT -> 1f | |
675 | cmp UL,UR | |
676 | jlos lable / 3rd entry ULE -> lable | |
677 | 1: | |
678 | */ | |
679 | ||
680 | int lbranches[][3] = { | |
681 | /*EQ*/ 0, NE, EQ, | |
682 | /*NE*/ NE, 0, NE, | |
683 | /*LE*/ LT, GT, ULE, | |
684 | /*LT*/ LT, GT, ULT, | |
685 | /*GE*/ GT, LT, UGE, | |
686 | /*GT*/ GT, LT, UGT, | |
687 | /*ULE*/ ULT, UGT, ULE, | |
688 | /*ULT*/ ULT, UGT, ULT, | |
689 | /*UGE*/ UGT, ULT, UGE, | |
690 | /*UGT*/ UGT, ULT, UGT, | |
691 | }; | |
692 | ||
693 | /* logical relations when compared in reverse order (cmp R,L) */ | |
694 | extern short revrel[] ; | |
695 | ||
696 | cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ | |
697 | register *plb; | |
698 | int lab1f; | |
699 | ||
700 | if( o == 0 ) printf( " jbr L%d\n", lab ); | |
701 | else if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] ); | |
702 | else { | |
703 | switch( brcase ) { | |
704 | ||
705 | case 'A': | |
706 | case 'C': | |
707 | plb = lbranches[ o-EQ ]; | |
708 | lab1f = getlab(); | |
709 | expand( brnode, FORCC, brcase=='C' ? "\tcmp\tAL,AR\n" : "\ttst\tAR\n" ); | |
710 | if( *plb != 0 ) | |
711 | printf( ccbranches[*plb-EQ], lab); | |
712 | if( *++plb != 0 ) | |
713 | printf( ccbranches[*plb-EQ], lab1f); | |
714 | expand( brnode, FORCC, brcase=='C' ? "\tcmp\tUL,UR\n" : "\ttst\tUR\n" ); | |
715 | printf( ccbranches[*++plb-EQ], lab); | |
716 | deflab( lab1f ); | |
717 | reclaim( brnode, RNULL, 0 ); | |
718 | break; | |
719 | ||
720 | default: | |
721 | if( mode=='F' ) o = revrel[ o-EQ ]; | |
722 | printf( ccbranches[o-EQ], lab ); | |
723 | break; | |
724 | } | |
725 | ||
726 | brcase = 0; | |
727 | brnode = 0; | |
728 | } | |
729 | } | |
730 | ||
731 | nextcook( p, cookie ) NODE *p; { | |
732 | /* we have failed to match p with cookie; try another */ | |
733 | if( cookie == FORREW ) return( 0 ); /* hopeless! */ | |
734 | if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); | |
735 | if( !(cookie&INTEMP) && asgop(p->op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); | |
736 | return( FORREW ); | |
737 | } | |
738 | ||
739 | lastchance( p, cook ) NODE *p; { | |
740 | /* forget it! */ | |
741 | return(0); | |
742 | } | |
743 | ||
744 | struct functbl { | |
745 | int fop; | |
746 | TWORD ftype; | |
747 | char *func; | |
748 | } opfunc[] = { | |
749 | MUL, LONG, "lmul", | |
750 | DIV, LONG, "ldiv", | |
751 | MOD, LONG, "lrem", | |
752 | ASG MUL, LONG, "almul", | |
753 | ASG DIV, LONG, "aldiv", | |
754 | ASG MOD, LONG, "alrem", | |
755 | MUL, ULONG, "lmul", | |
756 | DIV, ULONG, "uldiv", | |
757 | MOD, ULONG, "ulrem", | |
758 | ASG MUL, ULONG, "almul", | |
759 | ASG DIV, ULONG, "auldiv", | |
760 | ASG MOD, ULONG, "aulrem", | |
761 | 0, 0, 0 }; | |
762 | ||
763 | hardops(p) register NODE *p; { | |
764 | /* change hard to do operators into function calls. | |
765 | for pdp11 do long * / % */ | |
766 | register NODE *q; | |
767 | register struct functbl *f; | |
768 | register o; | |
769 | register TWORD t; | |
770 | ||
771 | o = p->op; | |
772 | t = p->type; | |
773 | if( t!=LONG && t!=ULONG ) return; | |
774 | ||
775 | for( f=opfunc; f->fop; f++ ) { | |
776 | if( o==f->fop && t==f->ftype ) goto convert; | |
777 | } | |
778 | return; | |
779 | ||
780 | /* need address of left node for ASG OP */ | |
781 | /* WARNING - this won't work for long in a REG */ | |
782 | convert: | |
783 | if( asgop( o ) ) { | |
784 | switch( p->left->op ) { | |
785 | ||
786 | case UNARY MUL: /* convert to address */ | |
787 | p->left->op = FREE; | |
788 | p->left = p->left->left; | |
789 | break; | |
790 | ||
791 | case NAME: /* convert to ICON pointer */ | |
792 | p->left->op = ICON; | |
793 | p->left->type = INCREF( p->left->type ); | |
794 | break; | |
795 | ||
796 | case OREG: /* convert OREG to address */ | |
797 | p->left->op = REG; | |
798 | p->left->type = INCREF( p->left->type ); | |
799 | if( p->left->lval != 0 ) { | |
800 | q = talloc(); | |
801 | q->op = PLUS; | |
802 | q->rall = NOPREF; | |
803 | q->type = p->left->type; | |
804 | q->left = p->left; | |
805 | q->right = talloc(); | |
806 | ||
807 | q->right->op = ICON; | |
808 | q->right->rall = NOPREF; | |
809 | q->right->type = INT; | |
810 | q->right->name[0] = '\0'; | |
811 | q->right->lval = p->left->lval; | |
812 | q->right->rval = 0; | |
813 | ||
814 | p->left->lval = 0; | |
815 | p->left = q; | |
816 | } | |
817 | break; | |
818 | ||
819 | default: | |
820 | cerror( "Bad address for hard ops" ); | |
821 | /* NO RETURN */ | |
822 | ||
823 | } | |
824 | } | |
825 | ||
826 | /* build comma op for args to function */ | |
827 | q = talloc(); | |
828 | q->op = CM; | |
829 | q->rall = NOPREF; | |
830 | q->type = INT; | |
831 | q->left = p->left; | |
832 | q->right = p->right; | |
833 | p->op = CALL; | |
834 | p->right = q; | |
835 | ||
836 | /* put function name in left node of call */ | |
837 | p->left = q = talloc(); | |
838 | q->op = ICON; | |
839 | q->rall = NOPREF; | |
840 | q->type = INCREF( FTN + p->type ); | |
841 | strcpy( q->name, f->func ); | |
842 | q->lval = 0; | |
843 | q->rval = 0; | |
844 | ||
845 | return; | |
846 | ||
847 | } | |
848 | ||
849 | optim2( p ) register NODE *p; { | |
850 | /* do local tree transformations and optimizations */ | |
851 | ||
852 | register NODE *r; | |
853 | ||
854 | switch( p->op ) { | |
855 | ||
856 | case AND: | |
857 | /* commute L and R to eliminate compliments and constants */ | |
858 | if( p->left->op==ICON || p->left->op==COMPL ) { | |
859 | r = p->left; | |
860 | p->left = p->right; | |
861 | p->right = r; | |
862 | } | |
863 | case ASG AND: | |
864 | /* change meaning of AND to ~R&L - bic on pdp11 */ | |
865 | r = p->right; | |
866 | if( r->op==ICON ) { /* compliment constant */ | |
867 | r->lval = ~r->lval; | |
868 | } | |
869 | else if( r->op==COMPL ) { /* ~~A => A */ | |
870 | r->op = FREE; | |
871 | p->right = r->left; | |
872 | } | |
873 | else { /* insert complement node */ | |
874 | p->right = talloc(); | |
875 | p->right->op = COMPL; | |
876 | p->right->rall = NOPREF; | |
877 | p->right->type = r->type; | |
878 | p->right->left = r; | |
879 | p->right->right = NULL; | |
880 | } | |
881 | break; | |
882 | ||
883 | } | |
884 | } | |
885 | ||
886 | myreader(p) register NODE *p; { | |
887 | walkf( p, hardops ); /* convert ops to function calls */ | |
888 | canon( p ); /* expands r-vals for fileds */ | |
889 | walkf( p, optim2 ); | |
890 | toff = 0; /* stack offset swindle */ | |
891 | } | |
892 | ||
893 | special( p, shape ) register NODE *p; { | |
894 | /* special shape matching routine */ | |
895 | ||
896 | switch( shape ) { | |
897 | ||
898 | case SCCON: | |
899 | if( p->op == ICON && p->name[0]=='\0' && p->lval>= -128 && p->lval <=127 ) return( 1 ); | |
900 | break; | |
901 | ||
902 | case SICON: | |
903 | if( p->op == ICON && p->name[0]=='\0' && p->lval>= 0 && p->lval <=32767 ) return( 1 ); | |
904 | break; | |
905 | ||
906 | default: | |
907 | cerror( "bad special shape" ); | |
908 | ||
909 | } | |
910 | ||
911 | return( 0 ); | |
912 | } | |
913 | ||
914 | # ifndef ONEPASS | |
915 | main( argc, argv ) char *argv[]; { | |
916 | return( mainp2( argc, argv ) ); | |
917 | } | |
918 | # endif |