Пример #1
0
int constant(LVALUE *lval)
{
        constype=CINT;
        conssign=dosigned;
        lval->is_const = 1 ;            /* assume constant will be found */
        if ( fnumber(&lval->const_val) ) {
                lval->val_type=DOUBLE;
		if ( doublestrings ) {
		    immedlit(litlab);
		    outdec(lval->const_val); nl();
		    callrts("__atof2");
                    WriteDefined("math_atof",1);
		} else {
		    immedlit(dublab);
		    outdec(lval->const_val); nl();
		    callrts("dload");
		}
                lval->is_const = 0 ;                    /*  floating point not constant */
                lval->flags=0;
                return(1);
        }
        else if ( number(&lval->const_val) || pstr(&lval->const_val) ) {
/* Insert long stuff/long pointer here? */
		if ( (unsigned long )lval->const_val >= 65536LU )
			constype = LONG;

                lval->val_type = constype ;
                lval->flags = (lval->flags&MKSIGN)|conssign;
                if (constype == LONG) vlongconst(lval->const_val);
                else vconst(lval->const_val);
                return(1);
        }
        else if ( tstr(&lval->const_val) ) {
                lval->is_const = 0 ;                    /* string address not constant */
                lval->ptr_type=CCHAR;   /* djm 9/3/99 */
                lval->val_type=CINT;
                lval->flags=0;
                immedlit(litlab);
        }
        else {
                lval->is_const = 0 ;
                return(0);       
        }
        outdec(lval->const_val);
        nl();
        return(1);
}
Пример #2
0
void
gen(Node *n)
{
	Node *l, nod;
	Prog *sp, *spc, *spb;
	Case *cn;
	long sbc, scc;
	int snbreak, sncontin;
	int f, o, oldreach;

loop:
	if(n == Z)
		return;
	nearln = n->lineno;
	o = n->op;
	if(debug['G'])
		if(o != OLIST)
			print("%L %O\n", nearln, o);

	if(!canreach) {
		switch(o) {
		case OLABEL:
		case OCASE:
		case OLIST:
		case OBREAK:
		case OFOR:
		case OWHILE:
		case ODWHILE:
			/* all handled specially - see switch body below */
			break;
		default:
			if(warnreach) {
				warn(n, "unreachable code %O", o);
				warnreach = 0;
			}
		}
	}

	switch(o) {

	default:
		complex(n);
		cgen(n, Z);
		break;

	case OLIST:
		gen(n->left);

	rloop:
		n = n->right;
		goto loop;

	case ORETURN:
		canreach = 0;
		warnreach = !suppress;
		complex(n);
		if(n->type == T)
			break;
		l = n->left;
		if(l == Z) {
			noretval(3);
			gbranch(ORETURN);
			break;
		}
		if(typecmplx[n->type->etype]) {
			sugen(l, nodret, n->type->width);
			noretval(3);
			gbranch(ORETURN);
			break;
		}
		regret(&nod, n);
		cgen(l, &nod);
		regfree(&nod);
		if(typefd[n->type->etype])
			noretval(1);
		else
			noretval(2);
		gbranch(ORETURN);
		break;

	case OLABEL:
		canreach = 1;
		l = n->left;
		if(l) {
			l->pc = pc;
			if(l->label)
				patch(l->label, pc);
		}
		gbranch(OGOTO);	/* prevent self reference in reg */
		patch(p, pc);
		goto rloop;

	case OGOTO:
		canreach = 0;
		warnreach = !suppress;
		n = n->left;
		if(n == Z)
			return;
		if(n->complex == 0) {
			diag(Z, "label undefined: %s", n->sym->name);
			return;
		}
		if(suppress)
			return;
		gbranch(OGOTO);
		if(n->pc) {
			patch(p, n->pc);
			return;
		}
		if(n->label)
			patch(n->label, pc-1);
		n->label = p;
		return;

	case OCASE:
		canreach = 1;
		l = n->left;
		if(cases == C)
			diag(n, "case/default outside a switch");
		if(l == Z) {
			newcase();
			cases->val = 0;
			cases->def = 1;
			cases->label = pc;
			cases->isv = 0;
			goto rloop;
		}
		complex(l);
		if(l->type == T)
			goto rloop;
		if(l->op == OCONST)
		if(typeword[l->type->etype] && l->type->etype != TIND) {
			newcase();
			cases->val = l->vconst;
			cases->def = 0;
			cases->label = pc;
			cases->isv = typev[l->type->etype];
			goto rloop;
		}
		diag(n, "case expression must be integer constant");
		goto rloop;

	case OSWITCH:
		l = n->left;
		complex(l);
		if(l->type == T)
			break;
		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
			diag(n, "switch expression must be integer");
			break;
		}

		gbranch(OGOTO);		/* entry */
		sp = p;

		cn = cases;
		cases = C;
		newcase();

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		gbranch(OGOTO);
		spb = p;

		gen(n->right);		/* body */
		if(canreach){
			gbranch(OGOTO);
			patch(p, breakpc);
			nbreak++;
		}

		patch(sp, pc);
		doswit(l);
		patch(spb, pc);

		cases = cn;
		breakpc = sbc;
		canreach = nbreak!=0;
		if(canreach == 0)
			warnreach = !suppress;
		nbreak = snbreak;
		break;

	case OWHILE:
	case ODWHILE:
		l = n->left;
		gbranch(OGOTO);		/* entry */
		sp = p;

		scc = continpc;
		continpc = pc;
		gbranch(OGOTO);
		spc = p;

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		gbranch(OGOTO);
		spb = p;

		patch(spc, pc);
		if(n->op == OWHILE)
			patch(sp, pc);
		bcomplex(l, Z);		/* test */
		patch(p, breakpc);
		if(l->op != OCONST || vconst(l) == 0)
			nbreak++;

		if(n->op == ODWHILE)
			patch(sp, pc);
		gen(n->right);		/* body */
		gbranch(OGOTO);
		patch(p, continpc);

		patch(spb, pc);
		continpc = scc;
		breakpc = sbc;
		canreach = nbreak!=0;
		if(canreach == 0)
			warnreach = !suppress;
		nbreak = snbreak;
		break;

	case OFOR:
		l = n->left;
		if(!canreach && l->right->left && warnreach) {
			warn(n, "unreachable code FOR");
			warnreach = 0;
		}
		gen(l->right->left);	/* init */
		gbranch(OGOTO);		/* entry */
		sp = p;

		/*
		 * if there are no incoming labels in the
		 * body and the top's not reachable, warn
		 */
		if(!canreach && warnreach && deadheads(n)) {
			warn(n, "unreachable code %O", o);
			warnreach = 0;
		}

		scc = continpc;
		continpc = pc;
		gbranch(OGOTO);
		spc = p;

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		sncontin = ncontin;
		ncontin = 0;
		gbranch(OGOTO);
		spb = p;

		patch(spc, pc);
		gen(l->right->right);	/* inc */
		patch(sp, pc);
		if(l->left != Z) {	/* test */
			bcomplex(l->left, Z);
			patch(p, breakpc);
			if(l->left->op != OCONST || vconst(l->left) == 0)
				nbreak++;
		}
		canreach = 1;
		gen(n->right);		/* body */
		if(canreach){
			gbranch(OGOTO);
			patch(p, continpc);
			ncontin++;
		}
		if(!ncontin && l->right->right && warnreach) {
			warn(l->right->right, "unreachable FOR inc");
			warnreach = 0;
		}

		patch(spb, pc);
		continpc = scc;
		breakpc = sbc;
		canreach = nbreak!=0;
		if(canreach == 0)
			warnreach = !suppress;
		nbreak = snbreak;
		ncontin = sncontin;
		break;

	case OCONTINUE:
		if(continpc < 0) {
			diag(n, "continue not in a loop");
			break;
		}
		gbranch(OGOTO);
		patch(p, continpc);
		ncontin++;
		canreach = 0;
		warnreach = !suppress;
		break;

	case OBREAK:
		if(breakpc < 0) {
			diag(n, "break not in a loop");
			break;
		}
		/*
		 * Don't complain about unreachable break statements.
		 * There are breaks hidden in yacc's output and some people
		 * write return; break; in their switch statements out of habit.
		 * However, don't confuse the analysis by inserting an
		 * unreachable reference to breakpc either.
		 */
		if(!canreach)
			break;
		gbranch(OGOTO);
		patch(p, breakpc);
		nbreak++;
		canreach = 0;
		warnreach = !suppress;
		break;

	case OIF:
		l = n->left;
		if(bcomplex(l, n->right)) {
			if(typefd[l->type->etype])
				f = !l->fconst;
			else
				f = !l->vconst;
			if(debug['c'])
				print("%L const if %s\n", nearln, f ? "false" : "true");
			if(f) {
				canreach = 1;
				supgen(n->right->left);
				oldreach = canreach;
				canreach = 1;
				gen(n->right->right);
				/*
				 * treat constant ifs as regular ifs for
				 * reachability warnings.
				 */
				if(!canreach && oldreach && debug['w'] < 2)
					warnreach = 0;
			}
			else {
				canreach = 1;
				gen(n->right->left);
				oldreach = canreach;
				canreach = 1;
				supgen(n->right->right);
				/*
				 * treat constant ifs as regular ifs for
				 * reachability warnings.
				 */
				if(!oldreach && canreach && debug['w'] < 2)
					warnreach = 0;
				canreach = oldreach;
			}
		}
		else {
			sp = p;
			canreach = 1;
			if(n->right->left != Z)
				gen(n->right->left);
			oldreach = canreach;
			canreach = 1;
			if(n->right->right != Z) {
				gbranch(OGOTO);
				patch(sp, pc);
				sp = p;
				gen(n->right->right);
			}
			patch(sp, pc);
			canreach = canreach || oldreach;
			if(canreach == 0)
				warnreach = !suppress;
		}
		break;

	case OSET:
	case OUSED:
	case OPREFETCH:
		usedset(n->left, o);
		break;
	}
}
Пример #3
0
/*
 *	calculate addressability as follows
 *		REGISTER ==> 12		register
 *		NAME ==> 11		name+value(SB/SP)
 *			note that 10 is no longer generated
 *		CONST ==> 20		$value
 *		*(20) ==> 21		value
 *		&(10) ==> 12		$name+value(SB)
 *		&(11) ==> 1		$name+value(SP)
 *		(12) + (20) ==> 12	fold constants
 *		(1) + (20) ==> 1	fold constants
 *		*(12) ==> 10		back to name
 *		*(1) ==> 11		back to name
 *
 *		(2,10,11) + (20) ==> 2	indirect w offset
 *		(2) ==> &13
 *		*(10,11) ==> 13		indirect, no index
 *
 *		(20) * (X) ==> 7	multiplier in indexing
 *		(X,7) + (12,1) ==> 8	adder in indexing (addresses)
 *		(X,7) + (10,11,2) ==> 8	adder in indexing (names)
 *		(8) ==> &9		index, almost addressable
 *
 *		(X)++ ==> X		fake addressability
 *
 *	calculate complexity (number of registers)
 */
