File:  [Research Unix] / researchv10no / cmd / lcc / gen3 / gen.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

/* C compiler: VAX subset code generator */

#include "c.h"

#ifdef DEBUG
#define debug(x,y) if (x) y
static void lprint(Node, char *);
static void nprint(Node);
static char *rnames(unsigned);
static int id;
static Node lhead;

#else
#define debug(x,y)
#endif

static int rflag;		/* != 0 to trace register allocation */
static int framesize;		/* size of activation record */
static int offset;		/* current frame offset */
static int argbuildsize;	/* size of argument build area */
static int argoffset;		/* offset from top of stack for next argument */
static int nregs = 12;		/* number of allocatable registers */
static unsigned rmask;		/* rmask&(1<<r) == 0 if register r is free */
static unsigned usedmask;	/* usedmask&(1<<r) == 1 if register r was used */
static int reginfo[] = {	/*      1<<x if op+x is legal; */
	0,			/* 0x1000<<x if op+x needs a register */
#include "reginfo.h"
};

static void genreloads(Node, Node, Symbol);
static Symbol genspill(Node);
static void getreg(Node);
static Node *linearize(Node, Node *, Node);
static int needsreg(Node);
static void putreg(Node);
static void ralloc(Node);
static void restore(unsigned);
static void save(unsigned);
static int spillee(Node, unsigned);
static void spill(int, unsigned, Node);
static unsigned uses(Node);
static int valid(int);

#define typecode(p) (optype(p->op) == U ? I : optype(p->op) == B ? P : optype(p->op))
#define sets(p) ((p)->x.rmask<<(p)->x.reg)

/* address - initialize q for addressing expression p+n */
static void address(Symbol q, Symbol p, int n) {
	if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN)
		q->x.name = stringf("%s%s%d", p->x.name, n >= 0 ? "+" : "", n);
	else {
		q->x.offset = p->x.offset + n;
		q->x.name = stringf("%d(%s)", q->x.offset,
			p->scope == PARAM ? "ap" : "fp");
	}
}

/* blockbeg - begin a compound statement */
static void blockbeg(Env *e) {
	assert(rmask == (((~0)<<nregs)|1));
	e->rmask = rmask;
	e->offset = offset;
}

/* blockend - end a compound statement */
static void blockend(Env *e) {
	if (offset > framesize)
		framesize = offset;
	offset = e->offset;
	rmask = e->rmask;
}

/* defaddress - initialize an address */
static void defaddress(Symbol p) {
	print(".long %s\n", p->x.name);
}

/* defconst - define a constant */
static void defconst(int ty, Value v) {
	switch (ty) {
	case C: print(".byte %d\n",   v.uc); break;
	case S: print(".word %d\n",   v.us); break;
	case I: print(".long %d\n",   v.i ); break;
	case U: print(".long 0x%x\n", v.u ); break;
	case P: print(".long 0x%x\n", v.p ); break;
#ifdef vax
	case F:
		print(".long 0x%x\n", ((unsigned *) &v.f)[0]);
		break;
	case D: 
		print(".long 0x%x,0x%x\n", ((unsigned *) &v.d)[0],
			((unsigned *) &v.d)[1]);
		break;
#else
	case F: {
		char buf[MAXLINE];
		sprintf(buf, ".float 0f%.8e\n", v.f);
		outs(buf);
		break;
		}
	case D: {
		char buf[MAXLINE];
		sprintf(buf, ".double 0d%.18e\n", v.d);
		outs(buf);
		break;
		}
#endif
	default: assert(0);
	}
}

/* defstring - emit a string constant */
static void defstring(int len, char *s) {
	while (len-- > 0)
		print(".byte %d\n", *s++);
}

/* defsymbol - initialize p's Xsymbol fields */
static void defsymbol(Symbol p) {
	if (p->scope == CONSTANTS)
		p->x.name = p->name;
	else if (p->scope >= LOCAL && p->sclass == STATIC)
		p->x.name = stringf("L%d", genlabel(1));
	else if (p->generated)
		p->x.name = stringf("L%s", p->name);
	else
		p->x.name = stringf("_%s", p->name);
}

		  /* " FDCSIUPVB" */
