예제 #1
0
파일: code.c 프로젝트: rheoli/pcc
/*
 * Sort arglist so that register assignments ends up last.
 */
static int
argsort(NODE *p)
{
	NODE *q, *r;
	int rv = 0;

	if (p->n_op != CM) {
		if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
		    coptype(p->n_right->n_op) != LTYPE) {
			q = tempnode(0, p->n_type, p->n_df, p->n_ap);
			r = ccopy(q);
			p->n_right = buildtree(COMOP,
			    buildtree(ASSIGN, q, p->n_right), r);
		}
		return rv;
	}
	if (p->n_right->n_op == CM) {
		/* fixup for small structs in regs */
		q = p->n_right->n_left;
		p->n_right->n_left = p->n_left;
		p->n_left = p->n_right;
		p->n_right = p->n_left->n_right;
		p->n_left->n_right = q;
	}
	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
	    coptype(p->n_right->n_right->n_op) != LTYPE) {
		/* move before everything to avoid reg trashing */
		q = tempnode(0, p->n_right->n_type,
		    p->n_right->n_df, p->n_right->n_ap);
		r = ccopy(q);
		p->n_right->n_right = buildtree(COMOP,
		    buildtree(ASSIGN, q, p->n_right->n_right), r);
	}
	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
		if (p->n_left->n_op == CM &&
		    p->n_left->n_right->n_op == STASG) {
			q = p->n_left->n_right;
			p->n_left->n_right = p->n_right;
			p->n_right = q;
			rv = 1;
		} else if (p->n_left->n_op == STASG) {
			q = p->n_left;
			p->n_left = p->n_right;
			p->n_right = q;
			rv = 1;
		}
	}
	return rv | argsort(p->n_left);
}
예제 #2
0
/*
 * See if there is a goto in the tree.
 * XXX this function is a hack for a flaw in handling of 
 * compound expressions and inline functions and should not be 
 * needed.
 */
static int
hasgoto(NODE *p)
{
	int o = coptype(p->n_op);

	if (o == LTYPE)
		return 0;
	if (p->n_op == GOTO)
		return 1;
	if (o == UTYPE)
		return hasgoto(p->n_left);
	if (hasgoto(p->n_left))
		return 1;
	return hasgoto(p->n_right);
}
예제 #3
0
파일: local.c 프로젝트: newgenius/LiteBSD
/* clocal() is called to do local transformations on
 * an expression tree preparitory to its being
 * written out in intermediate code.
 *
 * the major essential job is rewriting the
 * automatic variables and arguments in terms of
 * REG and OREG nodes
 * conversion ops which are not necessary are also clobbered here
 * in addition, any special features (such as rewriting
 * exclusive or) are easily handled here as well
 */
NODE *
clocal(NODE *p)
{

	register struct symtab *q;
	register NODE *r, *l;
	register int o;
	register int m;
	TWORD t;

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal: %p\n", p);
		fwalk(p, eprint, 0);
	}