void
xcom(Node *n)
{
	Node *l, *r;
	int g;

	if(n == Z)
		return;
	l = n->left;
	r = n->right;
	n->complex = 0;
	n->addable = 0;
	switch(n->op) {
	case OCONST:
		n->addable = 20;
		break;

	case ONAME:
		n->addable = 11;	/* difference to make relocatable */
		break;

	case OREGISTER:
		n->addable = 12;
		break;

	case OADDR:
		xcom(l);
		if(l->addable == 10)
			n->addable = 12;
		else
		if(l->addable == 11)
			n->addable = 1;
		break;

	case OADD:
		xcom(l);
		xcom(r);
		if(n->type->etype != TIND)
			break;

		if(l->addable == 20)
		switch(r->addable) {
		case 12:
		case 1:
			n->addable = r->addable;
			goto brk;
		}
		if(r->addable == 20)
		switch(l->addable) {
		case 12:
		case 1:
			n->addable = l->addable;
			goto brk;
		}
		break;

	case OIND:
		xcom(l);
		if(l->op == OADDR) {
			l = l->left;
			l->type = n->type;
			*n = *l;
			return;
		}
		switch(l->addable) {
		case 20:
			n->addable = 21;
			break;
		case 1:
			n->addable = 11;
			break;
		case 12:
			n->addable = 10;
			break;
		}
		break;

	case OASHL:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		g = vconst(r);
		if(g >= 0 && g < 4)
			n->addable = 7;
		break;

	case OMUL:
	case OLMUL:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		g = vlog(r);
		if(g >= 0) {
			n->op = OASHL;
			r->vconst = g;
			if(g < 4)
				n->addable = 7;
			break;
		}
		g = vlog(l);
		if(g >= 0) {
			n->left = r;
			n->right = l;
			l = r;
			r = n->right;
			n->op = OASHL;
			r->vconst = g;
			if(g < 4)
				n->addable = 7;
			break;
		}
		break;

	case ODIV:
	case OLDIV:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		g = vlog(r);
		if(g >= 0) {
			if(n->op == ODIV)
				n->op = OASHR;
			else
				n->op = OLSHR;
			r->vconst = g;
		}
		break;

	case OSUB:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		if(vconst(l) == 0) {
			n->op = ONEG;
			n->left = r;
			n->right = Z;
		}
		break;

	case OXOR:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		if(vconst(l) == -1) {
			n->op = OCOM;
			n->left = r;
			n->right = Z;
		}
		break;

	case OASMUL:
	case OASLMUL:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		g = vlog(r);
		if(g >= 0) {
			n->op = OASASHL;
			r->vconst = g;
		}
		goto aseae;

	case OASDIV:
	case OASLDIV:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;
		g = vlog(r);
		if(g >= 0) {
			if(n->op == OASDIV)
				n->op = OASASHR;
			else
				n->op = OASLSHR;
			r->vconst = g;
		}
		goto aseae;

	case OASLMOD:
	case OASMOD:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;

	aseae:		/* hack that there are no byte/short mul/div operators */
		if(n->type->etype == TCHAR || n->type->etype == TSHORT) {
			n->right = new1(OCAST, n->right, Z);
			n->right->type = types[TLONG];
			n->type = types[TLONG];
		}
		if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) {
			n->right = new1(OCAST, n->right, Z);
			n->right->type = types[TULONG];
			n->type = types[TULONG];
		}
		goto asop;

	case OASXOR:
	case OASOR:
	case OASADD:
	case OASSUB:
	case OASLSHR:
	case OASASHR:
	case OASASHL:
	case OASAND:
	case OAS:
		xcom(l);
		xcom(r);
		if(typev[n->type->etype])
			break;

	asop:
		if(l->addable > INDEXED &&
		   l->complex < FNX &&
		   r && r->complex < FNX)
			n->addable = l->addable;
		break;

	case OPOSTINC:
	case OPREINC:
	case OPOSTDEC:
	case OPREDEC:
		xcom(l);
		if(typev[n->type->etype])
			break;
		if(l->addable > INDEXED &&
		   l->complex < FNX)
			n->addable = l->addable;
		break;

	default:
		if(l != Z)
			xcom(l);
		if(r != Z)
			xcom(r);
		break;
	}

