1/*	Id: local2.c,v 1.102 2008/11/22 16:12:25 ragge Exp 	*/
2/*	$NetBSD$	*/
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
36void acon(FILE *, NODE *p);
37int argsize(NODE *p);
38void genargs(NODE *p);
39
40static int offlab;
41int offarg;
42static int addto;
43static int regoff[16];
44
45void
46deflab(int label)
47{
48	printf(LABFMT ":\n", label);
49}
50
51void
52prologue(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
80void
81eoftn(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
98void
99prologue(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 */
140void
141eoftn(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 */
195void
196hopcode(int f, int o)
197{
198	cerror("hopcode: f %d %d", f, o);
199}
200
201char *
202rnames[] = {  /* 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
209int
210tlen(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
241static char *
242binskip[] = {
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 */
254static CONSZ
255gethval(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 */
271static void
272twocomp(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 */
312static void
313ptrcomp(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 */
324static void
325twollcomp(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 */
399static void
400constput(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 */
430static int
431oneinstr(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 */
444static void
445emitshort(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]);
490signe:		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 */
512static void
513storeshort(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 */
568static void
569imuli(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 */
587static void
588idivi(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 */
606static void
607xmovei(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
630static void
631printcon(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
655static void
656putcond(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
673void
674zzzcode(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 */
827void
828setregs()
829{
830	fregs = 7;	/* 7 free regs on PDP10 (1-7) */
831}
832
833/*ARGSUSED*/
834int
835rewfld(NODE *p)
836{
837	return(1);
838}
839
840int
841fldexpand(NODE *p, int cookie, char **cp)
842{
843	return 0;
844}
845
846int
847flshape(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 */
856int
857shtemp(NODE *p)
858{
859	return(0);
860}
861
862int
863shumul(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
922void
923adrcon(CONSZ val)
924{
925	cerror("adrcon: val %llo\n", val);
926}
927
928void
929conput(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*/
954void
955insput(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 */
964void
965upput(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
988void
989adrput(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*/
1077void
1078acon(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 */
1087void
1088cbgen(int o,int lab)
1089{
1090}
1091
1092/*
1093 * Do some local optimizations that must be done after optim is called.
1094 */
1095static void
1096optim2(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
1180void
1181myreader(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 */
1200static void
1201pconv2(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
1223void
1224mycanon(NODE *p)
1225{
1226	walkf(p, pconv2, 0);
1227}
1228
1229/*
1230 * Remove last goto.
1231 */
1232void
1233myoptim(struct interpass *ip)
1234{
1235}
1236
1237/*
1238 * Return a class suitable for a specific type.
1239 */
1240int
1241gclass(TWORD t)
1242{
1243	return (szty(t) == 2 ? CLASSB : CLASSA);
1244}
1245
1246static int
1247argsiz(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 */
1259void
1260lastcall(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
1276void
1277rmove(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 */
1287int
1288COLORMAP(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 */
1310void
1311mflags(char *str)
1312{
1313}
1314/*
1315 * Do something target-dependent for xasm arguments.
1316 * Supposed to find target-specific constraints and rewrite them.
1317 */
1318int
1319myxasm(struct interpass *ip, NODE *p)
1320{
1321	return 0;
1322}
1323