#endif
	switch( o = p->n_op ){

	case NAME:
		if ((q = p->n_sp) == NULL)
			return p; /* Nothing to care about */

		switch (q->sclass) {

		case PARAM:
		case AUTO:
			/* fake up a structure reference */
			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
			slval(r, 0);
			r->n_rval = FPREG;
			p = stref(block(STREF, r, p, 0, 0, 0));
			break;

		case USTATIC:
			if (kflag == 0)
				break;
			/* FALLTHROUGH */
		case STATIC:
#ifdef TLS
			if (q->sflags & STLS) {
				p = tlsref(p);
				break;
			}
#endif
			break;

		case REGISTER:
			p->n_op = REG;
			slval(p, 0);
			p->n_rval = q->soffset;
			break;

		case EXTERN:
		case EXTDEF:
			if (q->sflags & STLS) {
				p = tlsref(p);
				break;
			}
			if (kflag == 0 || statinit)
				break;
			if (blevel > 0)
				p = picext(p);
			break;
		}
		break;

	case UCALL:
	case USTCALL:
		/* For now, always clear eax */
		l = block(REG, NIL, NIL, INT, 0, 0);
		regno(l) = RAX;
		p->n_right = clocal(buildtree(ASSIGN, l, bcon(0)));
		p->n_op -= (UCALL-CALL);
		break;

	case SCONV:
		/* Special-case shifts */
		if (p->n_type == LONG && (l = p->n_left)->n_op == LS && 
		    l->n_type == INT && l->n_right->n_op == ICON) {
			p->n_left = l->n_left;
			p = buildtree(LS, p, l->n_right);
			nfree(l);
			break;
		}

		l = p->n_left;

		/* Float conversions may need extra casts */
		if (p->n_type == FLOAT || p->n_type == DOUBLE ||
		    p->n_type == LDOUBLE) {
			if (l->n_type < INT || l->n_type == BOOL) {
				p->n_left = block(SCONV, l, NIL,
				    ISUNSIGNED(l->n_type) ? UNSIGNED : INT,
				    l->n_df, l->n_ap);
				break;
			}
		}

		if (p->n_type == l->n_type) {
			nfree(p);
			return l;
		}

		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
		    tsize(p->n_type, p->n_df, p->n_ap) ==
		    tsize(l->n_type, l->n_df, l->n_ap)) {
			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
			    l->n_type != FLOAT && l->n_type != DOUBLE &&
			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
				if (l->n_op == NAME || l->n_op == UMUL ||
				    l->n_op == TEMP) {
					l->n_type = p->n_type;
					nfree(p);
					return l;
				}
			}
		}

		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
		    coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
		    l->n_op != QUEST && l->n_op != ASSIGN) {
			l->n_type = p->n_type;
			nfree(p);
			return l;
		}

		o = l->n_op;
		m = p->n_type;

		if (o == ICON) {
			CONSZ val = glval(l);

			/* if named constant and pointer, allow cast 
			   to long/ulong */
			if (!nncon(l) && (l->n_type & TMASK) &&
			    (m == LONG || m == ULONG)) {
				l->n_type = m;
				l->n_ap = 0;
				return nfree(p);
			}

			if (ISPTR(l->n_type) && !nncon(l))
				break; /* cannot convert named pointers */

			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
			    switch (m) {
			case BOOL:
				val = nncon(l) ? (val != 0) : 1;
				slval(l, val);
				l->n_sp = NULL;
				break;
			case CHAR:
				slval(l, (char)val);
				break;
			case UCHAR:
				slval(l, val & 0377);
				break;
			case SHORT:
				slval(l, (short)val);
				break;
			case USHORT:
				slval(l, val & 0177777);
				break;
			case UNSIGNED:
				slval(l, val & 0xffffffff);
				break;
			case INT:
				slval(l, (int)val);
				break;
			case LONG:
			case LONGLONG:
				slval(l, (long long)val);
				break;
			case ULONG:
			case ULONGLONG:
				slval(l, val);
				break;
			case VOID:
				break;
			case LDOUBLE:
			case DOUBLE:
			case FLOAT:
				l->n_op = FCON;
				l->n_dcon = fltallo();
				FCAST(l->n_dcon)->fp = val;
				break;
			default:
				cerror("unknown type %d", m);
			}
			l->n_type = m;
			l->n_ap = NULL;
			nfree(p);
			return l;
		} else if (l->n_op == FCON) {
			CONSZ lv;
			if (p->n_type == BOOL)
				lv = !FLOAT_ISZERO(FCAST(l->n_dcon));
			else {
				FLOAT_FP2INT(lv, FCAST(l->n_dcon), m);
			}
			slval(l, lv);
			l->n_sp = NULL;
			l->n_op = ICON;
			l->n_type = m;
			l->n_ap = NULL;
			nfree(p);
			return clocal(l);
		}
		if ((p->n_type == CHAR || p->n_type == UCHAR ||
		    p->n_type == SHORT || p->n_type == USHORT) &&
		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
		    l->n_type == LDOUBLE)) {
			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
			p->n_left->n_type = INT;
			return p;
		}
		break;

	case MOD:
	case DIV:
		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
			break;
		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
			break;
		/* make it an int division by inserting conversions */
		p->n_left = makety(p->n_left, INT, 0, 0, 0);
		p->n_right = makety(p->n_right, INT, 0, 0, 0);
		p = makety(p, p->n_type, 0, 0, 0);
		p->n_left->n_type = INT;
		break;

	case FORCE:
		/* put return value in return reg */
		p->n_op = ASSIGN;
		p->n_right = p->n_left;
		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
		t = p->n_type;
		if (ISITY(t))
			t = t - (FIMAG-FLOAT);
		p->n_left->n_rval = p->n_left->n_type == BOOL ? 
		    RETREG(CHAR) : RETREG(t);
		break;

	case LS:
	case RS:
		/* shift count must be in a char */
		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
			break;
		p->n_right = makety(p->n_right, CHAR, 0, 0, 0);
		break;
	}
#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal end: %p\n", p);
		fwalk(p, eprint, 0);
	}
#endif
	return(p);
}
예제 #4
0
파일: optim.c 프로젝트: enukane/netbsd-src
/*
 * local optimizations, most of which are probably
 * machine independent
 */