brk:
	n->complex = 0;
	if(n->addable >= 10)
		return;
	if(l != Z)
		n->complex = l->complex;
	if(r != Z) {
		if(r->complex == n->complex)
			n->complex = r->complex+1;
		else
		if(r->complex > n->complex)
			n->complex = r->complex;
	}
	if(n->complex == 0)
		n->complex++;

	if(com64(n))
		return;

	switch(n->op) {

	case OFUNC:
		n->complex = FNX;
		break;

	case OADD:
	case OMUL:
	case OLMUL:
	case OXOR:
	case OAND:
	case OOR:
		/*
		 * symmetric operators, make right side simple
		 * if same, put constant on left to get movq
		 */
		if(r->complex > l->complex ||
		  (r->complex == l->complex && r->addable == 20)) {
			n->left = r;
			n->right = l;
		}
		break;

	case OLE:
	case OLT:
	case OGE:
	case OGT:
	case OEQ:
	case ONE:
		/*
		 * relational operators, make right side simple
		 * if same, put constant on left to get movq
		 */
		if(r->complex > l->complex || r->addable == 20) {
			n->left = r;
			n->right = l;
			n->op = invrel[relindex(n->op)];
		}
		break;
	}
}
Пример #4
0
void
gen(Node *n)
{
	Node *l;
	Prog *sp, *spc, *spb;
	Case *cn;
	long sbc, scc;
	int snbreak;
	int g, o;

loop:
	if(n == Z)
		return;
	nearln = n->lineno;
	o = n->op;
	if(debug['G'])
		if(o != OLIST)
			print("%L %O\n", nearln, o);

	retok = 0;
	switch(o) {

	default:
		complex(n);
		doinc(n, PRE);
		cgen(n, D_NONE, n);
		doinc(n, POST);
		break;

	case OLIST:
		gen(n->left);

	rloop:
		n = n->right;
		goto loop;

	case ORETURN:
		retok = 1;
		complex(n);
		if(n->type == T)
			break;
		l = n->left;
		if(l == Z) {
			noretval(3);
			gbranch(ORETURN);
			break;
		}
		doinc(l, PRE);
		if(typesuv[n->type->etype]) {
			sugen(l, D_TREE, nodret, n->type->width);
			doinc(l, POST);
			noretval(3);
			gbranch(ORETURN);
			break;
		}
		g = regalloc(n->type, regret(n->type));
		cgen(l, g, n);
		doinc(l, POST);
		if(typefd[n->type->etype])
			noretval(1);
		else
			noretval(2);
		gbranch(ORETURN);
		regfree(g);
		break;

	case OLABEL:
		l = n->left;
		if(l) {
			l->xoffset = pc;
			if(l->label)
				patch(l->label, pc);
		}
		gbranch(OGOTO);	/* prevent self reference in reg */
		patch(p, pc);
		goto rloop;

	case OGOTO:
		retok = 1;
		n = n->left;
		if(n == Z)
			return;
		if(n->complex == 0) {
			diag(Z, "label undefined: %s", n->sym->name);
			return;
		}
		gbranch(OGOTO);
		if(n->xoffset) {
			patch(p, n->xoffset);
			return;
		}
		if(n->label)
			patch(n->label, pc-1);
		n->label = p;
		return;

	case OCASE:
		l = n->left;
		if(cases == C)
			diag(n, "case/default outside a switch");
		if(l == Z) {
			casf();
			cases->val = 0;
			cases->def = 1;
			cases->label = pc;
			setsp();;
			goto rloop;
		}
		complex(l);
		if(l->type == T)
			goto rloop;
		if(l->op == OCONST)
		if(typechl[l->type->etype]) {
			casf();
			cases->val = l->vconst;
			cases->def = 0;
			cases->label = pc;
			setsp();
			goto rloop;
		}
		diag(n, "case expression must be integer constant");
		goto rloop;

	case OSWITCH:
		l = n->left;
		complex(l);
		doinc(l, PRE);
		if(l->type == T)
			break;
		if(!typechl[l->type->etype]) {
			diag(n, "switch expression must be integer");
			break;
		}
		g = regalloc(types[TLONG], D_NONE);
		n->type = types[TLONG];
		cgen(l, g, n);
		regfree(g);
		doinc(l, POST);
		setsp();
		gbranch(OGOTO);		/* entry */
		sp = p;

		cn = cases;
		cases = C;
		casf();

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		gbranch(OGOTO);
		spb = p;

		gen(n->right);
		gbranch(OGOTO);
		patch(p, breakpc);
		nbreak++;

		patch(sp, pc);
		doswit(g, l);

		patch(spb, pc);
		cases = cn;
		breakpc = sbc;
		nbreak = snbreak;
		setsp();
		break;

	case OWHILE:
	case ODWHILE:
		l = n->left;
		gbranch(OGOTO);		/* entry */
		sp = p;

		scc = continpc;
		continpc = pc;
		gbranch(OGOTO);
		spc = p;

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		gbranch(OGOTO);
		spb = p;

		patch(spc, pc);
		if(n->op == OWHILE)
			patch(sp, pc);
		bcomplex(l);	/* test */
		patch(p, breakpc);
		if(l->op != OCONST || vconst(l) == 0)
			nbreak++;

		if(n->op == ODWHILE)
			patch(sp, pc);
		gen(n->right);		/* body */
		gbranch(OGOTO);
		patch(p, continpc);

		patch(spb, pc);
		continpc = scc;
		breakpc = sbc;
		if(nbreak == 0)
			retok = 1;
		nbreak = snbreak;
		break;

	case OFOR:
		l = n->left;
		gen(l->right->left);	/* init */
		gbranch(OGOTO);			/* entry */
		sp = p;

		scc = continpc;
		continpc = pc;
		gbranch(OGOTO);
		spc = p;

		sbc = breakpc;
		breakpc = pc;
		snbreak = nbreak;
		nbreak = 0;
		gbranch(OGOTO);
		spb = p;

		patch(spc, pc);
		gen(l->right->right);	/* inc */
		patch(sp, pc);	
		if(l->left != Z) {	/* test */
			bcomplex(l->left);
			patch(p, breakpc);
			if(l->left->op != OCONST || vconst(l->left) == 0)
				nbreak++;
		}
		gen(n->right);		/* body */
		gbranch(OGOTO);
		patch(p, continpc);

		patch(spb, pc);
		continpc = scc;
		breakpc = sbc;
		if(nbreak == 0)
			retok = 1;
		nbreak = snbreak;
		break;

	case OCONTINUE:
		if(continpc < 0) {
			diag(n, "continue not in a loop");
			break;
		}
		gbranch(OGOTO);
		patch(p, continpc);
		break;

	case OBREAK:
		if(breakpc < 0) {
			diag(n, "break not in a loop");
			break;
		}
		gbranch(OGOTO);
		patch(p, breakpc);
		nbreak++;
		break;

	case OIF:
		l = n->left;
		bcomplex(l);
		sp = p;
		if(n->right->left != Z)
			gen(n->right->left);
		if(n->right->right != Z) {
			gbranch(OGOTO);
			patch(sp, pc);
			sp = p;
			gen(n->right->right);
		}
		patch(sp, pc);
		break;

	case OSET:
	case OUSED:
		usedset(n->left, o);
		break;
	}
}
Пример #5
0
Файл: tree.c Проект: kahrs/cda
void
Ceval(Node *tp)
{
	unsigned int i1, i2;
	Node * tp0;
	if(tp->Cone ||  tp->Czero) return;
	switch(tp->code) {
	case 0:
		return;
	case ELIST:
		if(tp->t1 != 0)
			Ceval(tp->t1);
		if(tp->t2 != 0)
			Ceval(tp->t2);
		tp->Czero = tp->Cone = 0;
		return;
	case ASSIGN:
		Ceval(tp->t2);
		tp->Czero = tp->t2->Czero;
		tp->Cone = tp->t2->Cone;
		return;
	case DONTCARE:
		Ceval(tp->t2);
		tp->Czero = tp->t2->Czero;
		tp->Cone = tp->t2->Cone;
		return;
	case AND:
		Ceval(tp->t2);
		Ceval(tp->t1);
		tp->Czero = tp->t2->Czero | tp->t1->Czero;
		tp->Cone = tp->t2->Cone & tp->t1->Cone;
		return;
	case OR:
		Ceval(tp->t2);
		Ceval(tp->t1);
		tp->Czero = tp->t2->Czero & tp->t1->Czero;
		tp->Cone = tp->t2->Cone | tp->t1->Cone;
		return;
	case LAND:
		Ceval(tp->t2);
		Ceval(tp->t1);
		tp->Czero = (~0 << 1) | ((tp->t2->Czero == ~0) || (tp->t1->Czero == ~0));
		tp->Cone = (tp->t1->Cone) && (tp->t2->Cone);
		return;
	case LOR:
		Ceval(tp->t2);
		Ceval(tp->t1);
		tp->Czero = (~0 << 1) | ((tp->t2->Czero == ~0) && (tp->t1->Czero == ~0));
		tp->Cone = (tp->t1->Cone) ||(tp->t2->Cone);
		return;
	case NEG:
		Ceval(tp->t1);
		tp->Cone = tp->Czero = 0;
		if(ISCONST(tp->t1))
			tp->Czero = ~(tp->Cone = -tp->t1->Cone);
		return;
	case XOR:
		Ceval(tp->t2);
		Ceval(tp->t1);
		tp->Czero = (tp->t2->Czero & tp->t1->Czero)
			| (tp->t2->Cone & tp->t1->Cone);
		tp->Cone = (tp->t2->Czero & tp->t1->Cone)
			| (tp->t2->Cone & tp->t1->Czero);
		return;
	case FLONE:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done find left one for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1);
		tp->Czero = ~tp->Cone;
		return;
	case FRONE:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done find right one for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1);
		tp->Czero = ~tp->Cone;
		return;
	case GREY:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done grey code for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1);
		tp->Czero = ~tp->Cone;
		return;
	case NOT:
		Ceval(tp->t1);
		tp->Cone = (tp->t1->Czero == ~0);
		tp->Czero = (tp->t1->Cone) ? ~0 : (~0 << 1);
		return;
	case COM:
		Ceval(tp->t1);
		tp->Cone = (tp->t1->Czero);
		tp->Czero = (tp->t1->Cone);
		return;
	case ADD:
		Ceval(tp->t2);
		Ceval(tp->t1);
		i1 = tp->t1->Cone | tp->t1->Czero;
		i1 = i1 & ~(i1 + 1);
		i2 = tp->t2->Cone | tp->t2->Czero;
		i2 = i2 & ~(i2 + 1);
		tp->Cone = i1 & i2 & (tp->t1->Cone + tp->t2->Cone);
		tp->Czero = i1 & i2 & ~tp->Cone;
		for(i1 = 0; ; i1 = i1<<1 | 1)
			if(((tp->t1->Czero | i1) == ~0)
				&& ((tp->t2->Czero | i1) == ~0)) break;
		tp->Czero |= ~(i1<<1 | 1);
		return;
	case SUB:
		Ceval(tp->t2);
		Ceval(tp->t1);
		i1 = tp->t1->Cone | tp->t1->Czero;
		i1 = i1 & ~(i1 + 1);
		i2 = tp->t2->Cone | tp->t2->Czero;
		i2 = i2 & ~(i2 + 1);
		tp->Cone = i1 & i2 & (tp->t1->Cone + tp->t2->Cone);
		tp->Czero = i1 & i2 & ~tp->Cone;
		for(i1 = 0; ; i1 = i1<<1 | 1)
			if(((tp->t1->Czero | i1) == ~0)
				&& ((tp->t2->Czero | i1) == ~0)) break;
		i2 = i1 ^ i1>>1;
		if((tp->t1->Cone & i2) && (tp->t2->Czero & i2)) 
			tp->Czero |= ~(i1<<1 | 1);
		else if((tp->t1->Czero & i2) && (tp->t2->Cone & i2)) 
			tp->Cone |= ~(i1<<1 | 1);
		return;
	case MUL:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done mult for variable\n");
			exits("error");;
		}
		if(!vconst(tp->t2)) {
			fprintf(stderr, "Restrick hasn't done mult for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1) * eval(tp->t2);
		tp->Czero = ~tp->Cone;
		return;
	case DIV:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done div for variable\n");
			exits("error");;
		}
		if(!vconst(tp->t2)) {
			fprintf(stderr, "Restrick hasn't done div for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1) / eval(tp->t2);
		tp->Czero = ~tp->Cone;
		return;
	case MOD:
		if(!vconst(tp->t1)) {
			fprintf(stderr, "Restrick hasn't done mod for variable\n");
			exits("error");;
		}
		if(!vconst(tp->t2)) {
			fprintf(stderr, "Restrick hasn't done mod for variable\n");
			exits("error");;
		}
		tp->Cone = eval(tp->t1) % eval(tp->t2);
		tp->Czero = ~tp->Cone;
		return;
	case GT:
	case LT:
	case GE:
	case LE:
		Ceval(tp->t2);
		Ceval(tp->t1);
		for(i1 = 0; ; i1 = i1<<1 | 1)
			if(((tp->t1->Czero | tp->t1->Cone | i1) == ~0)
				&& ((tp->t2->Czero | tp->t2->Cone | i1) == ~0)) break;
		i1 = ~i1;
		switch(tp->code) {
		case LT:
		case LE:
			tp->Cone = (tp->t1->Cone & i1) < (tp->t2->Cone & i1);
			tp->Czero = (tp->t1->Cone & i1) > (tp->t2->Cone & i1);
			break;
		case GT:
		case GE:
			tp->Cone = (tp->t1->Cone & i1) > (tp->t2->Cone & i1);
			tp->Czero = (tp->t1->Cone & i1) < (tp->t2->Cone & i1);
		}
		return;
	case EQ:
		Ceval(tp->t2);
		Ceval(tp->t1);
		if(ISCONST(tp->t1) && ISCONST(tp->t2)) {
			tp->Cone = (tp->t1->Cone == tp->t2->Cone) ? 1 : 0;
			tp->Czero = ~tp->Cone;
		}
		else {
			i1 = (tp->t1->Cone | tp->t1->Czero)
				& (tp->t2->Cone | tp->t2->Czero);
			tp->Czero = (i1 & (tp->t1->Cone ^ tp->t2->Cone)) ?
				~0 : ~1;
			tp->Cone = 0;
		}
		return;
	case NE:
		Ceval(tp->t2);
		Ceval(tp->t1);
		if(ISCONST(tp->t1) && ISCONST(tp->t2)) {
			tp->Cone = (tp->t1->Cone != tp->t2->Cone) ? 1 : 0;
			tp->Czero = ~tp->Cone;
		}
		else {
			tp->Czero = ~1;
			i1 = (tp->t1->Cone | tp->t1->Czero)
				& (tp->t2->Cone | tp->t2->Czero);
			tp->Cone = (i1 & (tp->t1->Cone ^ tp->t2->Cone)) ?
				1 : 0;
		}
		return;
	case LS:
		Ceval(tp->t2);
		Ceval(tp->t1);
		if(ISCONST(tp->t2)) {
			tp->Cone = tp->t1->Cone << tp->t2->Cone;
			tp->Czero = tp->t1->Czero << tp->t2->Cone;
			i1 = ~0 << tp->t2->Cone;
			tp->Czero |= ~i1;
			return;
		} 
		tp->Cone = tp->Czero = 0;
		return;
	case RS:
		Ceval(tp->t2);
		Ceval(tp->t1);
		if(ISCONST(tp->t2)) {
			tp->Cone = tp->t1->Cone >> tp->t2->Cone;
			tp->Czero = tp->t1->Czero >> tp->t2->Cone;
			i1 = ~0 >> tp->t2->Cone;
			tp->Czero |= ~i1;
			return;
		} 
		tp->Cone = tp->Czero = 0;
		return;
	case CND:
		Ceval(tp->t1);
		Ceval(tp->t2->t1);
		Ceval(tp->t2->t2);
		if(ISCONST(tp->t1)) {
			if (tp->t1->Cone) {
				tp->Cone = tp->t2->t1->Cone;
				tp->Czero = tp->t2->t1->Czero;
				return;
			}
			tp->Cone = tp->t2->t2->Cone;
			tp->Czero = tp->t2->t2->Czero;
			return;
		}
		tp->Cone = tp->t2->t1->Cone & tp->t2->t2->Cone;
		tp->Czero = tp->t2->t1->Czero & tp->t2->t2->Czero;
		return;
	case SWITCH:
	{
		int o, z;
		if(vconst(tp)) {
			tp->Cone = eval(tp);
			tp->Czero = ~tp->Cone;
			return;
		}
		Ceval(tp->t1);
		tp0 = tp;
		o = z = ~0;
		for(tp = tp->t2; tp; tp = tp->t2) {
			if(tp->code == ALT) {
				if(tp->t1) {
					Ceval(tp->t1);
					continue;
				}
				tp = tp->t2;
				if(tp == 0)
					break;
				if(tp->code != CASE)
					break;
				Ceval(tp->t1);
				o &= tp->t1->Cone;
				z &= tp->t1->Czero;
				continue;
			}
			if(tp->code != CASE)
				break;
			Ceval(tp->t1);
			o &= tp->t1->Cone;
			z &= tp->t1->Czero;
		}
		tp0->Cone = o;
		tp0->Czero = z;
		return;	
	}
	case EQN:
		tp0 = ((Hshtab *) (tp->t1))->assign;
		Ceval(tp0);
		tp->Cone = tp0->Cone;
		tp->Czero = tp0->Czero;
		return;
	case BOTH:
	case INPUT:
		tp->Czero = ~1;
		tp->Cone = 0;
		return;
	case FIELD:
		i1 =  HI((Hshtab *) tp->t1) - LO((Hshtab *) tp->t1);
		tp->Cone = 0;
		tp->Czero = (i1 > 31) ? 0 : ( ~0 << i1);
		return;
	case NUMBER:
		tp->Cone = (int) tp->t1;
		tp->Czero = ~tp->Cone;
		return;
	default:
		fprintf(stderr,"unknown Ceval op %d\n", tp->code);
		exits("error");;
	}
Пример #6
0
 //execute context
 l_thread::type_return l_thread::execute(l_call_context&  context)
 {
     //lock context
     context.lock();
     //save context
     register3(R_CONTEXT)      = l_variable( &context );
     //pc...
     unsigned int     pc       = 0;
     l_function&      function = m_vm->function(context.get_fun_id());
     l_list_command&  commands = function.m_commands;
     //macro
     #define raise(str)\
     {\
         push_error(str, pc, (unsigned int)commands[pc].m_line);\
         return T_RETURN_ERROR;\
     }
     #define vconst(c)  function.m_costants[c]
     #define top_size   (m_top+1)
     //for all commands
     for (pc = 0; pc < commands.size(); ++pc)
     {
         //current command
         l_command& cmp = commands[pc];
         //opcodes
         switch (cmp.m_op_code)
         {
             case L_JMP: pc = cmp.m_arg - 1; break;
             case L_RETURN:
                 //push return
                 if(cmp.m_arg)
                 {
                     //get value
                     register3(2) = pop();
                     //return...
                     return T_RETURN_VALUE;
                 }
                 else
                 {
                     //came back
                     return T_RETURN_VOID;
                 }
                 //..
             break;
                 
             case L_IF:
                 if(top().is_true())
                 {
                     pc = cmp.m_arg - 1;
                 }
                 pop();
             break;
                 
             case L_IF0:
                 if(top().is_false())
                 {
                     pc = cmp.m_arg - 1;
                 }
                 pop();
             break;
                 
             case L_IF_OR_POP:
                 if(top().is_true())
                 {
                     pc = cmp.m_arg - 1;
                 }
                 else
                 {
                     pop();
                 }
             break;
                 
             case L_IF0_OR_POP:
                 if(top().is_false())
                 {
                     pc = cmp.m_arg - 1;
                 }
                 else
                 {
                     pop();
                 }
             break;
                 
             case L_PUSH:          push( stack(cmp.m_arg) );  break;
             case L_PUSH_NULL:     push( l_variable() );      break;
             case L_PUSH_TRUE:     push( l_variable(true) );  break;
             case L_PUSH_FALSE:    push( l_variable(false) ); break;
             case L_PUSHK:         push( vconst(cmp.m_arg) ); break;
             case L_CLOSER:
             {
                 //get value
                 l_variable& call_fun = vconst(cmp.m_arg);
                 //...
                 if(call_fun.is_function())
                 {
                     
                     //new context
                     register3(0) = l_closer::gc_new(get_gc());
                     //init context
                     register3(0).to<l_closer>()->init(call_fun.m_value.m_fid, this, l_variable(&context));
                     //push context
                     push(register3(0));
                 }
             }
             break;
                 ////////////////////////////////////////////////////////////
             case L_ADD:
                 if(!stack(1).add(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_MUL:
                 if(!stack(1).mul(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_SUB:
                 if(!stack(1).sub(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_DIV:
                 if(!stack(1).div(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_MOD:
                 if(!stack(1).mod(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_UNM:
                 if(!stack(0).unm(stack(0))) raise("not valid operation");
             break;
             ////////////////////////////////////////////////////////////
             case L_EQ:
                 if(!stack(1).equal(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_NEQ:
                 if(!stack(1).not_equal(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_RT:
                 if(!stack(1).rt(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_RE:
                 if(!stack(1).re(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_LT:
                 if(!stack(1).lt(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_LE:
                 if(!stack(1).le(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
             ////////////////////////////////////////////////////////////
             case L_NOT:
                 if(!stack(0).not_value(stack(0))) raise("not valid operation");
             break;
                 
             case L_OR:
                 if(!stack(1).or_value(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
                 
             case L_AND:
                 if(!stack(1).and_value(stack(0),stack(1))) raise("not valid operation");
                 pop();
             break;
             ////////////////////////////////////////////////////////////
             case L_GET_GLOBAL:
                 push( global(context,cmp.m_arg) );
             break;
                 
             case L_SET_GLOBAL:
                 global(context,cmp.m_arg) = pop();
             break;
             ////////////////////////////////////////////////////////////
             case L_GET_LOCAL:
                 push( strick_local(context,cmp.m_arg) );
             break;
                 
             case L_SET_LOCAL:
                 strick_local(context,cmp.m_arg) = pop();
             break;
             ////////////////////////////////////////////////////////////
             case L_SET_UP_VALUE:
                 local(context,cmp.m_arg) = pop();
             break;
                 
             case L_GET_UP_VALUE:
                 push( local(context,cmp.m_arg) );
             break;
             ////////////////////////////////////////////////////////////
             case L_GET_THIS:
                 push(context.this_field());
             break;
             case L_SET_THIS:
                 context.this_field() = pop();
             break;
             case L_SET_THIS_NPOP:
                 context.this_field() = stack(cmp.m_arg);
             break;
             ////////////////////////////////////////////////////////////
             case L_NEW_ARRAY:
             {
                 register3(0) = l_array::gc_new(get_gc());
                 //init ?
                 if( cmp.m_arg > 0 )
                 {
                     //types
                     l_array* vector = register3(0).array();
                     //put stack into vector
                     for(int i = cmp.m_arg-1; i >= 0; --i)
                     {
                         vector->operator[](i) = pop();
                     }
                 }
                 //push array (n.b. gc run...)
                 push( register3(0) );
             }
             break;
             //alloc tablet
             case L_NEW_TABLE:
             {
                 register3(0) = l_table::gc_new(get_gc());
                 //init ?
                 if( cmp.m_arg > 0 )
                 {
                     //types
                     l_table* table = register3(0).table();
                     //assert
                     assert(!(cmp.m_arg % 2));
                     //put stack into vector
                     for(int i = (cmp.m_arg)-1; i >= 0; i-=2)
                     {
                         //push key and value
                         table->operator[](stack(1)) = stack(0);
                         //pop value
                         pop();
                         //pop key
                         pop();
                     }
                 }
                 //push table (n.b. gc run...)
                 push( register3(0) );
             }
             break;
             case L_GET_AT_VAL:
             {
                       l_variable& r_b = stack(1);
                 const l_variable& r_c = stack(0);
                 //try
                 if ( r_b.is_object() )
                 {
                     //is a vector
                     if(r_b.is_array())
                     {
                         //types
                         l_array* vector = r_b.array();
                         //to size int
                         size_t index = 0;
                         //cast
                         if( r_c.is_int() )  index= (size_t)r_c.m_value.m_i;
                         else if( r_c.is_float() )index= (size_t)r_c.m_value.m_f;
                         else raise( "value isn't a valid key" );
                         //save last
                         get_this() = stack(1);
                         //get
                         stack(1)   = vector->operator[](index) ;
                     }
                     else if(r_b.is_table())
                     {
                         //types
                         l_table* table =  r_b.table();
                         //is a string?
                         if(!r_c.is_string()) raise( "value isn't a valid key" );
                         //save last
                         get_this() = stack(1);
                         //get and pop value
                         stack(1) = table->operator[](r_c);
                     }
                     else
                     {
                         raise( "value isn't a vector/table, field not available" );
                     }
                 }
                 else
                 {
                     raise( "value isn't a vector/table/object, field not avaliable" );
                 }
                 //pop index
                 pop();
             }
             break;
             case L_SET_AT_VAL:
             {
                 //get table/array
                       l_variable& r_a = stack(2);
                 //get index
                 const l_variable& r_b = stack(1);
                 //try
                 if ( r_a.is_object() )
                 {
                     //is a vector
                     if(r_a.is_array())
                     {
                         //types
                         l_array* vector = r_a.array();
                         //to size int
                         size_t index = 0;
                         //cast
                              if( r_b.is_int()   ) index= (size_t)r_b.m_value.m_i;
                         else if( r_b.is_float() ) index= (size_t)r_b.m_value.m_f;
                         else raise( "value isn't a valid key" );
                         //get and pop value
                         vector->operator[](index) = pop();
                     }
                     else if(r_a.is_table())
                     {
                         //types
                         l_table* table =  r_a.table();
                         //is a string?
                         if(!r_b.is_string()) raise( "value isn't a valid key" );
                         //get and pop value
                         table->operator[](r_b) = pop();
                     }
                     else
                     {
                         raise( "value isn't a vector/table, field not available" );
                     }
                 }
                 else
                 {
                     //pop value
                     pop();
                 }
                 //pop index
                 pop();
                 //pop array/tablet
                 pop();
             }
             break;
             //for in
             case L_IT:
             {
                 //get index
                 l_variable& r_a = top();
                 //..
                 //try
                 if ( r_a.is_object() )
                 {
                     //get object
                     l_obj* this_obj = (l_obj*)r_a.m_value.m_pobj;
                     //is a vector
                     if(r_a.is_array())
                     {
                         //types
                         l_array* vector = r_a.array();
                         //pop value
                         pop();
                         //push it
                         push( vector->get_it() );
                     }
                     else if (r_a.is_table())
                     {
                         //types
                         l_table* table = r_a.table();
                         //pop value
                         pop();
                         //push it
                         push( table->get_it() );
                     }
                     else if (r_a.to<l_xrange>())
                     {
                         //types
                         l_xrange* xrange = static_cast< l_xrange* > ( this_obj );
                         //pop value
                         pop();
                         //push it
                         push( xrange->get_it() );
                     }
                     else
                     {
                         raise( "this value not have a iterator" );
                     }
                 }
                 else
                 {
                     //pop value
                     pop();
                     //..
                     raise( "value isn't a table/array/object, iterator not supported" );
                 }
             }
             break;
             //for of
             case L_FOR_IN:
             case L_FOR_OF:
             {
                 //get index
                 l_variable& r_it = top();
                 //try
                 if ( r_it.is_iterator() )
                 {
                     //types
                     l_iterator* l_it  = r_it.iterator();
                     //is array it
                     if(l_it)
                     {
                         //else assert
                         assert(l_it);
                         //push it
                         if(l_it->valid())
                         {
                             if(cmp.m_op_code == L_FOR_OF)
                             {
                                 //get next
                                 push( l_it->get() );
                             }
                             else //L_FOR_IN
                             {
                                 //get next
                                 push( l_it->get_id() );
                             }
                             //next
                             l_it->self_next();
                         }
                         else
                         {
                             //pop iterator
                             pop();
                             //and jump
                             pc = cmp.m_arg - 1;
                         }
                     }
                     else
                     {
                         raise( "value isn't a valid iterator" );
                     }
                 }
                 else
                 {
                     //pop it
                     pop();
                     //and jump
                     pc = cmp.m_arg - 1;
                     //...
                     raise( "value isn't an iterator" );
                 }
             }
             break;
             case L_THIS_CALL:
             case L_CALL:
             {
                 //get index
                 register3(0) = pop();
                 //get args
                 if( register3(0).is_cfunction() )
                 {
                     //return size
                     int n_return = register3(0).m_value.m_pcfun(this,cmp.m_arg);
                     //assert (1 return)
                     assert(n_return <= 1);
                     //error
                     if(n_return<0)
                     {
                         raise( "native call exception" );
                     }
                     else if(n_return>1)
                     {
                         raise( "native call can't return more than a value" );
                     }
                     //pop args
                     for(int i=0; i < cmp.m_arg; ++i)
                     {
                         pop();
                     }
                     //if return
                     if(n_return) push(get_return());
                 }
                 else if( register3(0).is_closer() )
                 {
                     //get context
                     l_closer* closer = register3(0).to<l_closer>();
                     //else assert
                     if(!closer){ assert(0); };
                     //new function
                     l_function& call_fun    = m_vm->function(closer->get_fun_id());
                     //save last context
                     l_variable last_ctx     = register3(R_CONTEXT);
                     //new context
                     register3(1)            = l_call_context::gc_new(get_gc());
                     l_call_context* new_ctx = register3(1).to<l_call_context>();
                     //this?
                     if(cmp.m_op_code == L_THIS_CALL)
                     {
                         new_ctx->this_field() = get_this();
                     }
                     //init
                     new_ctx->init(*closer);
                     //lock context
                     new_ctx->lock();
                     //n args
                     unsigned int n_fun_args = call_fun.m_args_size;
                     //alloc array args..?
                     if (call_fun.m_have_args_list)
                     {
                         //alloc array
                         register3(3) = l_array::gc_new(get_gc());
                     }
                     //put arguments
                     for(unsigned int
                         arg  = 0;
                         arg != cmp.m_arg;
                       ++arg)
                     {
                         if (arg < n_fun_args)
                         {
                             new_ctx->variable( call_fun.constant(arg) ) = pop();
                         }
                         else if (call_fun.m_have_args_list)
                         {
                             register3(3).array()->push(pop());
                         }
                         else
                         {
                             pop();
                         }
                     }
                     //add var list
                     if (call_fun.m_have_args_list)
                     {
                         //push array
                         new_ctx->variable( call_fun.constant(n_fun_args) ) = register3(3);
                         //to null
                         register3(3) = l_variable();
                     }
                     //save stack
                     long stack_top_bf_call = m_top;
                     //execute call
                     type_return n_return = execute(*new_ctx);
                     //error?
                     if(n_return==T_RETURN_ERROR)
                     {
                         raise( "call exception" );
                     }
                     //unlock context
                     new_ctx->unlock();
                     //reset last context
                     register3(R_CONTEXT) = last_ctx;
                     //restore stack
                     m_top = stack_top_bf_call;
                     //return?
                     if(n_return == T_RETURN_VALUE)
                     {
                         push(register3(2));
                     }
                 }
                 else
                 {
                     raise( "value isn't an function" );
                 }
                 //dealloc
                 if(cmp.m_op_code == L_THIS_CALL)
                 {
                     get_this() = l_variable();
                 }
             }
             break;
                 
             default:  break;
         }
     }
     
     return T_RETURN_VOID;
 }
Пример #7
0
Файл: cgen.c Проект: 8l/inferno
void
cgen(Node *n, int result, Node *nn)
{
	Node *l, *r, nod;
	int lg, rg, xg, yg, g, o;
	long v;
	Prog *p1;

	if(n == Z || n->type == T)
		return;
	if(typesuv[n->type->etype]) {
		sugen(n, result, nn, n->type->width);
		return;
	}
	if(debug['g']) {
		if(result == D_TREE)
			prtree(nn, "result");
		else
			print("result = %R\n", result);
		prtree(n, "cgen");
	}
	l = n->left;
	r = n->right;
	o = n->op;
	if(n->addable >= INDEXED) {
		if(result == D_NONE) {
			if(nn == Z)
				switch(o) {
				default:
					nullwarn(Z, Z);
					break;
				case OINDEX:
					nullwarn(l, r);
					break;
				}
			return;
		}
		gmove(n->type, nn->type, D_TREE, n, result, nn);
		return;
	}

	v = 0; /* set */
	switch(o) {
	default:
		diag(n, "unknown op in cgen: %O", o);
		break;

	case OAS:
		if(l->op == OBIT)
			goto bitas;
		/*
		 * recursive use of result
		 */
		if(result == D_NONE)
		if(l->addable > INDEXED)
		if(l->complex < FNX) {
			cgen(r, D_TREE, l);
			break;
		}

		/*
		 * function calls on both sides
		 */
		if(l->complex >= FNX && r->complex >= FNX) {
			cgen(r, D_TOS, r);
			v = argoff;
			lg = regaddr(result);
			lcgen(l, lg, Z);
			lg |= I_INDIR;
			adjsp(v - argoff);
			gmove(r->type, l->type, D_TOS, r, lg, l);
			if(result != D_NONE)
				gmove(l->type, nn->type, lg, l, result, nn);
			regfree(lg);
			break;
		}

		rg = D_TREE;
		lg = D_TREE;
		if(r->complex >= l->complex) {
			/*
			 * right side before left
			 */
			if(result != D_NONE) {
				rg = regalloc(n->type, result);
				cgen(r, rg, n);
			} else
			if(r->complex >= FNX || r->addable < INDEXED) {
				rg = regalloc(r->type, result);
				cgen(r, rg, r);
			}
			if(l->addable < INDEXED) {
				lg = regaddr(lg);
				lcgen(l, lg, Z);
				lg |= I_INDIR;
			}
		} else {
			/*
			 * left before right
			 */
			if(l->complex >= FNX || l->addable < INDEXED) {
				lg = regaddr(lg);
				lcgen(l, lg, Z);
				lg |= I_INDIR;
			}
			if(result != D_NONE) {
				rg = regalloc(n->type, result);
				cgen(r, rg, n);
			} else
			if(r->addable < INDEXED) {
				rg = regalloc(r->type, result);
				cgen(r, rg, r);
			}
		}
		if(result != D_NONE) {
			gmove(n->type, l->type, rg, r, lg, l);
			gmove(n->type, nn->type, rg, r, result, nn);
		} else
			gmove(r->type, l->type, rg, r, lg, l);
		regfree(lg);
		regfree(rg);
		break;

	bitas:
		n = l->left;
		rg = regalloc(tfield, result);
		if(l->complex >= r->complex) {
			lg = regaddr(D_NONE);
			lcgen(n, lg, Z);
			lg |= I_INDIR;
			cgen(r, rg, r);
		} else {
			cgen(r, rg, r);
			lg = regaddr(D_NONE);
			lcgen(n, lg, Z);
			lg |= I_INDIR;
		}
		g = regalloc(n->type, D_NONE);
		gmove(l->type, l->type, lg, l, g, l);
		bitstore(l, rg, lg, g, result, nn);
		break;

	case OBIT:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		g = bitload(n, D_NONE, D_NONE, result, nn);
		gopcode(OAS, nn->type, g, n, result, nn);
		regfree(g);
		break;

	case ODOT:
		sugen(l, D_TREE, nodrat, l->type->width);
		if(result != D_NONE) {
			warn(n, "non-interruptable temporary");
			nod = *nodrat;
			if(!r || r->op != OCONST) {
				diag(n, "DOT and no offset");
				break;
			}
			nod.xoffset += r->vconst;
			nod.type = n->type;
			cgen(&nod, result, nn);
		}
		break;

	case OASLDIV:
	case OASLMOD:
	case OASDIV:
	case OASMOD:
		if(l->op == OBIT)
			goto asbitop;
		if(typefd[n->type->etype])
			goto asbinop;
		rg = D_TREE;
		if(l->complex >= FNX || r->complex >= FNX) {
			rg = D_TOS;
			cgen(r, rg, r);
			v = argoff;
		} else
		if(r->addable < INDEXED) {
			rg = regalloc(n->type, D_NONE);
			cgen(r, rg, r);
		}
		lg = D_TREE;
		if(!simplv(l)) {
			lg = regaddr(D_NONE);
			lcgen(l, lg, Z);	/* destroys register optimization */
			lg |= I_INDIR;
		}
		g = regpair(result);
		gmove(l->type, n->type, lg, l, g, n);
		if(rg == D_TOS)
			adjsp(v - argoff);
		gopcode(o, n->type, rg, r, g, n);
		if(o == OASLMOD || o == OASMOD)
			gmove(n->type, l->type, g+1, n, lg, l);
		else
			gmove(n->type, l->type, g, n, lg, l);
		if(result != D_NONE)
		if(o == OASLMOD || o == OASMOD)
			gmove(n->type, nn->type, g+1, n, result, nn);
		else
			gmove(n->type, nn->type, g, n, result, nn);
		regfree(g);
		regfree(g+1);
		regfree(lg);
		regfree(rg);
		break;

	case OASXOR:
	case OASAND:
	case OASOR:
		if(l->op == OBIT)
			goto asbitop;
		if(l->complex >= FNX ||
		   l->addable < INDEXED ||
		   result != D_NONE ||
		   typefd[n->type->etype])
			goto asbinop;
		rg = D_TREE;
		if(r->op != OCONST) {
			rg = regalloc(n->type, D_NONE);
			cgen(r, rg, r);
		}
		gopcode(o, l->type, rg, r, D_TREE, l);
		regfree(rg);
		break;

	case OASADD:
	case OASSUB:
		if(l->op == OBIT ||
		   l->complex >= FNX ||
		   l->addable < INDEXED ||
		   result != D_NONE ||
		   typefd[n->type->etype])
			goto asbinop;
		v = vconst(r);
		if(v > 0 && v <= 8) {
			gopcode(o, n->type, D_TREE, r, D_TREE, l);
			break;
		}
		rg = regalloc(n->type, D_NONE);
		cgen(r, rg, r);
		gopcode(o, n->type, rg, r, D_TREE, l);
		regfree(rg);
		break;

	case OASLSHR:
	case OASASHR:
	case OASASHL:
		if(l->op == OBIT ||
		   l->complex >= FNX ||
		   l->addable < INDEXED ||
		   result != D_NONE ||
		   typefd[n->type->etype])
			goto asbinop;
		rg = D_TREE;
		v = vconst(r);
		if(v <= 0 || v > 8) {
			rg = regalloc(n->type, D_NONE);
			cgen(r, rg, r);
		}
		lg = regalloc(n->type, D_NONE);
		cgen(l, lg, l);
		gopcode(o, n->type, rg, r, lg, l);
		gmove(n->type, n->type, lg, l, D_TREE, l);
		regfree(lg);
		regfree(rg);
		break;

	case OASLMUL:
	case OASMUL:
	asbinop:
		if(l->op == OBIT)
			goto asbitop;
		rg = D_TREE;
		if(l->complex >= FNX || r->complex >= FNX) {
			rg = D_TOS;
			cgen(r, rg, r);
			v = argoff;
		} else
		if(r->addable < INDEXED) {
			rg = regalloc(n->type, D_NONE);
			cgen(r, rg, r);
		} else {
			if(o == OASLSHR || o == OASASHR || o == OASASHL) {
				v = vconst(r);
				if(v <= 0 || v > 8) {
					rg = regalloc(n->type, D_NONE);
					cgen(r, rg, r);
				}
			}
		}
		lg = D_TREE;
		if(!simplv(l)) {
			lg = regaddr(D_NONE);
			lcgen(l, lg, Z);	/* destroys register optimization */
			lg |= I_INDIR;
		}
		g = regalloc(n->type, result);
		gmove(l->type, n->type, lg, l, g, n);
		if(rg == D_TOS)
			adjsp(v - argoff);
		if(o == OASXOR)
			if(rg == D_TREE) {
				rg = regalloc(n->type, D_NONE);
				cgen(r, rg, r);
			}
		if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL)
			if(rg == D_TOS) {
				rg = regalloc(n->type, D_NONE);
				gmove(n->type, n->type, D_TOS, n, rg, n);
			}
		gopcode(o, n->type, rg, r, g, n);
		gmove(n->type, l->type, g, n, lg, l);
		if(result != D_NONE)
			gmove(n->type, nn->type, g, n, result, nn);
		regfree(g);
		regfree(lg);
		regfree(rg);
		break;

	asbitop:
		rg = regaddr(D_NONE);
		lg = regalloc(tfield, D_NONE);
		if(l->complex >= r->complex) {
			g = bitload(l, lg, rg, result, nn);
			xg = regalloc(r->type, D_NONE);
			cgen(r, xg, nn);
		} else {
			xg = regalloc(r->type, D_NONE);
			cgen(r, xg, nn);
			g = bitload(l, lg, rg, result, nn);
		}

		if(!typefd[n->type->etype]) {
			if(o == OASLDIV || o == OASDIV) {
				yg = regpair(result);
				gmove(tfield, n->type, g, l, yg, n);
				gopcode(o, n->type, xg, r, yg, n);
				gmove(n->type, tfield, yg, n, g, l);
				regfree(yg);
				regfree(yg+1);

				regfree(xg);
				bitstore(l, g, rg, lg, D_NONE, nn);
				break;
			}
			if(o == OASLMOD || o == OASMOD) {
				yg = regpair(result);
				gmove(tfield, n->type, g, l, yg, n);
				gopcode(o, n->type, xg, r, yg, n);
				gmove(n->type, tfield, yg+1, n, g, l);
				regfree(yg);
				regfree(yg+1);

				regfree(xg);
				bitstore(l, g, rg, lg, D_NONE, nn);
				break;
			}
		}

		yg = regalloc(n->type, result);
		gmove(tfield, n->type, g, l, yg, n);
		gopcode(o, n->type, xg, r, yg, n);
		gmove(n->type, tfield, yg, n, g, l);
		regfree(yg);

		regfree(xg);
		bitstore(l, g, rg, lg, D_NONE, nn);
		break;

	case OCAST:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		lg = result;
		if(l->complex >= FNX)
			lg = regret(l->type);
		lg = eval(l, lg);
		if(nocast(l->type, n->type)) {
			gmove(n->type, nn->type, lg, l, result, nn);
			regfree(lg);
			break;
		}
		if(nocast(n->type, nn->type)) {
			gmove(l->type, n->type, lg, l, result, nn);
			regfree(lg);
			break;
		}
		rg = regalloc(n->type, result);
		gmove(l->type, n->type, lg, l, rg, n);
		gmove(n->type, nn->type, rg, n, result, nn);
		regfree(rg);
		regfree(lg);
		break;

	case OCOND:
		doinc(l, PRE);
		boolgen(l, 1, D_NONE, Z, l);
		p1 = p;

		inargs++;
		doinc(r->left, PRE);
		cgen(r->left, result, nn);
		doinc(r->left, POST);
		gbranch(OGOTO);
		patch(p1, pc);
		p1 = p;

		doinc(r->right, PRE);
		cgen(r->right, result, nn);
		doinc(r->right, POST);
		patch(p1, pc);
		inargs--;
		break;

	case OIND:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		lg = nodalloc(types[TIND], result, &nod);
		nod.lineno = n->lineno;
		if(l->op == OADD) {
			if(l->left->op == OCONST) {
				nod.xoffset += l->left->vconst;
				l = l->right;
			} else
			if(l->right->op == OCONST) {
				nod.xoffset += l->right->vconst;
				l = l->left;
			}
		}
		cgen(l, lg, l);
		gmove(n->type, nn->type, D_TREE, &nod, result, nn);
		regfree(lg);
		break;

	case OFUNC:
		v = argoff;
		inargs++;
		gargs(r);
		lg = D_TREE;
		if(l->addable < INDEXED) {
			lg = regaddr(result);
			lcgen(l, lg, Z);
			lg |= I_INDIR;
		}
		inargs--;
		doinc(r, POST);
		doinc(l, POST);
		gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
		regfree(lg);
		if(inargs)
			adjsp(v - argoff);
		if(result != D_NONE) {
			lg = regret(n->type);
			gmove(n->type, nn->type, lg, n, result, nn);
		}
		break;

	case OLDIV:
	case OLMOD:
	case ODIV:
	case OMOD:
		if(result == D_NONE) {
			nullwarn(l, r);
			break;
		}
		if(typefd[n->type->etype])
			goto binop;
		if(r->addable >= INDEXED && r->complex < FNX) {
			lg = regpair(result);
			cgen(l, lg, l);
			rg = D_TREE;
		} else {
			cgen(r, D_TOS, r);
			v = argoff;
			lg = regpair(result);
			cgen(l, lg, l);
			adjsp(v - argoff);
			rg = D_TOS;
		}
		gopcode(o, n->type, rg, r, lg, l);
		if(o == OMOD || o == OLMOD)
			gmove(l->type, nn->type, lg+1, l, result, nn);
		else
			gmove(l->type, nn->type, lg, l, result, nn);
		regfree(lg);
		regfree(lg+1);
		break;

	case OMUL:
	case OLMUL:
		if(l->op == OCONST)
			if(mulcon(r, l, result, nn))
				break;
		if(r->op == OCONST)
			if(mulcon(l, r, result, nn))
				break;
		if(debug['M'])
			print("%L multiply\n", n->lineno);
		goto binop;

	case OAND:
		if(r->op == OCONST)
		if(typeil[n->type->etype])
		if(l->op == OCAST) {
			if(typec[l->left->type->etype])
			if(!(r->vconst & ~0xff)) {
				l = l->left;
				goto binop;
			}
			if(typeh[l->left->type->etype])
			if(!(r->vconst & ~0xffff)) {
				l = l->left;
				goto binop;
			}
		}
		goto binop;

	case OADD:
		if(result == D_TOS)
		if(r->addable >= INDEXED)
		if(l->op == OCONST)
		if(typeil[l->type->etype]) {
			v = l->vconst;
			if(v > -32768 && v < 32768) {
				rg = regaddr(D_NONE);
				gmove(r->type, r->type, D_TREE, r, rg, r);
				gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r);
				p->to.offset = v;
				p->to.type |= I_INDIR;
				regfree(rg);
				break;
			}
		}

	case OSUB:
		if(result == D_TOS)
		if(l->addable >= INDEXED)
		if(r->op == OCONST)
		if(typeil[r->type->etype]) {
			v = r->vconst;
			if(v > -32768 && v < 32768) {
				if(n->op == OSUB)
					v = -v;
				lg = regaddr(D_NONE);
				gmove(l->type, l->type, D_TREE, l, lg, l);
				gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l);
				p->to.offset = v;
				p->to.type |= I_INDIR;
				regfree(lg);
				break;
			}
		}
		goto binop;

	case OOR:
	case OXOR:
	binop:
		if(result == D_NONE) {
			nullwarn(l, r);
			break;
		}
		if(l->complex >= FNX && r->complex >= FNX) {
			cgen(r, D_TOS, r);
			v = argoff;
			lg = regalloc(l->type, result);
			cgen(l, lg, l);
			adjsp(v - argoff);
			if(o == OXOR) {
				rg = regalloc(r->type, D_NONE);
				gmove(r->type, r->type, D_TOS, r, rg, r);
				gopcode(o, n->type, rg, r, lg, l);
				regfree(rg);
			} else
				gopcode(o, n->type, D_TOS, r, lg, l);
			gmove(n->type, nn->type, lg, l, result, nn);
			regfree(lg);
			break;
		}
		if(l->complex >= r->complex) {
			if(l->op == OADDR && (o == OADD || o == OSUB))
				lg = regaddr(result);
			else
				lg = regalloc(l->type, result);
			cgen(l, lg, l);
			rg = eval(r, D_NONE);
		} else {
			rg = regalloc(r->type, D_NONE);
			cgen(r, rg, r);
			lg = regalloc(l->type, result);
			cgen(l, lg, l);
		}
		if(o == OXOR) {
			if(rg == D_TREE) {
				rg = regalloc(r->type, D_NONE);
				cgen(r, rg, r);
			}
			if(rg == D_TOS) {
				rg = regalloc(r->type, D_NONE);
				gmove(r->type, r->type, D_TOS, r, rg, r);
			}
		}
		gopcode(o, n->type, rg, r, lg, l);
		gmove(n->type, nn->type, lg, l, result, nn);
		regfree(lg);
		regfree(rg);
		break;

	case OASHL:
		if(r->op == OCONST)
			if(shlcon(l, r, result, nn))
				break;
	case OLSHR:
	case OASHR:
		if(result == D_NONE) {
			nullwarn(l, r);
			break;
		}

		if(l->complex >= FNX && r->complex >= FNX) {
			cgen(r, D_TOS, r);
			v = argoff;
			lg = regalloc(l->type, result);
			cgen(l, lg, l);
			adjsp(v - argoff);
			rg = regalloc(r->type, D_NONE);
			gopcode(OAS, r->type, D_TOS, r, rg, r);
			gopcode(n->op, n->type, rg, r, lg, l);
			gmove(n->type, nn->type, lg, l, result, nn);
			regfree(lg);
			regfree(rg);
			break;
		}
		if(l->complex >= r->complex) {
			lg = regalloc(l->type, result);
			cgen(l, lg, l);
			v = vconst(r);
			if(v <= 0 || v > 8) {
				rg = regalloc(r->type, D_NONE);
				cgen(r, rg, r);
			} else
				rg = eval(r, D_NONE);
		} else {
			rg = regalloc(r->type, D_NONE);
			cgen(r, rg, r);
			lg = regalloc(l->type, result);
			cgen(l, lg, l);
		}
		gopcode(o, n->type, rg, r, lg, l);
		gmove(n->type, nn->type, lg, l, result, nn);
		regfree(lg);
		regfree(rg);
		break;

	case ONEG:
	case OCOM:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		lg = regalloc(l->type, result);
		cgen(l, lg, l);
		gopcode(o, l->type, D_NONE, Z, lg, l);
		gmove(n->type, nn->type, lg, l, result, nn);
		regfree(lg);
		break;

	case OADDR:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		lcgen(l, result, nn);
		break;

	case OEQ:
	case ONE:
	case OLE:
	case OLT:
	case OGE:
	case OGT:
	case OLO:
	case OLS:
	case OHI:
	case OHS:
		if(result == D_NONE) {
			nullwarn(l, r);
			break;
		}
		boolgen(n, 1, result, nn, Z);
		break;

	case OANDAND:
	case OOROR:
		boolgen(n, 1, result, nn, Z);
		if(result == D_NONE)
			patch(p, pc);
		break;

	case OCOMMA:
		cgen(l, D_NONE, l);
		doinc(l, POST);
		doinc(r, PRE);
		cgen(r, result, nn);
		break;

	case ONOT:
		if(result == D_NONE) {
			nullwarn(l, Z);
			break;
		}
		boolgen(n, 1, result, nn, Z);
		break;

	case OPOSTINC:
	case OPOSTDEC:
		v = 1;
		if(l->type->etype == TIND)
			v = l->type->link->width;
		if(o == OPOSTDEC)
			v = -v;
		if(l->op == OBIT)
			goto bitinc;
		if(nn == Z)
			goto pre;

		lg = D_TREE;
		if(l->addable < INDEXED) {
			lg = regaddr(D_NONE);
			lcgen(l, lg, Z);
			lg |= I_INDIR;
		}
		if(result != D_NONE)
			gmove(l->type, nn->type, lg, l, result, nn);
		if(typefd[n->type->etype]) {
			rg = regalloc(n->type, D_NONE);
			gmove(l->type, l->type, lg, l, rg, l);
			gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
			gmove(l->type, l->type, rg, l, lg, l);
			regfree(rg);
		} else {
			if(v < 0)
				gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
			else
				gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
		}
		regfree(lg);
		break;

	case OPREINC:
	case OPREDEC:
		v = 1;
		if(l->type->etype == TIND)
			v = l->type->link->width;
		if(o == OPREDEC)
			v = -v;
		if(l->op == OBIT)
			goto bitinc;

	pre:
		lg = D_TREE;
		if(l->addable < INDEXED) {
			lg = regaddr(D_NONE);
			lcgen(l, lg, Z);
			lg |= I_INDIR;
		}
		if(typefd[n->type->etype]) {
			rg = regalloc(n->type, D_NONE);
			gmove(l->type, l->type, lg, l, rg, l);
			gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
			gmove(l->type, l->type, rg, l, lg, l);
			regfree(rg);
		} else {
			if(v < 0)
				gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
			else
				gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
		}
		if(result != D_NONE)
			gmove(l->type, nn->type, lg, l, result, nn);
		regfree(lg);
		break;

	bitinc:
		rg = regaddr(D_NONE);
		lg = regalloc(tfield, D_NONE);
		if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) {
			g = bitload(l, lg, rg, D_NONE, nn);
			if(nn != Z)
				gmove(l->type, nn->type, g, l, result, nn);
			if(v < 0)
				gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
			else
				gopcode(o, n->type, D_CONST, nodconst(v), g, n);
			bitstore(l, g, rg, lg, D_NONE, nn);
			break;
		}
		g = bitload(l, lg, rg, result, nn);
		if(v < 0)
			gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
		else
			gopcode(o, n->type, D_CONST, nodconst(v), g, n);
		if(result != D_NONE)
			gmove(l->type, nn->type, g, l, result, nn);
		bitstore(l, g, rg, lg, D_NONE, nn);
		break;
	}
}