Пример #1
0
/*
 * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
 */
static void
emulop(NODE *p)
{
	char *ch = NULL;

	if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
	else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
	    DEUNSIGN(p->n_type) == INT))
		ch = "ashlsi3";

	else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
	else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
		ch = "lshrsi3";

	else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
	else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
		ch = "ashrsi3";
	
	else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
	else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
		ch = "divsi3";

	else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
	else if (p->n_op == DIV && (p->n_type == ULONG ||
	    p->n_type == UNSIGNED))
		ch = "udivsi3";

	else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
	else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
		ch = "modsi3";

	else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
	else if (p->n_op == MOD && (p->n_type == ULONG ||
	    p->n_type == UNSIGNED))
		ch = "umodsi3";

	else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
	else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
		ch = "mulsi3";

	else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
	else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";

	else ch = 0, comperr("ZE");
	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
	printf("\tjal __%s\t# emulated operation\n", exname(ch));
	printf("\tnop\n");
	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
}
Пример #2
0
static NODE *
moveargs(NODE *p, int *regp)
{
	NODE *r, **rp;
	int reg;

	if (p->n_op == CM) {
		p->n_left = moveargs(p->n_left, regp);
		r = p->n_right;
		rp = &p->n_right;
	} else {
		r = p;
		rp = &p;
	}

	reg = *regp;

	if (reg > R3 && r->n_op != STARG) {
		*rp = pusharg(r, regp);
	} else if (r->n_op == STARG) {
		*rp = movearg_struct(r, regp);
	} else if (DEUNSIGN(r->n_type) == LONGLONG) {
		*rp = movearg_64bit(r, regp);
	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
		*rp = movearg_double(r, regp);
	} else if (r->n_type == FLOAT) {
		*rp = movearg_float(r, regp);
	} else {
		*rp = movearg_32bit(r, regp);
	}

	return straighten(p);
}
Пример #3
0
static int
argsiz(NODE *p)
{
	TWORD t;
	int size = 0;
	int sz = 0;

	if (p->n_op == CM) {
		size = argsiz(p->n_left);
		p = p->n_right;
	}

	t = p->n_type;
	if (t < LONGLONG || t > BTMASK)
		sz = 4;
	else if (DEUNSIGN(t) == LONGLONG)
		sz = 8;
	else if (t == DOUBLE || t == LDOUBLE)
		sz = 8;
	else if (t == FLOAT)
		sz = 4;
	else if (t == STRTY || t == UNIONTY)
		sz = p->n_stsize;

	if (p->n_type == STRTY || p->n_type == UNIONTY) {
		return (size + sz);
	}

	/* alignment */
	if (sz == 8 && (size & 7) != 0)
		sz += 4;

//	printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
	return (size + sz);
}
Пример #4
0
static NODE *
moveargs(NODE *p, int *regp)
{
        NODE *r, **rp;
	int lastreg;
	int reg;

        if (p->n_op == CM) {
                p->n_left = moveargs(p->n_left, regp);
                r = p->n_right;
		rp = &p->n_right;
        } else {
		r = p;
		rp = &p;
	}

 	lastreg = A0 + nargregs - 1;
        reg = *regp;

	if (reg > lastreg && r->n_op != STARG)
		*rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
	else if (r->n_op == STARG) {
		*rp = movearg_struct(r, p, regp);
	} else if (DEUNSIGN(r->n_type) == LONGLONG) {
		*rp = movearg_64bit(r, regp);
	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
		/* XXX bounce in and out of temporary to change to longlong */
		NODE *t1 = tempnode(0, LONGLONG, 0, 0);
		int tmpnr = regno(t1);
		NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
		t1 =  movearg_64bit(t1, regp);
		r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
		if (p->n_op == CM) {
			p->n_left = buildtree(CM, p->n_left, t1);
			p->n_right = r;
		} else {
			p = buildtree(CM, t1, r);
		}
	} else if (r->n_type == FLOAT) {
		/* XXX bounce in and out of temporary to change to int */
		NODE *t1 = tempnode(0, INT, 0, 0);
		int tmpnr = regno(t1);
		NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
		t1 =  movearg_32bit(t1, regp);
		r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
		if (p->n_op == CM) {
			p->n_left = buildtree(CM, p->n_left, t1);
			p->n_right = r;
		} else {
			p = buildtree(CM, t1, r);
		}
	} else {
		*rp = movearg_32bit(r, regp);
	}

	return p;
}
Пример #5
0
NODE *
mips_builtin_va_arg(NODE *f, NODE *a, TWORD t)
{
	NODE *p, *q, *r;
	int sz, tmpnr;

	/* check num args and type */
	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
	    !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
		goto bad;

	r = a->n_right;

	/* get type size */
	sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
	if (sz < SZINT/SZCHAR) {
		werror("%s%s promoted to int when passed through ...",
			r->n_type & 1 ? "unsigned " : "",
			DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
		sz = SZINT/SZCHAR;
	}

	/* alignment */
	p = tcopy(a->n_left);
	if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
		p = buildtree(PLUS, p, bcon(7));
		p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
	}

	/* create a copy to a temp node */
	q = tempnode(0, p->n_type, p->n_df, p->n_ap);
	tmpnr = regno(q);
	p = buildtree(ASSIGN, q, p);

	q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
	q = buildtree(PLUS, q, bcon(sz));
	q = buildtree(ASSIGN, a->n_left, q);

	q = buildtree(COMOP, p, q);

	nfree(a->n_right);
	nfree(a);
	nfree(f); 

	p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
	p = buildtree(UMUL, p, NIL);
	p = buildtree(COMOP, q, p);

	return p;

bad:
	uerror("bad argument to __builtin_va_arg");
	return bcon(0);
}
Пример #6
0
/*
 * If we're big endian, then all OREG loads of a type
 * larger than the destination, must have the
 * offset changed to point to the correct bytes in memory.
 */