NODE *
optim(NODE *p)
{
	int o, ty;
	NODE *sp, *q;
	OFFSZ sz;
	int i;

	if (odebug) return(p);

	ty = coptype(p->n_op);
	if( ty == LTYPE ) return(p);

	if( ty == BITYPE ) p->n_right = optim(p->n_right);
	p->n_left = optim(p->n_left);

	/* collect constants */
again:	o = p->n_op;
	switch(o){

	case SCONV:
		if (concast(p->n_left, p->n_type)) {
			q = p->n_left;
			nfree(p);
			p = q;
			break;
		}
		/* FALLTHROUGH */
	case PCONV:
		if (p->n_type != VOID)
			p = clocal(p);
		break;

	case FORTCALL:
		p->n_right = fortarg( p->n_right );
		break;

	case ADDROF:
		if (LO(p) == TEMP)
			break;
		if( LO(p) != NAME ) cerror( "& error" );

		if( !andable(p->n_left) && !statinit)
			break;

		LO(p) = ICON;

		setuleft:
		/* paint over the type of the left hand side with the type of the top */
		p->n_left->n_type = p->n_type;
		p->n_left->n_df = p->n_df;
		p->n_left->n_ap = p->n_ap;
		q = p->n_left;
		nfree(p);
		p = q;
		break;

	case NOT:
	case UMINUS:
	case COMPL:
		if (LCON(p) && conval(p->n_left, o, p->n_left))
			p = nfree(p);
		break;

	case UMUL:
		/* Do not discard ADDROF TEMP's */
		if (LO(p) == ADDROF && LO(p->n_left) != TEMP) {
			q = p->n_left->n_left;
			nfree(p->n_left);
			nfree(p);
			p = q;
			break;
		}
		if( LO(p) != ICON ) break;
		LO(p) = NAME;
		goto setuleft;

	case RS:
		if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
			goto zapright;

		sz = tsize(p->n_type, p->n_df, p->n_ap);

		if (LO(p) == RS && RCON(p->n_left) && RCON(p) &&
		    (RV(p) + RV(p->n_left)) < sz) {
			/* two right-shift  by constants */
			RV(p) += RV(p->n_left);
			p->n_left = zapleft(p->n_left);
		}
#if 0
		  else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
			RV(p) -= RV(p->n_left);
			if (RV(p) < 0)
				o = p->n_op = LS, RV(p) = -RV(p);
			p->n_left = zapleft(p->n_left);
		}
#endif
		if (RO(p) == ICON) {
			if (RV(p) < 0) {
				RV(p) = -RV(p);
				p->n_op = LS;
				goto again;
			}
#ifdef notyet /* must check for side effects, --a >> 32; */
			if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) &&
			    ISUNSIGNED(p->n_type)) { /* ignore signed shifts */
				/* too many shifts */
				tfree(p->n_left);
				nfree(p->n_right);
				p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
			} else
#endif
			/* avoid larger shifts than type size */
			if (RV(p) >= sz) {
				RV(p) = RV(p) % sz;
				werror("shift larger than type");
			}
			if (RV(p) == 0)
				p = zapleft(p);
		}
		break;

	case LS:
		if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
			goto zapright;

		sz = tsize(p->n_type, p->n_df, p->n_ap);

		if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
			/* two left-shift  by constants */
			RV(p) += RV(p->n_left);
			p->n_left = zapleft(p->n_left);
		}
#if 0
		  else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) {
			RV(p) -= RV(p->n_left);
			p->n_left = zapleft(p->n_left);
		}
#endif
		if (RO(p) == ICON) {
			if (RV(p) < 0) {
				RV(p) = -RV(p);
				p->n_op = RS;
				goto again;
			}
#ifdef notyet /* must check for side effects */
			if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) {
				/* too many shifts */
				tfree(p->n_left);
				nfree(p->n_right);
				p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
			} else
#endif
			/* avoid larger shifts than type size */
			if (RV(p) >= sz) {
				RV(p) = RV(p) % sz;
				werror("shift larger than type");
			}
			if (RV(p) == 0)  
				p = zapleft(p);
		}
		break;

	case MINUS:
		if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) {
			/* link-time constants, but both are the same */
			/* solve it now by forgetting the symbols */
			p->n_left->n_sp = p->n_right->n_sp = NULL;
		}
		if( !nncon(p->n_right) ) break;
		RV(p) = -RV(p);
		o = p->n_op = PLUS;

	case MUL:
		/*
		 * Check for u=(x-y)+z; where all vars are pointers to
		 * the same struct. This has two advantages:
		 * 1: avoid a mul+div
		 * 2: even if not allowed, people may get surprised if this
		 *    calculation do not give correct result if using
		 *    unaligned structs.
		 */
		if (p->n_type == INTPTR && RCON(p) &&
		    LO(p) == DIV && RCON(p->n_left) &&
		    RV(p) == RV(p->n_left) &&
		    LO(p->n_left) == MINUS) {
			q = p->n_left->n_left;
			if (q->n_left->n_type == PTR+STRTY &&
			    q->n_right->n_type == PTR+STRTY &&
			    strmemb(q->n_left->n_ap) ==
			    strmemb(q->n_right->n_ap)) {
				p = zapleft(p);
				p = zapleft(p);
			}
		}
		/* FALLTHROUGH */
	case PLUS:
	case AND:
	case OR:
	case ER:
		/* commutative ops; for now, just collect constants */
		/* someday, do it right */
		if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) )
			SWAP( p->n_left, p->n_right );
		/* make ops tower to the left, not the right */
		if( RO(p) == o ){
			NODE *t1, *t2, *t3;
			t1 = p->n_left;
			sp = p->n_right;
			t2 = sp->n_left;
			t3 = sp->n_right;
			/* now, put together again */
			p->n_left = sp;
			sp->n_left = t1;
			sp->n_right = t2;
			sp->n_type = p->n_type;
			p->n_right = t3;
			}
		if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) &&
		   conval(p->n_right, MINUS, p->n_left->n_right)){
			zapleft:

			q = p->n_left->n_left;
			nfree(p->n_left->n_right);
			nfree(p->n_left);
			p->n_left = q;
		}
		if( RCON(p) && LO(p)==o && RCON(p->n_left) &&
		    conval( p->n_right, o, p->n_left->n_right ) ){
			goto zapleft;
			}
		else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){
			zapright:
			nfree(p->n_right);
			q = makety(p->n_left, p->n_type, p->n_qual,
			    p->n_df, p->n_ap);
			nfree(p);
			p = clocal(q);
			break;
			}

		/* change muls to shifts */

		if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){
			if( i == 0 ) { /* multiplication by 1 */
				goto zapright;
				}
			o = p->n_op = LS;
			p->n_right->n_type = INT;
			p->n_right->n_df = NULL;
			RV(p) = i;
			}

		/* change +'s of negative consts back to - */
		if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){
			RV(p) = -RV(p);
			o = p->n_op = MINUS;
			}

		/* remove ops with RHS 0 */
		if ((o == PLUS || o == MINUS || o == OR || o == ER) &&
		    nncon(p->n_right) && RV(p) == 0) {
			goto zapright;
		}
		break;

	case DIV:
		if( nncon( p->n_right ) && p->n_right->n_lval == 1 )
			goto zapright;
		if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right))
			goto zapright;
		if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) {
			p->n_op = RS;
			RV(p) = i;
			q = p->n_right;
			if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT)
				p->n_right = makety(q, INT, 0, 0, 0);

			break;
		}
		break;

	case MOD:
		if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) {
			p->n_op = AND;
			RV(p) = RV(p) -1;
			break;
		}
		break;

	case EQ:
	case NE:
	case LT:
	case LE:
	case GT:
	case GE:
	case ULT:
	case ULE:
	case UGT:
	case UGE:
		if( !LCON(p) ) break;

		/* exchange operands */

		sp = p->n_left;
		p->n_left = p->n_right;
		p->n_right = sp;
		p->n_op = revrel[p->n_op - EQ ];
		break;

