Exemplo n.º 1
0
/*
 * Evaluate AND/OR/ER.  p1 and p2 are pointers to ti struct.
 */
static NODE *
gcc_andorer(int op, NODE *p1, NODE *p2)
{
	char *n = tistack();
	NODE *p, *t1, *t2, *p3;

	t1 = tempnode(0, p1->n_type, p1->n_df, p1->n_ap);
	t2 = tempnode(0, p2->n_type, p2->n_df, p2->n_ap);

	p1 = buildtree(ASSIGN, p1tcopy(t1), p1);
	p2 = buildtree(ASSIGN, p1tcopy(t2), p2);
	p = buildtree(COMOP, p1, p2);

	p3 = buildtree(ADDROF, eve(bdty(NAME, n)), NIL);
	p1 = buildtree(ASSIGN, structref(p1tcopy(p3), STREF, hiti),
	    buildtree(op, structref(p1tcopy(t1), STREF, hiti),
	    structref(p1tcopy(t2), STREF, hiti)));
	p = buildtree(COMOP, p, p1);
	p1 = buildtree(ASSIGN, structref(p1tcopy(p3), STREF, loti),
	    buildtree(op, structref(t1, STREF, loti),
	    structref(t2, STREF, loti)));
	p = buildtree(COMOP, p, p1);
	p = buildtree(COMOP, p, buildtree(UMUL, p3, NIL));
	return p;
}
Exemplo n.º 2
0
/*
 * Check if we may have to do a cast to/from TI.
 */
NODE *
gcc_eval_ticast(int op, NODE *p1, NODE *p2)
{
	struct attr *a1, *a2;
	int t;

	a2 = NULL; /* XXX flow analysis */
	if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL)
		return NIL;

	if (op == RETURN)
		p1 = p1tcopy(p1);
	if (a1 == NULL) {
		if (a2 == NULL)
			cerror("gcc_eval_ticast error");
		switch (p1->n_type) {
		case LDOUBLE:
			p2 = doacall(floatuntixfsp,
			    nametree(floatuntixfsp), p2);
			tfree(p1);
			break;
		case ULONG:
		case LONG:
			p2 = cast(structref(p2, DOT, loti), p1->n_type, 0);
			tfree(p1);
			break;
		case VOID:
			return NIL;
		default:
			uerror("gcc_eval_ticast: %d", p1->n_type);
		}
		return p2;
	}
	/* p2 can be anything, but we must cast it to p1 */
	t = a1->iarg(1);

	if (p2->n_type == STRTY &&
	    (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) &&
	    strcmp(a2->sarg(0), TISTR) == 0) {
		/* Already TI, just add extra mode bits */
		a2 = attr_new(GCC_ATYP_MODE, 3);
		a2->sarg(0) = TISTR;
		a2->iarg(1) = t;
		p2->n_ap = attr_add(p2->n_ap, a2);
	} else  {
		p2 = ticast(p2, t);
	}
	tfree(p1);
	return p2;
}
Exemplo n.º 3
0
/*
 * Create a ti node from something not a ti node.
 * This usually means:  allocate space on stack, store val, give stack address.
 */
static NODE *
ticast(NODE *p, int u)
{
	CONSZ val;
	NODE *q;
	char *n;
	int u2;

	n = tistack();

	/* store val */
	switch (p->n_op) {
	case ICON:
		val = 0;
		if (u == 0 && glval(p) < 0)
			val = -1;
		q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti)));
		q = buildtree(ASSIGN, q, p);
		p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti));
		p = eve(biop(ASSIGN, p, bcon(val)));
		q = buildtree(COMOP, q, p);
		p = buildtree(COMOP, q, eve(bdty(NAME, n)));
		break;

	default:
		u2 = ISUNSIGNED(p->n_type);
		q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti)));
		q = buildtree(ASSIGN, q, p);
		p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti));
		if (u2) {
			p = eve(biop(ASSIGN, p, bcon(0)));
		} else {
			q = buildtree(ASSIGN, eve(p1tcopy(p)), q);
			p = buildtree(RSEQ, eve(p), bcon(SZLONG-1));
		}
		q = buildtree(COMOP, q, p);
		p = buildtree(COMOP, q, eve(bdty(NAME, n)));
		break;
	}
	return p;
}
Exemplo n.º 4
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;
	}
Exemplo n.º 5
0
/*
 * Evaluate 128-bit operands.
 */
NODE *
gcc_eval_timode(int op, NODE *p1, NODE *p2)
{
	struct attr *a1, *a2;
	struct symtab *sp;
	NODE *p;
	int isu = 0, gotti, isaop;

	if (op == CM)
		return buildtree(op, p1, p2);

	a1 = isti(p1);
	a2 = isti(p2);

	if (a1 == NULL && a2 == NULL)
		return NULL;

	if (op == ASSIGN)
		return timodeassign(p1, p2);

	gotti = (a1 != NULL);
	gotti += (a2 != NULL);

	if (gotti == 0)
		return NULL;

	if (a1 != NULL)
		isu = a1->iarg(1);
	if (a2 != NULL && !isu)
		isu = a2->iarg(1);

	if (a1 == NULL) {
		p1 = ticast(p1, isu);
		a1 = attr_find(p1->n_ap, GCC_ATYP_MODE);
	}
	if (a2 == NULL && (cdope(op) & SHFFLG) == 0) {
		p2 = ticast(p2, isu);
		a2 = attr_find(p2->n_ap, GCC_ATYP_MODE);
	}

	switch (op) {
	case GT:
	case GE:
	case LT:
	case LE:
	case EQ:
	case NE:
		/* change to call */
		sp = isu ? ucmpti2sp : cmpti2sp;
		p = doacall(sp, nametree(sp), buildtree(CM, p1, p2));
		p = buildtree(op, p, bcon(1));
		break;

	case AND:
	case ER:
	case OR:
		if (!ISPTR(p1->n_type))
			p1 = buildtree(ADDROF, p1, NIL);
		if (!ISPTR(p2->n_type))
			p2 = buildtree(ADDROF, p2, NIL);
		p = gcc_andorer(op, p1, p2);
		break;

	case LSEQ:
	case RSEQ:
	case LS:
	case RS:
		sp = op == LS || op == LSEQ ? ashldi3sp :
		    isu ? lshrdi3sp : ashrdi3sp;
		p2 = cast(p2, INT, 0);
		/* XXX p1 p1tcopy may have side effects */
		p = doacall(sp, nametree(sp), buildtree(CM, p1tcopy(p1), p2));
		if (op == LSEQ || op == RSEQ) {
			p = buildtree(ASSIGN, p1, p);
		} else
			tfree(p1);
		break;

	case PLUSEQ:
	case MINUSEQ:
	case MULEQ:
	case DIVEQ:
	case MODEQ:
	case PLUS:
	case MINUS:
	case MUL:
	case DIV:
	case MOD:
		isaop = (cdope(op)&ASGOPFLG);
		if (isaop)
			op = UNASG op;
		sp = op == PLUS ? addvti3sp :
		    op == MINUS ? subvti3sp :
		    op == MUL ? mulvti3sp :
		    op == DIV ? (isu ? udivti3sp : divti3sp) :
		    op == MOD ? (isu ? umodti3sp : modti3sp) : 0;
		/* XXX p1 p1tcopy may have side effects */
		p = doacall(sp, nametree(sp), buildtree(CM, p1tcopy(p1), p2));
		if (isaop)
			p = buildtree(ASSIGN, p1, p);
		else
			tfree(p1);
		break;

	default:
		uerror("unsupported TImode op %d", op);
		p = bcon(0);
	}
	return p;
}