#define suffix(p)    ".fdbwllll."[optype((p)->op)]
#define binary(inst) print("%s%c3 r%d,r%d,r%d\n", inst, suffix(p), \
                        b->x.reg, a->x.reg, r)
#define unary(inst)  print("%s%c r%d,r%d\n", inst, suffix(p), a->x.reg, r)
#define compare(cp)  print("cmp%c r%d,r%d; j%s %s\n", suffix(p), \
                        a->x.reg, b->x.reg, cp, p->syms[0]->x.name)

/* emit - emit the dags on list p */
static void emit(Node p) {
	for (; p; p = p->x.next) {
		Node a = p->kids[0], b = p->kids[1];
		int r = p->x.reg;
		switch (p->op) {
		case BANDU:				binary("bic");   break;
		case BORU:				binary("bis");   break;
		case BXORU:				binary("xor");   break;
		case ADDD:  case ADDF:			binary("add");   break;
		case ADDI:  case ADDP:  case ADDU:	binary("add");   break;
		case SUBD:  case SUBF:			binary("sub");   break;
		case SUBI:  case SUBP:  case SUBU:	binary("sub");   break;
		case MULD:  case MULF:			binary("mul");   break;
		case MULI:  case MULU:			binary("mul");   break;
		case DIVD:  case DIVF:  case DIVI:	binary("div");   break;
		case DIVU:
			save(p->x.busy&0x3e);
			print("pushl r%d; pushl r%d; calls $2,udiv; movl r0,r%d\n",
				b->x.reg, a->x.reg, r);
			restore(p->x.busy&0x3e);
			break;
		case MODI:
			print("divl3 r%d,r%d,r0; mull2 r%d,r0; subl3 r0,r%d,r%d\n",
				b->x.reg, a->x.reg, b->x.reg, a->x.reg, r);
			break;
		case MODU:
			save(p->x.busy&0x3e);
			print("pushl r%d; pushl r%d; calls $2,urem; movl r0,r%d\n",
				b->x.reg, a->x.reg, r);
			restore(p->x.busy&0x3e);
			break;
		case RSHU:
			print("subl3 r%d,$32,r0; extzv r%d,r0,r%d,r%d\n",
				b->x.reg, b->x.reg, a->x.reg, r);
			break;
		case RSHI: case LSHI: case LSHU:
			print("ashl r%d,r%d,r%d\n", b->x.reg, a->x.reg, r);
			break;
		case INDIRB:
			print("moval (r%d),r%d\n", a->x.reg, r);
			break;
		case INDIRC: case INDIRD: case INDIRF: case INDIRI:
		case INDIRP: case INDIRS:
			print("mov%c (r%d),r%d\n", suffix(p), a->x.reg, r);
			break;
		case BCOMU:				unary("mcom" );  break;
		case NEGD:  case NEGF:  case NEGI:	unary("mneg" );  break;
		case CVCI:				unary("cvtb" );  break;
		case CVCU:				unary("movzb");  break;
		case CVSI:				unary("cvtw" );  break;
		case CVSU:				unary("movzw");  break;
		case CVDF:  case CVDI:			unary("cvtd" );  break;
		case CVFD:				unary("cvtf" );  break;
		case CVUC:  case CVUS:			unary("cvtl" );  break;
		case CVIC:  case CVIS:  case CVID:	unary("cvtl" );  break;
		case CVIU:  case CVUI: 			unary("mov"  );  break;
		case CVPU:  case CVUP: 			unary("mov"  );  break;
		case RETD: case RETF: case RETI:
			print("mov%c r%d,r0; ret\n", suffix(p), a->x.reg);
			break;
		case RETV:
			print("ret\n");
			break;
		case ADDRGP: case ADDRFP: case ADDRLP:
			print("moval %s,r%d\n", p->syms[0]->x.name, r);
			break;
		case CNSTC: case CNSTI: case CNSTP:
		case CNSTS: case CNSTU:
			print("movl $%s,r%d\n", p->syms[0]->x.name, r);
			break;
		case JUMPV:
			print("jmp (r%d)\n", a->x.reg);
			break;
		case ASGNB:
			save(p->x.busy&0x3f);
			print("movc3 $%s,(r%d),(r%d)\n", p->syms[0]->x.name,
				b->x.reg, a->x.reg);
			restore(p->x.busy&0x3f);
			break;
		case ASGNC: case ASGND: case ASGNF: case ASGNI: case ASGNP: case ASGNS:
			print("mov%c r%d,(r%d)\n", suffix(p), b->x.reg, a->x.reg);
			break;
		case ARGB:
			save(p->x.busy&0x3f);
			print("movc3 $%s,(r%d),%d(sp)\n", p->syms[0]->x.name,
				a->x.reg, p->x.argoffset);
			restore(p->x.busy&0x3f);
			break;
		case ARGD: case ARGF: case ARGI: case ARGP:
			print("mov%c r%d,%d(sp)\n", suffix(p),
				a->x.reg, p->x.argoffset);
			break;
		case CALLB:
			save(p->x.busy&0x3e);
			if (a->x.reg == 1) {
				print("movl r1,r0\n");
				a->x.reg = 0;
			}
			if (b->x.reg != 1)
				print("movl r%d,r1\n", b->x.reg);
			print("calls $0,(r%d)\n", a->x.reg);
			restore(p->x.busy&0x3e);
			break;
		case CALLD: case CALLF: case CALLI: case CALLV:
			save(p->x.busy&0x3e);
			print("calls $0,(r%d)\n", a->x.reg);
			if (p->op != CALLV)
				print("mov%c r0,r%d\n", suffix(p), r);
			restore(p->x.busy&0x3e);
			break;
		case EQD:   case EQF:   case EQI:	compare("eql" ); break;
		case GED:   case GEF:   case GEI:	compare("geq" ); break;
		case GEU:				compare("gequ"); break;
		case GTD:   case GTF:   case GTI:	compare("gtr" ); break;
		case GTU:				compare("gtru"); break;
		case LED:   case LEF:   case LEI:	compare("leq" ); break;
		case LEU:				compare("lequ"); break;
		case LTD:   case LTF:   case LTI:	compare("lss" ); break;
		case LTU:				compare("lssu"); break;
		case NED:   case NEF:   case NEI:	compare("neq" ); break;
		case LABELV:
			print("%s:", p->syms[0]->x.name);
			break;
		default: assert(0);
		}
	}
}