#ifdef notyet
	case ASSIGN:
		/* Simple test to avoid two branches */
		if (RO(p) != NE)
			break;
		q = p->n_right;
		if (RCON(q) && RV(q) == 0 && LO(q) == AND &&
		    RCON(q->n_left) && (i = ispow2(RV(q->n_left))) &&
		    q->n_left->n_type == INT) {
			q->n_op = RS;
			RV(q) = i;
		}
		break;
#endif
	}

	return(p);
	}
예제 #5
0
NODE *
clocal(NODE *p)
{
	struct symtab *q;
	NODE *r, *l;
	TWORD t;
	int o;

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal\n");
		fwalk(p, eprint, 0);
	}
#endif

	switch( o = p->n_op ){
	case NAME:
		/* handle variables */
		if ((q = p->n_sp) == NULL)
			return p; /* Nothing to care about */
		switch (q->sclass) {
		case PARAM:
		case AUTO:
			if (0 && q->soffset < MAXZP * SZINT &&
			    q->sclass != PARAM) {
				p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2;
				p->n_sp = NULL;
			} else {
				/* fake up a structure reference */
				r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
				r->n_lval = 0;
				r->n_rval = FPREG;
				p = stref(block(STREF, r, p, 0, 0, 0));
			}
			break;
		default:
			break;
		}
		break;

	case PMCONV:
	case PVCONV:
                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
                nfree(p);
                p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
		break;

	case PCONV:
		t = p->n_type;
		if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
		    t == INCREF(BOOL) || t == INCREF(VOID))
			break;
		l = p->n_left;
		t = l->n_type;
		if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
		    t == INCREF(BOOL) || t == INCREF(VOID))
			break;
		if (p->n_type <= UCHAR || l->n_type <= UCHAR)
			break; /* must do runtime ptr conv */
		/* if conversion to another pointer type, just remove */
		if (p->n_type > BTMASK && l->n_type > BTMASK)
			goto delp;
		if (l->n_op == ICON && l->n_sp == NULL)
			goto delp;
		break;

	delp:	l->n_type = p->n_type;
		l->n_qual = p->n_qual;
		l->n_df = p->n_df;
		l->n_ap = p->n_ap;
		p = nfree(p);
		break;
	}

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal end\n");
		fwalk(p, eprint, 0);
	}
#endif

#if 0
	register struct symtab *q;
	register NODE *r, *l;
	register int o;
	register int m;
	TWORD t;

