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