⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccgen2.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
	{
	if (!r)
	    return (VREG *)-1;		/* Stop if just checking. */
	code1(P_AND, r, ((INT) 1 << fbitsize)-1);	/* Zap! */
	}
    return r;
}

/* GINCDEC - Generate code for prefix/postfix increment/decrement.
**	This is special-cased (instead of being handled by general
**	arith code) both for efficiency and because the address is
**	only supposed to be evaluated once.  The code also checks
**	for NF_DISCARD to see whether the result value is needed or not;
**	if not, it forces the operation to be prefix instead of postfix,
**	so that all fixup work can be avoided!
*/

static VREG *
gincdec(NODE *n, int inc, int pre)
/* The inc/dec expression node, +1 for increment, -1 for decrement, and 
 * True if prefix, else postfix.
 */
{
    VREG *r, *ra, *r2;
    INT size = 1;		/* Default size for most common case */
    int savaddr;
    int volat;

    if (n->Nflag & NF_DISCARD)	/* Will result be discarded? */
	pre = 1;		/* If so, prefix form is always better! */
    n = n->Nleft;		/* Mainly interested in operand */
    if ((volat = tisvolatile(n->Ntype)) != 0)
	flushcode();		/* Barfo, avoid optimiz of volatile obj */

    if (Register_Id(n))
	{
	void codr1(int, int, INT);
	if (pre)	/* r->Vrloc = n->Nid->Sreg, if preserve reg */
	    r_preserve = n->Nid->Sreg;

	switch(n->Ntype->Tspec)
	    {
	    case TS_FLOAT:
		r = vrget();
		r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		code00(P_MOVE, r->Vrloc, n->Nid->Sreg);
		codr1(P_FADR, n->Nid->Sreg,(INT) ((inc > 0)? 1.0 : -1.0)); // FW KCC-NT
		break;
#if 0	/* for next version of KCC regs */
	    case TS_DOUBLE:
	    case TS_LNGDBL:
		r = vrdget();
		r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		if (!pre)
		    {
		    code00(P_DMOVE, r->Vrloc, n->Nid->Sreg);
		    r_preserve = n->Nid->Sreg;
		    ra = vrdget();
		    ra->Vrtype = n->Ntype;/* Set C type of object in reg */
		    code9(P_DFAD, ra, ((inc > 0)? 1.0 : -1.0), 1);
		    vrfree(ra);
		    }
		else
		    code9(P_DFAD, r, ((inc > 0)? 1.0 : -1.0), 1);
		break;
	    case TS_PTR:			/* Hacking pointer? */
	    case TS_ENUM:
	    case TS_BITF:
	    case TS_UBITF:
#endif
	    case TS_INT:
	    case TS_UINT:
	    case TS_LONG:
	    case TS_ULONG:
	    case TS_CHAR:
	    case TS_UCHAR:
	    case TS_SHORT:
	    case TS_USHORT:
		r = vrget();
		r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		code00(P_MOVE, r->Vrloc, n->Nid->Sreg);
		codr1(P_ADD, n->Nid->Sreg,((inc > 0)? 1 : -1));
		break;
	    default:
		int_error("gincdec: bad reg type %N", n);
		return NULL;
	    }
	}
    else
	switch (n->Ntype->Tspec)
	    {
	    case TS_FLOAT:
		r = vrget();
		r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		code9(P_MOVE, r, (inc > 0 ? 1.0 : -1.0), 0);
		code4(P_FADR+POF_BOTH, r, gaddress(n));
		if (!pre)
		    code9(P_FSBR, r, (inc > 0 ? 1.0 : -1.0), 0);
		break;

	    case TS_DOUBLE:
	    case TS_LNGDBL:
		r = vrdget();
		r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		if ((savaddr = sideffp(n)) != 0) /* See if lvalue has side effects */
		    {
		    ra = gaddress(n);		/* Yes, make address first */
		    code9(P_DMOVE, r, (inc > 0 ? 1.0 : -1.0), 1);
		    codek4(P_DFAD, r, ra);	/* Do op, keep address reg around */
		    code4(P_DMOVEM, r, ra);
		    }
		else
		    {
		    code9(P_DMOVE, r, (inc > 0 ? 1.0 : -1.0), 1);
		    code4(P_DFAD, r, gaddress(n));
		    code4(P_DMOVEM, r, gaddress(n));
		    }
		if (!pre)
		    code9(P_DFSB, r, (inc > 0 ? 1.0 : -1.0), 1);
		break;

	    case TS_PTR:			/* Hacking pointer? */
		size = sizeptobj(n->Ntype);	/* Find size of obj */
		if (!size)
		    int_error("gincdec: 0-size obj %N", n);
		if (tisbytepointer(n->Ntype))	/* Special if a (char *) */
		    {
		    if (inc < 0)
			size = -size;
		    if ((savaddr = sideffp(n)) != 0) /* See addr has side effs */
			ra = gaddress(n);		/* Ugh, find & save it */
		    r = vrget();
		    r->Vrtype = n->Ntype;		/* Set C type of obj in reg */

		/* If doing post-increment, save orig pointer value */
		    if (!pre)
			{
			r2 = vrget();
			r->Vrtype = n->Ntype;	/* Set C type of obj in reg */
			if (savaddr)
			    codek4(P_MOVE, r2, ra);	/* Save ptr */
			else
			    code4(P_MOVE, r2, gaddress(n));
			}

		/* Now perform the increment.  If the address of the pointer
		** was saved in ra, it is released in this process.  r has
		** a copy of the new pointer value.
		*/
		    if (size == 1)		/* Special case */
			{
			if (savaddr)
			    codek4(P_IBP, 0, ra);
			else
			    code4(P_IBP, (VREG *)NULL, gaddress(n));
			if (pre)			/* If will need val, get it. */
			    code4(P_MOVE, r, (savaddr ? ra : gaddress(n)));
			}
		    else			/* General case */
			{
			code1(P_MOVE, r, size);	/* get how much */
			if (savaddr)
			    codek4(P_ADJBP, r, ra);
			else
			    code4(P_ADJBP, r, gaddress(n));
			code4(P_MOVEM, r,		/* store back in memory */
				    (savaddr ? ra : gaddress(n)));
			}

		/* Now, if doing postincrement, flush r and use r2 instead */
		    if (!pre)
			{
			vrfree(r);
			r = r2;
			}
		    break;		/* Break out to return R */
		    }
	    /* Drop through to handle non-char pointer as integer */


	    case TS_ENUM:
	    case TS_INT:
	    case TS_UINT:
	    case TS_LONG:
	    case TS_ULONG:
		r = vrget();
		r->Vrtype = n->Ntype;	/* Set C type of obj in reg */
		if (size == 1)
		    code4((inc > 0 ? P_AOS : P_SOS), r, gaddress(n));
		else				/* inc/dec by non-1 integer */
		    {
		    code1(P_MOVE, r, (inc > 0 ? size : -size));
		    code4(P_ADD+POF_BOTH, r, gaddress(n));
		    }
		if (!pre)			/* For postincrement, undo reg */
		    code1((inc > 0 ? P_SUB : P_ADD), r, size); /* undo change */
		break;

	    case TS_BITF:
	    case TS_UBITF:
	    case TS_CHAR:
	    case TS_UCHAR:
	    case TS_SHORT:
	    case TS_USHORT:
		if (inc < 0)
		    size = -size;
		savaddr = sideffp(n);       /* See if addr has side effs */
		ra = gaddress(n);		/* Ugh, find & save it */
	    /* Fetch byte, save addr if savaddr != 0 */
		r = getmem(ra, n->Ntype, 1, savaddr);

		code1(P_ADD, r, size);	/* Add inc/dec value */

	    /* Now store byte back */
		if (!savaddr)
		    ra = gaddress(n);	/* else, re-use ra */
		stomem(r, ra, 1, 1);

		if (!pre)				/* For postfix, undo reg */
		    code1(P_SUB, r, size);		/* undo change */
		break;

	    default:
		int_error("gincdec: bad type %N", n);
		return NULL;
	    }
    if (volat)
	flushcode();		/* Finish up after volatile obj */
    return r;
}