//printf("in:\n");
//fwalk(p, eprint, 0);
	switch( o = p->n_op ){

	case NAME:
		if ((q = p->n_sp) == NULL)
			return p; /* Nothing to care about */

		switch (q->sclass) {

		case PARAM:
		case AUTO:
			/* fake up a structure reference */
			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
			r->n_lval = 0;
			r->n_rval = FPREG;
			p = stref(block(STREF, r, p, 0, 0, 0));
			break;

		case STATIC:
			if (q->slevel == 0)
				break;
			p->n_lval = 0;
			p->n_sp = q;
			break;

		case REGISTER:
			p->n_op = REG;
			p->n_lval = 0;
			p->n_rval = q->soffset;
			break;

			}
		break;

	case STCALL:
	case CALL:
		/* Fix function call arguments. On x86, just add funarg */
		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
			if (r->n_right->n_op != STARG &&
			    r->n_right->n_op != FUNARG)
				r->n_right = block(FUNARG, r->n_right, NIL, 
				    r->n_right->n_type, r->n_right->n_df,
				    r->n_right->n_sue);
		}
		if (r->n_op != STARG && r->n_op != FUNARG) {
			l = talloc();
			*l = *r;
			r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
		}
		break;
		
	case CBRANCH:
		l = p->n_left;

		/*
		 * Remove unnecessary conversion ops.
		 */
		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
			if (coptype(l->n_op) != BITYPE)
				break;
			if (l->n_right->n_op == ICON) {
				r = l->n_left->n_left;
				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
					break;
				/* Type must be correct */
				t = r->n_type;
				nfree(l->n_left);
				l->n_left = r;
				l->n_type = t;
				l->n_right->n_type = t;
			}
		}
		break;

	case PCONV:
		/* Remove redundant PCONV's. Be careful */
		l = p->n_left;
		if (l->n_op == ICON) {
			l->n_lval = (unsigned)l->n_lval;
			goto delp;
		}
		if (l->n_type < INT || l->n_type == LONGLONG || 
		    l->n_type == ULONGLONG) {
			/* float etc? */
			p->n_left = block(SCONV, l, NIL,
			    UNSIGNED, 0, 0);
			break;
		}
		/* if left is SCONV, cannot remove */
		if (l->n_op == SCONV)
			break;
		/* if conversion to another pointer type, just remove */
		if (p->n_type > BTMASK && l->n_type > BTMASK)
			goto delp;
		break;

	delp:	l->n_type = p->n_type;
		l->n_qual = p->n_qual;
		l->n_df = p->n_df;
		l->n_sue = p->n_sue;
		nfree(p);
		p = l;
		break;

	case SCONV:
		l = p->n_left;

		if (p->n_type == l->n_type) {
			nfree(p);
			return l;
		}

		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
			    l->n_type != FLOAT && l->n_type != DOUBLE &&
			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
				if (l->n_op == NAME || l->n_op == UMUL ||
				    l->n_op == TEMP) {
					l->n_type = p->n_type;
					nfree(p);
					return l;
				}
			}
		}

		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
		    coptype(l->n_op) == BITYPE) {
			l->n_type = p->n_type;
			nfree(p);
			return l;
		}

		o = l->n_op;
		m = p->n_type;

		if (o == ICON) {
			CONSZ val = l->n_lval;

			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
			    switch (m) {
			case CHAR:
				l->n_lval = (char)val;
				break;
			case UCHAR:
				l->n_lval = val & 0377;
				break;
			case SHORT:
				l->n_lval = (short)val;
				break;
			case USHORT:
				l->n_lval = val & 0177777;
				break;
			case ULONG:
			case UNSIGNED:
				l->n_lval = val & 0xffffffff;
				break;
			case LONG:
			case INT:
				l->n_lval = (int)val;
				break;
			case LONGLONG:
				l->n_lval = (long long)val;
				break;
			case ULONGLONG:
				l->n_lval = val;
				break;
			case VOID:
				break;
			case LDOUBLE:
			case DOUBLE:
			case FLOAT:
				l->n_op = FCON;
				l->n_dcon = val;
				break;
			default:
				cerror("unknown type %d", m);
			}
			l->n_type = m;
			l->n_sue = 0;
			nfree(p);
			return l;
		}
		if (DEUNSIGN(p->n_type) == SHORT &&
		    DEUNSIGN(l->n_type) == SHORT) {
			nfree(p);
			p = l;
		}
		if ((p->n_type == CHAR || p->n_type == UCHAR ||
		    p->n_type == SHORT || p->n_type == USHORT) &&
		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
		    l->n_type == LDOUBLE)) {
			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
			p->n_left->n_type = INT;
			return p;
		}
		break;

	case MOD:
	case DIV:
		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
			break;
		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
			break;
		/* make it an int division by inserting conversions */
		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
		p = block(SCONV, p, NIL, p->n_type, 0, 0);
		p->n_left->n_type = INT;
		break;

	case PMCONV:
	case PVCONV:
                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
                nfree(p);
                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));

	case FORCE:
		/* put return value in return reg */
		p->n_op = ASSIGN;
		p->n_right = p->n_left;
		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
		p->n_left->n_rval = RETREG(p->n_type);
		break;

	case LS:
	case RS:
		/* shift count must be in a char
		 * unless longlong, where it must be int */
		if (p->n_right->n_op == ICON)
			break; /* do not do anything */
		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
			if (p->n_right->n_type != INT)
				p->n_right = block(SCONV, p->n_right, NIL,
				    INT, 0, 0);
			break;
		}
		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
			break;
		p->n_right = block(SCONV, p->n_right, NIL,
		    CHAR, 0, 0);
		break;
	}
//printf("ut:\n");
//fwalk(p, eprint, 0);

#endif

	return(p);
}
예제 #6
0
/* this is called to do local transformations on
 * an expression tree preparitory to its being
 * written out in intermediate code.
 */
NODE *
clocal(NODE *p)
{
	struct symtab *q;
	NODE *r, *l;
	int o;
	int m;
	TWORD ty;
	int tmpnr, isptrvoid = 0;

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal in: %p\n", p);
		fwalk(p, eprint, 0);
	}