static void
offchg(NODE *p, void *arg)
{
	NODE *l;

	if (p->n_op != SCONV)
		return;

	l = p->n_left;

	if (l->n_op != OREG)
		return;

	switch (l->n_type) {
	case SHORT:
	case USHORT:
		if (DEUNSIGN(p->n_type) == CHAR)
			l->n_lval += 1;
		break;
	case LONG:
	case ULONG:
	case INT:
	case UNSIGNED:
		if (DEUNSIGN(p->n_type) == CHAR)
			l->n_lval += 3;
		else if (DEUNSIGN(p->n_type) == SHORT)
			l->n_lval += 2;
		break;
	case LONGLONG:
	case ULONGLONG:
		if (DEUNSIGN(p->n_type) == CHAR)
			l->n_lval += 7;
		else if (DEUNSIGN(p->n_type) == SHORT)
			l->n_lval += 6;
		else if (DEUNSIGN(p->n_type) == INT ||
		    DEUNSIGN(p->n_type) == LONG)
			l->n_lval += 4;
		break;
	default:
		comperr("offchg: unknown type");
		break;
	}
}
Пример #7
0
/*
 * If we're big endian, then all OREG loads of a type
 * larger than the destination, must have the
 * offset changed to point to the correct bytes in memory.
 */
static void
offchg(NODE *p, void *arg)
{
	NODE *l;

	if (p->n_op != SCONV)
		return;

	l = p->n_left;

	if (l->n_op != OREG)
		return;

	switch (l->n_type) {
	case SHORT:
	case USHORT:
		if (DEUNSIGN(p->n_type) == CHAR)
			setlval(l, getlval(l) + 1);
		break;
	case LONG:
	case ULONG:
	case INT:
	case UNSIGNED:
		if (DEUNSIGN(p->n_type) == CHAR)
			setlval(l, getlval(l + 3));
		else if (DEUNSIGN(p->n_type) == SHORT)
			setlval(l, getlval(l + 2));
		break;
	case LONGLONG:
	case ULONGLONG:
		if (DEUNSIGN(p->n_type) == CHAR)
			setlval(l, getlval(l + 7));
		else if (DEUNSIGN(p->n_type) == SHORT)
			setlval(l, getlval(l + 6));
		else if (DEUNSIGN(p->n_type) == INT ||
		    DEUNSIGN(p->n_type) == LONG)
			setlval(l, getlval(l + 4));
		break;
	default:
		comperr("offchg: unknown type");
		break;
	}
}
Пример #8
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
 */
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);
}
Пример #9
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);
}
Пример #10
0
/*
 * print out a constant node
 * mat be associated with a label
 */
