File:  [Plan 9 NeXT] / lucent / sys / src / alef / k / inst.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:01:04 2018 UTC (8 years, 1 month ago) by root
Branches: lucent, MAIN
CVS tags: plan9, HEAD
Plan 9 NeXT

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#define Extern extern
#include "parl.h"
#include "globl.h"

/* These are machine specific convs which generate no code */
ulong
nopconv[Ntype] =
{
	0,			/* TXXX */
	MINT|MUINT|MIND,	/* TINT */
	MINT|MUINT|MIND,	/* TUINT */
	MSINT|MSUINT,		/* TSINT */
	MSINT|MSUINT,		/* TSUINT */
	MCHAR,			/* TCHAR */
	MFLOAT,			/* TFLOAT */
	MINT|MUINT|MIND,	/* TIND */
	0,			/* TCHANNEL */
	0,			/* TARRAY */
	MAGGREGATE,		/* TAGGREGATE */
	MUNION,			/* TUNION */
	0,			/* TFUNC */
	0,			/* TVOID */
	TADT,			/* TADT */
};

Inst*
ai(void)
{
	Inst *i;

	i = malloc(sizeof(Inst));
	i->src1.type = A_NONE;
	i->dst.type = A_NONE;
	i->reg = Nreg;
	i->next = 0;
	i->lineno = iline;
	return i;
}

/* Emit an assembler instruction */
Inst*
instruction(int op, Node *s1, Node *s2, Node *dst)
{
	Inst *i;

	i = ai();
	i->op = op;
	i->pc = pc++;

	if(s1)
		mkaddr(s1, &i->src1, 1);

	if(s2 && s2 != dst) {
		switch(s2->type) {
		case OREGISTER:
			break;
		case OCONST:
			if(s2->ival == 0) {
				s2->reg = 0;
				break;
			}
			/* Fall */
		default:
			fatal("inst %s %N,%N,%N", itab[op], s1, s2, dst);
		}
		if(s2->t->type == TFLOAT)
			i->reg = s2->reg - Freg;
		else
			i->reg = s2->reg;
	}

	if(dst) {
		mkaddr(dst, &i->dst, 1);
		if(i->dst.type == A_REG)
		if(i->reg == i->dst.reg)
			i->reg = Nreg;
	}
	ilink(i);
	return ipc;
}

void
ilink(Inst *i)
{
	if(opt('c'))
		print("(%d)%i\n", i->lineno, i);

	if(proghead)
		ipc->next = i;
	else
		proghead = i;

	ipc = i;
}

/* Back patch a branch */
void
label(Inst *i, ulong pc)
{
	Adres *a;

	switch(i->op) {
	case ABA:
	case ABCC:
	case ABCS:
	case ABE:
	case ABG:
	case ABGE:
	case ABGU:
	case ABL:
	case ABLE:
	case ABLEU:
	case ABN:
	case ABNE:
	case ABNEG:
	case ABPOS:
	case ABVC:
	case ABVS:
	case AJMPL:
	case AJMP:
	case AFBA:
	case AFBE:
	case AFBG:
	case AFBGE:
	case AFBL:
	case AFBLE:
	case AFBLG:
	case AFBN:
	case AFBNE:
	case AFBO:
	case AFBU:
	case AFBUE:
	case AFBUG:
	case AFBUGE:
	case AFBUL:
	case AFBULE:
		break;

	default:
		fatal("label not branch");
	}
	a = &i->dst;
	a->type = A_BRANCH;
	a->ival = pc;
}

/* Select code for arithmetic operations */
void
codmop(Node *o, Node *l, Node *r, Node *dst)
{
	int op;

	op = AGOK;
	switch(o->type) {
	case OADD:
	case OADDEQ:
		switch(o->t->type) {
		default:
			op = AADD;
			break;
		case TFLOAT:
			op = AFADDD;
			break;
		}
		break;

	case OSUB:
	case OSUBEQ:
		switch(o->t->type) {
		default:
			op = ASUB;
			break;
		case TFLOAT:
			op = AFSUBD;
			break;
		}
		break;

	case OMUL:
	case OMULEQ:
		switch(o->t->type) {
		default:
			op = AMUL;
			break;
		case TFLOAT:
			op = AFMULD;
			break;
		}
		break;

	case ODIV:
	case ODIVEQ:	
		switch(o->t->type) {
		default:
			op = ADIV;
			break;
		case TUINT:
		case TSUINT:
			op = ADIVL;
			break;
		case TFLOAT:
			op = AFDIVD;
			break;
		}
		break;

	case OMOD:
	case OMODEQ:
		switch(o->t->type) {
		default:
			op = AMOD;
			break;
		case TUINT:
		case TSUINT:
			op = AMODL;
			break;
		}
		break;

	case OALSH:
	case OLSH:
	case OLSHEQ:
		op = ASLL;
		break;

	case ORSH:
	case ORSHEQ:
		op = ASRL;
		break;

	case OXOR:
	case OXOREQ:
		op = AXOR;
		break;

	case OLOR:
	case OOREQ:
		op = AOR;
		break;

	case OLAND:
	case OANDEQ:
		op = AAND;
		break;

	case OARSH:
		op = ASRA;
		break;
	}
	instruction(op, l, r, dst);
}