/* GPRIMARY - Generate primary expression.
**
** This handles all primary expressions, which are composed of node ops
**	N_FNCALL,
**	Q_DOT,		(may be lvalue)
**	Q_MEMBER,	(always lvalue)
**	Q_IDENT,	(always lvalue)
**	N_ICONST, N_FCONST, N_PCONST, N_SCONST, N_VCONST, Q_ASM.
** The first three of those are not terminal nodes and may have further
** sub-expressions.
** Note that array subscripting is done as pointer arithmetic rather than
** using a specific operator.  Similarly, parenthesized expressions have
** no specific op since the parse tree structure reflects any parenthesizing.
**	This is where array and function names are caught and turned into
** pointers instead.  Arrays and functions are the only Q_IDENTs for which
** the node type (Ntype) is different from the symbol type (Stype)!  The
** symbol type will have the actual type of the name, whereas the node type
** will be that of "pointer to <Stype>".
**	Note special checking for fetching a value from "volatile"-qualified
** lvalues.  There are only four nodes that can be lvalues -- the three above,
** plus N_PTR which is handled in gunary().  Storing into those lvalues is
** handled by gassign() and gincdec().  Because the peephole optimizer is
** such a mess, we can't easily tell it to avoid volatile objects; instead
** we simply flush out all peephole code before and after generating the
** fetch from (or store into) a volatile object!  Crude, but should work.
*/
static VREG *
gprimary(NODE *n)
{
    VREG *q, *r;
    INT siz;
    int volat, t;

    switch (n->Nop)
	{

	case Q_IDENT:		/* Variable name */
	    if ((t = n->Nid->Stype->Tspec) == TS_FUNCT || t == TS_ARRAY )
		{
	   /* Check for funct/array. Make sure Ntype is ptr */
		if (n->Ntype->Tspec != TS_PTR)
/* Later make this error again */
		    int_warn("gprimary: array/funct %N", n);
		return gaddress(n);	/* Yup, just return ptr to object */
		}
	/* Normal variable or structure/union */
	    if ((volat = tisanyvolat(n->Ntype)) != 0)
		flushcode();		/* If volatile, avoid optimization */

	    if (Register_Id(n))	/* approximate getmem() for registers */
#if 0
		r = rgetmem(gaddress(n), n->Ntype, tisbyte(n->Ntype), 0);
#else
		r = rgetmem(gaddress(n), n->Ntype, 0);
#endif
	    else
		r = getmem(gaddress(n), n->Ntype, tisbyte(n->Ntype), 0);

	    if (volat)
		flushcode();
	    return r;

	case N_SCONST:		/* Literal string - get char pointer to it */
	    n->Nsclab = newlabel();
	    n->Nscnext = litstrings;	/* link on string stack */
	    litstrings = n;			/* include this one */
	    r = vrget();
	    r->Vrtype = n->Ntype;		/* Set C type of object in reg */
	/* Get byte ptr to str, using given bytesize of type! */
	    code10(P_MOVE, r, n->Nsclab, elembsize(n->Ntype), 0);
	    return r;

	case N_VCONST:		/* Void "constant" */
	    return NULL;		/* No register used! */
	case N_ICONST:		/* Integer constant */
	case N_PCONST:		/* Pointer constant uses same cell etc */
	    r = vrget();
	    r->Vrtype = n->Ntype;	/* Set C type of object in reg */
	    code1(P_MOVE, r, n->Niconst);
	    return r;

	case N_FCONST:		/* Floating-point constant */
	    switch (n->Ntype->Tspec)
		{
		case TS_FLOAT:
		    r = vrget();
		    r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		    code9(P_MOVE, r, n->Nfconst, 0);
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    r = vrdget();
		    r->Vrtype = n->Ntype;	/* Set C type of object in reg */
		    code9(P_DMOVE, r, n->Nfconst, 1);
		    break;
		}
	    return r;

	case Q_ASM:
	    gasm(n);
	    return NULL;		/* Currently never returns anything */

	case N_FNCALL:		/* Function call */
	    return gcall(n);

	case Q_DOT:			/* (). direct component selection */
	    if (!(n->Nleft->Nflag & NF_LVALUE))
		break;		/* Ugh, do hairy stuff if not lvalue! */

	    if ((debcsi == KCC_DBG_NULL) && (n->Nleft->Nop == Q_MEMBER))
		{
		_chnl = n->Nleft->sfline;
		if (n->Nleft->Nleft->Nop == N_CAST)
		    code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft->Nleft));
		else
		    code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft));
		}

	/* OK, fall thru to handle like Q_MEMBER */

	case Q_MEMBER:		/* ()-> indirect component selection */
	    if ((volat = tisanyvolat(n->Ntype)) != 0)
		flushcode();		/* Ugh, avoid optimiz of volatile */