int
ninval(CONSZ off, int fsz, NODE *p)
{
        union { float f; double d; int i[2]; } u;
        struct symtab *q;
        TWORD t;
#ifndef USE_GAS
        int i, j;
#endif

        t = p->n_type;
        if (t > BTMASK)
		p->n_type = t = INT; /* pointer */

        if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
                uerror("element not constant");

        switch (t) {
        case LONGLONG:
        case ULONGLONG:
#ifdef USE_GAS
                printf("\t.dword %lld\n", (long long)p->n_lval);
#else
                i = p->n_lval >> 32;
                j = p->n_lval & 0xffffffff;
                p->n_type = INT;
		if (bigendian) {
			p->n_lval = j;
	                ninval(off, 32, p);
			p->n_lval = i;
			ninval(off+32, 32, p);
		} else {
			p->n_lval = i;
	                ninval(off, 32, p);
			p->n_lval = j;
			ninval(off+32, 32, p);
		}
#endif
                break;
        case INT:
        case UNSIGNED:
                printf("\t.word " CONFMT, (CONSZ)p->n_lval);
                if ((q = p->n_sp) != NULL) {
                        if ((q->sclass == STATIC && q->slevel > 0)) {
                                printf("+" LABFMT, q->soffset);
                        } else
                                printf("+%s",
				    q->soname ? q->soname : exname(q->sname));
                }
                printf("\n");
                break;
        case SHORT:
        case USHORT:
		astypnames[SHORT] = astypnames[USHORT] = "\t.half";
                return 0;
        case LDOUBLE:
        case DOUBLE:
                u.d = (double)p->n_dcon;
		if (bigendian) {
	                printf("\t.word\t%d\n", u.i[0]);
			printf("\t.word\t%d\n", u.i[1]);
		} else {
			printf("\t.word\t%d\n", u.i[1]);
	                printf("\t.word\t%d\n", u.i[0]);
		}
                break;
        case FLOAT:
                u.f = (float)p->n_dcon;
                printf("\t.word\t0x%x\n", u.i[0]);
                break;
        default:
                return 0;
        }
	return 1;
}
Пример #11
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);
}
Пример #12
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;
	}
Пример #13
0
/*
 * code for the beginning of a function; a is an array of
 * indices in symtab for the arguments; n is the number
 */