/* export - announce an exported symbol */
static void export(Symbol p) {
	print(".globl %s\n", p->x.name);
}

/* function - generate code for a function */
static void function(Symbol f, Symbol caller[],
	Symbol callee[], int ncalls) {
	int i;

	offset = 4;
	for (i = 0; caller[i] && callee[i]; i++) {
		offset = roundup(offset, caller[i]->type->align);
		callee[i]->x.offset = caller[i]->x.offset = offset;
		callee[i]->x.name = caller[i]->x.name = stringf("%d(ap)", offset);
		offset += caller[i]->type->size;
		callee[i]->sclass = AUTO;
	}
	usedmask = argbuildsize = framesize = offset = 0;
	gencode(caller, callee);
	print("%s:.word 0x%x\n", f->x.name, usedmask&~0x3f);
	framesize += 4*nregs + argbuildsize;
	print("subl2 $%d,sp\n", framesize);
	if (isstruct(freturn(f->type)))
		print("movl r1,-4(fp)\n");
	emitcode();
	if (glevel > 1)
		print("ret\n");
}

/* gen - generate code for the dags on list p */
static Node gen(Node p) {
	Node head, *last;

	debug(1,id = 0);
	for (last = &head; p; p = p->link)
		last = linearize(p, last, 0);
	debug(rflag,(lhead = head, lprint(head," before ralloc")));
	for (p = head; p; p = p->x.next) {
		ralloc(p);
		if (p->count == 0 && sets(p))
			putreg(p);
	}
	debug(rflag,lprint(lhead," after ralloc"));
	return head;
}

