aijuprogress!93d470012 years agoHistory
729 lines · 14.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include "dat.h"#include "fns.h" Function *curfunc; typedef struct Patch Patch; struct Patch {	Line;	IRBlock **p;	Symbol *sym;	Patch *next;}; Patch *patches; voidnewfunc(Type *t){	curfunc = emalloc(sizeof(Function));	if(t->t != TFUNC)		sysfatal("newfunc: not a function type");	curfunc->type = t;	curfunc->bllist.next = curfunc->bllist.prev = &curfunc->bllist;} static voidaddir(IRBlock *b, IR *i){	i->prev = b->instr.prev;	i->next = &b->instr;	i->prev->next = i;	i->next->prev = i;} IR *irop(Line *l, int op){	IR *i;		i = emalloc(sizeof(*i));	i->Line = *l;	i->op = op;	return i;} static voiddelir(IR *i){	i->next->prev = i->prev;	i->prev->next = i->next;} Targ *targ(int n, ...){	va_list va;	Targ *t;		va_start(va, n);	t = emalloc(sizeof(*t));	t->num = -1;	t->Rn = -1;	t->t = n;	switch(n){	case TARGRETV:		t->type = va_arg(va, Type *);		break;	case TARGFP:	case TARGCONST:	case TARGARG:		t->off = va_arg(va, int);		t->type = regtype;		break;	case TARGSYM:		t->sym = va_arg(va, Symbol *);		t->type = t->sym->t;		break;	case TARGSSA:		t->sym = va_arg(va, Symbol *);		t->type = t->sym->t;		t->n = va_arg(va, int);		t->up = va_arg(va, Targ *);		break;	case TARGIND:		t->link = va_arg(va, Targ *);		t->type = va_arg(va, Type *);		break;	case TARGADDR:		t->sym = va_arg(va, Symbol *);		t->n = va_arg(va, int);		break;	case TARGSH:		t->op = va_arg(va, int);		t->a = va_arg(va, Targ *);		t->b = va_arg(va, Targ *);		break;	default:		sysfatal("targ: unhandled %d", n);	}	va_end(va);	return t;} static Targ *newtemp(Type *type){	Targ *t;		t = emalloc(sizeof(*t));	t->t = TARGTEMP;	t->tn = curfunc->tempcnt++;	t->num = -1;	t->Rn = -1;	t->type = type;	return t;} static IRBlock *newblock(void){	IRBlock *bl;		bl = emalloc(sizeof(*bl));	bl->instr.next = bl->instr.prev = &bl->instr;	bl->next = &curfunc->bllist;	bl->prev = curfunc->bllist.prev;	bl->next->prev = bl;	bl->prev->next = bl;	return bl;} static IRBlock *delblock(IRBlock *b){	IRBlock *bn;		bn = b->next;	b->next->prev = b->prev;	b->prev->next = b->next;	free(b);	return bn;} intlegalc(ulong c){	c |= c >> 12 | c << 20;	c |= c >> 6 | c << 26;	c |= c >> 3 | c << 29;	c |= (c >> 1 | c << 30) | (c >> 2 | c << 29);	return ~c & 0x55555555;} static Targ *irread(Line *l, Targ *t, IRBlock *b, int arith){	Type *ty;	Symbol *s;	IR *i; 	ty = regtype;	switch(t->t){	case TARGSYM:		s = t->sym;		if((s->class & BMEM) != 0){			ty = s->t;			goto move;		}		return t;	default:		print("irread: unhandled %d\n", t->t);		goto move;	case TARGCONST:	/*	if(arith && legalc(t->lval))			return t;*/		goto move;	case TARGADDR:		goto move;	case TARGTEMP:		return t;	case TARGIND:		ty = t->type;		break;	}move:	i = irop(l, OPMOV);	i->r = newtemp(ty);	i->a = t;	addir(b, i);	return i->r;	} static Targ *ircast(Line *l, IRBlock *b, Targ *t, int type){	IR *i;	int o; 	if(type)		o = OPSXTB + ((type - 1) >> 1);	else		o = OPZXTB + ((type - 1) >> 1);	i = irop(l, o);	i->r = newtemp(t->type);	i->a = t;	addir(b, i);	return i->r;} static Targ *irexpr(ASTNode *, IRBlock *, IRBlock **); static Targ *addrof(ASTNode *n, IRBlock *b, IRBlock **br){	IR *i; 	switch(n->t){	case ASTSYM:		*br = b;		return targ(TARGADDR, n->sym, 0);	case ASTMEMB:		i = irop(n, OPADD);		i->r = newtemp(regtype);		i->a = addrof(n->n, b, &b);		i->b = targ(TARGCONST, n->mb.m != nil ? n->mb.m->off : 0);		addir(b, i);		*br = b;		return i->r;	case ASTDEREF:		return irexpr(n->n, b, br);	default:		sysfatal("addrof: unhandled %A", n->t);		return nil;	}} static void condbranch(ASTNode *, IRBlock *, IRBlock *, IRBlock *); static Targ *irexpr(ASTNode *n, IRBlock *b, IRBlock **br){	IRBlock *b0, *b1, *b2;	Targ *t, *l, *r, **a;	IR *i;	int k, o;	Type *ty; 	*br = b;	switch(n->t){	case ASTSYM:		if((t = n->sym->targ) != nil)			return t;		return n->sym->targ = targ(TARGSYM, n->sym);	case ASTCLONG:		return targ(TARGCONST, n->lval);	case ASTADDROF:		return addrof(n->n, b, br);	case ASTBIN:		switch(OPTYPE(n->op)){		case OPNORM:			k = n->type == &types[TFLOAT] || n->type == &types[TDOUBLE] ? OPFADD - OPADD : 0;			i = irop(n, n->op + k);			i->a = irexpr(n->n1, b, &b);			i->a = irread(n, i->a, b, 1);			i->b = irexpr(n->n2, b, &b);			i->b = irread(n, i->b, b, 1);			i->r = newtemp(n->type);			addir(b, i);			*br = b;			return i->r;		case OPBRANCH:			b0 = newblock();			b1 = newblock();			b2 = newblock();			condbranch(n, b, b0, b1);			i = irop(n, OPMOV);			i->a = targ(TARGCONST, 1);			i->r = t = newtemp(regtype);			addir(b0, i);			b0->branch = b2;			i = irop(n, OPMOV);			i->a = targ(TARGCONST, 0);			i->r = r = newtemp(regtype);			addir(b1, i);			b1->branch = b2;			i = newφ(n, 2);			i->φ.r = l = newtemp(regtype);			i->φ.a[0] = t;			i->φ.a[1] = r;			addφ(b2, i);			*br = b2;			return l;		default:			error(n, "irexpr: can't handle binary op %#x", OPTYPE(n->op));			return nil;		}	case ASTUN:		i = irop(n, n->op);		i->a = irexpr(n->n1, b, &b);		i->a = irread(n, i->a, b, 1);		i->r = newtemp(n->type);		addir(b, i);		*br = b;		return i->r;	case ASTDEREF:		t = irexpr(n->n, b, &b);		t = targ(TARGIND, irread(n, t, b, 0), n->type);		*br = b;		return t;	case ASTMEMB:		return targ(TARGIND, addrof(n, b, br), n->type);	case ASTASS:		if(n->op == OPMOV){			i = irop(n, OPMOV);			t = irexpr(n->n2, b, &b);			i->a = t = irread(n, t, b, 0);			i->r = irexpr(n->n1, b, &b);			addir(b, i);			*br = b;		}else{			i = irop(n, n->op);			i->b = irexpr(n->n2, b, &b);			l = irexpr(n->n1, b, &b);			i->a = irread(n, l, b, 1);			i->r = t = newtemp(n->type);			addir(b, i);			if(n->op <= OPMOD && n->type->t < TUINT)				t = ircast(n, b, t, n->type->t);			i = irop(n, OPMOV);			i->r = l;			i->a = t;			addir(b, i);			*br = b;		}		return t;	case ASTINC:		k = n->type->t == TIND ? n->type->link->size : 1;		i = irop(n, n->op <= POSTINC ? OPADD : OPSUB);		i->r = t = newtemp(n->type);		l = irexpr(n->n1, b, &b);		i->a = r = irread(n, l, b, 1);		i->b = targ(TARGCONST, k);		addir(b, i);		if(n->type->t < TUINT)			t = ircast(n, b, t, n->type->t);		if((n->op & 1) != 0){			i = irop(n, OPMOV);			i->a = r;			i->r = r = newtemp(n->type);			addir(b, i);		}else			r = t;		i = irop(n, OPMOV);		i->r = l;		i->a = t;		addir(b, i);		return r;	case ASTTERN:		b0 = newblock();		b1 = newblock();		b2 = newblock();		l = newtemp(n->type);		condbranch(n->cond, b, b0, b1);		t = irexpr(n->block, b0, &b0);		i = irop(n, OPMOV);		i->a = t;		i->r = t = newtemp(n->type);		addir(b0, i);		b0->branch = b2;		r = irexpr(n->elsebl, b1, &b1);		i = irop(n, OPMOV);		i->a = r;		i->r = r = newtemp(n->type);		addir(b1, i);		b1->branch = b2;		i = newφ(n, 2);		i->φ.r = l;		i->φ.a[0] = t;		i->φ.a[1] = r;		addφ(b2, i);		*br = b2;		return l;	case ASTCOMMA:		irexpr(n->n1, b, &b);		return irexpr(n->n2, b, br);	case ASTCALL:		a = emalloc(sizeof(Targ*) * n->func.argn);		for(k = 0; k < n->func.argn; k++)			a[k] = irexpr(n->func.args[k], b, &b);		o = 0;		for(k = 0; k < n->func.argn; k++){			i = irop(n, OPMOV);			i->a = a[k];			ty = n->func.args[k]->type;			if(k > 0 || ty->t == TFLOAT || ty->t == TDOUBLE)				i->r = targ(TARGIND, targ(TARGARG, o), ty);			else				i->r = targ(TARGRETV, regtype);			addir(b, i);			o += ty->size;			o = o + 3 & -4;		}		free(a);		i = irop(n, OPCALL);		i->a = irread(n, addrof(n->func.n, b, &b), b, 0);		addir(b, i);		i = irop(n, OPMOV);		i->r = newtemp(n->type);		i->a = targ(TARGRETV, n->type);		addir(b, i);		*br = b;		return i->r;	default:		sysfatal("irexpr: unhandled %A", n->t);		return nil;	}} static voidbranch(IRBlock *cur, IRBlock *next){	if(cur != nil)		cur->branch = next;} static voidcondbranch(ASTNode *n, IRBlock *cur, IRBlock *true, IRBlock *false){	IR *i;	IRBlock *b0; 	switch(n->t){	case ASTBIN:		if(n->op == OPLAND){			b0 = newblock();			condbranch(n->n1, cur, b0, false);			condbranch(n->n2, b0, true, false);			return;		}		if(n->op == OPLOR){			b0 = newblock();			condbranch(n->n1, cur, true, b0);			condbranch(n->n2, b0, true, false);			return;		}		if(OPTYPE(n->op) == OPBRANCH){			i = irop(n, OPCMP);			i->a = irexpr(n->n1, cur, &cur);			i->a = irread(n, i->a, cur, 1);			i->b = irexpr(n->n2, cur, &cur);			i->b = irread(n, i->b, cur, 1);			addir(cur, i);			i = irop(n, n->op);			i->targ = true;			addir(cur, i);			cur->branch = false;			return;		}	case ASTUN:		if(n->op == OPISZ){			condbranch(n->n1, cur, false, true);			return;		}	default:		i = irop(n, OPTST);		i->a = irexpr(n, cur, &cur);		addir(cur, i);		i = irop(n, OPNE);		i->targ = true;		addir(cur, i);		cur->branch = false;		break;	case ASTCLONG:		if(n->lval != 0)			cur->branch = true;		else			cur->branch = false;		return;	}} static IRBlock *irstat(ASTNode *n, IRBlock *b, IRBlock *brk, IRBlock *cont){	IRBlock *b1, *b2, *b3;	ASTNode *m;	Patch *p;	IR *i; 	if(n == nil)		return b;	if(b == nil){		error(n, "unreachable code %A", n->t);		return nil;	}	switch(n->t){	default:

Lines 1–500 of 729.