void
bfcode(struct symtab **sp, int cnt)
{
	union arglist *usym;
	int lastreg = A0 + nargregs - 1;
	int saveallargs = 0;
	int i, reg;

	/*
	 * Detect if this function has ellipses and save all
	 * argument register onto stack.
	 */
	usym = cftnsp->sdf->dfun;
	while (usym && usym->type != TNULL) {
		if (usym->type == TELLIPSIS) {
			saveallargs = 1;
			break;
		}
		++usym;
	}

	reg = A0;

	/* assign hidden return structure to temporary */
	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
		param_retptr();
		++reg;
	}

        /* recalculate the arg offset and create TEMP moves */
        for (i = 0; i < cnt; i++) {

		if ((reg > lastreg) && !xtemps)
			break;
		else if (reg > lastreg) 
			putintemp(sp[i]);
		else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
			param_struct(sp[i], &reg);
		else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
			param_64bit(sp[i], &reg, xtemps && !saveallargs);
		else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
			param_double(sp[i], &reg, xtemps && !saveallargs);
		else if (sp[i]->stype == FLOAT)
			param_float(sp[i], &reg, xtemps && !saveallargs);
		else
			param_32bit(sp[i], &reg, xtemps && !saveallargs);
	}

	/* if saveallargs, save the rest of the args onto the stack */
	if (!saveallargs)
		return;
	while (reg <= lastreg) {
		NODE *p, *q;
		int off = ARGINIT/SZINT + (reg - A0);
		q = block(REG, NIL, NIL, INT, 0, 0);
		q->n_rval = reg++;
		p = block(REG, NIL, NIL, INT, 0, 0);
		p->n_rval = FP;
		p = block(PLUS, p, bcon(4*off), INT, 0, 0);
		p = block(UMUL, p, NIL, INT, 0, 0);
		p = buildtree(ASSIGN, p, q);
		ecomp(p);
	}

}
Пример #14
0
/*
 * code for the beginning of a function; a is an array of
 * indices in symtab for the arguments; n is the number
 *
 * Classifying args on i386; not simple:
 * - Args may be on stack or in registers (regparm)
 * - There may be a hidden first arg, unless OpenBSD struct return.
 * - Regparm syntax is not well documented.
 * - There may be stdcall functions, where the called function pops stack
 * - ...probably more
 */
void
bfcode(struct symtab **sp, int cnt)
{
	extern int argstacksize;
#ifdef GCC_COMPAT
	struct attr *ap;
#endif
	struct symtab *sp2;
	extern int gotnr;
	NODE *n, *p;
	int i, regparmarg;
	int argbase, nrarg, sz;

	argbase = ARGINIT;
	nrarg = regparmarg = 0;

#ifdef GCC_COMPAT
        if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
                cftnsp->sflags |= SSTDCALL;
        if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM)))
                regparmarg = ap->iarg(0);
#endif

	/* Function returns struct, create return arg node */
	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
		{
			if (regparmarg) {
				n = block(REG, 0, 0, INT, 0, 0);
				regno(n) = regpregs[nrarg++];
			} else {
				n = block(OREG, 0, 0, INT, 0, 0);
				n->n_lval = argbase/SZCHAR;
				argbase += SZINT;
				regno(n) = FPREG;
			}
			p = tempnode(0, INT, 0, 0);
			structrettemp = regno(p);
			p = buildtree(ASSIGN, p, n);
			ecomp(p);
		}
	}

	/*
	 * Find where all params are so that they end up at the right place.
	 * At the same time recalculate their arg offset on stack.
	 * We also get the "pop size" for stdcall.
	 */
	for (i = 0; i < cnt; i++) {
		sp2 = sp[i];
		sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
		
		SETOFF(sz, SZINT);

		if (cisreg(sp2->stype) == 0 ||
		    ((regparmarg - nrarg) * SZINT < sz)) {	/* not in reg */
			sp2->soffset = argbase;
			argbase += sz;
			nrarg = regparmarg;	/* no more in reg either */
		} else {					/* in reg */
			sp2->soffset = nrarg;
			nrarg += sz/SZINT;
			sp2->sclass = REGISTER;
		}
	}

	/*
	 * Now (argbase - ARGINIT) is used space on stack.
	 * Move (if necessary) the args to something new.
	 */
	for (i = 0; i < cnt; i++) {
		int reg, j;

		sp2 = sp[i];

		if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) {
			/* must move to stack */
			sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
			SETOFF(sz, SZINT);
			SETOFF(autooff, SZINT);
			reg = sp2->soffset;
			sp2->sclass = AUTO;
			sp2->soffset = NOOFFSET;
			oalloc(sp2, &autooff);
                        for (j = 0; j < sz/SZCHAR; j += 4) {
                                p = block(OREG, 0, 0, INT, 0, 0);
                                p->n_lval = sp2->soffset/SZCHAR + j;
                                regno(p) = FPREG;
                                n = block(REG, 0, 0, INT, 0, 0);
                                regno(n) = regpregs[reg++];
                                p = block(ASSIGN, p, n, INT, 0, 0);
                                ecomp(p);
                        }
		} else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) &&
		    ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) {
			/* just put rest in temps */
			if (sp2->sclass == REGISTER) {
				n = block(REG, 0, 0, sp2->stype,
				    sp2->sdf, sp2->sap);
				if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG)
					regno(n) = longregs[sp2->soffset];
				else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL)
					regno(n) = charregs[sp2->soffset];
				else
					regno(n) = regpregs[sp2->soffset];
			} else {
                                n = block(OREG, 0, 0, sp2->stype,
				    sp2->sdf, sp2->sap);
                                n->n_lval = sp2->soffset/SZCHAR;
                                regno(n) = FPREG;
			}
			p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap);
			sp2->soffset = regno(p);
			sp2->sflags |= STNODE;
			n = buildtree(ASSIGN, p, n);
			ecomp(n);
		}
	}

        argstacksize = 0;
        if (cftnsp->sflags & SSTDCALL) {
		argstacksize = (argbase - ARGINIT)/SZCHAR;
        }

}
Пример #15
0
/*
 * Beginning-of-function code:
 *
 * 'sp' is an array of indices in symtab for the arguments
 * 'cnt' is the number of arguments
 */
void
bfcode(struct symtab **sp, int cnt)
{
	union arglist *usym;
	int saveallargs = 0;
	int i, argofs = 0;

	/*
	 * Detect if this function has ellipses and save all
	 * argument registers onto stack.
	 */
	usym = cftnsp->sdf->dfun;
	while (usym && usym->type != TNULL) {
		if (usym->type == TELLIPSIS) {
			saveallargs = 1;
			break;
		}
		++usym;
	}

	/* if returning a structure, move the hidden argument into a TEMP */
	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
		param_retstruct();
		++argofs;
	}

	/* recalculate the arg offset and create TEMP moves */
	for (i = 0; i < cnt; i++) {

		if (sp[i] == NULL)
			continue;

		if ((argofs >= NARGREGS) && !xtemps)
			break;

		if (argofs > NARGREGS) {
			putintemp(sp[i]);
		} else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
			param_struct(sp[i], &argofs);
		} else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
			param_64bit(sp[i], &argofs, xtemps && !saveallargs);
		} else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
			if (features(FEATURE_HARDFLOAT))
				param_double(sp[i], &argofs,
				    xtemps && !saveallargs);
			else
				param_64bit(sp[i], &argofs,
				    xtemps && !saveallargs);
		} else if (sp[i]->stype == FLOAT) {
			if (features(FEATURE_HARDFLOAT))
				param_float(sp[i], &argofs,
				    xtemps && !saveallargs);
			else
				param_32bit(sp[i], &argofs,
				    xtemps && !saveallargs);
		} else {
			param_32bit(sp[i], &argofs, xtemps && !saveallargs);
		}
	}

	/* if saveallargs, save the rest of the args onto the stack */
	while (saveallargs && argofs < NARGREGS) {
      		NODE *p, *q;
		int off = ARGINIT/SZINT + argofs;
		q = block(REG, NIL, NIL, INT, 0, 0);
		regno(q) = R0 + argofs++;
		p = block(REG, NIL, NIL, INT, 0, 0);
		regno(p) = FPREG;
		p = block(PLUS, p, bcon(4*off), INT, 0, 0);
		p = block(UMUL, p, NIL, INT, 0, 0);
		p = buildtree(ASSIGN, p, q);
		ecomp(p);
	}

}
Пример #16
0
NODE *
clocal(NODE *p)
{
	/* this 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 */

	struct symtab *q;
	NODE *l, *r;
	int o;
	TWORD ml;

	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 PCONV:
		ml = p->n_left->n_type;
		l = p->n_left;
		if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON)
			break;
		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 (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) {
			nfree(p);
			return l;
		}
		if (l->n_op == ICON) {
			CONSZ val = l->n_lval;
			switch (p->n_type) {
			case CHAR:
				l->n_lval = (char)val;
				break;
			case UCHAR:
				l->n_lval = val & 0377;
				break;
			case SHORT:
			case INT:
				l->n_lval = (short)val;
				break;
			case USHORT:
			case UNSIGNED:
				l->n_lval = val & 0177777;
				break;
			case ULONG:
			case ULONGLONG:
				l->n_lval = val & 0xffffffff;
				break;
			case LONG:
			case LONGLONG:
				l->n_lval = (int)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", p->n_type);
			}
			l->n_type = p->n_type;
			nfree(p);
			return l;
		}
		break;
		

	}

	return(p);
}
Пример #17
0
/*
 * code for the beginning of a function; a is an array of
 * indices in symtab for the arguments; n is the number
 * On m16k, space is allocated on stack for register arguments,
 * arguments are moved to the stack and symtab is updated accordingly.
 */
void
bfcode(struct symtab **a, int n)
{
	struct symtab *s;
	int i, r0l, r0h, a0, r2, sz, hasch, stk;
	int argoff = ARGINIT;

	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
		/* Function returns struct, adjust arg offset */
		for (i = 0; i < n; i++)
			a[i]->soffset += SZPOINT(INT);
	}
	/* first check if there are 1-byte parameters */
	for (hasch = i = 0; i < n && i < 6; i++)
		if (DEUNSIGN(a[i]->stype) == CHAR)
			hasch = 1;

	stk = r0l = r0h = a0 = r2 = 0;
	for (i = 0; i < n; i++) {
		s = a[i];
		sz = tsize(s->stype, s->sdf, s->ssue);
		if (ISPTR(s->stype) && ISFTN(DECREF(s->stype)))
			sz = SZLONG; /* function pointers are always 32 */
		if (stk == 0)
		    switch (sz) {
		case SZCHAR:
			if (r0l) {
				if (r0h)
					break;
				argmove(s, 1);
				r0h = 1;
			} else {
				argmove(s, 0);
				r0l = 1;
			}
			continue;

		case SZINT:
			if (s->stype > BTMASK) {
				/* is a pointer */
				if (a0) {
					if (r0l || hasch) {
						if (r2)
							break;
						argmove(s, R2);
						r2 = 1;
					} else {
						argmove(s, R0);
						r0l = r0h = 1;
					}
				} else {
					argmove(s, A0);
					a0 = 1;
				}
			} else if (r0l || hasch) {
				if (r2) {
					if (a0)
						break;
					argmove(s, A0);
					a0 = 1;
				} else {
					argmove(s, R2);
					r2 = 1;
				}
			} else {
				argmove(s, R0);
				r0l = r0h = 1;
			}
			continue;
		case SZLONG:
			if (r0l||r0h||r2)
				break;
			argmove(s, R0);
			r0l = r0h = r2 = 1;
			continue;

		default:
			break;
		}
		stk = 1;
		s->soffset = argoff;
		argoff += sz;
	}
}
Пример #18
0
void
zzzcode(NODE *p, int c)
{
	NODE *l, *r;
	TWORD t;
	int m;
	char *ch;

	switch (c) {
	case 'N':  /* logical ops, turned into 0-1 */
		/* use register given by register 1 */
		cbgen( 0, m=getlab2());
		deflab( p->n_label );
		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->n_rval] );
		deflab( m );
		return;

	case 'A': /* Assign a constant directly to a memory position */
		printf("\t");
		if (p->n_type < LONG || ISPTR(p->n_type))
			casg(p);
		else
			casg64(p);
		printf("\n");
		break;

	case 'B': /* long long compare */
		twollcomp(p);
		break;

	case 'C':	/* num words pushed on arg stack */
		printf("$%d", p->n_qual);
		break;

	case 'D':	/* INCR and DECR */
		zzzcode(p->n_left, 'A');
		printf("\n	");