/* getreg - allocate 1 or 2 registers for node p */
static void getreg(Node p) {
	int r, m = optype(p->op) == D ? 3 : 1;

	for (r = 0; r < nregs; r++)
		if ((rmask&(m<<r)) == 0) {
			p->x.rmask = m;
			p->x.reg = r;
			rmask |= sets(p);
			usedmask |= sets(p);
			debug(rflag,fprint(2,"allocating %s to node #%d\n", rnames(sets(p)), p->x.id));
			return;
		}
	debug(rflag,lprint(lhead, " before spillee"));
	r = spillee(p, m);
	spill(r, m, p);
	debug(rflag,lprint(lhead, " after spill"));
	assert((rmask&(m<<r)) == 0);
	getreg(p);
}

/* genreloads - make the nodes after dot use reloads of temp instead of p's register */
static void genreloads(Node dot, Node p, Symbol temp) {
	int i;
	Node last;

	for (last = dot; dot = dot->x.next; last = dot)
		for (i = 0; i < MAXKIDS; i++)
			if (dot->kids[i] == p) {
				dot->kids[i] = newnode(INDIR + typecode(p),
					newnode(ADDRL+P, 0, 0, temp), 0, 0);
				dot->kids[i]->count = 1;
				p->count--;
				linearize(dot->kids[i], &last->x.next, last->x.next);
				last = dot->kids[i];
			}
	assert(p->count == 0);
}

/* genspill - generate code to spill p's register and return the temporary used */
static Symbol genspill(Node p) {
	Symbol temp = newtemp(AUTO, typecode(p));
	Node q = p->x.next;

	linearize(newnode(ASGN + typecode(p),
		newnode(ADDRLP, 0, 0, temp), p, 0),
		&p->x.next, p->x.next);
	rmask &= ~1;
	for (p = p->x.next; p != q; p = p->x.next)
		ralloc(p);
	rmask |= 1;
	return temp;
}

/* global - global id */
static void global(Symbol p) {
	switch (p->type->align) {
	case 2: print(".align 1; "); break;
	case 4: print(".align 2; "); break;
	case 8: print(".align 3; "); break;
	}
	print("%s:", p->x.name);
}

/* import - announce an imported symbol */
static void import(Symbol p) {
}

/* linearize - linearize node list p */
static Node *linearize(Node p, Node *last, Node next) {
	if (p && !p->x.visited) {
		last = linearize(p->kids[0], last, 0);
		last = linearize(p->kids[1], last, 0);
		p->x.visited = 1;
		*last = p;
		last = &p->x.next;
		debug(1,if (p->x.id == 0) p->x.id = ++id);		
		debug(rflag,{fprint(2,"listing node "); nprint(p);})
	}
	*last = next;
	return last;
}

/* local - local variable */
static void local(Symbol p) {
	offset = roundup(offset + p->type->size, p->type->align);
	offset = roundup(offset, 4);
	p->x.offset = -offset;
	p->x.name = stringf("%d(fp)", -offset);
	p->sclass = AUTO;
}

/* needsreg - does p need a register? */
static int needsreg(p) Node p; {
	assert(opindex(p->op) > 0 && opindex(p->op) < sizeof reginfo/sizeof reginfo[0]);
	return reginfo[opindex(p->op)]&(0x1000<<optype(p->op));
}

/* progbeg - beginning of program */
static void progbeg(int argc, char *argv[]) {
	extern int atoi(char *);		/* (omit) */
	while (--argc > 0)
		if (**++argv == '-' && argv[0][1] >= '0' && argv[0][1] <= '9')
			nregs = atoi(*argv + 1);
		else if (strcmp(*argv, "-r") == 0)	/* (omit) */
			rflag++;			/* (omit) */
	rmask = ((~0)<<nregs)|1;
}

/* progend - end of program */
static void progend(void) {
}

