xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/pdp10/local2.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
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