#endif

	switch (o = p->n_op) {

	case UCALL:
	case CALL:
	case STCALL:
	case USTCALL:
		if (p->n_type == VOID)
			break;
		/*
		 * if the function returns void*, ecode() invokes
		 * delvoid() to convert it to uchar*.
		 * We just let this happen on the ASSIGN to the temp,
		 * and cast the pointer back to void* on access
		 * from the temp.
		 */
		if (p->n_type == PTR+VOID)
			isptrvoid = 1;
		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
		tmpnr = regno(r);
		r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);

		p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
		if (isptrvoid) {
			p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
		}
		p = buildtree(COMOP, r, p);
		break;

	case NAME:
		if ((q = p->n_sp) == NULL)
			return p; /* Nothing to care about */

		switch (q->sclass) {

		case PARAM:
		case AUTO:
			/* fake up a structure reference */
			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
			r->n_lval = 0;
			r->n_rval = FP;
			p = stref(block(STREF, r, p, 0, 0, 0));
			break;

		case STATIC:
			if (q->slevel == 0)
				break;
			p->n_lval = 0;
			p->n_sp = q;
			break;

		case REGISTER:
			p->n_op = REG;
			p->n_lval = 0;
			p->n_rval = q->soffset;
			break;

		}
		break;

	case FUNARG:
		/* Args smaller than int are given as int */
		if (p->n_type != CHAR && p->n_type != UCHAR && 
		    p->n_type != SHORT && p->n_type != USHORT)
			break;
		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
		p->n_type = INT;
		p->n_ap = 0;
		p->n_rval = SZINT;
		break;

	case CBRANCH:
		l = p->n_left;

		/*
		 * Remove unnecessary conversion ops.
		 */
		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
			if (coptype(l->n_op) != BITYPE)
				break;
			if (l->n_right->n_op == ICON) {
				r = l->n_left->n_left;
				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
					break;
				/* Type must be correct */
				ty = r->n_type;
				nfree(l->n_left);
				l->n_left = r;
				l->n_type = ty;
				l->n_right->n_type = ty;
			}
#if 0
			  else if (l->n_right->n_op == SCONV &&
			    l->n_left->n_type == l->n_right->n_type) {
				r = l->n_left->n_left;
				nfree(l->n_left);
				l->n_left = r;
				r = l->n_right->n_left;
				nfree(l->n_right);
				l->n_right = r;
			}
#endif
		}
		break;

	case PCONV:
		/* Remove redundant PCONV's. Be careful */
		l = p->n_left;
		if (l->n_op == ICON) {
			l->n_lval = (unsigned)l->n_lval;
			goto delp;
		}
		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
			/* float etc? */
			p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
			break;
		}
		/* if left is SCONV, cannot remove */
		if (l->n_op == SCONV)
			break;

		/* avoid ADDROF TEMP */
		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
			break;

		/* if conversion to another pointer type, just remove */
		if (p->n_type > BTMASK && l->n_type > BTMASK)
			goto delp;
		break;

	delp:	l->n_type = p->n_type;
		l->n_qual = p->n_qual;
		l->n_df = p->n_df;
		l->n_ap = p->n_ap;
		nfree(p);
		p = l;
		break;

	case SCONV:
		l = p->n_left;

		if (p->n_type == l->n_type) {
			nfree(p);
			p = l;
			break;
		}

		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
		    tsize(p->n_type, p->n_df, p->n_ap) ==
		    tsize(l->n_type, l->n_df, l->n_ap)) {
			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
			    l->n_type != FLOAT && l->n_type != DOUBLE &&
			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
				if (l->n_op == NAME || l->n_op == UMUL ||
				    l->n_op == TEMP) {
					l->n_type = p->n_type;
					nfree(p);
					p = l;
					break;
				}
			}
		}

		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
		    coptype(l->n_op) == BITYPE) {
			l->n_type = p->n_type;
			nfree(p);
			p = l;
		}

		if (DEUNSIGN(p->n_type) == SHORT &&
		    DEUNSIGN(l->n_type) == SHORT) {
			nfree(p);
			p = l;
		}

		/* convert float/double to int before to (u)char/(u)short */
		if ((DEUNSIGN(p->n_type) == CHAR ||
		    DEUNSIGN(p->n_type) == SHORT) &&
                    (l->n_type == FLOAT || l->n_type == DOUBLE ||
		    l->n_type == LDOUBLE)) {
			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
			p->n_left->n_type = INT;
			break;
                }

		/* convert (u)char/(u)short to int before float/double */
		if  ((p->n_type == FLOAT || p->n_type == DOUBLE ||
		    p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
		    DEUNSIGN(l->n_type) == SHORT)) {
			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
			p->n_left->n_type = INT;
			break;
                }

		o = l->n_op;
		m = p->n_type;

		if (o == ICON) {
			CONSZ val = l->n_lval;

			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
			    switch (m) {
			case BOOL:
				l->n_lval = l->n_lval != 0;
				break;
			case CHAR:
				l->n_lval = (char)val;
				break;
			case UCHAR:
				l->n_lval = val & 0377;
				break;
			case SHORT:
				l->n_lval = (short)val;
				break;
			case USHORT:
				l->n_lval = val & 0177777;
				break;
			case ULONG:
			case UNSIGNED:
				l->n_lval = val & 0xffffffff;
				break;
			case LONG:
			case INT:
				l->n_lval = (int)val;
				break;
			case LONGLONG:
				l->n_lval = (long long)val;
				break;
			case ULONGLONG:
				l->n_lval = val;
				break;
			case VOID:
				break;
			case LDOUBLE:
			case DOUBLE:
			case FLOAT:
				l->n_op = FCON;
				l->n_dcon = val;
				break;
			default:
				cerror("unknown type %d", m);
			}
			l->n_type = m;
			nfree(p);
			p = l;
		} else if (o == FCON) {
			l->n_lval = l->n_dcon;
			l->n_sp = NULL;
			l->n_op = ICON;
			l->n_type = m;
			l->n_ap = 0;
			nfree(p);
			p = clocal(l);
		}
		break;

	case MOD:
	case DIV:
		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
			break;
		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
			break;
		/* make it an int division by inserting conversions */
		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
		p = block(SCONV, p, NIL, p->n_type, 0, 0);
		p->n_left->n_type = INT;
		break;

	case FORCE:
		/* put return value in return reg */
		p->n_op = ASSIGN;
		p->n_right = p->n_left;
		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
		p->n_left->n_rval = RETREG(p->n_type);
		break;
	}

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal out: %p\n", p);
		fwalk(p, eprint, 0);
	}