/* putreg - decrement register usage */
static void putreg(Node p) {
	if (p && --p->count <= 0)
		{ assert(p->x.rmask);
		rmask &= ~sets(p);
		debug(rflag,fprint(2,"deallocating %s from node #%d\n", rnames(sets(p)), p->x.id)); }
}

/* ralloc - assign a register for p */
static void ralloc(Node p) {
	int i;

	assert(p);
	assert(p->x.rmask == 0);
	switch (generic(p->op)) {
	case ARG:
		argoffset = roundup(argoffset, p->syms[1]->u.c.v.i);
		p->x.argoffset = argoffset;
		argoffset += p->syms[0]->u.c.v.i;
		if (argoffset > argbuildsize)
			argbuildsize = roundup(argoffset, 4);
		break;
	case CALL:
		argoffset = 0;
		break;
	default:assert(valid(p->op));
	}
	for (i = 0; i < MAXKIDS; i++)
		putreg(p->kids[i]);
	p->x.busy = rmask;
	if (needsreg(p))
		getreg(p);
}

/* restore - restore registers in mask */
static void restore(unsigned mask) {
	int i;

	for (i = 1; i < nregs; i++)
		if (mask&(1<<i))
			print("movl %d(fp),r%d\n",
				4*i - framesize + argbuildsize, i);
}

/* save - save registers in mask */
static void save(unsigned mask) {
	int i;

	for (i = 1; i < nregs; i++)
		if (mask&(1<<i))
			print("movl r%d,%d(fp)\n", i,
				4*i - framesize + argbuildsize);
}

/* segment - switch to logical segment s */
static void segment(int s) {
	switch (s) {
	case CODE: print(".text\n");   break;
	case  LIT: print(".text 1\n"); break;
	case DATA:
	case  BSS: print(".data\n");   break;
	default: assert(0);
	}
}

/* space - initialize n bytes of space */
static void space(int n) {
	print(".space %d\n", n);
}

/* spill - spill all registers that overlap (r,m) */
static void spill(int r, unsigned m, Node dot) {
	int i;
	Node p = dot;

	while (p = p->x.next)
		for (i = 0; i < MAXKIDS; i++)
			if (p->kids[i] && sets(p->kids[i])&(m<<r)) {
				Symbol temp = genspill(p->kids[i]);
				rmask &= ~sets(p->kids[i]);
				genreloads(dot, p->kids[i], temp);
			}
}

/* spillee - identify the most-distantly-used register */
static int spillee(Node dot, unsigned m) {
	int bestdist = -1, bestreg = 0, dist, r;
	Node q;

	debug(rflag,fprint(2,"spillee: dot is node #%d\n", dot->x.id));
	for (r = 1; r < nregs - (m>>1); r++) {
		dist = 0;
		for (q = dot->x.next; q && !(uses(q)&(m<<r)); q = q->x.next)
			dist++;
		assert(q);	/* (omit) */
		debug(rflag,fprint(2,"r%d used in node #%d at distance %d\n", r, q->x.id, dist));
		if (dist > bestdist) {
			bestdist = dist;
			bestreg = r;
		}
	}
	debug(rflag,fprint(2,"spilling %s\n",rnames(m<<bestreg)));
	assert(bestreg);	/* (omit) */
	return bestreg;
}

/* uses - return mask of registers used by node p */
static unsigned uses(Node p) {
	int i;
	unsigned m = 0;

	for (i = 0; i < MAXKIDS; i++)
		if (p->kids[i])
			m |= sets(p->kids[i]);
	return m;
}

/* valid - is operator op a valid operator ? */
static int valid(op) {
	return opindex(op) > 0 && opindex(op) < sizeof reginfo/sizeof reginfo[0] ?
		reginfo[opindex(op)]&(1<<optype(op)) : 0;
}

#ifdef DEBUG
/* lprint - print the nodelist beginning at p */
static void lprint(Node p, char *s) {
	fprint(2, "node list%s:\n", s);
	if (p) {
		char buf[100];
		sprintf(buf, "%-4s%-8s%-8s%-8s%-7s%-13s%s",
			" #", "op", "kids", "syms", "count", "uses", "sets");
		fprint(2, "%s\n", buf);
	}
	for ( ; p; p = p->x.next)
		nprint(p);
}

