1 /* $Id: local2.c,v 1.105 2012/09/26 20:33:03 plunky Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30 # include "pass2.h"
31 # include <ctype.h>
32
33 void acon(FILE *, NODE *p);
34 int argsize(NODE *p);
35 void genargs(NODE *p);
36
37 static int offlab;
38 int offarg;
39 static int addto;
40 static int regoff[16];
41
42 void
deflab(int label)43 deflab(int label)
44 {
45 printf(LABFMT ":\n", label);
46 }
47
48 void
prologue(struct interpass_prolog * ipp)49 prologue(struct interpass_prolog *ipp)
50 {
51 int i, j;
52
53 if (ipp->ipp_vis)
54 printf(" .globl %s\n", ipp->ipp_name);
55 printf("%s:\n", ipp->ipp_name);
56 addto = p2maxautooff;
57 if (addto >= AUTOINIT/SZCHAR)
58 addto -= AUTOINIT/SZCHAR;
59 addto /= SZINT/SZCHAR; /* use words here */
60 printf(" push %s,%s\n",rnames[STKREG], rnames[FPREG]);
61 printf(" move %s,%s\n", rnames[FPREG],rnames[STKREG]);
62
63 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
64 if (i & 1)
65 regoff[j] = addto++;
66 }
67 if (addto)
68 printf(" addi %s,0%o\n", rnames[STKREG], addto);
69
70 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
71 if (i & 1)
72 printf(" movem %s,%d(%s)\n",
73 rnames[j], regoff[j], rnames[STKREG]);
74 }
75 }
76
77 void
eoftn(struct interpass_prolog * ipp)78 eoftn(struct interpass_prolog *ipp)
79 {
80 int i, j;
81
82 if (ipp->ipp_ip.ip_lbl == 0)
83 return; /* no code needs to be generated */
84 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
85 if (i & 1)
86 printf(" move %s,%d(%s)\n",
87 rnames[j], regoff[j], rnames[STKREG]);
88 }
89 printf(" move %s,%s\n", rnames[STKREG], rnames[FPREG]);
90 printf(" pop %s,%s\n", rnames[STKREG], rnames[FPREG]);
91 printf(" popj %s,\n", rnames[STKREG]);
92 }
93
94 #if 0
95 void
96 prologue(int regs, int autos)
97 {
98 int i, addto;
99
100 offlab = getlab2();
101 if (regs < 0 || autos < 0) {
102 /*
103 * non-optimized code, jump to epilogue for code generation.
104 */
105 ftlab1 = getlab2();
106 ftlab2 = getlab2();
107 printf(" jrst L%d\n", ftlab1);
108 printf("L%d:\n", ftlab2);
109 } else {
110 /*
111 * We here know what register to save and how much to
112 * add to the stack.
113 */
114 autos = autos + (SZINT-1);
115 addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
116 if (addto || gflag) {
117 printf(" push %s,%s\n",rnames[017], rnames[016]);
118 printf(" move %s,%s\n", rnames[016],rnames[017]);
119 for (i = regs; i < MAXRVAR; i++) {
120 int db = ((i+1) < MAXRVAR);
121 printf(" %smovem %s,0%o(%s)\n",
122 db ? "d" : "",
123 rnames[i+1], i+1-regs, rnames[016]);
124 if (db)
125 i++;
126 }
127 if (addto)
128 printf(" addi %s,0%o\n", rnames[017], addto);
129 } else
130 offarg = 1;
131 }
132 }
133
134 /*
135 * End of block.
136 */
137 void
138 eoftn(int regs, int autos, int retlab)
139 {
140 register OFFSZ spoff; /* offset from stack pointer */
141 int i;
142
143 spoff = autos + (SZINT-1);
144 if (spoff >= AUTOINIT)
145 spoff -= AUTOINIT;
146 spoff /= SZINT;
147 /* return from function code */
148 printf("L%d:\n", retlab);
149 if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
150 for (i = regs; i < MAXRVAR; i++) {
151 int db = ((i+1) < MAXRVAR);
152 printf(" %smove %s,0%o(%s)\n", db ? "d" : "",
153 rnames[i+1], i+1-regs, rnames[016]);
154 if (db)
155 i++;
156 }
157 printf(" move %s,%s\n", rnames[017], rnames[016]);
158 printf(" pop %s,%s\n", rnames[017], rnames[016]);
159 }
160 printf(" popj %s,\n", rnames[017]);
161
162 /* Prolog code */
163 if (isoptim == 0) {
164 printf("L%d:\n", ftlab1);
165 printf(" push %s,%s\n", rnames[017], rnames[016]);
166 printf(" move %s,%s\n", rnames[016], rnames[017]);
167 for (i = regs; i < MAXRVAR; i++) {
168 int db = ((i+1) < MAXRVAR);
169 printf(" %smovem %s,0%o(%s)\n", db ? "d" : "",
170 rnames[i+1], i+1-regs, rnames[016]);
171 spoff++;
172 if (db)
173 i++, spoff++;
174 }
175 if (spoff)
176 printf(" addi %s,0%llo\n", rnames[017], spoff);
177 printf(" jrst L%d\n", ftlab2);
178 }
179 printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
180 offarg = isoptim = 0;
181 }
182 #endif
183
184 /*
185 * add/sub/...
186 *
187 * Param given:
188 * R - Register
189 * M - Memory
190 * C - Constant
191 */
192 void
hopcode(int f,int o)193 hopcode(int f, int o)
194 {
195 cerror("hopcode: f %d %d", f, o);
196 }
197
198 char *
199 rnames[] = { /* keyed to register number tokens */
200 "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
201 "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
202 "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
203 "%10", "%11", "%12", "%13", "%14", "%15",
204 };
205
206 int
tlen(p)207 tlen(p) NODE *p;
208 {
209 switch(p->n_type) {
210 case CHAR:
211 case UCHAR:
212 return(1);
213
214 case SHORT:
215 case USHORT:
216 return(SZSHORT/SZCHAR);
217
218 case DOUBLE:
219 return(SZDOUBLE/SZCHAR);
220
221 case INT:
222 case UNSIGNED:
223 case LONG:
224 case ULONG:
225 return(SZINT/SZCHAR);
226
227 case LONGLONG:
228 case ULONGLONG:
229 return SZLONGLONG/SZCHAR;
230
231 default:
232 if (!ISPTR(p->n_type))
233 cerror("tlen type %d not pointer");
234 return SZPOINT(0)/SZCHAR;
235 }
236 }
237
238 static char *
239 binskip[] = {
240 "e", /* jumpe */
241 "n", /* jumpn */
242 "le", /* jumple */
243 "l", /* jumpl */
244 "ge", /* jumpge */
245 "g", /* jumpg */
246 };
247
248 /*
249 * Extract the higher 36 bits from a longlong.
250 */
251 static CONSZ
gethval(CONSZ lval)252 gethval(CONSZ lval)
253 {
254 CONSZ hval = (lval >> 35) & 03777777777LL;
255
256 if ((hval & 03000000000LL) == 03000000000LL) {
257 hval |= 0777000000000LL;
258 } else if ((hval & 03000000000LL) == 02000000000LL) {
259 hval &= 01777777777LL;
260 hval |= 0400000000000LL;
261 }
262 return hval;
263 }
264
265 /*
266 * Do a binary comparision, and jump accordingly.
267 */
268 static void
twocomp(NODE * p)269 twocomp(NODE *p)
270 {
271 int o = p->n_op;
272 extern int negrel[];
273 int isscon = 0, iscon = p->n_right->n_op == ICON;
274
275 if (o < EQ || o > GT)
276 cerror("bad binary conditional branch: %s", opst[o]);
277
278 if (iscon && p->n_right->n_name[0] != 0) {
279 printf(" cam%s ", binskip[negrel[o-EQ]-EQ]);
280 adrput(stdout, getlr(p, 'L'));
281 putchar(',');
282 printf("[ .long ");
283 adrput(stdout, getlr(p, 'R'));
284 putchar(']');
285 printf("\n jrst L%d\n", p->n_label);
286 return;
287 }
288 if (iscon)
289 isscon = p->n_right->n_lval >= 0 &&
290 p->n_right->n_lval < 01000000;
291
292 printf(" ca%c%s ", iscon && isscon ? 'i' : 'm',
293 binskip[negrel[o-EQ]-EQ]);
294 adrput(stdout, getlr(p, 'L'));
295 putchar(',');
296 if (iscon && (isscon == 0)) {
297 printf("[ .long ");
298 adrput(stdout, getlr(p, 'R'));
299 putchar(']');
300 } else
301 adrput(stdout, getlr(p, 'R'));
302 printf("\n jrst L%d\n", p->n_label);
303 }
304
305 /*
306 * Compare byte/word pointers.
307 * XXX - do not work for highest bit set in address
308 */
309 static void
ptrcomp(NODE * p)310 ptrcomp(NODE *p)
311 {
312 printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
313 printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
314 twocomp(p);
315 }
316
317 /*
318 * Do a binary comparision of two long long, and jump accordingly.
319 * XXX - can optimize for constants.
320 */
321 static void
twollcomp(NODE * p)322 twollcomp(NODE *p)
323 {
324 int o = p->n_op;
325 int iscon = p->n_right->n_op == ICON;
326 int m = 0; /* XXX gcc */
327
328 if (o < EQ || o > GT)
329 cerror("bad long long conditional branch: %s", opst[o]);
330
331 /* Special strategy for equal/not equal */
332 if (o == EQ || o == NE) {
333 if (o == EQ)
334 m = getlab2();
335 printf(" came ");
336 upput(getlr(p, 'L'), SZLONG);
337 putchar(',');
338 if (iscon)
339 printf("[ .long ");
340 upput(getlr(p, 'R'), SZLONG);
341 if (iscon)
342 putchar(']');
343 printf("\n jrst L%d\n", o == EQ ? m : p->n_label);
344 printf(" cam%c ", o == EQ ? 'n' : 'e');
345 adrput(stdout, getlr(p, 'L'));
346 putchar(',');
347 if (iscon)
348 printf("[ .long ");
349 adrput(stdout, getlr(p, 'R'));
350 if (iscon)
351 putchar(']');
352 printf("\n jrst L%d\n", p->n_label);
353 if (o == EQ)
354 printf("L%d:\n", m);
355 return;
356 }
357 /* First test highword */
358 printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g');
359 adrput(stdout, getlr(p, 'L'));
360 putchar(',');
361 if (iscon)
362 printf("[ .long ");
363 adrput(stdout, getlr(p, 'R'));
364 if (iscon)
365 putchar(']');
366 printf("\n jrst L%d\n", p->n_label);
367
368 /* Test equality */
369 printf(" came ");
370 adrput(stdout, getlr(p, 'L'));
371 putchar(',');
372 if (iscon)
373 printf("[ .long ");
374 adrput(stdout, getlr(p, 'R'));
375 if (iscon)
376 putchar(']');
377 printf("\n jrst L%d\n", m = getlab2());
378
379 /* Test lowword. Only works with pdp10 format for longlongs */
380 printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g',
381 o == LT || o == GT ? 'e' : ' ');
382 upput(getlr(p, 'L'), SZLONG);
383 putchar(',');
384 if (iscon)
385 printf("[ .long ");
386 upput(getlr(p, 'R'), SZLONG);
387 if (iscon)
388 putchar(']');
389 printf("\n jrst L%d\n", p->n_label);
390 printf("L%d:\n", m);
391 }
392
393 /*
394 * Print the correct instruction for constants.
395 */
396 static void
constput(NODE * p)397 constput(NODE *p)
398 {
399 CONSZ val = p->n_right->n_lval;
400 int reg = p->n_left->n_rval;
401
402 /* Only numeric constant */
403 if (p->n_right->n_name[0] == '\0') {
404 if (val == 0) {
405 printf("movei %s,0", rnames[reg]);
406 } else if ((val & 0777777000000LL) == 0) {
407 printf("movei %s,0%llo", rnames[reg], val);
408 } else if ((val & 0777777) == 0) {
409 printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
410 } else {
411 printf("move %s,[ .long 0%llo]", rnames[reg],
412 szty(p->n_right->n_type) > 1 ? val :
413 val & 0777777777777LL);
414 }
415 /* Can have more tests here, hrloi etc */
416 return;
417 } else {
418 printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
419 if (val)
420 printf("+" CONFMT, val);
421 }
422 }
423
424 /*
425 * Return true if the constant can be bundled in an instruction (immediate).
426 */
427 static int
oneinstr(NODE * p)428 oneinstr(NODE *p)
429 {
430 if (p->n_name[0] != '\0')
431 return 0;
432 if ((p->n_lval & 0777777000000ULL) != 0)
433 return 0;
434 return 1;
435 }
436
437 /*
438 * Emit a halfword or byte instruction, from OREG to REG.
439 * Sign extension must also be done here.
440 */
441 static void
emitshort(NODE * p)442 emitshort(NODE *p)
443 {
444 CONSZ off = p->n_lval;
445 TWORD type = p->n_type;
446 int reg = p->n_rval;
447 int issigned = !ISUNSIGNED(type);
448 int ischar = type == CHAR || type == UCHAR;
449 int reg1 = getlr(p, '1')->n_rval;
450
451 if (off < 0) { /* argument, use move instead */
452 printf(" move ");
453 } else if (off == 0 && p->n_name[0] == 0) {
454 printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]);
455 /* XXX must sign extend here even if not necessary */
456 switch (type) {
457 case CHAR:
458 printf(" lsh %s,033\n", rnames[reg1]);
459 printf(" ash %s,-033\n", rnames[reg1]);
460 break;
461 case SHORT:
462 printf(" hrre %s,%s\n",
463 rnames[reg1], rnames[reg1]);
464 break;
465 }
466 return;
467 } else if (ischar) {
468 if (off >= 0700000000000LL && p->n_name[0] != '\0') {
469 cerror("emitsh");
470 /* reg contains index integer */
471 // if (!istreg(reg))
472 // cerror("emitshort !istreg");
473 printf(" adjbp %s,[ .long 0%llo+%s ]\n",
474 rnames[reg], off, p->n_name);
475 printf(" ldb ");
476 adrput(stdout, getlr(p, '1'));
477 printf(",%s\n", rnames[reg]);
478 goto signe;
479 }
480 printf(" ldb ");
481 adrput(stdout, getlr(p, '1'));
482 if (off)
483 printf(",[ .long 0%02o11%02o%06o ]\n",
484 (int)(27-(9*(off&3))), reg, (int)off/4);
485 else
486 printf(",%s\n", rnames[reg]);
487 signe: if (issigned) {
488 printf(" lsh ");
489 adrput(stdout, getlr(p, '1'));
490 printf(",033\n ash ");
491 adrput(stdout, getlr(p, '1'));
492 printf(",-033\n");
493 }
494 return;
495 } else {
496 printf(" h%cr%c ", off & 1 ? 'r' : 'l',
497 issigned ? 'e' : 'z');
498 }
499 p->n_lval /= (ischar ? 4 : 2);
500 adrput(stdout, getlr(p, '1'));
501 putchar(',');
502 adrput(stdout, getlr(p, 'L'));
503 putchar('\n');
504 }
505
506 /*
507 * Store a short from a register. Destination is a OREG.
508 */
509 static void
storeshort(NODE * p)510 storeshort(NODE *p)
511 {
512 NODE *l = p->n_left;
513 CONSZ off = l->n_lval;
514 int reg = l->n_rval;
515 int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;
516
517 if (l->n_op == NAME) {
518 if (ischar) {
519 printf(" dpb ");
520 adrput(stdout, getlr(p, 'R'));
521 printf(",[ .long 0%02o%010o+%s ]\n",
522 070+((int)off&3), (int)(off/4), l->n_name);
523 return;
524 }
525 printf(" hr%cm ", off & 1 ? 'r' : 'l');
526 l->n_lval /= 2;
527 adrput(stdout, getlr(p, 'R'));
528 putchar(',');
529 adrput(stdout, getlr(p, 'L'));
530 putchar('\n');
531 return;
532 }
533
534 if (off || reg == FPREG) { /* Can emit halfword instructions */
535 if (off < 0) { /* argument, use move instead */
536 printf(" movem ");
537 } else if (ischar) {
538 printf(" dpb ");
539 adrput(stdout, getlr(p, '1'));
540 printf(",[ .long 0%02o11%02o%06o ]\n",
541 (int)(27-(9*(off&3))), reg, (int)off/4);
542 return;
543 } else {
544 printf(" hr%cm ", off & 1 ? 'r' : 'l');
545 }
546 l->n_lval /= 2;
547 adrput(stdout, getlr(p, 'R'));
548 putchar(',');
549 adrput(stdout, getlr(p, 'L'));
550 } else {
551 printf(" dpb ");
552 adrput(stdout, getlr(p, 'R'));
553 putchar(',');
554 l = getlr(p, 'L');
555 l->n_op = REG;
556 adrput(stdout, l);
557 l->n_op = OREG;
558 }
559 putchar('\n');
560 }
561
562 /*
563 * Multiply a register with a constant.
564 */
565 static void
imuli(NODE * p)566 imuli(NODE *p)
567 {
568 NODE *r = p->n_right;
569
570 if (r->n_lval >= 0 && r->n_lval <= 0777777) {
571 printf(" imuli ");
572 adrput(stdout, getlr(p, 'L'));
573 printf(",0%llo\n", r->n_lval);
574 } else {
575 printf(" imul ");
576 adrput(stdout, getlr(p, 'L'));
577 printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
578 }
579 }
580
581 /*
582 * Divide a register with a constant.
583 */
584 static void
idivi(NODE * p)585 idivi(NODE *p)
586 {
587 NODE *r = p->n_right;
588
589 if (r->n_lval >= 0 && r->n_lval <= 0777777) {
590 printf(" idivi ");
591 adrput(stdout, getlr(p, '1'));
592 printf(",0%llo\n", r->n_lval);
593 } else {
594 printf(" idiv ");
595 adrput(stdout, getlr(p, '1'));
596 printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
597 }
598 }
599
600 /*
601 * move a constant into a register.
602 */
603 static void
xmovei(NODE * p)604 xmovei(NODE *p)
605 {
606 /*
607 * Trick: If this is an unnamed constant, just move it directly,
608 * otherwise use xmovei to get section number.
609 */
610 if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
611 printf(" ");
612 zzzcode(p, 'D');
613 putchar(' ');
614 adrput(stdout, getlr(p, '1'));
615 putchar(',');
616 zzzcode(p, 'E');
617 } else {
618 printf(" xmovei ");
619 adrput(stdout, getlr(p, '1'));
620 printf(",%s", p->n_name);
621 if (p->n_lval != 0)
622 printf("+0%llo", p->n_lval);
623 }
624 putchar('\n');
625 }
626
627 static void
printcon(NODE * p)628 printcon(NODE *p)
629 {
630 CONSZ cz;
631
632 p = p->n_left;
633 if (p->n_lval >= 0700000000000LL) {
634 /* converted to pointer in clocal() */
635 conput(stdout, p);
636 return;
637 }
638 if (p->n_lval == 0 && p->n_name[0] == '\0') {
639 putchar('0');
640 return;
641 }
642 if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
643 cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
644 else
645 cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
646 cz |= 0700000000000LL;
647 printf("0%llo", cz);
648 if (p->n_name[0] != '\0')
649 printf("+%s", p->n_name);
650 }
651
652 static void
putcond(NODE * p)653 putcond(NODE *p)
654 {
655 char *c = 0; /* XXX gcc */
656
657 switch (p->n_op) {
658 case EQ: c = "e"; break;
659 case NE: c = "n"; break;
660 case LE: c = "le"; break;
661 case LT: c = "l"; break;
662 case GT: c = "g"; break;
663 case GE: c = "ge"; break;
664 default:
665 cerror("putcond");
666 }
667 printf("%s", c);
668 }
669
670 void
zzzcode(NODE * p,int c)671 zzzcode(NODE *p, int c)
672 {
673 NODE *l;
674 CONSZ hval;
675
676 switch (c) {
677 case 'A': /* ildb right arg */
678 adrput(stdout, p->n_left->n_left);
679 break;
680
681 case 'B': /* remove from stack after subroutine call */
682 if (p->n_qual)
683 printf(" subi %%17,0%o\n", p->n_qual);
684 break;
685
686 case 'C':
687 constput(p);
688 break;
689
690 case 'D': /* Find out which type of const load insn to use */
691 if (p->n_op != ICON)
692 cerror("zzzcode not ICON");
693 if (p->n_name[0] == '\0') {
694 if ((p->n_lval <= 0777777) && (p->n_lval > 0))
695 printf("movei");
696 else if ((p->n_lval & 0777777) == 0)
697 printf("hrlzi");
698 else
699 printf("move");
700 } else
701 printf("move");
702 break;
703
704 case 'E': /* Print correct constant expression */
705 if (p->n_name[0] == '\0') {
706 if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
707 printf("0%llo", p->n_lval);
708 } else if ((p->n_lval & 0777777) == 0) {
709 printf("0%llo", p->n_lval >> 18);
710 } else {
711 if (p->n_lval < 0)
712 printf("[ .long -0%llo]", -p->n_lval);
713 else
714 printf("[ .long 0%llo]", p->n_lval);
715 }
716 } else {
717 if (p->n_lval == 0)
718 printf("[ .long %s]", p->n_name);
719 else
720 printf("[ .long %s+0%llo]",
721 p->n_name, p->n_lval);
722 }
723 break;
724
725 case 'G': /* structure argument */
726 printf(" addl %%17,0%o\n", p->n_stsize/(SZINT/SZCHAR));
727 printf(" foo...\n");
728 break;
729
730 case 'P':
731 p = getlr(p, 'R');
732 /* FALLTHROUGH */
733 case 'O':
734 /*
735 * Print long long expression.
736 */
737 hval = gethval(p->n_lval);
738 printf("[ .long 0%llo,0%llo", hval,
739 (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
740 if (p->n_name[0] != '\0')
741 printf("+%s", p->n_name);
742 printf(" ]");
743 break;
744
745 case 'F': /* Print an "opsimp" instruction based on its const type */
746 hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
747 break;
748
749 case 'H': /* Print a small constant */
750 p = p->n_right;
751 printf("0%llo", p->n_lval & 0777777);
752 break;
753
754 case 'Q': /* two-param long long comparisions */
755 twollcomp(p);
756 break;
757
758 case 'R': /* two-param conditionals */
759 twocomp(p);
760 break;
761
762 case 'U':
763 emitshort(p);
764 break;
765
766 case 'V':
767 storeshort(p);
768 break;
769
770 case 'Z':
771 ptrcomp(p);
772 break;
773
774 case 'a':
775 imuli(p);
776 break;
777
778 case 'b':
779 idivi(p);
780 break;
781
782 case 'c':
783 xmovei(p);
784 break;
785
786 case 'd':
787 printcon(p);
788 break;
789
790 case 'e':
791 putcond(p);
792 break;
793
794 case 'g':
795 if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
796 comperr("bad Zg oreg");
797 printf("%s", rnames[p->n_right->n_rval]);
798 break;
799
800 #if 0
801 case '1': /* double upput */
802 p = getlr(p, '1');
803 p->n_rval += 2;
804 adrput(stdout, p);
805 p->n_rval -= 2;
806 break;
807 #endif
808
809 case 'i': /* Write instruction for short load from name */
810 l = getlr(p, 'L');
811 printf(" h%cr%c %s,%s+" CONFMT "\n",
812 l->n_lval & 1 ? 'r' : 'l',
813 ISUNSIGNED(p->n_type) ? 'z' : 'e',
814 rnames[getlr(p, '1')->n_rval],
815 l->n_name, l->n_lval >> 1);
816 break;
817
818 default:
819 cerror("zzzcode %c", c);
820 }
821 }
822
823 /* set up temporary registers */
824 void
setregs(void)825 setregs(void)
826 {
827 fregs = 7; /* 7 free regs on PDP10 (1-7) */
828 }
829
830 /*ARGSUSED*/
831 int
rewfld(NODE * p)832 rewfld(NODE *p)
833 {
834 return(1);
835 }
836
837 int
fldexpand(NODE * p,int cookie,char ** cp)838 fldexpand(NODE *p, int cookie, char **cp)
839 {
840 return 0;
841 }
842
843 int
flshape(NODE * p)844 flshape(NODE *p)
845 {
846 register int o = p->n_op;
847
848 return (o == REG || o == NAME || o == ICON ||
849 (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
850 }
851
852 /* INTEMP shapes must not contain any temporary registers */
853 int
shtemp(NODE * p)854 shtemp(NODE *p)
855 {
856 return(0);
857 }
858
859 int
shumul(NODE * p,int order)860 shumul(NODE *p, int order)
861 {
862 register int o;
863
864 if (x2debug) {
865 int val;
866 printf("shumul(%p)\n", p);
867 eprint(p, 0, &val, &val);
868 }
869
870 o = p->n_op;
871 #if 0
872 if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
873 return(STARNM);
874 #endif
875
876 #if 0
877 if ((o == INCR) &&
878 (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
879 p->n_right->n_name[0] == '\0') {
880 switch (p->n_type) {
881 case CHAR|PTR:
882 case UCHAR|PTR:
883 o = 1;
884 break;
885
886 case SHORT|PTR:
887 case USHORT|PTR:
888 o = 2;
889 break;
890
891 case INT|PTR:
892 case UNSIGNED|PTR:
893 case LONG|PTR:
894 case ULONG|PTR:
895 case FLOAT|PTR:
896 o = 4;
897 break;
898
899 case DOUBLE|PTR:
900 case LONGLONG|PTR:
901 case ULONGLONG|PTR:
902 o = 8;
903 break;
904
905 default:
906 if (ISPTR(p->n_type) &&
907 ISPTR(DECREF(p->n_type))) {
908 o = 4;
909 break;
910 } else
911 return(0);
912 }
913 return( 0);
914 }
915 #endif
916 return( SRNOPE );
917 }
918
919 void
adrcon(CONSZ val)920 adrcon(CONSZ val)
921 {
922 cerror("adrcon: val %llo\n", val);
923 }
924
925 void
conput(FILE * fp,NODE * p)926 conput(FILE *fp, NODE *p)
927 {
928 switch (p->n_op) {
929 case ICON:
930 if (p->n_lval != 0) {
931 acon(fp, p);
932 if (p->n_name[0] != '\0')
933 fputc('+', fp);
934 }
935 if (p->n_name[0] != '\0')
936 fprintf(fp, "%s", p->n_name);
937 if (p->n_name[0] == '\0' && p->n_lval == 0)
938 fputc('0', fp);
939 return;
940
941 case REG:
942 fprintf(fp, "%s", rnames[p->n_rval]);
943 return;
944
945 default:
946 cerror("illegal conput");
947 }
948 }
949
950 /*ARGSUSED*/
951 void
insput(NODE * p)952 insput(NODE *p)
953 {
954 cerror("insput");
955 }
956
957 /*
958 * Write out the upper address, like the upper register of a 2-register
959 * reference, or the next memory location.
960 */
961 void
upput(NODE * p,int size)962 upput(NODE *p, int size)
963 {
964
965 size /= SZLONG;
966 switch (p->n_op) {
967 case REG:
968 printf("%s", rnames[p->n_rval + size]);
969 break;
970
971 case NAME:
972 case OREG:
973 p->n_lval += size;
974 adrput(stdout, p);
975 p->n_lval -= size;
976 break;
977 case ICON:
978 printf(CONFMT, p->n_lval >> (36 * size));
979 break;
980 default:
981 cerror("upput bad op %d size %d", p->n_op, size);
982 }
983 }
984
985 void
adrput(FILE * fp,NODE * p)986 adrput(FILE *fp, NODE *p)
987 {
988 int r;
989 /* output an address, with offsets, from p */
990
991 if (p->n_op == FLD)
992 p = p->n_left;
993
994 switch (p->n_op) {
995
996 case NAME:
997 if (p->n_name[0] != '\0')
998 fputs(p->n_name, fp);
999 if (p->n_lval != 0)
1000 fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
1001 return;
1002
1003 case OREG:
1004 r = p->n_rval;
1005 #if 0
1006 if (R2TEST(r)) { /* double indexing */
1007 register int flags;
1008
1009 flags = R2UPK3(r);
1010 if (flags & 1)
1011 putc('*', fp);
1012 if (flags & 4)
1013 putc('-', fp);
1014 if (p->n_lval != 0 || p->n_name[0] != '\0')
1015 acon(p);
1016 if (R2UPK1(r) != 100)
1017 printf("(%s)", rnames[R2UPK1(r)]);
1018 if (flags & 2)
1019 putchar('+');
1020 printf("[%s]", rnames[R2UPK2(r)]);
1021 return;
1022 }
1023 #endif
1024 if (R2TEST(r))
1025 cerror("adrput: unwanted double indexing: r %o", r);
1026 if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
1027 fprintf(fp, "%s", p->n_name);
1028 acon(fp, p);
1029 fprintf(fp, "(%s)", rnames[p->n_rval]);
1030 return;
1031 }
1032 if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
1033 p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
1034 } else if (p->n_lval != 0)
1035 acon(fp, p);
1036 if (p->n_name[0] != '\0')
1037 fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
1038 if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
1039 fprintf(fp, "+" LABFMT, offlab);
1040 if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
1041 fprintf(fp, "(017)");
1042 else
1043 fprintf(fp, "(%s)", rnames[p->n_rval]);
1044 return;
1045 case ICON:
1046 /* addressable value of the constant */
1047 if (p->n_lval > 0) {
1048 acon(fp, p);
1049 if (p->n_name[0] != '\0')
1050 putc('+', fp);
1051 }
1052 if (p->n_name[0] != '\0')
1053 fprintf(fp, "%s", p->n_name);
1054 if (p->n_lval < 0)
1055 acon(fp, p);
1056 if (p->n_name[0] == '\0' && p->n_lval == 0)
1057 putc('0', fp);
1058 return;
1059
1060 case REG:
1061 fputs(rnames[p->n_rval], fp);
1062 return;
1063
1064 default:
1065 cerror("illegal address, op %d", p->n_op);
1066 return;
1067
1068 }
1069 }
1070
1071 /*
1072 * print out a constant
1073 */
1074 void
acon(FILE * fp,NODE * p)1075 acon(FILE *fp, NODE *p)
1076 {
1077 if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
1078 fprintf(fp, "-" CONFMT, -p->n_lval);
1079 else
1080 fprintf(fp, CONFMT, p->n_lval);
1081 }
1082
1083 /* printf conditional and unconditional branches */
1084 void
cbgen(int o,int lab)1085 cbgen(int o,int lab)
1086 {
1087 }
1088
1089 /*
1090 * Do some local optimizations that must be done after optim is called.
1091 */
1092 static void
optim2(NODE * p,void * arg)1093 optim2(NODE *p, void *arg)
1094 {
1095 int op = p->n_op;
1096 int m, ml;
1097 NODE *l;
1098
1099 /* Remove redundant PCONV's */
1100 if (op == PCONV) {
1101 l = p->n_left;
1102 m = BTYPE(p->n_type);
1103 ml = BTYPE(l->n_type);
1104 if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
1105 m == DOUBLE || m == STRTY || m == UNIONTY ||
1106 m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
1107 (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
1108 ml == DOUBLE || ml == STRTY || ml == UNIONTY ||
1109 ml == UNSIGNED || ml == ULONG ||
1110 ml == ULONGLONG) && ISPTR(l->n_type)) {
1111 *p = *l;
1112 nfree(l);
1113 op = p->n_op;
1114 } else
1115 if (ISPTR(DECREF(p->n_type)) &&
1116 (l->n_type == INCREF(STRTY))) {
1117 *p = *l;
1118 nfree(l);
1119 op = p->n_op;
1120 } else
1121 if (ISPTR(DECREF(l->n_type)) &&
1122 (p->n_type == INCREF(INT) ||
1123 p->n_type == INCREF(STRTY) ||
1124 p->n_type == INCREF(UNSIGNED))) {
1125 *p = *l;
1126 nfree(l);
1127 op = p->n_op;
1128 }
1129
1130 }
1131 /* Add constands, similar to the one in optim() */
1132 if (op == PLUS && p->n_right->n_op == ICON) {
1133 l = p->n_left;
1134 if (l->n_op == PLUS && l->n_right->n_op == ICON &&
1135 (p->n_right->n_name[0] == '\0' ||
1136 l->n_right->n_name[0] == '\0')) {
1137 l->n_right->n_lval += p->n_right->n_lval;
1138 if (l->n_right->n_name[0] == '\0')
1139 l->n_right->n_name = p->n_right->n_name;
1140 nfree(p->n_right);
1141 *p = *l;
1142 nfree(l);
1143 }
1144 }
1145
1146 /* Convert "PTR undef" (void *) to "PTR uchar" */
1147 /* XXX - should be done in MI code */
1148 if (BTYPE(p->n_type) == VOID)
1149 p->n_type = (p->n_type & ~BTMASK) | UCHAR;
1150 if (op == ICON) {
1151 if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
1152 && p->n_lval == 0 && p->n_name[0] != '\0')
1153 p->n_lval = 0700000000000LL;
1154 if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
1155 && p->n_lval == 0 && p->n_name[0] != '\0')
1156 p->n_lval = 0750000000000LL;
1157 }
1158 if (op == MINUS) {
1159 if ((p->n_left->n_type == (PTR|CHAR) ||
1160 p->n_left->n_type == (PTR|UCHAR)) &&
1161 (p->n_right->n_type == (PTR|CHAR) ||
1162 p->n_right->n_type == (PTR|UCHAR))) {
1163 l = talloc();
1164 l->n_op = SCONV;
1165 l->n_type = INT;
1166 l->n_left = p->n_right;
1167 p->n_right = l;
1168 l = talloc();
1169 l->n_op = SCONV;
1170 l->n_type = INT;
1171 l->n_left = p->n_left;
1172 p->n_left = l;
1173 }
1174 }
1175 }
1176
1177 void
myreader(struct interpass * ipole)1178 myreader(struct interpass *ipole)
1179 {
1180 struct interpass *ip;
1181
1182 DLIST_FOREACH(ip, ipole, qelem) {
1183 if (ip->type != IP_NODE)
1184 continue;
1185 walkf(ip->ip_node, optim2, 0);
1186 }
1187
1188 if (x2debug) {
1189 printf("myreader final tree:\n");
1190 printip(ipole);
1191 }
1192 }
1193
1194 /*
1195 * Remove some PCONVs after OREGs are created.
1196 */
1197 static void
pconv2(NODE * p,void * arg)1198 pconv2(NODE *p, void *arg)
1199 {
1200 NODE *q;
1201
1202 if (p->n_op == PLUS) {
1203 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
1204 if (p->n_right->n_op != ICON)
1205 return;
1206 if (p->n_left->n_op != PCONV)
1207 return;
1208 if (p->n_left->n_left->n_op != OREG)
1209 return;
1210 q = p->n_left->n_left;
1211 nfree(p->n_left);
1212 p->n_left = q;
1213 /*
1214 * This will be converted to another OREG later.
1215 */
1216 }
1217 }
1218 }
1219
1220 void
mycanon(NODE * p)1221 mycanon(NODE *p)
1222 {
1223 walkf(p, pconv2, 0);
1224 }
1225
1226 /*
1227 * Remove last goto.
1228 */
1229 void
myoptim(struct interpass * ip)1230 myoptim(struct interpass *ip)
1231 {
1232 }
1233
1234 /*
1235 * Return a class suitable for a specific type.
1236 */
1237 int
gclass(TWORD t)1238 gclass(TWORD t)
1239 {
1240 return (szty(t) == 2 ? CLASSB : CLASSA);
1241 }
1242
1243 static int
argsiz(NODE * p)1244 argsiz(NODE *p)
1245 {
1246 TWORD t = p->n_type;
1247
1248 if (t == STRTY || t == UNIONTY)
1249 return p->n_stsize/(SZINT/SZCHAR);
1250 return szty(t);
1251 }
1252
1253 /*
1254 * Calculate argument sizes.
1255 */
1256 void
lastcall(NODE * p)1257 lastcall(NODE *p)
1258 {
1259 NODE *op = p;
1260 int size = 0;
1261
1262 p->n_qual = 0;
1263 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1264 return;
1265 for (p = p->n_right; p->n_op == CM; p = p->n_left)
1266 if (p->n_right->n_op != ASSIGN)
1267 size += argsiz(p->n_right);
1268 if (p->n_op != ASSIGN)
1269 size += argsiz(p);
1270 op->n_qual = size; /* XXX */
1271 }
1272
1273 void
rmove(int s,int d,TWORD t)1274 rmove(int s, int d, TWORD t)
1275 {
1276 printf(" %smove %s,%s\n",
1277 (s > 017 ? "d" : ""), rnames[d], rnames[s]);
1278 }
1279
1280 /*
1281 * For class c, find worst-case displacement of the number of
1282 * registers in the array r[] indexed by class.
1283 */
1284 int
COLORMAP(int c,int * r)1285 COLORMAP(int c, int *r)
1286 {
1287 int num;
1288
1289 switch (c) {
1290 case CLASSA:
1291 /* there are 13 classa, so min 6 classb are needed to block */
1292 num = r[CLASSB] * 2;
1293 num += r[CLASSA];
1294 return num < 13;
1295 case CLASSB:
1296 /* 7 classa may block all classb */
1297 num = r[CLASSB] + r[CLASSA];
1298 return num < 7;
1299 }
1300 comperr("COLORMAP");
1301 return 0; /* XXX gcc */
1302 }
1303
1304 /*
1305 * Target-dependent command-line options.
1306 */
1307 void
mflags(char * str)1308 mflags(char *str)
1309 {
1310 }
1311
1312 /*
1313 * Do something target-dependent for xasm arguments.
1314 * Supposed to find target-specific constraints and rewrite them.
1315 */
1316 int
myxasm(struct interpass * ip,NODE * p)1317 myxasm(struct interpass *ip, NODE *p)
1318 {
1319 return 0;
1320 }
1321