int
mulcon(Node *n, Node *nn)
{
	int o;
	long v;
	Multab *m;
	Node *l, *r, nod1, nod2, mop;
	char code[sizeof(m->code)+2], *p;

	if(n->t->type == TFLOAT)
		return 0;

	mop.t = n->t;
	l = n->left;
	r = n->right;
	if(l->type == OCONST) {
		l = r;
		r = n->left;
	}
	if(r->type != OCONST)
		return 0;

	v = r->ival;
	m = mulcon0(v);
	if(!m) {
		if(opt('M'))
			print("%L multiply table: %lld\n", r->ival);
		return 0;
	}
	if(opt('M'))
		print("%L multiply: %ld\n", v);

	memmove(code, m->code, sizeof(m->code));
	code[sizeof(m->code)] = 0;

	p = code;
	if(p[1] == 'i')
		p += 2;
	reg(&nod1, n->t, nn);
	genexp(l, &nod1);
	if(v < 0) {
		mop.type = OSUB;
		codmop(&mop, &nod1, con(0), &nod1);
	}
	reg(&nod2, n->t, ZeroN);

	for(;;) {
		switch(*p) {
		case '\0':
			regfree(&nod2);
			assign(&nod1, nn);
			regfree(&nod1);
			return 1;
		case '+':
			o = OADD;
			goto addsub;
		case '-':
			o = OSUB;
		addsub:	/* number is r,n,l */
			v = p[1] - '0';
			r = &nod1;
			if(v&4)
				r = &nod2;
			n = &nod1;
			if(v&2)
				n = &nod2;
			l = &nod1;
			if(v&1)
				l = &nod2;
			mop.type = o;
			codmop(&mop, l, n, r);
			break;
		default: /* op is shiftcount, number is r,l */
			v = p[1] - '0';
			r = &nod1;
			if(v&2)
				r = &nod2;
			l = &nod1;
			if(v&1)
				l = &nod2;
			v = *p - 'a';
			if(v < 0 || v >= 32) {
				diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
				break;
			}
			mop.type = OALSH;
			codmop(&mop, con(v), l, r);
			break;
		}
		p += 2;
	}
	return 0;
}

int
vconst(Node *n)
{
	int i;

	if(n == ZeroN || n->type != OCONST || n->t == ZeroT)
		return -159;

	switch(n->t->type) {
	case TFLOAT:
		i = 100;
		if(n->fval > i || n->fval < -i)
			return -159;
		i = n->fval;
		if(i != n->fval)
			return -159;
		return i;

	case TCHAR:
	case TSINT:
	case TSUINT:
	case TINT:
	case TUINT:
	case TIND:
		i = n->ival;
		if(i != n->ival)
			return -159;
		return i;
	}
}

/* Select code for conditional operators */
void
codcond(int comp, Node *src1, Node *src2)
{
	int a, t;

	if(src1->type == OCONST)
	if(src1->ival == 0)
	if(src1->t->type != TFLOAT)
		src1 = regn(0);

	if(src2->type == OCONST)
	if(src2->ival == 0)
	if(src2->t->type != TFLOAT)
		src2 = regn(0);

	t = src1->t->type;
	switch(comp) {
	default:
		fatal("codcond: %N %s %N", src1, treeop[comp]+1, src2);

	case OEQ:
		a = ABE;
		if(t == TFLOAT)
			a = AFBE;
		break;

	case ONEQ:
		a = ABNE;
		if(t == TFLOAT)
			a = AFBNE;
		break;

	case OLT:
		a = ABL;
		if(t == TFLOAT)
			a = AFBL;
		break;
		
	case OGT:
		a = ABG;
		if(t == TFLOAT)
			a = AFBG;
		break;

	case OLEQ:
		a = ABLE;
		if(t == TFLOAT)
			a = AFBLE;
		break;

	case OGEQ:
		a = ABGE;
		if(t == TFLOAT)
			a = AFBGE;
		break;

	case OLO:
		a = ABCS;
		break;

	case OHI:
		a = ABGU;
		break;

	case OLOS:
		a = ABLEU;
		break;

	case OHIS:
		a = ABCC;
		break;
	}

	if(t == TFLOAT)
		instruction(AFCMPD,src1, ZeroN, src2);
	else
		instruction(ACMP, src1, ZeroN, src2);

	instruction(a, ZeroN, ZeroN, ZeroN);
}

