1 /*	$Id: reader.c,v 1.290 2014/10/11 09:50:21 ragge Exp $	*/
2 /*
3  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  *
34  * Redistributions of source code and documentation must retain the above
35  * copyright notice, this list of conditions and the following disclaimer.
36  * Redistributions in binary form must reproduce the above copyright
37  * notice, this list of conditionsand the following disclaimer in the
38  * documentation and/or other materials provided with the distribution.
39  * All advertising materials mentioning features or use of this software
40  * must display the following acknowledgement:
41  * 	This product includes software developed or owned by Caldera
42  *	International, Inc.
43  * Neither the name of Caldera International, Inc. nor the names of other
44  * contributors may be used to endorse or promote products derived from
45  * this software without specific prior written permission.
46  *
47  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
48  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
49  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51  * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
52  * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
56  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
57  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60 
61 /*
62  * Everything is entered via pass2_compile().  No functions are
63  * allowed to recurse back into pass2_compile().
64  */
65 
66 # include "pass2.h"
67 
68 #include <string.h>
69 #include <stdarg.h>
70 #include <stdlib.h>
71 
72 /*	some storage declarations */
73 int nrecur;
74 int thisline;
75 int fregs;
76 int p2autooff, p2maxautooff;
77 
78 NODE *nodepole;
79 struct interpass prepole;
80 
81 void saveip(struct interpass *ip);
82 void deltemp(NODE *p, void *);
83 static void cvtemps(struct interpass *ipole, int op, int off);
84 static void fixxasm(struct p2env *);
85 
86 static void gencode(NODE *p, int cookie);
87 static void genxasm(NODE *p);
88 static void afree(void);
89 
90 struct p2env p2env;
91 
92 int
getlab2(void)93 getlab2(void)
94 {
95 	extern int getlab(void);
96 	int rv = getlab();
97 #ifdef PCC_DEBUG
98 	if (p2env.epp->ip_lblnum != rv)
99 		comperr("getlab2 error: %d != %d", p2env.epp->ip_lblnum, rv);
100 #endif
101 	p2env.epp->ip_lblnum++;
102 	return rv;
103 }
104 
105 #ifdef PCC_DEBUG
106 static int *lbldef, *lbluse;
107 static void
cktree(NODE * p,void * arg)108 cktree(NODE *p, void *arg)
109 {
110 	int i;
111 
112 	if (p->n_op > MAXOP)
113 		cerror("%p) op %d slipped through", p, p->n_op);
114 #ifndef FIELDOPS
115 	if (p->n_op == FLD)
116 		cerror("%p) FLD slipped through", p);
117 #endif
118 	if (BTYPE(p->n_type) > MAXTYPES)
119 		cerror("%p) type %x slipped through", p, p->n_type);
120 	if (p->n_op == CBRANCH) {
121 		 if (!logop(p->n_left->n_op))
122 			cerror("%p) not logop branch", p);
123 		i = (int)p->n_right->n_lval;
124 		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
125 			cerror("%p) label %d outside boundaries %d-%d",
126 			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
127 		lbluse[i-p2env.ipp->ip_lblnum] = 1;
128 	}
129 	if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN)
130 		cerror("%p) asgop %d slipped through", p, p->n_op);
131 	if (p->n_op == TEMP &&
132 	    (regno(p) < p2env.ipp->ip_tmpnum || regno(p) >= p2env.epp->ip_tmpnum))
133 		cerror("%p) temporary %d outside boundaries %d-%d",
134 		    p, regno(p), p2env.ipp->ip_tmpnum, p2env.epp->ip_tmpnum);
135 	if (p->n_op == GOTO && p->n_left->n_op == ICON) {
136 		i = (int)p->n_left->n_lval;
137 		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
138 			cerror("%p) label %d outside boundaries %d-%d",
139 			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
140 		lbluse[i-p2env.ipp->ip_lblnum] = 1;
141 	}
142 }
143 
144 /*
145  * Check that the trees are in a suitable state for pass2.
146  */
147 static void
sanitychecks(struct p2env * p2e)148 sanitychecks(struct p2env *p2e)
149 {
150 	struct interpass *ip;
151 	int i;
152 #ifdef notyet
153 	TMPMARK();
154 #endif
155 	lbldef = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
156 	lbluse = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
157 
158 	DLIST_FOREACH(ip, &p2env.ipole, qelem) {
159 		if (ip->type == IP_DEFLAB) {
160 			i = ip->ip_lbl;
161 			if (i < p2e->ipp->ip_lblnum || i >= p2e->epp->ip_lblnum)
162 				cerror("label %d outside boundaries %d-%d",
163 				    i, p2e->ipp->ip_lblnum, p2e->epp->ip_lblnum);
164 			lbldef[i-p2e->ipp->ip_lblnum] = 1;
165 		}
166 		if (ip->type == IP_NODE)
167 			walkf(ip->ip_node, cktree, 0);
168 	}
169 	for (i = 0; i < (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum); i++)
170 		if (lbluse[i] != 0 && lbldef[i] == 0)
171 			cerror("internal label %d not defined",
172 			    i + p2e->ipp->ip_lblnum);
173 
174 #ifdef notyet
175 	TMPFREE();
176 #endif
177 }
178 #endif
179 
180 /*
181  * Look if a temporary comes from a on-stack argument, in that case
182  * use the already existing stack position instead of moving it to
183  * a new place, and remove the move-to-temp statement.
184  */
185 static int
stkarg(int tnr,int (* soff)[2])186 stkarg(int tnr, int (*soff)[2])
187 {
188 	struct p2env *p2e = &p2env;
189 	struct interpass *ip;
190 	NODE *p;
191 
192 	ip = DLIST_NEXT((struct interpass *)p2e->ipp, qelem);
193 	while (ip->type != IP_DEFLAB) /* search for first DEFLAB */
194 		ip = DLIST_NEXT(ip, qelem);
195 
196 	ip = DLIST_NEXT(ip, qelem); /* first NODE */
197 
198 	for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
199 		if (ip->type != IP_NODE)
200 			continue;
201 
202 		p = ip->ip_node;
203 		if (p->n_op == XASM)
204 			continue; /* XXX - hack for x86 PIC */
205 #ifdef notdef
206 		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
207 			comperr("temparg");
208 #endif
209 		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
210 			continue; /* unknown tree */
211 
212 		if (p->n_right->n_op != OREG && p->n_right->n_op != UMUL)
213 			continue; /* arg in register */
214 		if (tnr != regno(p->n_left))
215 			continue; /* wrong assign */
216 		p = p->n_right;
217 		if (p->n_op == UMUL &&
218 		    p->n_left->n_op == PLUS &&
219 		    p->n_left->n_left->n_op == REG &&
220 		    p->n_left->n_right->n_op == ICON) {
221 			soff[0][0] = regno(p->n_left->n_left);
222 			soff[0][1] = (int)p->n_left->n_right->n_lval;
223 		} else if (p->n_op == OREG) {
224 			soff[0][0] = regno(p);
225 			soff[0][1] = (int)p->n_lval;
226 		} else
227 			comperr("stkarg: bad arg");
228 		tfree(ip->ip_node);
229 		DLIST_REMOVE(ip, qelem);
230 		return 1;
231 	}
232 	return 0;
233 }
234 
235 /*
236  * See if an ADDROF is somewhere inside the expression tree.
237  * If so, fill in the offset table.
238  */
239 static void
findaof(NODE * p,void * arg)240 findaof(NODE *p, void *arg)
241 {
242 	int (*aof)[2] = arg;
243 	int tnr;
244 
245 	if (p->n_op != ADDROF || p->n_left->n_op != TEMP)
246 		return;
247 	tnr = regno(p->n_left);
248 	if (aof[tnr][0])
249 		return; /* already gotten stack address */
250 	if (stkarg(tnr, &aof[tnr]))
251 		return;	/* argument was on stack */
252 	aof[tnr][0] = FPREG;
253 	aof[tnr][1] = freetemp(szty(p->n_left->n_type));
254 }
255 
256 /*
257  * Check if a node has side effects.
258  */
259 static int
isuseless(NODE * n)260 isuseless(NODE *n)
261 {
262 	switch (n->n_op) {
263 	case XASM:
264 	case FUNARG:
265 	case UCALL:
266 	case UFORTCALL:
267 	case FORCE:
268 	case ASSIGN:
269 	case CALL:
270 	case FORTCALL:
271 	case CBRANCH:
272 	case RETURN:
273 	case GOTO:
274 	case STCALL:
275 	case USTCALL:
276 	case STASG:
277 	case STARG:
278 		return 0;
279 	default:
280 		return 1;
281 	}
282 }
283 
284 /*
285  * Delete statements with no meaning (like a+b; or 513.4;)
286  */
287 NODE *
deluseless(NODE * p)288 deluseless(NODE *p)
289 {
290 	struct interpass *ip;
291 	NODE *l, *r;
292 
293 	if (optype(p->n_op) == LTYPE) {
294 		nfree(p);
295 		return NULL;
296 	}
297 	if (isuseless(p) == 0)
298 		return p;
299 
300 	if (optype(p->n_op) == UTYPE) {
301 		l = p->n_left;
302 		nfree(p);
303 		return deluseless(l);
304 	}
305 
306 	/* Be sure that both leaves may be valid */
307 	l = deluseless(p->n_left);
308 	r = deluseless(p->n_right);
309 	nfree(p);
310 	if (l && r) {
311 		ip = ipnode(l);
312 		DLIST_INSERT_AFTER(&prepole, ip, qelem);
313 		return r;
314 	} else if (l)
315 		return l;
316 	else if (r)
317 		return r;
318 	return NULL;
319 }
320 
321 /*
322  * Receives interpass structs from pass1.
323  */
324 void
pass2_compile(struct interpass * ip)325 pass2_compile(struct interpass *ip)
326 {
327 	void deljumps(struct p2env *);
328 	struct p2env *p2e = &p2env;
329 	int (*addrp)[2];
330 	MARK mark;
331 
332 	if (ip->type == IP_PROLOG) {
333 		memset(p2e, 0, sizeof(struct p2env));
334 		p2e->ipp = (struct interpass_prolog *)ip;
335 		DLIST_INIT(&p2e->ipole, qelem);
336 	}
337 	DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
338 	if (ip->type != IP_EPILOG)
339 		return;
340 
341 #ifdef PCC_DEBUG
342 	if (e2debug) {
343 		printf("Entering pass2\n");
344 		printip(&p2e->ipole);
345 	}
346 #endif
347 
348 	afree();
349 	p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
350 	p2maxautooff = p2autooff = p2e->epp->ipp_autos;
351 
352 #ifdef PCC_DEBUG
353 	sanitychecks(p2e);
354 #endif
355 	myreader(&p2e->ipole); /* local massage of input */
356 
357 	/*
358 	 * Do initial modification of the trees.  Two loops;
359 	 * - first, search for ADDROF of TEMPs, these must be
360 	 *   converterd to OREGs on stack.
361 	 * - second, do the actual conversions, in case of not xtemps
362 	 *   convert all temporaries to stack references.
363 	 */
364 	markset(&mark);
365 	if (p2e->epp->ip_tmpnum != p2e->ipp->ip_tmpnum) {
366 		addrp = tmpcalloc(sizeof(*addrp) *
367 		    (p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum));
368 		addrp -= p2e->ipp->ip_tmpnum;
369 	} else
370 		addrp = NULL;
371 	if (xtemps) {
372 		DLIST_FOREACH(ip, &p2e->ipole, qelem) {
373 			if (ip->type == IP_NODE)
374 				walkf(ip->ip_node, findaof, addrp);
375 		}
376 	}
377 	DLIST_FOREACH(ip, &p2e->ipole, qelem)
378 		if (ip->type == IP_NODE)
379 			walkf(ip->ip_node, deltemp, addrp);
380 	markfree(&mark);
381 
382 #ifdef PCC_DEBUG
383 	if (e2debug) {
384 		printf("Efter ADDROF/TEMP\n");
385 		printip(&p2e->ipole);
386 	}
387 #endif
388 
389 	DLIST_INIT(&prepole, qelem);
390 	DLIST_FOREACH(ip, &p2e->ipole, qelem) {
391 		if (ip->type != IP_NODE)
392 			continue;
393 		canon(ip->ip_node);
394 		if ((ip->ip_node = deluseless(ip->ip_node)) == NULL) {
395 			DLIST_REMOVE(ip, qelem);
396 		} else while (!DLIST_ISEMPTY(&prepole, qelem)) {
397 			struct interpass *tipp;
398 
399 			tipp = DLIST_NEXT(&prepole, qelem);
400 			DLIST_REMOVE(tipp, qelem);
401 			DLIST_INSERT_BEFORE(ip, tipp, qelem);
402 		}
403 	}
404 
405 	fixxasm(p2e); /* setup for extended asm */
406 
407 	optimize(p2e);
408 	ngenregs(p2e);
409 
410 	if (xtemps && xdeljumps)
411 		deljumps(p2e);
412 
413 	DLIST_FOREACH(ip, &p2e->ipole, qelem)
414 		emit(ip);
415 }
416 
417 void
emit(struct interpass * ip)418 emit(struct interpass *ip)
419 {
420 	NODE *p, *r;
421 	struct optab *op;
422 	int o;
423 
424 	switch (ip->type) {
425 	case IP_NODE:
426 		p = ip->ip_node;
427 
428 		nodepole = p;
429 		canon(p); /* may convert stuff after genregs */
430 #ifdef PCC_DEBUG
431 		if (c2debug > 1) {
432 			printf("emit IP_NODE:\n");
433 			fwalk(p, e2print, 0);
434 		}
435 #endif
436 		switch (p->n_op) {
437 		case CBRANCH:
438 			/* Only emit branch insn if RESCC */
439 			/* careful when an OPLOG has been elided */
440 			if (p->n_left->n_su == 0 && p->n_left->n_left != NULL) {
441 				op = &table[TBLIDX(p->n_left->n_left->n_su)];
442 				r = p->n_left;
443 			} else {
444 				op = &table[TBLIDX(p->n_left->n_su)];
445 				r = p;
446 			}
447 			if (op->rewrite & RESCC) {
448 				o = p->n_left->n_op;
449 				gencode(r, FORCC);
450 				cbgen(o, p->n_right->n_lval);
451 			} else {
452 				gencode(r, FORCC);
453 			}
454 			break;
455 		case FORCE:
456 			gencode(p->n_left, INREGS);
457 			break;
458 		case XASM:
459 			genxasm(p);
460 			break;
461 		default:
462 			if (p->n_op != REG || p->n_type != VOID) /* XXX */
463 				gencode(p, FOREFF); /* Emit instructions */
464 		}
465 
466 		tfree(p);
467 		break;
468 	case IP_PROLOG:
469 		prologue((struct interpass_prolog *)ip);
470 		break;
471 	case IP_EPILOG:
472 		eoftn((struct interpass_prolog *)ip);
473 		p2maxautooff = p2autooff = AUTOINIT/SZCHAR;
474 		break;
475 	case IP_DEFLAB:
476 		deflab(ip->ip_lbl);
477 		break;
478 	case IP_ASM:
479 		printf("%s", ip->ip_asm);
480 		break;
481 	default:
482 		cerror("emit %d", ip->type);
483 	}
484 }
485 
486 #ifdef PCC_DEBUG
487 char *cnames[] = {
488 	"SANY",
489 	"SAREG",
490 	"SBREG",
491 	"SCREG",
492 	"SDREG",
493 	"SCC",
494 	"SNAME",
495 	"SCON",
496 	"SFLD",
497 	"SOREG",
498 	"STARNM",
499 	"STARREG",
500 	"INTEMP",
501 	"FORARG",
502 	"SWADD",
503 	0,
504 };
505 
506 /*
507  * print a nice-looking description of cookie
508  */
509 char *
prcook(int cookie)510 prcook(int cookie)
511 {
512 	static char buf[50];
513 	int i, flag;
514 
515 	if (cookie & SPECIAL) {
516 		switch (cookie) {
517 		case SZERO:
518 			return "SZERO";
519 		case SONE:
520 			return "SONE";
521 		case SMONE:
522 			return "SMONE";
523 		default:
524 			snprintf(buf, sizeof(buf), "SPECIAL+%d", cookie & ~SPECIAL);
525 			return buf;
526 		}
527 	}
528 
529 	flag = 0;
530 	buf[0] = 0;
531 	for (i = 0; cnames[i]; ++i) {
532 		if (cookie & (1<<i)) {
533 			if (flag)
534 				strlcat(buf, "|", sizeof(buf));
535 			++flag;
536 			strlcat(buf, cnames[i], sizeof(buf));
537 		}
538 	}
539 	return buf;
540 }
541 #endif
542 
543 int
geninsn(NODE * p,int cookie)544 geninsn(NODE *p, int cookie)
545 {
546 	NODE *p1, *p2;
547 	int q, o, rv = 0;
548 
549 #ifdef PCC_DEBUG
550 	if (o2debug) {
551 		printf("geninsn(%p, %s)\n", p, prcook(cookie));
552 		fwalk(p, e2print, 0);
553 	}
554 #endif
555 
556 	q = cookie & QUIET;
557 	cookie &= ~QUIET; /* XXX - should not be necessary */
558 
559 again:	switch (o = p->n_op) {
560 	case EQ:
561 	case NE:
562 	case LE:
563 	case LT:
564 	case GE:
565 	case GT:
566 	case ULE:
567 	case ULT:
568 	case UGE:
569 	case UGT:
570 		p1 = p->n_left;
571 		p2 = p->n_right;
572 		if (p2->n_op == ICON && p2->n_lval == 0 && *p2->n_name == 0 &&
573 		    (dope[p1->n_op] & (FLOFLG|DIVFLG|SIMPFLG|SHFFLG))) {
574 #ifdef mach_pdp11 /* XXX all targets? */
575 			if ((rv = geninsn(p1, FORCC|QUIET)) != FFAIL)
576 				break;
577 #else
578 			if (findops(p1, FORCC) > 0)
579 				break;
580 #endif
581 		}
582 		rv = relops(p);
583 		break;
584 
585 	case PLUS:
586 	case MINUS:
587 	case MUL:
588 	case DIV:
589 	case MOD:
590 	case AND:
591 	case OR:
592 	case ER:
593 	case LS:
594 	case RS:
595 		rv = findops(p, cookie);
596 		break;
597 
598 	case ASSIGN:
599 #ifdef FINDMOPS
600 		if ((rv = findmops(p, cookie)) != FFAIL)
601 			break;
602 		/* FALLTHROUGH */
603 #endif
604 	case STASG:
605 		rv = findasg(p, cookie);
606 		break;
607 
608 	case UMUL: /* May turn into an OREG */
609 		rv = findumul(p, cookie);
610 		break;
611 
612 	case REG:
613 	case TEMP:
614 	case NAME:
615 	case ICON:
616 	case FCON:
617 	case OREG:
618 		rv = findleaf(p, cookie);
619 		break;
620 
621 	case STCALL:
622 	case CALL:
623 		/* CALL arguments are handled special */
624 		for (p1 = p->n_right; p1->n_op == CM; p1 = p1->n_left)
625 			(void)geninsn(p1->n_right, FOREFF);
626 		(void)geninsn(p1, FOREFF);
627 		/* FALLTHROUGH */
628 	case FLD:
629 	case COMPL:
630 	case UMINUS:
631 	case PCONV:
632 	case SCONV:
633 /*	case INIT: */
634 	case GOTO:
635 	case FUNARG:
636 	case STARG:
637 	case UCALL:
638 	case USTCALL:
639 	case ADDROF:
640 		rv = finduni(p, cookie);
641 		break;
642 
643 	case CBRANCH:
644 		p1 = p->n_left;
645 		p2 = p->n_right;
646 		p1->n_label = (int)p2->n_lval;
647 		(void)geninsn(p1, FORCC);
648 		p->n_su = 0;
649 		break;
650 
651 	case FORCE: /* XXX needed? */
652 		(void)geninsn(p->n_left, INREGS);
653 		p->n_su = 0; /* su calculations traverse left */
654 		break;
655 
656 	case XASM:
657 		for (p1 = p->n_left; p1->n_op == CM; p1 = p1->n_left)
658 			(void)geninsn(p1->n_right, FOREFF);
659 		(void)geninsn(p1, FOREFF);
660 		break;	/* all stuff already done? */
661 
662 	case XARG:
663 		/* generate code for correct class here */
664 #if 0
665 		geninsn(p->n_left, 1 << p->n_label);
666 #endif
667 		break;
668 
669 	default:
670 		comperr("geninsn: bad op %s, node %p", opst[o], p);
671 	}
672 	if (rv == FFAIL && !q)
673 		comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]);
674 	if (rv == FRETRY)
675 		goto again;
676 #ifdef PCC_DEBUG
677 	if (o2debug) {
678 		printf("geninsn(%p, %s) rv %d\n", p, prcook(cookie), rv);
679 		fwalk(p, e2print, 0);
680 	}
681 #endif
682 	return rv;
683 }
684 
685 #ifdef PCC_DEBUG
686 #define	CDEBUG(x) if (c2debug) printf x
687 #else
688 #define	CDEBUG(x)
689 #endif
690 
691 /*
692  * Do a register-register move if necessary.
693  * Called if a RLEFT or RRIGHT is found.
694  */
695 static void
ckmove(NODE * p,NODE * q)696 ckmove(NODE *p, NODE *q)
697 {
698 	struct optab *t = &table[TBLIDX(p->n_su)];
699 	int reg;
700 
701 	if (q->n_op != REG || p->n_reg == -1)
702 		return; /* no register */
703 
704 	/* do we have a need for special reg? */
705 	if ((t->needs & NSPECIAL) &&
706 	    (reg = rspecial(t, p->n_left == q ? NLEFT : NRIGHT)) >= 0)
707 		;
708 	else
709 		reg = DECRA(p->n_reg, 0);
710 
711 	if (reg < 0 || reg == DECRA(q->n_reg, 0))
712 		return; /* no move necessary */
713 
714 	CDEBUG(("rmove: node %p, %s -> %s\n", p, rnames[DECRA(q->n_reg, 0)],
715 	    rnames[reg]));
716 	rmove(DECRA(q->n_reg, 0), reg, p->n_type);
717 	q->n_reg = q->n_rval = reg;
718 }
719 
720 /*
721  * Rewrite node to register after instruction emit.
722  */
723 static void
rewrite(NODE * p,int dorewrite,int cookie)724 rewrite(NODE *p, int dorewrite, int cookie)
725 {
726 	NODE *l, *r;
727 	int o;
728 
729 	l = getlr(p, 'L');
730 	r = getlr(p, 'R');
731 	o = p->n_op;
732 	p->n_op = REG;
733 	p->n_lval = 0;
734 	p->n_name = "";
735 
736 	if (o == ASSIGN || o == STASG) {
737 		/* special rewrite care */
738 		int reg = DECRA(p->n_reg, 0);
739 #define	TL(x) (TBLIDX(x->n_su) || x->n_op == REG)
740 		if (p->n_reg == -1)
741 			;
742 		else if (TL(l) && (DECRA(l->n_reg, 0) == reg))
743 			;
744 		else if (TL(r) && (DECRA(r->n_reg, 0) == reg))
745 			;
746 		else if (TL(l))
747 			rmove(DECRA(l->n_reg, 0), reg, p->n_type);
748 		else if (TL(r))
749 			rmove(DECRA(r->n_reg, 0), reg, p->n_type);
750 #if 0
751 		else
752 			comperr("rewrite");
753 #endif
754 #undef TL
755 	}
756 	if (optype(o) != LTYPE)
757 		tfree(l);
758 	if (optype(o) == BITYPE)
759 		tfree(r);
760 	if (dorewrite == 0)
761 		return;
762 	CDEBUG(("rewrite: %p, reg %s\n", p,
763 	    p->n_reg == -1? "<none>" : rnames[DECRA(p->n_reg, 0)]));
764 	p->n_rval = DECRA(p->n_reg, 0);
765 }
766 
767 #ifndef XASM_TARGARG
768 #define	XASM_TARGARG(x,y) 0
769 #endif
770 
771 /*
772  * printout extended assembler.
773  */
774 void
genxasm(NODE * p)775 genxasm(NODE *p)
776 {
777 	NODE *q, **nary;
778 	int n = 1, o = 0, v = 0;
779 	char *w;
780 
781 	if (p->n_left->n_op != ICON || p->n_left->n_type != STRTY) {
782 		for (q = p->n_left; q->n_op == CM; q = q->n_left)
783 			n++;
784 		nary = tmpcalloc(sizeof(NODE *)*(n+1));
785 		o = n;
786 		for (q = p->n_left; q->n_op == CM; q = q->n_left) {
787 			gencode(q->n_right->n_left, INREGS);
788 			nary[--o] = q->n_right;
789 		}
790 		gencode(q->n_left, INREGS);
791 		nary[--o] = q;
792 	} else
793 		nary = 0;
794 
795 	w = p->n_name;
796 	putchar('\t');
797 	while (*w != 0) {
798 		if (*w == '%') {
799 			if (w[1] == '%')
800 				putchar('%');
801 			else if (XASM_TARGARG(w, nary))
802 				; /* handled by target */
803 			else if (w[1] == '=') {
804 				if (v == 0) v = getlab2();
805 				printf("%d", v);
806 			} else if (w[1] == 'c') {
807 				q = nary[(int)w[2]-'0'];
808 				if (q->n_left->n_op != ICON)
809 					uerror("impossible constraint");
810 				printf(CONFMT, q->n_left->n_lval);
811 				w++;
812 			} else if (w[1] < '0' || w[1] > (n + '0'))
813 				uerror("bad xasm arg number %c", w[1]);
814 			else {
815 				if (w[1] == (n + '0'))
816 					q = nary[(int)w[1]-'0' - 1]; /* XXX */
817 				else
818 					q = nary[(int)w[1]-'0'];
819 				adrput(stdout, q->n_left);
820 			}
821 			w++;
822 		} else if (*w == '\\') { /* Always 3-digit octal */
823 			int num = *++w - '0';
824 			num = (num << 3) + *++w - '0';
825 			num = (num << 3) + *++w - '0';
826 			putchar(num);
827 		} else
828 			putchar(*w);
829 		w++;
830 	}
831 	putchar('\n');
832 }
833 
834 /*
835  * Allocate temporary registers for use while emitting this table entry.
836  */
837 static void
allo(NODE * p,struct optab * q)838 allo(NODE *p, struct optab *q)
839 {
840 	extern int stktemp;
841 	int i, n = ncnt(q->needs);
842 
843 	for (i = 0; i < NRESC; i++)
844 		if (resc[i].n_op != FREE)
845 			comperr("allo: used reg");
846 	if (n == 0 && (q->needs & NTMASK) == 0)
847 		return;
848 	for (i = 0; i < n+1; i++) {
849 		resc[i].n_op = REG;
850 		resc[i].n_type = p->n_type; /* XXX should be correct type */
851 		resc[i].n_rval = DECRA(p->n_reg, i);
852 		resc[i].n_su = p->n_su; /* ??? */
853 	}
854 	if (i > NRESC)
855 		comperr("allo: too many allocs");
856 	if (q->needs & NTMASK) {
857 #ifdef	MYALLOTEMP
858 		MYALLOTEMP(resc[i], stktemp);
859 #else
860 		resc[i].n_op = OREG;
861 		resc[i].n_lval = stktemp;
862 		resc[i].n_rval = FPREG;
863 		resc[i].n_su = p->n_su; /* ??? */
864 		resc[i].n_name = "";
865 #endif
866 	}
867 }
868 
869 static void
afree(void)870 afree(void)
871 {
872 	int i;
873 
874 	for (i = 0; i < NRESC; i++)
875 		resc[i].n_op = FREE;
876 }
877 
878 void
gencode(NODE * p,int cookie)879 gencode(NODE *p, int cookie)
880 {
881 	struct optab *q = &table[TBLIDX(p->n_su)];
882 	NODE *p1, *l, *r;
883 	int o = optype(p->n_op);
884 #ifdef FINDMOPS
885 	int ismops = (p->n_op == ASSIGN && (p->n_flags & 1));
886 #endif
887 
888 	l = p->n_left;
889 	r = p->n_right;
890 
891 	if (TBLIDX(p->n_su) == 0) {
892 		if (o == BITYPE && (p->n_su & DORIGHT))
893 			gencode(r, 0);
894 		if (optype(p->n_op) != LTYPE)
895 			gencode(l, 0);
896 		if (o == BITYPE && !(p->n_su & DORIGHT))
897 			gencode(r, 0);
898 		return;
899 	}
900 
901 	CDEBUG(("gencode: node %p\n", p));
902 
903 	if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval)
904 		return; /* meaningless move to itself */
905 
906 	if (callop(p->n_op))
907 		lastcall(p); /* last chance before function args */
908 	if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) {
909 		/* Print out arguments first */
910 		for (p1 = r; p1->n_op == CM; p1 = p1->n_left)
911 			gencode(p1->n_right, FOREFF);
912 		gencode(p1, FOREFF);
913 		o = UTYPE; /* avoid going down again */
914 	}
915 
916 	if (o == BITYPE && (p->n_su & DORIGHT)) {
917 		gencode(r, INREGS);
918 		if (q->rewrite & RRIGHT)
919 			ckmove(p, r);
920 	}
921 	if (o != LTYPE) {
922 		gencode(l, INREGS);
923 #ifdef FINDMOPS
924 		if (ismops)
925 			;
926 		else
927 #endif
928 		     if (q->rewrite & RLEFT)
929 			ckmove(p, l);
930 	}
931 	if (o == BITYPE && !(p->n_su & DORIGHT)) {
932 		gencode(r, INREGS);
933 		if (q->rewrite & RRIGHT)
934 			ckmove(p, r);
935 	}
936 
937 #ifdef FINDMOPS
938 	if (ismops) {
939 		/* reduce right tree to make expand() work */
940 		if (optype(r->n_op) != LTYPE) {
941 			p->n_op = r->n_op;
942 			r = tcopy(r->n_right);
943 			tfree(p->n_right);
944 			p->n_right = r;
945 		}
946 	}
947 #endif
948 
949 	canon(p);
950 
951 	if (q->needs & NSPECIAL) {
952 		int rr = rspecial(q, NRIGHT);
953 		int lr = rspecial(q, NLEFT);
954 
955 		if (rr >= 0) {
956 #ifdef PCC_DEBUG
957 			if (optype(p->n_op) != BITYPE)
958 				comperr("gencode: rspecial borked");
959 #endif
960 			if (r->n_op != REG)
961 				comperr("gencode: rop != REG");
962 			if (rr != r->n_rval)
963 				rmove(r->n_rval, rr, r->n_type);
964 			r->n_rval = r->n_reg = rr;
965 		}
966 		if (lr >= 0) {
967 			if (l->n_op != REG)
968 				comperr("gencode: %p lop != REG", p);
969 			if (lr != l->n_rval)
970 				rmove(l->n_rval, lr, l->n_type);
971 			l->n_rval = l->n_reg = lr;
972 		}
973 		if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr))
974 			comperr("gencode: cross-reg-move");
975 	}
976 
977 	if (p->n_op == ASSIGN &&
978 	    p->n_left->n_op == REG && p->n_right->n_op == REG &&
979 	    p->n_left->n_rval == p->n_right->n_rval &&
980 	    (p->n_su & RVCC) == 0) { /* XXX should check if necessary */
981 		/* do not emit anything */
982 		CDEBUG(("gencode(%p) assign nothing\n", p));
983 		rewrite(p, q->rewrite, cookie);
984 		return;
985 	}
986 
987 	CDEBUG(("emitting node %p\n", p));
988 	if (TBLIDX(p->n_su) == 0)
989 		return;
990 
991 	allo(p, q);
992 	expand(p, cookie, q->cstring);
993 
994 #ifdef FINDMOPS
995 	if (ismops && DECRA(p->n_reg, 0) != regno(l) && cookie != FOREFF) {
996 		CDEBUG(("gencode(%p) rmove\n", p));
997 		rmove(regno(l), DECRA(p->n_reg, 0), p->n_type);
998 	} else
999 #endif
1000 	if (callop(p->n_op) && cookie != FOREFF &&
1001 	    DECRA(p->n_reg, 0) != RETREG(p->n_type)) {
1002 		CDEBUG(("gencode(%p) retreg\n", p));
1003 		rmove(RETREG(p->n_type), DECRA(p->n_reg, 0), p->n_type);
1004 	} else if (q->needs & NSPECIAL) {
1005 		int rr = rspecial(q, NRES);
1006 
1007 		if (rr >= 0 && DECRA(p->n_reg, 0) != rr) {
1008 			CDEBUG(("gencode(%p) nspec retreg\n", p));
1009 			rmove(rr, DECRA(p->n_reg, 0), p->n_type);
1010 		}
1011 	} else if ((q->rewrite & RESC1) &&
1012 	    (DECRA(p->n_reg, 1) != DECRA(p->n_reg, 0))) {
1013 		CDEBUG(("gencode(%p) RESC1 retreg\n", p));
1014 		rmove(DECRA(p->n_reg, 1), DECRA(p->n_reg, 0), p->n_type);
1015 	}
1016 #if 0
1017 		/* XXX - kolla upp det h{r */
1018 	   else if (p->n_op == ASSIGN) {
1019 		/* may need move added if RLEFT/RRIGHT */
1020 		/* XXX should be handled in sucomp() */
1021 		if ((q->rewrite & RLEFT) && (p->n_left->n_op == REG) &&
1022 		    (p->n_left->n_rval != DECRA(p->n_reg, 0)) &&
1023 		    TCLASS(p->n_su)) {
1024 			rmove(p->n_left->n_rval, DECRA(p->n_reg, 0), p->n_type);
1025 		} else if ((q->rewrite & RRIGHT) && (p->n_right->n_op == REG) &&
1026 		    (p->n_right->n_rval != DECRA(p->n_reg, 0)) &&
1027 		    TCLASS(p->n_su)) {
1028 			rmove(p->n_right->n_rval, DECRA(p->n_reg, 0), p->n_type);
1029 		}
1030 	}
1031 #endif
1032 	rewrite(p, q->rewrite, cookie);
1033 	afree();
1034 }
1035 
1036 int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;  /* negatives of relationals */
1037 size_t negrelsize = sizeof negrel / sizeof negrel[0];
1038 
1039 #ifdef PCC_DEBUG
1040 #undef	PRTABLE
1041 void
e2print(NODE * p,int down,int * a,int * b)1042 e2print(NODE *p, int down, int *a, int *b)
1043 {
1044 #ifdef PRTABLE
1045 	extern int tablesize;
1046 #endif
1047 
1048 	*a = *b = down+1;
1049 	while( down >= 2 ){
1050 		printf("\t");
1051 		down -= 2;
1052 		}
1053 	if( down-- ) printf("    " );
1054 
1055 
1056 	printf("%p) %s", p, opst[p->n_op] );
1057 	switch( p->n_op ) { /* special cases */
1058 
1059 	case FLD:
1060 		printf(" sz=%d, shift=%d",
1061 		    UPKFSZ(p->n_rval), UPKFOFF(p->n_rval));
1062 		break;
1063 
1064 	case REG:
1065 		printf(" %s", rnames[p->n_rval] );
1066 		break;
1067 
1068 	case TEMP:
1069 		printf(" %d", regno(p));
1070 		break;
1071 
1072 	case XASM:
1073 	case XARG:
1074 		printf(" '%s'", p->n_name);
1075 		break;
1076 
1077 	case ICON:
1078 	case NAME:
1079 	case OREG:
1080 		printf(" " );
1081 		adrput(stdout, p );
1082 		break;
1083 
1084 	case STCALL:
1085 	case USTCALL:
1086 	case STARG:
1087 	case STASG:
1088 		printf(" size=%d", p->n_stsize );
1089 		printf(" align=%d", p->n_stalign );
1090 		break;
1091 		}
1092 
1093 	printf(", " );
1094 	tprint(p->n_type, p->n_qual);
1095 	printf(", " );
1096 
1097 	prtreg(p);
1098 	printf(", SU= %d(%cREG,%s,%s,%s,%s,%s,%s)\n",
1099 	    TBLIDX(p->n_su),
1100 	    TCLASS(p->n_su)+'@',
1101 #ifdef PRTABLE
1102 	    TBLIDX(p->n_su) >= 0 && TBLIDX(p->n_su) <= tablesize ?
1103 	    table[TBLIDX(p->n_su)].cstring : "",
1104 #else
1105 	    "",
1106 #endif
1107 	    p->n_su & LREG ? "LREG" : "", p->n_su & RREG ? "RREG" : "",
1108 	    p->n_su & RVEFF ? "RVEFF" : "", p->n_su & RVCC ? "RVCC" : "",
1109 	    p->n_su & DORIGHT ? "DORIGHT" : "");
1110 }
1111 #endif
1112 
1113 /*
1114  * change left TEMPs into OREGs
1115  */
1116 void
deltemp(NODE * p,void * arg)1117 deltemp(NODE *p, void *arg)
1118 {
1119 	int (*aor)[2] = arg;
1120 	NODE *l;
1121 
1122 	if (p->n_op == TEMP) {
1123 		if (aor[regno(p)][0] == 0) {
1124 			if (xtemps)
1125 				return;
1126 			aor[regno(p)][0] = FPREG;
1127 			aor[regno(p)][1] = freetemp(szty(p->n_type));
1128 		}
1129 		storemod(p, aor[regno(p)][1], aor[regno(p)][0]);
1130 	} else if (p->n_op == ADDROF && p->n_left->n_op == OREG) {
1131 		p->n_op = PLUS;
1132 		l = p->n_left;
1133 		l->n_op = REG;
1134 		l->n_type = INCREF(l->n_type);
1135 		p->n_right = mklnode(ICON, l->n_lval, 0, INT);
1136 	} else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) {
1137 		l = p->n_left;
1138 		*p = *p->n_left->n_left;
1139 		nfree(l->n_left);
1140 		nfree(l);
1141 	}
1142 }
1143 
1144 /*
1145  * for pointer/integer arithmetic, set pointer at left node
1146  */
1147 static void
setleft(NODE * p,void * arg)1148 setleft(NODE *p, void *arg)
1149 {
1150 	NODE *q;
1151 
1152 	/* only additions for now */
1153 	if (p->n_op != PLUS)
1154 		return;
1155 	if (ISPTR(p->n_right->n_type) && !ISPTR(p->n_left->n_type)) {
1156 		q = p->n_right;
1157 		p->n_right = p->n_left;
1158 		p->n_left = q;
1159 	}
1160 }
1161 
1162 /* It is OK to have these as externals */
1163 static int oregr;
1164 static CONSZ oregtemp;
1165 static char *oregcp;
1166 /*
1167  * look for situations where we can turn * into OREG
1168  * If sharp then do not allow temps.
1169  */
1170 int
oregok(NODE * p,int sharp)1171 oregok(NODE *p, int sharp)
1172 {
1173 
1174 	NODE *q;
1175 	NODE *ql, *qr;
1176 	int r;
1177 	CONSZ temp;
1178 	char *cp;
1179 
1180 	q = p->n_left;
1181 #if 0
1182 	if ((q->n_op == REG || (q->n_op == TEMP && !sharp)) &&
1183 	    q->n_rval == DECRA(q->n_reg, 0)) {
1184 #endif
1185 	if (q->n_op == REG || (q->n_op == TEMP && !sharp)) {
1186 		temp = q->n_lval;
1187 		r = q->n_rval;
1188 		cp = q->n_name;
1189 		goto ormake;
1190 	}
1191 
1192 	if (q->n_op != PLUS && q->n_op != MINUS)
1193 		return 0;
1194 	ql = q->n_left;
1195 	qr = q->n_right;
1196 
1197 #ifdef R2REGS
1198 
1199 	/* look for doubly indexed expressions */
1200 	/* XXX - fix checks */
1201 
1202 	if( q->n_op == PLUS) {
1203 		int i;
1204 		if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
1205 			makeor2(p, ql, r, i);
1206 			return 1;
1207 		} else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
1208 			makeor2(p, qr, r, i);
1209 			return 1;
1210 		}
1211 	}
1212 
1213 
1214 #endif
1215 
1216 #if 0
1217 	if( (q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
1218 			(ql->n_op==REG || (ql->n_op==TEMP && !sharp)) &&
1219 			szty(qr->n_type)==1 &&
1220 			(ql->n_rval == DECRA(ql->n_reg, 0) ||
1221 			/* XXX */
1222 			 ql->n_rval == FPREG || ql->n_rval == STKREG)) {
1223 #endif
1224 	if ((q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
1225 	    (ql->n_op==REG || (ql->n_op==TEMP && !sharp))) {
1226 
1227 		temp = qr->n_lval;
1228 		if( q->n_op == MINUS ) temp = -temp;
1229 		r = ql->n_rval;
1230 		temp += ql->n_lval;
1231 		cp = qr->n_name;
1232 		if( *cp && ( q->n_op == MINUS || *ql->n_name ) )
1233 			return 0;
1234 		if( !*cp ) cp = ql->n_name;
1235 
1236 		ormake:
1237 		if( notoff( p->n_type, r, temp, cp ))
1238 			return 0;
1239 		oregtemp = temp;
1240 		oregr = r;
1241 		oregcp = cp;
1242 		return 1;
1243 	}
1244 	return 0;
1245 }
1246 
1247 static void
1248 ormake(NODE *p)
1249 {
1250 	NODE *q = p->n_left;
1251 
1252 	p->n_op = OREG;
1253 	p->n_rval = oregr;
1254 	p->n_lval = oregtemp;
1255 	p->n_name = oregcp;
1256 	tfree(q);
1257 }
1258 
1259 /*
1260  * look for situations where we can turn * into OREG
1261  */
1262 void
1263 oreg2(NODE *p, void *arg)
1264 {
1265 	if (p->n_op != UMUL)
1266 		return;
1267 	if (oregok(p, 1))
1268 		ormake(p);
1269 	if (p->n_op == UMUL)
1270 		myormake(p);
1271 }
1272 
1273 void
1274 canon(NODE *p)
1275 {
1276 	/* put p in canonical form */
1277 
1278 	walkf(p, setleft, 0);	/* ptrs at left node for arithmetic */
1279 	walkf(p, oreg2, 0);	/* look for and create OREG nodes */
1280 	mycanon(p);		/* your own canonicalization routine(s) */
1281 }
1282 
1283 void
1284 comperr(char *str, ...)
1285 {
1286 	extern char *ftitle;
1287 	va_list ap;
1288 
1289 	if (nerrors) {
1290 		fprintf(stderr,
1291 		    "cannot recover from earlier errors: goodbye!\n");
1292 		exit(1);
1293 	}
1294 
1295 	va_start(ap, str);
1296 	fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline);
1297 	vfprintf(stderr, str, ap);
1298 	fprintf(stderr, "\n");
1299 	va_end(ap);
1300 
1301 #ifdef PCC_DEBUG
1302 	if (nodepole && nodepole->n_op != FREE)
1303 		fwalk(nodepole, e2print, 0);
1304 #endif
1305 	exit(1);
1306 }
1307 
1308 /*
1309  * allocate k integers worth of temp space
1310  * we also make the convention that, if the number of words is
1311  * more than 1, it must be aligned for storing doubles...
1312  * Returns bytes offset from base register.
1313  */
1314 int
1315 freetemp(int k)
1316 {
1317 	int t, al, sz;
1318 
1319 	al = (k > 1 ? ALDOUBLE/ALCHAR : ALINT/ALCHAR);
1320 	sz = k * (SZINT/SZCHAR);
1321 
1322 #ifndef BACKTEMP
1323 	SETOFF(p2autooff, al);
1324 	t = p2autooff;
1325 	p2autooff += sz;
1326 #else
1327 	p2autooff += sz;
1328 	SETOFF(p2autooff, al);
1329 	t = ( -p2autooff );
1330 #endif
1331 	if (p2autooff > p2maxautooff)
1332 		p2maxautooff = p2autooff;
1333 	return (t);
1334 }
1335 
1336 NODE *
1337 storenode(TWORD t, int off)
1338 {
1339 	NODE *p;
1340 
1341 	p = talloc();
1342 	p->n_type = t;
1343 	storemod(p, off, FPREG); /* XXX */
1344 	return p;
1345 }
1346 
1347 #ifndef MYSTOREMOD
1348 void
1349 storemod(NODE *q, int off, int reg)
1350 {
1351 	NODE *l, *r, *p;
1352 
1353 	l = mklnode(REG, 0, reg, INCREF(q->n_type));
1354 	r = mklnode(ICON, off, 0, INT);
1355 	p = mkbinode(PLUS, l, r, INCREF(q->n_type));
1356 	q->n_op = UMUL;
1357 	q->n_left = p;
1358 	q->n_rval = q->n_su = 0;
1359 }
1360 #endif
1361 
1362 NODE *
1363 mklnode(int op, CONSZ lval, int rval, TWORD type)
1364 {
1365 	NODE *p = talloc();
1366 
1367 	p->n_name = "";
1368 	p->n_qual = 0;
1369 	p->n_op = op;
1370 	p->n_label = 0;
1371 	p->n_lval = lval;
1372 	p->n_rval = rval;
1373 	p->n_type = type;
1374 	p->n_regw = NULL;
1375 	p->n_su = 0;
1376 	return p;
1377 }
1378 
1379 NODE *
1380 mkbinode(int op, NODE *left, NODE *right, TWORD type)
1381 {
1382 	NODE *p = talloc();
1383 
1384 	p->n_name = "";
1385 	p->n_qual = 0;
1386 	p->n_op = op;
1387 	p->n_label = 0;
1388 	p->n_left = left;
1389 	p->n_right = right;
1390 	p->n_type = type;
1391 	p->n_regw = NULL;
1392 	p->n_su = 0;
1393 	return p;
1394 }
1395 
1396 NODE *
1397 mkunode(int op, NODE *left, int rval, TWORD type)
1398 {
1399 	NODE *p = talloc();
1400 
1401 	p->n_name = "";
1402 	p->n_qual = 0;
1403 	p->n_op = op;
1404 	p->n_label = 0;
1405 	p->n_left = left;
1406 	p->n_rval = rval;
1407 	p->n_type = type;
1408 	p->n_regw = NULL;
1409 	p->n_su = 0;
1410 	return p;
1411 }
1412 
1413 struct interpass *
1414 ipnode(NODE *p)
1415 {
1416 	struct interpass *ip = tmpalloc(sizeof(struct interpass));
1417 
1418 	ip->ip_node = p;
1419 	ip->type = IP_NODE;
1420 	ip->lineno = thisline;
1421 	return ip;
1422 }
1423 
1424 int
1425 rspecial(struct optab *q, int what)
1426 {
1427 	struct rspecial *r = nspecial(q);
1428 	while (r->op) {
1429 		if (r->op == what)
1430 			return r->num;
1431 		r++;
1432 	}
1433 	return -1;
1434 }
1435 
1436 #ifndef XASM_NUMCONV
1437 #define	XASM_NUMCONV(x,y,z)	0
1438 #endif
1439 
1440 /*
1441  * change numeric argument redirections to the correct node type after
1442  * cleaning up the other nodes.
1443  * be careful about input operands that may have different value than output.
1444  */
1445 static void
1446 delnums(NODE *p, void *arg)
1447 {
1448 	struct interpass *ip = arg, *ip2;
1449 	NODE *r = ip->ip_node->n_left;
1450 	NODE *q;
1451 	TWORD t;
1452 	int cnt, num;
1453 
1454 	/* gcc allows % in constraints, but we ignore it */
1455 	if (p->n_name[0] == '%' && p->n_name[1] >= '0' && p->n_name[1] <= '9')
1456 		p->n_name++;
1457 
1458 	if (p->n_name[0] < '0' || p->n_name[0] > '9')
1459 		return; /* not numeric */
1460 	if ((q = listarg(r, p->n_name[0] - '0', &cnt)) == NIL)
1461 		comperr("bad delnums");
1462 
1463 	/* target may have opinions whether to do this conversion */
1464 	if (XASM_NUMCONV(ip, p, q))
1465 		return;
1466 
1467 	/* Delete number by adding move-to/from-temp.  Later on */
1468 	/* the temps may be rewritten to other LTYPEs */
1469 	num = p2env.epp->ip_tmpnum++;
1470 
1471 	/* pre node */
1472 	t = p->n_left->n_type;
1473 	r = mklnode(TEMP, 0, num, t);
1474 	ip2 = ipnode(mkbinode(ASSIGN, tcopy(r), p->n_left, t));
1475 	DLIST_INSERT_BEFORE(ip, ip2, qelem);
1476 	p->n_left = r;
1477 
1478 	/* post node */
1479 	t = q->n_left->n_type;
1480 	r = mklnode(TEMP, 0, num, t);
1481 	ip2 = ipnode(mkbinode(ASSIGN, q->n_left, tcopy(r), t));
1482 	DLIST_INSERT_AFTER(ip, ip2, qelem);
1483 	q->n_left = r;
1484 
1485 	p->n_name = tmpstrdup(q->n_name);
1486 	if (*p->n_name == '=')
1487 		p->n_name++;
1488 }
1489 
1490 /*
1491  * Ensure that a node is correct for the destination.
1492  */
1493 static void
1494 ltypify(NODE *p, void *arg)
1495 {
1496 	struct interpass *ip = arg;
1497 	struct interpass *ip2;
1498 	TWORD t = p->n_left->n_type;
1499 	NODE *q, *r;
1500 	int cw, ooff, ww;
1501 	char *c;
1502 
1503 again:
1504 	if (myxasm(ip, p))
1505 		return;	/* handled by target-specific code */
1506 
1507 	cw = xasmcode(p->n_name);
1508 	switch (ww = XASMVAL(cw)) {
1509 	case 'p':
1510 		/* pointer */
1511 		/* just make register of it */
1512 		p->n_name = tmpstrdup(p->n_name);
1513 		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
1514 		*c = 'r';
1515 		/* FALLTHROUGH */
1516 	case 'g':  /* general; any operand */
1517 		if (ww == 'g' && p->n_left->n_op == ICON) {
1518 			/* should only be input */
1519 			p->n_name = "i";
1520 			break;
1521 		}
1522 		/* FALLTHROUGH */
1523 	case 'r': /* general reg */
1524 		/* set register class */
1525 		p->n_label = gclass(p->n_left->n_type);
1526 		if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
1527 			break;
1528 		q = p->n_left;
1529 		r = (cw & XASMINOUT ? tcopy(q) : q);
1530 		p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
1531 		if ((cw & XASMASG) == 0) {
1532 			ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), r, t));
1533 			DLIST_INSERT_BEFORE(ip, ip2, qelem);
1534 		}
1535 		if (cw & (XASMASG|XASMINOUT)) {
1536 			/* output parameter */
1537 			ip2 = ipnode(mkbinode(ASSIGN, q, tcopy(p->n_left), t));
1538 			DLIST_INSERT_AFTER(ip, ip2, qelem);
1539 		}
1540 		break;
1541 
1542 	case '0': case '1': case '2': case '3': case '4':
1543 	case '5': case '6': case '7': case '8': case '9':
1544 		break;
1545 
1546 	case 'm': /* memory operand */
1547 		/* store and reload value */
1548 		q = p->n_left;
1549 		if (optype(q->n_op) == LTYPE) {
1550 			if (q->n_op == TEMP) {
1551 				ooff = freetemp(szty(t));
1552 				cvtemps(ip, q->n_rval, ooff);
1553 			} else if (q->n_op == REG)
1554 				comperr("xasm m and reg");
1555 		} else if (q->n_op == UMUL &&
1556 		    (q->n_left->n_op != TEMP && q->n_left->n_op != REG)) {
1557 			t = q->n_left->n_type;
1558 			ooff = p2env.epp->ip_tmpnum++;
1559 			ip2 = ipnode(mkbinode(ASSIGN,
1560 			    mklnode(TEMP, 0, ooff, t), q->n_left, t));
1561 			q->n_left = mklnode(TEMP, 0, ooff, t);
1562 			DLIST_INSERT_BEFORE(ip, ip2, qelem);
1563 		}
1564 		break;
1565 
1566 	case 'i': /* immediate constant */
1567 	case 'n': /* numeric constant */
1568 		if (p->n_left->n_op == ICON)
1569 			break;
1570 		p->n_name = tmpstrdup(p->n_name);
1571 		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
1572 		if (c[1]) {
1573 			c[0] = c[1], c[1] = 0;
1574 			goto again;
1575 		} else
1576 			uerror("constant required");
1577 		break;
1578 
1579 	default:
1580 		uerror("unsupported xasm option string '%s'", p->n_name);
1581 	}
1582 }
1583 
1584 /* Extended assembler hacks */
1585 static void
1586 fixxasm(struct p2env *p2e)
1587 {
1588 	struct interpass *pole = &p2e->ipole;
1589 	struct interpass *ip;
1590 	NODE *p;
1591 
1592 	DLIST_FOREACH(ip, pole, qelem) {
1593 		if (ip->type != IP_NODE || ip->ip_node->n_op != XASM)
1594 			continue;
1595 		thisline = ip->lineno;
1596 		p = ip->ip_node->n_left;
1597 
1598 		if (p->n_op == ICON && p->n_type == STRTY)
1599 			continue;
1600 
1601 		/* replace numeric redirections with its underlying type */
1602 		flist(p, delnums, ip);
1603 
1604 		/*
1605 		 * Ensure that the arg nodes can be directly addressable
1606 		 * We decide that everything shall be LTYPE here.
1607 		 */
1608 		flist(p, ltypify, ip);
1609 	}
1610 }
1611 
1612 /*
1613  * Extract codeword from xasm string */
1614 int
1615 xasmcode(char *s)
1616 {
1617 	int cw = 0, nm = 0;
1618 
1619 	while (*s) {
1620 		switch ((int)*s) {
1621 		case '=': cw |= XASMASG; break;
1622 		case '&': cw |= XASMCONSTR; break;
1623 		case '+': cw |= XASMINOUT; break;
1624 		case '%': break;
1625 		default:
1626 			if ((*s >= 'a' && *s <= 'z') ||
1627 			    (*s >= 'A' && *s <= 'Z') ||
1628 			    (*s >= '0' && *s <= '9')) {
1629 				if (nm == 0)
1630 					cw |= *s;
1631 				else
1632 					cw |= (*s << ((nm + 1) * 8));
1633 				nm++;
1634 				break;
1635 			}
1636 			uerror("bad xasm constraint %c", *s);
1637 		}
1638 		s++;
1639 	}
1640 	return cw;
1641 }
1642 
1643 static int xasnum, xoffnum;
1644 
1645 static void
1646 xconv(NODE *p, void *arg)
1647 {
1648 	if (p->n_op != TEMP || p->n_rval != xasnum)
1649 		return;
1650 	storemod(p, xoffnum, FPREG); /* XXX */
1651 }
1652 
1653 /*
1654  * Convert nodes of type TEMP to op with lval off.
1655  */
1656 static void
1657 cvtemps(struct interpass *ipl, int tnum, int off)
1658 {
1659 	struct interpass *ip;
1660 
1661 	xasnum = tnum;
1662 	xoffnum = off;
1663 
1664 	DLIST_FOREACH(ip, ipl, qelem)
1665 		if (ip->type == IP_NODE)
1666 			walkf(ip->ip_node, xconv, 0);
1667 	walkf(ipl->ip_node, xconv, 0);
1668 }
1669