#endif

	return(p);
}
예제 #7
0
/* clocal() is called to do local transformations on
 * an expression tree preparitory to its being
 * written out in intermediate code.
 *
 * the major essential job is rewriting the
 * automatic variables and arguments in terms of
 * REG and OREG nodes
 * conversion ops which are not necessary are also clobbered here
 * in addition, any special features (such as rewriting
 * exclusive or) are easily handled here as well
 */
P1ND *
clocal(P1ND *p)
{

	struct attr *ap;
	register struct symtab *q;
	register P1ND *r, *l, *n, *s;
	register int o;
	register int m;

#ifdef PCC_DEBUG
	if (xdebug) {
		printf("clocal: %p\n", p);
		p1fwalk(p, eprint, 0);
	}
#endif
	switch( o = p->n_op ){

	case NAME:
		if ((q = p->n_sp) == NULL)
			return p; /* Nothing to care about */

		switch (q->sclass) {

		case PARAM:
		case AUTO:
			/* fake up a structure reference */
			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
			slval(r, 0);
			r->n_rval = FPREG;
			p = stref(block(STREF, r, p, 0, 0, 0));
			break;

		case USTATIC:
			if (kflag == 0)
				break;
			/* FALLTHROUGH */
		case STATIC:
#ifdef TLS
			if (q->sflags & STLS) {
				p = tlsref(p);
				break;
			}
#endif
			if (kflag == 0) {
				if (q->slevel == 0)
					break;
			} else if (kflag && !statinit && blevel > 0 &&
#ifdef GCC_COMPAT
			    attr_find(q->sap, GCC_ATYP_WEAKREF)) {
#else
			    0) {
#endif
				/* extern call */
				p = picext(p);
			} else if (blevel > 0 && !statinit)
				p = picstatic(p);
			break;

		case REGISTER:
			p->n_op = REG;
			slval(p, 0);
			p->n_rval = q->soffset;
			break;

		case EXTERN:
		case EXTDEF:
#ifdef TLS
			if (q->sflags & STLS) {
				p = tlsref(p);
				break;
			}
#endif

#ifdef PECOFFABI
			if (q->sflags & SDLLINDIRECT)
				p = import(p);
#endif
#ifdef GCC_COMPAT
			if ((ap = attr_find(q->sap,
			    GCC_ATYP_VISIBILITY)) != NULL &&
			    strcmp(ap->sarg(0), "hidden") == 0)
				printf(PRTPREF "\t.hidden %s\n", getsoname(q));
#endif
			if (kflag == 0)
				break;
			if (blevel > 0 && !statinit)
				p = picext(p);
			break;
		}
		break;

	case ADDROF:
		if (kflag == 0 || blevel == 0 || statinit)
			break;
		/* char arrays may end up here */
		l = p->n_left;
		if (l->n_op != NAME ||
		    (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
			break;
		l = p;
		p = picstatic(p->n_left);
		p1nfree(l);
		if (p->n_op != UMUL)
			cerror("ADDROF error");
		l = p;
		p = p->n_left;
		p1nfree(l);
		break;

	case UCALL:
		if (kflag == 0)
			break;
		l = block(REG, NIL, NIL, INT, 0, 0);
		l->n_rval = EBX;
		p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
		p->n_op -= (UCALL-CALL);
		break;

	case USTCALL:
#if defined(os_openbsd)
		ap = strattr(p->n_left->n_ap);
		if (ap->amsize == SZCHAR || ap->amsize == SZSHORT ||
		    ap->amsize == SZINT || ap->amsize == SZLONGLONG)
#else
		if (attr_find(p->n_left->n_ap, ATTR_COMPLEX) &&
		    (ap = strattr(p->n_left->n_ap)) &&
		    ap->amsize == SZLONGLONG)
#endif
		{
			/* float complex */
			/* fake one arg to make pass2 happy */
			p->n_right = block(FUNARG, bcon(0), NIL, INT, 0, 0);
			p->n_op -= (UCALL-CALL);
			break;
		}

		/* Add hidden arg0 */
		r = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
		regno(r) = EBP;
#ifdef GCC_COMPAT
		if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL &&
		    ap->iarg(0) > 0) {
			l = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
			regno(l) = EAX;
			p->n_right = buildtree(ASSIGN, l, r);
		} else
#endif
			p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0);
		p->n_op -= (UCALL-CALL);

		if (kflag == 0)
			break;
		l = block(REG, NIL, NIL, INT, 0, 0);
		regno(l) = EBX;
		r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
		p->n_right = block(CM, r, p->n_right, INT, 0, 0);
		break;
	
	/* FALLTHROUGH */
#if defined(MACHOABI)
	case CALL:
	case STCALL:
		if (p->n_type == VOID)
			break;

		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
		l = tcopy(r);
		p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
#endif
			
		break;

#ifdef notyet
	/* XXX breaks sometimes */
	case CBRANCH:
		l = p->n_left;

		/*
		 * Remove unnecessary conversion ops.
		 */
		if (!clogop(l->n_op) || l->n_left->n_op != SCONV)
			break;
		if (coptype(l->n_op) != BITYPE)
			break;
		if (l->n_right->n_op != ICON)
			break;
		r = l->n_left->n_left;
		if (r->n_type >= FLOAT)
			break;
		if (toolarge(r->n_type, l->n_right->n_lval))
			break;
		l->n_right->n_type = r->n_type;
		if (l->n_op >= ULE && l->n_op <= UGT)
			l->n_op -= (UGT-ULE);
		p->n_left = buildtree(l->n_op, r, l->n_right);
		p1nfree(l->n_left);
		p1nfree(l);
		break;
#endif

	case PCONV:
		l = p->n_left;

		/* Make int type before pointer */
		if (l->n_type < INT || l->n_type == LONGLONG || 
		    l->n_type == ULONGLONG || l->n_type == BOOL) {
			/* float etc? */
			p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
		}
		break;

	case SCONV:
		if (p->n_left->n_op == COMOP)
			break;  /* may propagate wrong type later */
		l = p->n_left;

		if (p->n_type == l->n_type) {
			p1nfree(p);
			return l;
		}

		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
		    tsize(p->n_type, p->n_df, p->n_ap) ==
		    tsize(l->n_type, l->n_df, l->n_ap)) {
			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
			    l->n_type != FLOAT && l->n_type != DOUBLE &&
			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
				if (l->n_op == NAME || l->n_op == UMUL ||
				    l->n_op == TEMP) {
					l->n_type = p->n_type;
					p1nfree(p);
					return l;
				}
			}
		}

		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
		    coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
		    l->n_op != QUEST && l->n_op != ASSIGN) {
			l->n_type = p->n_type;
			p1nfree(p);
			return l;
		}

		o = l->n_op;
		m = p->n_type;

		if (o == ICON) {
			/*
			 * Can only end up here if o is an address,
			 * and in that case the only compile-time conversion
			 * possible is to int.
			 */
			if ((TMASK & l->n_type) == 0 && l->n_sp == NULL)
				cerror("SCONV ICON");
			if (l->n_sp == 0) {
				p->n_type = UNSIGNED;
				concast(l, m);
			} else if (m != INT && m != UNSIGNED)
				break;
			l->n_type = m;
			l->n_ap = 0;
			p1nfree(p);
			return l;
		} else if (l->n_op == FCON)
			cerror("SCONV FCON");
		if ((p->n_type == CHAR || p->n_type == UCHAR ||
		    p->n_type == SHORT || p->n_type == USHORT) &&
		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
		    l->n_type == LDOUBLE)) {
			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
			p->n_left->n_type = INT;
			return p;
		}
		break;

	case MOD:
	case DIV:
		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
			break;
		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
			break;
		/* make it an int division by inserting conversions */
		p->n_left = makety(p->n_left, INT, 0, 0, 0);
		p->n_right = makety(p->n_right, INT, 0, 0, 0);
		o = p->n_type;
		p->n_type = INT;
		p = makety(p, o, 0, 0, 0);
		break;

	case FORCE:
		/* put return value in return reg */
		p->n_op = ASSIGN;
		p->n_right = p->n_left;
		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
		p->n_left->n_rval = p->n_left->n_type == BOOL ? 
		    RETREG(CHAR) : RETREG(p->n_type);
		break;

	case LS:
	case RS:
		/* shift count must be in a char */
		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
			break;
		p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0);
		break;

		/* If not using pcc struct return */
	case STASG:
		r = p->n_right;
		if (r->n_op != STCALL && r->n_op != USTCALL)
			break;
		m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap);
		if (m == SZCHAR)
			m = CHAR;
		else if (m == SZSHORT)
			m = SHORT;
		else if (m == SZINT)
			m = INT;
		else if (m == SZLONGLONG)
			m = LONGLONG;
		else
			break;
#if !defined(os_openbsd)
		if (attr_find(r->n_ap, ATTR_COMPLEX) == 0)
			break;	/* float _Complex always in regs */
#endif
		l = buildtree(ADDROF, p->n_left, NIL);
		p1nfree(p);

		r->n_op -= (STCALL-CALL);
		r->n_type = m;

		/* r = long, l = &struct */

		n = tempnode(0, m, r->n_df, r->n_ap);
		r = buildtree(ASSIGN, p1tcopy(n), r);

		s = tempnode(0, l->n_type, l->n_df, l->n_ap);
		l = buildtree(ASSIGN, p1tcopy(s), l);

		p = buildtree(COMOP, r, l);

		l = buildtree(CAST,
		    block(NAME, NIL, NIL, m|PTR, 0, 0), p1tcopy(s));
		r = l->n_right;
		p1nfree(l->n_left);
		p1nfree(l);

		r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n);
		p = buildtree(COMOP, p, r);
		p = buildtree(COMOP, p, s);
		break;
	}