void
mkdata(Node *n, int off, int size, Inst *i)
{
	Adres *a;

	if(n->type != ONAME)
		fatal("mkdata %N\n", n);

	a = &i->src1;

	a->reg = Nreg;
	a->ival = off;
	a->sym = n->sym;
	a->type = A_INDREG;
	a->class = n->t->class;
	a->etype = n->t->type;

	i->reg = size;
}

void
mkaddr(Node *n, Adres *a, int ur0)
{
	long o;
	Tinfo *ti;

	a->sym = ZeroS;
	a->reg = Nreg;

	switch(n->type) {
	default:
		fatal("mkaddr: %N\n", n);

	case ONAME:
		ti = n->ti;

		a->type = A_INDREG;
		a->etype = ti->t->type;
		a->ival = ti->offset;
		a->sym = n->sym;
		if(ti->class == Argument) {
			a->reg = RegSP;
			a->class = A_NONE;
			break;
		}
		a->class = ti->class;
		break;

	case OCONST:
		switch(n->t->type) {
		default:
			if(ur0 && n->ival == 0) {
				a->type = A_REG;
				a->reg = 0;
				break;
			}
			a->type = A_CONST;
			a->ival = n->ival;
			break;
		case TFLOAT:
			a->type = A_FCONST;
			a->fval = n->fval;
			break;
		}
		break;

	case OADD:
		if(n->left->type == OCONST) {
			mkaddr(n->left, a, 0);
			o = a->ival;
			mkaddr(n->right, a, 1);
		}
		else {
			mkaddr(n->right, a, 0);
			o = a->ival;
			mkaddr(n->left, a, 1);
		}
		a->ival += o;
		break;

	case OINDREG:
		a->type = A_INDREG;
		a->reg = n->reg;
		a->ival = n->ival;
		break;

	case OREGISTER:
		a->type = A_REG;
		switch(n->t->type) {
		default:
			a->reg = n->reg;
			break;
	
		case TFLOAT:
			a->type = A_FREG;
			if(n->reg == Retfreg)
				a->reg = Retfregno;
			else
				a->reg = n->reg - Freg;
			break;
		}
		break;

	case OIND:
		mkaddr(n->left, a, 1);
		if(a->type == A_REG || a->type == A_CONST)
			a->type = A_INDREG;
		break;

	case OADDR:
		mkaddr(n->left, a, 1);
		a->type = A_CONST;
		a->ival += n->ival;
		break;
	}
}

/* Generate function preamble and assign parameter offsets */
void
preamble(Node *name)
{
	Inst *i;
	Node *n;

	i = ai();
	i->op = ATEXT;
	i->pc = pc++;
	i->lineno = name->srcline;

	n = an(0, ZeroN, ZeroN);
	*n = *name;
	n->type = ONAME;
	mkaddr(n, &i->src1, 0);
	mkaddr(con(0), &i->dst, 0);
	ilink(i);
	funentry = i;		/* To back patch arg space */
	becomentry = i;
}

/* Output accumulated string constants */
void
strop(void)
{
	String *s;
	int c, l;
	Inst *i;
	char *p;

	for(s = strdat; s; s = s->next) {
		i = ai();
		i->op = AGLOBL;
		mkaddr(&s->n, &i->src1, 0);
		mkaddr(con(s->len), &i->dst, 0);
		ilink(i);

		c = 0;
		p = s->string;
		while(s->len) {
			l = s->len;
			if(l > 8)
				l = 8;

			iline = s->n.srcline;
			i = ai();
			i->op = ADATA;
			i->dst.type = A_STRING;
			memset(i->dst.str, 0, sizeof(i->dst.str));
			memmove(i->dst.str, p, l);
			s->len -= l;
			mkdata(&s->n, c, l, i);
			p += l;
			c += l;
			ilink(i);
		}
	}
}

unix.superglobalmegacorp.com

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