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