/* nprint - print a line describing node p */
static void nprint(Node p) {
	int i;
	char *kids = "", *syms = "", buf[200];

	if (p->kids[0]) {
		static char buf[100];
		buf[0] = 0;
		for (i = 0; i < MAXKIDS && p->kids[i]; i++)
			sprintf(buf + strlen(buf), "%3d", p->kids[i]->x.id);
		kids = &buf[1];
	}
	if (p->syms[0] && p->syms[0]->x.name) {
		static char buf[100];
		buf[0] = 0;
		for (i = 0; i < MAXSYMS && p->syms[i]; i++) {
			if (p->syms[i]->x.name)
				sprintf(buf + strlen(buf), " %s", p->syms[i]->x.name);
			if (p->syms[i]->u.c.loc)
				sprintf(buf + strlen(buf), "=%s", p->syms[i]->u.c.loc->name);
		}
		syms = &buf[1];
	}
	sprintf(buf, "%2d. %-8s%-8s%-8s %2d    %-13s",
		p->x.id, opname(p->op), kids, syms, p->count, rnames(uses(p)));
	sprintf(buf + strlen(buf), "%s", rnames(sets(p)));
	fprint(2, "%s\n", buf);
}

/* rnames - return names of registers given by mask m */
static char *rnames(unsigned m) {
	static char buf[100];
	int r;

	buf[0] = buf[1] = 0;
	for (r = 0; r < nregs; r++)
		if (m&(1<<r))
			sprintf(buf + strlen(buf), " r%d", r);
	return &buf[1];
}
#endif

#ifndef V9
#include <errno.h>
#ifndef errno
extern int errno;
#endif

/* strtol - interpret str as a base b number; if ptr!=0, *ptr gets updated str */
long strtol(str, ptr, b) char *str, **ptr; {
	long n = 0;
	char *s, sign = '+';
	int d, overflow = 0;

	if (ptr)
		*ptr = str;
	if (b < 0 || b == 1 || b > 36)
		return 0;
	while (*str==' '||*str=='\f'||*str=='\n'||*str=='\r'||*str=='\t'||*str=='\v')
		str++;
	if (*str == '-' || *str == '+')
		sign = *str++;
	if (b == 0)
		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
			b = 16;
			str += 2;
		} else if (str[0] == '0')
			b = 8;
		else
			b = 10;
	for (s = str; *str; str++) {
		if (*str >= '0' && *str <= '9')
			d = *str - '0';
		else if (*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z')
			d = (*str&~040) - 'A' + 10;
		else
			break;
		if (d >= b)
			break;
		if (n < (LONG_MIN + d)/b)
			overflow = 1;
		n = b*n - d;
	}
	if (s == str)
		return 0;
	if (ptr)
		*ptr = str;
	if (overflow || (sign == '+' && n == LONG_MIN)) {
		errno = ERANGE;
		return sign == '+' ? LONG_MAX : LONG_MIN;
	}
	return sign == '+' ? -n : n;
}
#endif

static Interface naiveVAX = {
	"naiveVAX",
	1, 1, 0,	/* char */
	2, 2, 0,	/* short */
	4, 4, 0,	/* int */
	4, 4, 1,	/* float */
	8, 4, 1,	/* double */
	4, 4, 0,	/* T * */
	0, 1, 0,	/* struct */
	1,		/* left_to_right */
	1,		/* little_endian */
	0,		/* jump_on_return */
	0,		/* mulops_are_calls */ 
	1,		/* compl_band */
	0,		/* no_argb */
	0,		/* no_dag */
	address,
	blockbeg,
	blockend,
	defaddress,
	defconst,
	defstring,
	defsymbol,
	emit,
	export,
	function,
	gen,
	global,
	import,
	local,
	progbeg,
	progend,
	segment,
	space,
};
Interface *interfaces[] = { &naiveVAX, 0 };


unix.superglobalmegacorp.com

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