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