File:  [Research Unix] / researchv10no / cmd / ccom / vax / gencode.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

#include "gencode.h"
#define fieldbotch(p) if(p->left->op == Fld) {rewritefld(p); longjmp(back, 1);}
jmp_buf back;
int acnt, Pflag, bbcnt;
NODE *svq;		/* just for printing at FAIL */

gencode(p)
NODE *p;
{	mnod *q;
	ret s;
	int svtemp, svregvar, i, svbb;
	extern int bothdebug;
	svtemp = tmpoff;
	svregvar = regvar;
	svbb = ++bbcnt;
	svq = p;
	if(setjmp(back)) {
		pr("#\treg\t%d\n", ++acnt) /*,prtree(q), putchar('\n')*/;
		if(acnt > 20) {
			prtree(q);
			outpr();
			tmpoff = svtemp;
			bbcnt = svbb;
			uerror("expression too complicated");
			return;
		}
	}
	else
		q = copytree(p);
	buf = bufs[1];
	prptr = prbuf;
	if(Pflag && q->op != Init) {
		pr("#\tincl\tlocprof+%d\n", 4*(svbb+3));
	}
	s = doit(q, 0, 0, REGMASK);
	if(s.flag & FAIL)
		uerror("codegen failed at top level");
	acnt = ntree = 0;
	if(Pflag && q->op != Init)
		printx("#%d ", svbb), prtree(q), printx("\n");
	outpr();
	tmpoff = svtemp;
	regvar = svregvar;
}