#if 0 /* KAR-1/92, leaving this as #if 0 in case I need it later */
	    if ((debcsi == KCC_DBG_NULL) && (n->Nop == Q_MEMBER))
		{
		_chnl = n->sfline;
		code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft));
		}
#endif

	    if (Register_Id(n))	/* approximate getmem() for registers */
#if 0
		r = rgetmem(gaddress(n), n->Ntype,
			    (n->Nxoff < 0) || tisbyte(n->Ntype), 0);
#else
		r = rgetmem(gaddress(n), n->Ntype, 0);
#endif
	    else
		r = getmem(gaddress(n), n->Ntype,
			    (n->Nxoff < 0) || tisbyte(n->Ntype), 0);
	    if (volat)
		flushcode();
	    return r;

	case Q_MUUO:
	    return gmuuo(n);

	default:
	    int_error("gprimary: bad op %N", n);
	    return NULL;
	}

    /* Hairy stuff for Q_DOT of something that isn't an lvalue.
    ** This can only happen for a struct returned from a function call.
    ** The structure resulting from the expression will either be
    ** completely contained in the registers (if size <= 2) or the register
    ** will contain the structure address.
    */
    if ((siz = sizetype(n->Nleft->Ntype)) > 2)	/* Find # wds in it */
	/* Fake out gaddress into using genexpr instead of another gaddress
	** when evaluating the structure expression, since result will
	** be a pointer.
	*/
	{
	n->Nop = Q_MEMBER;

	if (Register_Id(n))	/* approximate getmem() for registers */
#if 0
	    return rgetmem(gaddress(n), n->Ntype,
			(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
#else
	    return rgetmem(gaddress(n), n->Ntype, 0);
#endif
	else
	    return getmem(gaddress(n), n->Ntype,
			(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
	}

    /* Pull component out of structure in 1- or 2-word register */
    r = genexpr(n->Nleft);	/* Get the structure */
    switch (n->Nxoff)		/* See which part of it we want */
	{
	case 0:			/* Want first word? */
	    if (siz == 2 && sizetype(n->Ntype) == 1)
		vrnarrow(r);	/* Keep 1st word of a 2-word value */
	    return r;
	case 1:			/* Want second word? */
	    vrnarrow(r = VR2(r)); /* Keep second word of a 2-word value */
	    return r;

	default:			/* Bitfield of some kind */
	/* NOTE: This generates a very uncommon use of PTA_BYTEPOINT
	** wherein the E field of the byte pointer is actually a register
	** address.  This is why vrreal() is called, to get the
	** actual register number.  As long as this is one of the return-value
	** registers as it should be, this usage is probably safe from
	** the peephole optimizer.
	*/
	    q = vrget();		/* Get another register */
	    q->Vrtype = n->Ntype;	/* Set C type of object in reg */
	    (void) vrstoreal(q, r);	/* Make sure both regs are active! */
	    codebp(P_LDB, vrreal(q), (unsigned)((- (n->Nxoff)) & 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -