Beispiel #1
0
Datei: code.c Projekt: rheoli/pcc
/*
 * code for the end of a function
 * deals with struct return here
 * The return value is in (or pointed to by) RETREG.
 */
void
efcode(void)
{
	struct symtab *sp;
	extern int gotnr;
	TWORD t;
	NODE *p, *r, *l;
	int typ, ssz, rno;

	gotnr = 0;	/* new number for next fun */
	sp = cftnsp;
	t = DECREF(sp->stype);
	if (t != STRTY && t != UNIONTY)
		return;

	/* XXX should have one routine for this */
	ngpr = nsse = 0;
	if ((typ = argtyp(t, sp->sdf, sp->sap)) == STRREG || typ == STRCPX) {
		/* Cast to long pointer and move to the registers */
		/* XXX can overrun struct size */
		/* XXX check carefully for SSE members */

		if ((ssz = tsize(t, sp->sdf, sp->sap)) > SZLONG*2)
			cerror("efcode1");

		if (typ == STRCPX) {
			t = DOUBLE;
			rno = XMM0;
		} else {
			t = LONG;
			rno = RAX;
		}
		if (ssz > SZLONG) {
			p = block(REG, NIL, NIL, INCREF(t), 0, 0);
			regno(p) = RAX;
			p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
			ecomp(movtoreg(p, rno+1));
		}
		p = block(REG, NIL, NIL, INCREF(t), 0, 0);
		regno(p) = RAX;
		p = buildtree(UMUL, p, NIL);
		ecomp(movtoreg(p, rno));
	} else if (typ == STRMEM) {
		r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
		regno(r) = RAX;
		r = buildtree(UMUL, r, NIL);
		l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
		l = buildtree(UMUL, l, NIL);
		ecomp(buildtree(ASSIGN, l, r));
		l = block(REG, NIL, NIL, LONG, 0, 0);
		regno(l) = RAX;
		r = tempnode(stroffset, LONG, 0, 0);
		ecomp(buildtree(ASSIGN, l, r));
	} else
		cerror("efcode");
}
Beispiel #2
0
Datei: code.c Projekt: rheoli/pcc
/*
 * Called with a function call with arguments as argument.
 * This is done early in buildtree() and only done once.
 * Returns p.
 */
NODE *
funcode(NODE *p)
{
	NODE *l, *r;
	TWORD t;
	int i;

	nsse = ngpr = nrsp = 0;
	/* Check if hidden arg needed */
	/* If so, add it in pass2 */
	if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
	    l->n_type == INCREF(FTN)+UNIONTY) {
		int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
		if (ssz > 2*SZLONG)
			ngpr++;
	}

	/* Convert just regs to assign insn's */
	p->n_right = argput(p->n_right);

	/* Must sort arglist so that STASG ends up first */
	/* This avoids registers being clobbered */
	while (argsort(p->n_right))
		;
	/* Check if there are varargs */
	if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
		; /* Need RAX */
	} else {
		union arglist *al = l->n_df->dfun;

		for (; al->type != TELLIPSIS; al++) {
			if ((t = al->type) == TNULL)
				return p; /* No need */
			if (ISSOU(BTYPE(t)))
				al++;
			for (i = 0; t > BTMASK; t = DECREF(t))
				if (ISARY(t) || ISFTN(t))
					i++;
			if (i)
				al++;
		}
	}

	/* Always emit number of SSE regs used */
	l = movtoreg(bcon(nsse), RAX);
	if (p->n_right->n_op != CM) {
		p->n_right = block(CM, l, p->n_right, INT, 0, 0);
	} else {
		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
			;
		r->n_left = block(CM, l, r->n_left, INT, 0, 0);
	}
	return p;
}
Beispiel #3
0
/*
 * Do the "hard work" in assigning correct destination for arguments.
 * Also convert arguments < INT to inte (default argument promotions).
 * XXX - should be dome elsewhere.
 */
static NODE *
argput(NODE *p)
{
	NODE *q;
	TWORD ty;
	int typ, r, ssz;

	if (p->n_op == CM) {
		p->n_left = argput(p->n_left);
		p->n_right = argput(p->n_right);
		return p;
	}

	/* first arg may be struct return pointer */
	/* XXX - check if varargs; setup al */
	switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
	case INTEGER:
	case SSE:
		if (typ == SSE)
			r = XMM0 + nsse++;
		else
			r = argregsi[ngpr++];
		if (p->n_type < INT || p->n_type == BOOL)
			p = cast(p, INT, 0);
		p = movtoreg(p, r);
		break;

	case X87:
		r = nrsp;
		nrsp += SZLDOUBLE;
		p = movtomem(p, r, STKREG);
		break;

	case SSEMEM:
		r = nrsp;
		nrsp += SZDOUBLE;
		p = movtomem(p, r, STKREG);
		break;

	case INTMEM:
		r = nrsp;
		nrsp += SZLONG;
		p = movtomem(p, r, STKREG);
		break;

	case STRCPX:
	case STRREG: /* Struct in registers */
		/* Cast to long pointer and move to the registers */
		/* XXX can overrun struct size */
		/* XXX check carefully for SSE members */
		ssz = tsize(p->n_type, p->n_df, p->n_ap);

		if (typ == STRCPX) {
			ty = DOUBLE;
			r = XMM0 + nsse++;
		} else {
			ty = LONG;
			r = argregsi[ngpr++];
		}
		if (ssz <= SZLONG) {
			q = cast(p->n_left, INCREF(ty), 0);
			nfree(p);
			q = buildtree(UMUL, q, NIL);
			p = movtoreg(q, r);
		} else if (ssz <= SZLONG*2) {
			NODE *ql, *qr;

			qr = cast(ccopy(p->n_left), INCREF(ty), 0);
			qr = movtoreg(buildtree(UMUL, qr, NIL), r);

			ql = cast(p->n_left, INCREF(ty), 0);
			ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
			r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]);
			ql = movtoreg(ql, r);

			nfree(p);
			p = buildtree(CM, ql, qr);
		} else
			cerror("STRREG");
		break;

	case STRMEM: {
		struct symtab s;
		NODE *l, *t;

		q = buildtree(UMUL, p->n_left, NIL);

		s.stype = p->n_type;
		s.squal = 0;
		s.sdf = p->n_df;
		s.sap = p->n_ap;
		s.soffset = nrsp;
		s.sclass = AUTO;

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

		l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
		l->n_lval = 0;
		regno(l) = STKREG;

		t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
		t->n_sp = &s;
		t = stref(block(STREF, l, t, 0, 0, 0));

		t = (buildtree(ASSIGN, t, q));
		nfree(p);
		p = t->n_left;
		nfree(t);
		break;
		}

	default:
		cerror("argument %d", typ);
	}
	return p;
}