ret
doit(p, flag, dest, regmask)
mnod *p;
ret dest;
{	ret s, t, x, y;
	char *pp;
	mnod snode, *q;
	int i, j, svmask = regmask;
	switch(p->op) {
	default:
		pr("#\tweird??? %d\n", p->op);
		return(dest);
	case Andeq:
		fieldbotch(p)
		if(dest.ans && p->left->op == Star)
			longjmp(back, mediumstar(p));
		flag |= DESTISLEFT;
		flag &= ~CC;
	case And:
		if((flag & CC)) {	/* short b; reg int *c; if(b & *c++); */
			if(p->left->op == Conv && incrsize(p->left->left) < 4)
				p->left = p->left->left;
			if(p->right->op == Conv
				&& incrsize(p->right->left) < 4)
				p->right = p->right->left;
		}
		t = doit(p->left, VALUE|USED, 0, regmask);
		if(t.flag & FAIL)
			return(t);
		regmask &= ~t.regmask;
		s = doit(p->right, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			goto binfail;
		if(flag & CC) {
			if(incrsize(p->left) == incrsize(p->right))
				i = type(p->right);
			else if(incrsize(p->left) < incrsize(p->right)) {
				if(s.flag & INDEX) {
					totemp(p, RIGHT);
					longjmp(back, 1);
				}
				i = childtype(p);
			}
			else {
				if(t.flag & INDEX) {
					totemp(p, LEFT);
					longjmp(back, 1);
				}
				i = type(p->right);
			}
			pr("#\tbit%c\t%s,%s\n", i, str(s), str(t));
			dest.ans = 0;
			dest.flag = CC;
			dest.regmask = 0;
			return(dest);
		}
		regmask &= ~s.regmask;
		/* p->right->op == Compl is a useful special case */
		if((flag & DESTISLEFT) && dest.ans == 0)
			dest = x = t;
		if(dest.ans == 0)
			if(s.flag & SCRATCH)
				dest = x = s;
			else if(t.flag & SCRATCH) {
				dest = t;
				x = allocreg(p, regmask);
			}
			else
				dest = x = allocreg(p, regmask);
		else
			x = allocreg(p, regmask);
		if(p->right->op == Icon) {
			x = tostack();	/* to get a buf */
			sprintx(str(x), "$%d", -p->right->lval - 1);
		}
		else
			pr("#\tmcom%c\t%s,%s\n", childtype(p), str(s), str(x));
		if(strcmp(str(t), str(dest)) == 0)
			pr("#\tbic%c2\t%s,%s\n", childtype(p), str(x), str(dest));
		else if(flag & DESTISLEFT) {
			pr("#\tbic%c2\t%s,%s\n", childtype(p), str(x), str(t));
			if(strcmp(str(t), str(dest))) {
				x = t;
				goto movexdest;
			}
		}
		else
			pr("#\tbic%c3\t%s,%s,%s\n", childtype(p), str(x),
				str(t), str(dest));
		if(flag & ASADDR)
			goto toaddr;
		dest.flag |= CC;
		return(dest);
	case Call:
call:
		s.flag = funargs(p->right, regmask);
		if(s.flag & FAIL)
			return(s);
		i = p->argsize/32;
		if(i > 255)
			uerror("%d arguments is too many", i);
called:
		s = doit(p->left, VALUE|ASADDR|USED, 0, regmask);
		pp = str(s);
aftercall:
		if(svmask != REGMASK) {
			debugpr("#FAIL aftercall ");
			s.flag = FAIL;
			return(s);
		}
		x = specialreg(p, regmask);
		pr("#\tcalls\t$%d,%s\n", i, pp);
		if(flag & ASADDR) {
			strcat(str(x), ")");
			strshift(str(x), 1);
			str(x)[0] = '(';
		}
		if(dest.ans == 0)
			if(flag & DESTISLEFT)
				dest = doit(p->left->op == Conv?
					p->left->left:
					p->left, 0/* ? */, 0, regmask & ~x.regmask);
			else
				return(x);
movexdest:	/* type(p), not childtype, for a = a % b */
		if(strcmp(str(x), str(dest)) == 0)
			return(x);
		if((flag & TOSTACK) && incrsize(p) == 4)
			pr("#\tpush%c\t%s\n", type(p), str(x));
		else if(x.flag & ICON0)
			pr("#\tclr%c\t%s\n", type(p), str(dest));
		else if(isfloat(p) != isfloat(p->left)
			&& p->op != Call && p->op != Ucall)
			pr("#\tcvt%c%c\t%s,%s\n", childtype(p), type(p), str(x), str(dest));
		else if((flag & TOSTACK) && (incrsize(p) != 8))
			pr("#\tcvt%cl\t%s,-(sp)\n", type(p), str(x));
		else {
			pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
			dest = simpler(x, dest);
		}
		dest.flag |= CC;
		return(dest);
	case Cmp:
		if(p->left->op == Conv && p->right->op == Conv
			&& childtype(p->left) == childtype(p->right)
			&& !isfloat(p->left->left)) {	/* bogus? */
			p->left = p->left->left;
			p->right = p->right->left;
		}
		else if(p->left->op == Conv && p->right->op == Icon
			&& p->right->lval >= 0
			&& ((incrsize(p->left->left) == 1
				&& p->right->lval < 128)
			|| (incrsize(p->left->left) == 2
				&& p->right->lval < 32768)))
			p->left = p->left->left;
		/* the above rewriting depends on childype being of p->left */
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		t = doit(p->right, VALUE|USED, 0, regmask);
		if(t.flag & FAIL) {
			t = doit(p->right, VALUE|USED, 0, REGMASK);
			if(!(t.flag & FAIL) && svmask != REGMASK)
				return(t.flag = FAIL, t);
			totemp(p, LEFT);
			longjmp(back, 1);
		}
		pr("#\tcmp%c\t%s,%s\n", childtype(p), str(s), str(t));
		dest.ans = dest.regmask = 0;
		dest.flag = CC;
		return(dest);
	case Comop:	/* qnodes lurking underneath */
		if(p->left->op == Genlab && hasqnode(p->right)) {
			if(dest.ans == 0) {
				dest = allocreg(p, regmask);
			}
			t = doit(p->left, VALUE|(flag & CC), dest, regmask);
		}
		else
			t = doit(p->left, 0, 0, regmask);
		if(t.flag & FAIL)
			return(t);
		s = doit(p->right, VALUE|(flag & (USED|CC)), dest, regmask);
		if(s.flag & FAIL)
			return(s);
		if(flag & ASADDR) {
			dest.ans = 0;
			i = (s.flag & (ISREG|CANINDIR|SCRATCH));
			j = s.regmask;
			buf = str(s);
			goto convbuf;
		}
		return(s);
	case Compl:
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		if(dest.ans == 0)
			if(s.flag & SCRATCH)
				dest = s;
			else
				dest = allocreg(p, regmask & ~s.regmask);
		pr("#\tmcom%c\t%s,%s\n", childtype(p), str(s), str(dest));
		dest.flag |= CC;
		return(dest);
	case Conv:
		if(p->left->op == Asg && p->left->left->op == Star) {
			if(dest.ans == 0) {
				dest = allocreg(p, regmask);
				s = doit(p->left, VALUE|USED, dest, regmask);
			}
			else {
				x = allocreg(p, regmask);
				s = doit(p->left, VALUE|USED, x, regmask & ~x.regmask);
			}
			if(s.flag & FAIL) {
				asgwrite(p->left);
				longjmp(back, 1);
			}
		}
		else
			s = doit(p->left, VALUE|USED, 0, regmask);
		if(childtype(p) == type(p) && dest.ans == 0)
			return(s);
		if(s.flag & FAIL)
			return(s);
		if(dest.ans == 0)
			if(s.flag & SCRATCH)
				dest = checksize(p, s, regmask);
			else
				dest = allocreg(p, regmask);
		if(isunsigned(p->left) && incrsize(p) > incrsize(p->left)) {
			if(type(p) != 'f' && type(p) != 'd')
				pp = "movz";
			else {	/* uns to float or double */
				rewriteconv(p);
				longjmp(back, 1);
			}
		}
		else
			pp = "cvt";
		if(isfloat(p) != isfloat(p->left))
			goto cvtop;
		if(incrsize(p) < incrsize(p->left)) {
			if(isfloat(p))
				goto cvtop;
			pr("#\tmov%c\t%s,%s\n", type(p), str(s), str(dest));
			dest = simpler(s, dest);
		}
		else if(incrsize(p) > incrsize(p->left))
cvtop:
			pr("#\t%s%c%c\t%s,%s\n", pp, childtype(p), type(p), str(s), str(dest));
		else {	/* types were the same, but dest.ans != 0 */
			pr("#\tmov%c\t%s,%s\n", type(p), str(s), str(dest));
			dest = simpler(s, dest);
		}
		dest.flag |= CC;
		return(dest);
	case Decr:
		i = -1;
		pp = "sub";
incrop:
		if(p->type == Tfloat)
			uerror("no float ++/--");
		fieldbotch(p)
		/* if the dest uses regs, it may be from a qnode, so that reg
		 * shouldn't be used (i?*a->b++:x()) where b has offset > 0
		 */
		s = doit(p->left, USED, 0, dest.ans? regmask & ~dest.regmask: regmask);
		if(s.flag & FAIL)
			return(s);
		t = doit(p->right, 0, 0, 0);
		if(flag & VALUE) {
			if(dest.ans == 0)
				dest = allocreg(p, regmask & ~s.regmask);
			pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(dest));
			if(t.flag & ICON1) {
				if(i == 1)
					pp = "inc";
				else
					pp = "dec";
				pr("#\t%s%c\t%s\n", pp, childtype(p), str(s));
			}
			else
				pr("#\t%s%c2\t%s,%s\n", pp, childtype(p),
					str(t), str(s));
toaddr:
			if(flag & ASADDR) {
				if(dest.flag & ISREG) {
					sprintx(buf, "(%s)", str(dest));
					done(dest, CANINDIR, dest.regmask);
				}
				if(dest.flag & CANINDIR) {
					sprintx(buf, "*%s", str(dest));
					done(dest, 0, dest.regmask);
				}
				uerror("weird asaddr in incrop");
			}
			dest.flag &= ~CC;
			return(dest);
		}
		if(t.flag & ICON1) {
			if(i == 1)
				pp = "inc";
			else
				pp = "dec";
			pr("#\t%s%c\t%s\n", pp, childtype(p), str(s));
		}
		else
			pr("#\t%s%c2\t%s,%s\n", pp, childtype(p), str(t), str(s));
		if(dest.ans) {
			x = s;
			goto movexdest;
		}
		s.flag &= ~CC;
		return(s);
	case Diveq:
		fieldbotch(p)
		if(rewriteasgop(p))
			goto assign;
		flag |= DESTISLEFT;
	case Div:
		/* trees wrong: uns/=int and int/=uns */
		if(!isunsigned(p->right) && !isunsigned(p->left)) {
			pp = "div";
			goto binop;
		}
		pp = "udiv";
unsdiv:
		/* *p++ /= uns is hard */
		if(p->left->op == Star && fixuns(p))
			longjmp(back, 1);	/* *A op= B => (T=A, *T op= B) */
		if(incrsize(p->right) != 4) {
			snode.op = Conv;
			snode.left = p->right;
			snode.type = Tulong;
			s = doit(&snode, VALUE|TOSTACK, tostack(), regmask);
		}
		else
			s = doit(p->right, TOSTACK, tostack(), regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		if(incrsize(p->left) != 4) {		
			snode.op = Conv;
			snode.left = p->left;
			snode.type = Tulong;
			t = doit(&snode, VALUE|TOSTACK, tostack(), regmask);
		}
		else
			t = doit(p->left, VALUE|TOSTACK, tostack(), regmask);
		if(t.flag & FAIL) {
			if(dest.ans || svmask != REGMASK) {
				t = doit(p->left, VALUE|TOSTACK, tostack(), svmask);
				if(t.flag & FAIL)
					return(t);
			}
			totemp(p, RIGHT);
			longjmp(back, 1);
		}
		i = 2;
		goto aftercall;
	case Xoreq:
		fieldbotch(p)
		flag |= DESTISLEFT;
	case Xor:
		pp = "xor";
binop:
		if((flag & DESTISLEFT) && dest.ans && p->left->op == Star)
			longjmp(back, mediumstar(p));
		t = doit(p->left, VALUE|USED, 0, regmask);
		if(t.flag & FAIL) {
			return(t);
		}
		regmask &= ~t.regmask;
		s = doit(p->right, VALUE|USED, 0, regmask);
		if(s.flag & FAIL) {
binfail:
			if(dest.ans || svmask != REGMASK) {
				s = doit(p->right, VALUE|USED, 0, svmask);
				if(s.flag & FAIL)
					return(s);
			}
			/* *foo op= expr  requires care */
			if((flag & DESTISLEFT) && p->left->op == Star)
				totemp(p->left, LEFT);
			else
				totemp(p, LEFT);
			longjmp(back, 1);
		}
		if(type(p) != childtype(p)) {
			x = allocreg(p, regmask);
			pr("#\t%s%c3\t%s,%s,%s\n", pp, childtype(p), str(s),
				str(t), str(x));
			if(dest.ans == 0)
				if(flag & DESTISLEFT)
					dest = t;
				else
					dest = x;
			if(!isfloat(p) && !isfloat(p->left)
				&& incrsize(p) < incrsize(p->left)) {
				pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
				dest = simpler(x, dest);
			}
			else
				pr("#\tcvt%c%c\t%s,%s\n", childtype(p), type(p),
					str(x), str(dest));
			dest.flag |= CC;
			return(dest);
		}	
		if(dest.ans == 0)
			if((t.flag & SCRATCH) || (flag & DESTISLEFT)) {
twoop:
				dest = t;
				if(*pp == 'a' && (s.flag & ICON1))
					pr("#\tinc%c\t%s\n", childtype(p), str(t));
				else if(*pp == 's' && (s.flag & ICON1))
					pr("#\tdec%c\t%s\n", childtype(p), str(t));
				else
					pr("#\t%s%c2\t%s,%s\n", pp, childtype(p),
						str(s), str(t));
				if(flag & ASADDR)
					goto binopaddr;
				if(flag & TOSTACK)
					pr("#\tpush%c\t%s\n", type(p), str(t));
				dest.flag |= CC;
				return(dest);
			}
			else if(s.flag & SCRATCH)
				dest = s;
			else
				dest = allocreg(p, regmask);
		if(dest.ans && (flag & DESTISLEFT)) {
			pr("#\t%s%c2\t%s,%s\n", pp, childtype(p), str(s), str(t));
			x = t;
			goto movexdest;
		}
		if(commutes(p->op) && strcmp(str(s), str(dest)) == 0) {
			dest = s;
			s = t;
			t = dest;
			goto twoop;
		}
		if(strcmp(str(t), str(dest)) == 0)
			goto twoop;
			
		pr("#\t%s%c3\t%s,%s,%s\n", pp, childtype(p), str(s), str(t), str(dest));
binopaddr:
		if(flag & ASADDR) {
			if(dest.flag & ISREG) {
				strcat(str(dest), ")");
				strshift(str(dest), 1);
				str(dest)[0] = '(';
				return(dest);
			}
			if(dest.flag & CANINDIR) {
				strshift(str(dest), 1);
				str(dest)[0] = '*';
				dest.flag &= ~CANINDIR;
				return(dest);
			}
			debugpr("#FAIL doubtful ");
			dest.flag = FAIL;	/* doubtful */
			return(dest);
		}
		dest.flag |= CC;
		return(dest);	
	case Fld:
		/* this is rvalues */
		s = doit(p->left, USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		if(dest.ans == 0)
			dest = allocreg(p, regmask);
		if((s.flag & INDEX) && p->left->op == Star
			&& incrsize(p->left) != 1) {
		/* over-enthusiastic use of index mode */
			if(dest.flag & SCRATCH)
				x = dest;
			else
				x = allocreg(p, regmask);
			pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(x));
			s = x;
		}
		pr("#\text%sv\t$%d,$%d,%s,%s\n", isunsigned(p->left)? "z": "",
			p->rval/64, p->rval%64, str(s), str(dest));
		dest.flag |= CC;
		return(dest);
	case Genbr:
		if(p->left->op == Conv)
			s = doit(p->left->left, CC|VALUE|USED, 0, regmask);
		/*else if(p->left->op == And && pow2(p->left->right->lval) > 0) {
			s = doit(p->left->left, CC|VALUE, 0, regmask);
			pp = genjbc(p->lop);
			pr("#\t%s\t$%d,%s,L%d\n", pp, pow2(p->left->right->lval),
				str(s), p->label);
			goto genbr0;
		} not a win on 8550 */
		else
			s = doit(p->left, CC|VALUE|USED, 0, regmask);
		pp = genjmp(p->lop);
		if(s.flag & CC)
			if(p->left->op != Conv || p->left->type >= Tint)
				pr("#\t%s\t", pp);
			else
				pr("#\ttst%c\t%s\n\t%s\t", childtype(p),
					str(s), pp);
		else if(p->left->op == Conv)
			pr("#\ttst%c\t%s\n#\t%s\t", childtype(p->left), str(s), pp);
		else
			pr("#\ttst%c\t%s\n#\t%s\t", childtype(p), str(s), pp);
		pr("L%d\n", p->label);
genbr0:
		s.flag |= CC;	/* ?? */
		if(Pflag) {
			++bbcnt;
			pr("#\tincl\tlocprof+%d\n", 4*(bbcnt+3));
		}
		return(s);
	case Genlab:
		s = doit(p->left, flag, dest, regmask);
		pr("#L%d:\n", p->label);
		if(Pflag) {
			++bbcnt;
			pr("#\tincl\tlocprof+%d\n", 4*(bbcnt+3));
		}
		return(s);
	case Genubr:
		s = doit(p->left, flag & CC, dest, regmask);
		if((flag & CC) && !(s.flag & CC))
			pr("#\ttst%c\t%s\n", childtype(p), str(s));
		pr("#\tjbr\tL%d\n", p->label);
		return(s);
	case Icon:
		if(p->name)
			if(p->lval)
				sprintx(buf, "%s+%d", p->name, p->lval);
			else
				sprintx(buf, "%s", p->name);
		else
			sprintx(buf, "%d", p->lval);
		if(!(flag & ASADDR)) {
			strshift(buf, 1);;
			buf[0] = '$';
		}
		i = 0;
		if(p->name == 0)
			if(p->lval == 0)
				i = ICON0;
			else if(p->lval == 1)
				i = ICON1;
		j = 0;
convbuf:	/* the cookie is in buf */
		if(dest.ans == 0 && !(flag & TOSTACK)) {
			if(p->op == Icon || !(flag & ASADDR)) {
				done(s, i, j);
			}
			if(i & CANINDIR) {
				strshift(buf, 1);
				buf[0] = '*';
				done(s, i & ~CANINDIR, j);
			}
			if(i & ISREG) {
				strcat(buf, ")");
				strshift(buf, 1);
				buf[0] = '(';
				done(s, i, j);
			}
			pp = buf;
			buf += BUF;
			s = allocreg(p, regmask);
			pr("#\tmov%c\t%s,%s\n", type(p), pp, str(s));
			flag &= ~ASADDR;
			goto inreg;
		}
		if(flag & TOSTACK)
			if(incrsize(p) == 4)
				pr("#\tpushl\t%s\n", buf);
			else if(incrsize(p) == 8)
				pr("#\tmovd\t%s,%s\n", buf, str(dest));
			else
				pr("#\tcvt%cl\t%s,%s\n", type(p), buf, str(dest));
		else if(i & ICON0)
			pr("#\tclr%c\t%s\n", type(p), str(dest));
		else {	
			pr("#\tmov%c\t%s,%s\n", type(p), buf, str(dest));
			if(!(dest.flag & INDEX) || !index(str(dest), '+')
				&& !index(str(dest), '-'))
				;
			else if(!(i & INDEX) || !index(buf, '+')
				&& !index(buf, '-')) {
				done(s, (i|CC), j);
			}
			else
				dest.flag |= USED;
		}
		dest.flag |= CC;
		return(dest);
	case Incr:
		i = 1;
		pp = "add";
		goto incrop;
	case Init:	/* knows it is ICON */
		s = doit(p->left, ASADDR, 0, 0);
		pr("#\t.long\t%s\n", str(s));
		return(dest);
	case Lseq:
		if(incrsize(p) != 4)
			lsconv(p);
		if(rewriteasgop(p))
			goto assign;
		fieldbotch(p)
		flag |= DESTISLEFT;
		if(dest.ans && p->left->op == Star)
			longjmp(back, mediumstar(p));
	case Ls:	/* stupid vax */
		if(incrsize(p) != 4)
			lsconv(p);
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		t = doit(p->right, VALUE|USED, 0, regmask);
		if(t.flag & FAIL)
			goto binfail;
		if((t.flag & INDEX) && p->right->op == Star
			&& incrsize(p->right) != 1) {
		/* over-enthusiastic use of index mode */
			if(dest.flag & SCRATCH)
				x = dest;
			else
				x = allocreg(p, regmask);
			pr("#\tmov%c\t%s,%s\n", childtype(p), str(t), str(x));
			t = x;
		}
		if(dest.ans == 0)
			if((s.flag & SCRATCH) || (flag & DESTISLEFT))
				dest = s;
			else
				dest = allocreg(p, regmask);
		if(incrsize(p) != 4) {	/* stupid vax */
			x = allocreg(p, regmask);
			pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(x));
			pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
			if(flag & DESTISLEFT)
				pr("#\tmovl\t%s,%s\n", str(x), str(s));
			dest.flag |= CC;
			return(dest);
		}
		if(p->right->op == Icon && (i = p->right->lval) <= 4
			&& (dest.flag & ISREG) && !(s.flag&AUTO)) {
			if(strcmp(str(s), str(dest))) {
				i--;
				pr("#\taddl3\t%s,%s,%s\n", str(s), str(s), str(dest));
			}
			while(i-- > 0)
				pr("#\taddl2\t%s,%s\n", str(dest), str(dest));
		}
		else if(flag & DESTISLEFT)
			pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(s));
		else
			pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(dest));
		if((flag & DESTISLEFT) && strcmp(str(dest), str(s)))
			pr("#\tmovl\t%s,%s\n", str(s), str(dest));
		dest.flag |= CC;
		return(dest);
	case Minuseq:
		fieldbotch(p)
		if(rewriteasgop(p))
			goto assign;
		flag |= DESTISLEFT;
	case Minus:
		pp = "sub";
		/* you won't believe this: type x[], *y where type is shorter than
		 * int, generates subx $_x,y which the assembler barfs on.
		 * instead, generate crummy code (stupid assembler)
		 */
		if(incrsize(p) < 4) {
			if(p->left->op == Icon && p->left->name) {
				p->left->type = Tint;
				totemp(p, LEFT);
			}
			if(p->right->op == Icon && p->right->name) {
				p->right->type = Tint;
				totemp(p, RIGHT);
			}
		}
		goto binop;
	case Modeq:
		fieldbotch(p)
		if(rewriteasgop(p))
			goto assign;
		if(dest.ans && p->left->op == Star)
			longjmp(back, mediumstar(p));
		flag |= DESTISLEFT;
	case Mod:
		if(isunsigned(p->right) || isunsigned(p->left)) {
			pp = "urem";
			goto unsdiv;
		}
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		t = doit(p->right, VALUE|USED, 0, regmask);
		if(t.flag & FAIL)
			goto binfail;
		regmask &= ~t.regmask;
		x = allocreg(p, regmask);
		pr("#\tdiv%c3\t%s,%s,%s\n", childtype(p), str(t), str(s), str(x));
		pr("#\tmul%c2\t%s,%s\n", childtype(p), str(t), str(x));
		pr("#\tsub%c3\t%s,%s,%s\n", childtype(p), str(x), str(s), str(x));
		if(dest.ans)
			goto movexdest;
		if(flag & DESTISLEFT) {
			dest = s;
			goto movexdest;
		}
		x.flag |= CC;
		return(x);
	case Muleq:
		fieldbotch(p)
		if(rewriteasgop(p))
			goto assign;
		flag |= DESTISLEFT;
	case Mul:
		pp = "mul";
		goto binop;
	case Name:	/* ASADDR? */
		if(p->lval && p->name)
			sprintx(buf, "%s+%d", p->name, p->lval);
		else if(p->name)
			sprintx(buf, "%s", p->name);
		else if(p->lval)
			sprintf(buf, "%d", p->lval);
		else
			sprintx(buf, "0");
		j = 0;
		i = CANINDIR;
		goto convbuf;
	case Oreq:
		fieldbotch(p)
		flag |= DESTISLEFT;
	case Or:
		pp = "bis";
		goto binop;
	case Pluseq:
		fieldbotch(p)
		if(rewriteasgop(p))
			goto assign;
		flag |= DESTISLEFT;
	case Plus:
		pp = "add";
		goto binop;
	case Reg:
		sprintx(buf, "%s", regnames[p->rval]);
		j = 0;
		i = ISREG;
		if(p->lval == 1)
			i |= SCRATCH;
		goto convbuf;
	case Rnode: case Snode:
		x = specialreg(p, 3);
		x.regmask = 0;
		if(dest.ans)
			goto movexdest;
		return(x);
	case Qnode:
		return(specialreg(p, regmask));
	case Rseq:
		fieldbotch(p)
		if(incrsize(p) != 4)
			lsconv(p);
		if(rewriteasgop(p))
			goto assign;
		flag |= DESTISLEFT;
	case Rs:	/* all right shifts are unsigned */
		if(incrsize(p->left) != 4)	/* shifting funny objects */
			lsconv(p);
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		if(p->left->op == Icon ||
			(s.flag & INDEX) && p->left->op == Star
			&& incrsize(p->left) != 1 ||
			(s.flag & AUTO) && incrsize(p->left) != 1) {
		/* over-enthusiastic use of index mode */
		/* 12 >> i generates a byte immediate */
			if((s.flag & INDEX) && (flag & DESTISLEFT)) {/* *a++ >>= 1 */
				lsconv(p);	/* not best */
				longjmp(back, 1);
			}
			if((flag & DESTISLEFT) && dest.ans == 0) {
				dest = s;
				regmask &= ~s.regmask;
			}
			if(dest.flag & SCRATCH)
				x = dest;
			else
				x = allocreg(p, regmask);
			pr("#\tmovl\t%s,%s\n", str(s), str(x));
			s = x;
		}
		regmask &= ~s.regmask;
		if(dest.ans == 0)
			if((flag & DESTISLEFT) || (s.flag & SCRATCH))
				dest = s;
			else
				dest = allocreg(p, regmask);
		dest.flag |= CC;
		regmask &= ~dest.regmask;
		if(incrsize(p) != 4)
			x = allocreg(p, regmask);
		else if(flag & DESTISLEFT)
			x = s;
		else
			x = dest;
		if(p->right->op == Icon && (i = p->right->lval) >= 0) {
			pr("#\textzv\t$%d,$%d,%s,%s\n", i, 32 - i, str(s), str(x));
			goto movexdest;
		}
		t = doit(p->right, VALUE|USED, 0, regmask);
		if(t.flag & FAIL)
			goto binfail;
		y = allocreg(p, regmask & ~t.regmask);
		pr("#\tsubl3\t%s,$32,%s\n", str(t), str(y));
		pr("#\textzv\t%s,%s,%s,%s\n", str(t), str(y), str(s), str(x));
		goto movexdest;
	case Star:
		switch(p->left->op) {
		case Icon:	/* as in foo((a, a)), where a is a struct */
			s = doit(p->left, VALUE, 0, regmask);
			sprintx(buf, "%s", str(s)+1);
			i = j = 0;
			goto convbuf;
		case Auto:
		case Param:
		case Name:
			s = doit(p->left, VALUE, 0, regmask);
			sprintx(buf, "*%s", str(s));
			j = i = 0;
			goto convbuf;
		case Reg:
			s = doit(p->left, VALUE, 0, regmask);
inreg:
			if(s.flag & ISREG) {
				sprintx(buf, "(%s)", str(s));
				j = s.regmask;
				i = CANINDIR;
				goto convbuf;
			}
			else if(s.flag & CANINDIR) {
				sprintx(buf, "*%s", str(s));
				j = s.regmask;
				i = 0;
				goto convbuf;
			}
			else {
				debugpr("#FAIL STAR REG ");
				s.flag = FAIL;
				return(s);
			}
		}
		q = p->left;
		if(q->op == Incr && !(flag & INDEX)
			&& q->right->op == Icon && q->left->op == Reg
			&& incrsize(p) == (int) q->right->lval) {
			s = doit(q->left, VALUE, 0, regmask);
			sprintx(buf, "(%s)+", str(s));
			i = INDEX|AUTO;
			j = s.regmask;
			goto convbuf;
		}
		if(q->op == Plus && q->left->op == Ls
			&& !(flag & INDEX)
			&& q->left->right->op == Icon
			&& shiftsize(p) == (int) q->left->right->lval) {
			s = doit(q->left->left, VALUE|USED, 0, regmask);
			if(s.flag & FAIL)
				return(s);
			regmask &= ~s.regmask;
			if(!(s.flag & ISREG)) {
				x = allocreg(p, regmask);
				pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
				regmask |= s.regmask;
				regmask &= ~x.regmask;
				s = x;
				if(!(s.flag & ISREG)) {
					debugpr("#FAIL a[b] ");
					s.flag = FAIL;
					return(s);
				}
			}
			t = doit(q->right, ASADDR|USED|VALUE, 0, regmask);
			if(t.flag & FAIL) {
				totemp(q, LEFT);
				longjmp(back, 1);
			}
			sprintx(buf, "%s[%s]", str(t), str(s));
			i = INDEX;
			j = s.regmask | t.regmask;
			goto convbuf;
		}
		if(q->op == Plus && q->right->op == Icon) {
			s = doit(q->left, VALUE|USED, 0, regmask);
			if(s.flag & FAIL)
				return(s);
			if(!(s.flag & ISREG)) {
				x = allocreg(p, regmask);
				pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
				s = x;
				if(!(s.flag & ISREG)) {
					debugpr("#FAIL a(b) ");
					s.flag = FAIL;
					return(s);
				}
			}
			regmask &= ~s.regmask;
			t = doit(q->right, ASADDR|USED, 0, regmask);
			sprintx(buf, "%s(%s)", str(t), str(s));
			i = CANINDIR;
			j = s.regmask;
			goto convbuf;
		}
		if(q->op == Minus && q->right->op == Icon) {
			s = doit(q->left, VALUE|USED, 0, regmask);
			if(s.flag & FAIL)
				return(s);
			if(!(s.flag & ISREG)) {
				x = allocreg(p, regmask);
				pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
				s = x;
				if(!(s.flag & ISREG)) {
					debugpr("#FAIL %d(a) ");
					s.flag = FAIL;
					return(s);
				}
			}
			regmask &= ~s.regmask;
			sprintx(buf, "%d(%s)", -q->right->lval, str(s));
			i = CANINDIR;
			j = s.regmask;
			goto convbuf;
		}
		if(q->op == Minuseq && !(flag & (INDEX|USED))
			&& q->right->op == Icon && q->left->op == Reg
			&& incrsize(p) == (int) q->right->lval) {
			s = doit(q->left, VALUE, 0, regmask);
			sprintx(buf, "-(%s)", str(s));
			i = INDEX|AUTO;
			j = s.regmask;
			goto convbuf;
		}
		if(q->op == Plus && q->left->op == Reg
			&& !(flag & INDEX) && q->right->op == Reg
			&& incrsize(p) == 1) {
			sprintx(buf, "(r%d)[r%d]", q->right->rval,
				q->left->rval);
			i = INDEX;
			j = 0;
			goto convbuf;
		}
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		if(s.flag & CANINDIR) {
			sprintx(buf, "*%s", str(s));
			i = 0;
			j = s.regmask;
			goto convbuf;
		}
		if(!(s.flag & ISREG)) {
			x = allocreg(p, regmask);
			pr("#\tmov%c\t%s,%s\n", type(q), str(s), str(x));
			regmask |= s.regmask;
			regmask &= ~x.regmask;
			s = x;
		}
		if(!(s.flag & ISREG)) {
			debugpr("#FAIL STAR ");
			s.flag = FAIL;
			return(s);
		}
		sprintx(buf, "(%s)", str(s));
		i = 0;
		j = s.regmask;
		goto convbuf;
	case Stasg:
		if(p->stsize/8 == 4) {
			i = 'l';
stasg:
			s = doit(p->left, VALUE|ASADDR|USED|FSTASG, 0, regmask);
			if(s.flag & FAIL)
				return(s);
			regmask &= ~s.regmask;
			t = doit(p->right, VALUE|ASADDR|USED|FSTASG, 0, regmask);
			if(t.flag & FAIL) {
				t = doit(p->right, VALUE|ASADDR|USED|FSTASG, 0, REGMASK);
				if(!(t.flag & FAIL) && svmask != REGMASK)
					return(t.flag = FAIL, t);
				totemp(p, LEFT);
				longjmp(back, 1);
			}
			pr("#\tmov%c\t%s,%s\n", i, str(t), str(s));
			if(!(flag & FSTASG))
				s = addrsimp(s, t);
			return(s);
		}
		else if(p->stsize/8 == 8) {
			i = 'q';
			goto stasg;
		}
		if(regmask != REGMASK) {
			debugpr("#FAIL stasg ");
			s.flag = FAIL;
			return(s);
		}
		s = doit(p->right, VALUE|USED|FSTASG, 0, regmask);
		if(s.flag & INDEX) {
		/* over-enthusiastic use of index mode */
			x = allocreg(p, regmask);
			pr("#\tmovl\t%s,%s\n", str(s), str(x));
			s = x;
		}
		regmask &= ~s.regmask;
		t = doit(p->left, VALUE|USED|FSTASG, 0, regmask);
		if(t.flag & FAIL) {
			totemp(p, RIGHT);
			longjmp(back, 1);
		}
		if(t.flag & INDEX) {
		/* over-enthusiastic use of index mode */
			x = allocreg(p, regmask);
			pr("#\tmovl\t%s,%s\n", str(t), str(x));
			t = x;
		}
		t = indirit(t);
		if(t.flag & FAIL) {
			if(p->left->op != Star)
				cerror("codegen failure in struct asg");
			totemp(p->left, LEFT);
			longjmp(back, 1);
		}
		s = indirit(s);
		if(s.flag & FAIL) {
			if(p->right->op != Star)
				cerror("codgen fail in stasg");
			totemp(p->right, LEFT);
			longjmp(back, 1);
		}
		pr("#\tmovc3\t$%d,%s,%s\n", p->stsize/8, str(s), str(t));
		if(flag & USED) {
			t = specialreg(p, REGMASK);
			pr("#\tsubl3\t$%d,r3,r0\n", p->stsize/8);
		}
		else
			t.flag = 0;
		return(t);
	case Stcall:
		goto call;
	case Auto:
		sprintx(buf, "%d(%s)", p->lval, frameptr);
		j = 0;
		i = CANINDIR;
		goto convbuf;
	case Param:
		sprintx(buf, "%d(%s)", p->lval, argptr);
		j = 0;
		i = CANINDIR;
		goto convbuf;
	case Addr:
		s = doit(p->left, USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		regmask &= ~s.regmask;
		if(dest.ans == 0) {
			dest = allocreg(p, regmask);
		}
		if(s.flag & ISREG) {
			x = alloctmp(p);
			pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(x));
			s = x;
		}
		if(flag & TOSTACK)
			pr("#\tpushal\t%s\n", str(s));
		else
			pr("#\tmova%c\t%s,%s\n", type(p), str(s), str(dest));
		if(flag & ASADDR) {
			if(dest.flag & ISREG) {
				strcat(str(dest), ")");
				strshift(str(dest), 1);
				str(dest)[0] = '(';
			}
			else {
				strshift(str(dest), 1);
				str(dest)[0] = '*';
			}
		}
		return(dest);
	case Ucall:
		i = 0;
		goto called;
	case Uminus:
		s = doit(p->left, VALUE|USED, 0, regmask);
		if(s.flag & FAIL)
			return(s);
		if(dest.ans == 0)
			if(s.flag & SCRATCH)
				dest = s;
			else
				dest = allocreg(p, regmask & ~s.regmask);
		pr("#\tmneg%c\t%s,%s\n", childtype(p), str(s), str(dest));
		dest.flag |= CC;
		return(dest);
	case Ustcall:
		i = 0;
		goto called;
	case Asg:
assign:
		if(p->left->op == Qnode && dest.ans) {
			s = doit(p->right, VALUE|(flag&USED? USED: 0),
				dest, regmask);
			return(s);
		}
		if(p->left->op == Rnode || p->left->op == Snode) {
			s = doit(p->right, VALUE|(flag&USED? USED: 0),
				dest, regmask);
			if(s.flag & FAIL)
				return(s);
			x = s;
			dest = doit(p->left, USED, 0, 0);
			goto movexdest;
		}
		if(p->left->op == Fld) {
			s = doit(p->left->left, INDEX, 0, regmask);
			regmask &= ~s.regmask;
			if(p->right->op == Asg) {
				x = allocreg(p->right, regmask);
				t = doit(p->right, VALUE|USED, x, regmask & ~x.regmask);
			}
			else
				t = doit(p->right, VALUE|USED, 0, regmask);
			if(t.flag & FAIL) {	/* was fldstar */
				totemp(p->left->left, LEFT);
				totemp(p, RIGHT);
				longjmp(back, 1);
			}
			i = '$';
			pr("#\tinsv\t%s,%c%d,%c%d,%s\n", str(t), i,
				p->left->rval/64, i,
				p->left->rval % 64, str(s));
			if(dest.ans) {
				pr("#\tmovl\t%s,%s\n", str(t), str(dest));
				t.flag |= CC;
			}
			return(t);
		}
		if(dest.ans && p->left->op == Star) {
			if(dest.flag & SCRATCH)
				x = dest;
			else
				x = allocreg(p, regmask);
			s = doit(p->right, VALUE|USED, x, regmask);
			if(s.flag & FAIL)
				return(s);
			regmask &= ~s.regmask;
			t = doit(p->left, USED, 0, regmask);
			if(t.flag & FAIL) {
			/* did we fail because of a dest, or was it us? */
				if(dest.ans || svmask != REGMASK) {
					t = doit(p->left, USED, 0, svmask);
					if(t.flag & FAIL) {
						return(t);
					}
					starasg(p);
				}
				else
					asgwrite(p);
				longjmp(back, 1);
			}
			pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(t));
			if(strcmp(str(x), str(dest)) == 0) {
				dest.flag |= CC;
				return(dest);
			}
			goto movexdest;
		}
		if(p->right->op == Fld && incrsize(p) != 4) {
			/* ext sets whole word */
			asgwrite(p);
			p->left->type = isunsigned(p)? Tuint: Tint;
			longjmp(back, 1);
		}
		t = doit(p->left, USED, 0, regmask);
		regmask &= ~t.regmask;
		if(p->right->op == Genlab || p->right->op == Comop)
			extracheck(p);	/* slightly worse code in usual case */
		s = doit(p->right, VALUE, t, regmask);	/* VALUE is't right:
			register char *a, *b; return((*a++ = *b++ | 40) != 3); */
		if(s.flag & NOGOOD) {
		/* did we fail because of a dest, or was it us? */
			if(s.flag & FAIL) {
				if(dest.ans || svmask != REGMASK) {
					s = doit(p->right, VALUE, t, svmask);
					if(s.flag & FAIL) {
						return(s);
					}
				}
				asgwrite(p);
				longjmp(back, 1);
			}
			else if((flag & USED) && !((flag & CC) && (s.flag & CC))) {
				/* presumably USED as in *p++=*q++ */
				totemp(p, RIGHT);
				longjmp(back, 1);
			}
		}
		if(dest.ans) {
			x = s;
			goto movexdest;
		}
		else if(flag & ASADDR) {
			i = (s.flag & (ISREG|CANINDIR|SCRATCH));
			j = s.regmask;
			buf = str(s);
			goto convbuf;
		}
		return(s);
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.