#if 0
	case 'E':	/* INCR and DECR, FOREFF */
		if (p->n_right->n_lval == 1)
			{
			printf("%s", (p->n_op == INCR ? "inc" : "dec") );
			prtype(p->n_left);
			printf("	");
			adrput(stdout, p->n_left);
			return;
			}
		printf("%s", (p->n_op == INCR ? "add" : "sub") );
		prtype(p->n_left);
		printf("2	");
		adrput(stdout, p->n_right);
		printf(",");
		adrput(p->n_left);
		return;
#endif

	case 'F':	/* register type of right operand */
		{
		register NODE *n;
		register int ty;

		n = getlr( p, 'R' );
		ty = n->n_type;

		if (x2debug) printf("->%d<-", ty);

		if ( ty==DOUBLE) printf("d");
		else if ( ty==FLOAT ) printf("f");
		else printf("l");
		return;
		}

	case 'G': /* emit conversion instructions */
		sconv(p);
		break;

	case 'J': /* jump or ret? */
		{
			struct interpass *ip =
			    DLIST_PREV((struct interpass *)p2env.epp, qelem);
			if (ip->type != IP_DEFLAB ||
			    ip->ip_lbl != getlr(p, 'L')->n_lval)
				expand(p, FOREFF, "jbr	LL");
			else
				printf("ret");
		}
		break;

	case 'L':	/* type of left operand */
	case 'R':	/* type of right operand */
		{
		register NODE *n;

		n = getlr ( p, c);
		if (x2debug) printf("->%d<-", n->n_type);

		prtype(n);
		return;
		}

	case 'O': /* print out emulated ops */
		expand(p, FOREFF, "\tmovq	AR,-(%sp)\n");
		expand(p, FOREFF, "\tmovq	AL,-(%sp)\n");
		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
		else if (p->n_op == DIV) ch = "div";
		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
		else if (p->n_op == MOD) ch = "mod";
		else if (p->n_op == MUL) ch = "mul";
		else ch = 0, comperr("ZO %d", p->n_op);
		printf("\tcalls	$4,__%sdi3\n", ch);
		break;


	case 'Z':	/* complement mask for bit instr */
		printf("$%Ld", ~p->n_right->n_lval);
		return;

	case 'U':	/* 32 - n, for unsigned right shifts */
		t = DEUNSIGN(p->n_left->n_type);
		m = t == CHAR ? 8 : t == SHORT ? 16 : 32;
		printf("$" CONFMT, m - p->n_right->n_lval);
		return;

	case 'T':	/* rounded structure length for arguments */
		{
		int size;

		size = p->n_stsize;
		SETOFF( size, 4);
		printf("$%d", size);
		return;
		}

	case 'S':  /* structure assignment */
		{
			register int size;

			size = p->n_stsize;
			l = r = NULL; /* XXX gcc */
			if( p->n_op == STASG ){
				l = p->n_left;
				r = p->n_right;

				}
			else if( p->n_op == STARG ){
				/* store an arg into a temporary */
				printf("\tsubl2 $%d,%%sp\n",
				    size < 4 ? 4 : size);
				l = mklnode(OREG, 0, SP, INT);
				r = p->n_left;
				}
			else cerror( "STASG bad" );

			if( r->n_op == ICON ) r->n_op = NAME;
			else if( r->n_op == REG ) r->n_op = OREG;
			else if( r->n_op != OREG ) cerror( "STASG-r" );

		if (size != 0) {
			if( size <= 0 || size > 65535 )
				cerror("structure size <0=0 or >65535");

			switch(size) {
				case 1:
					printf("	movb	");
					break;
				case 2:
					printf("	movw	");
					break;
				case 4:
					printf("	movl	");
					break;
				case 8:
					printf("	movq	");
					break;
				default:
					printf("	movc3	$%d,", size);
					break;
			}
			adrput(stdout, r);
			printf(",");
			adrput(stdout, l);
			printf("\n");
		}

			if( r->n_op == NAME ) r->n_op = ICON;
			else if( r->n_op == OREG ) r->n_op = REG;
			if (p->n_op == STARG)
				tfree(l);

			}
		break;

	default:
		comperr("illegal zzzcode '%c'", c);
	}
}