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

📄 ccgen2.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
{
    VREG *r;
    int volat;

    switch (n->Nop)
	{
	case N_PREINC:
	    return gincdec(n,  1, 1);
	case N_PREDEC:
	    return gincdec(n, -1, 1);
	case N_POSTINC:
	    return gincdec(n,  1, 0);
	case N_POSTDEC:
	    return gincdec(n, -1, 0);

	case N_CAST:
	    return gcast(n);
	case N_ADDR:
	    return gaddress(n->Nleft);

	case N_PTR:
	/* See comments at gprimary() about volatile objects. */
	    if ((volat = tisvolatile(n->Ntype)) != 0)
		flushcode();		/* Obj is volatile, avoid optimiz */

	    if (debcsi == KCC_DBG_NULL)
		{
		_chnl = n->sfline;
		switch (n->Nleft->Nop)
		    {
		    case Q_IDENT:
			code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft));
			break;
		    case N_PREINC:
		    case N_PREDEC:
		    case N_POSTINC:
		    case N_POSTDEC:
			code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft));
			break;
		    default:
			_chnl = -1;
			break;
		    }
		}

	/* Special check for doing ILDB.  Safer to do here instead of
	** in peephole, at least until peepholer fixed to allow keeping
	** an index reg around!
	*/
	    if (Register_Id(n->Nleft))
		{
#if 0	/* Reg linkage */
		if (optgen && tisbytepointer(n->Nleft->Ntype)) /* if byte ptr */
		    {
		    r = vrget();
		    r->Vrtype = n->Ntype; /* Set C type of object in reg */
		    if (n->Nleft->Nop == N_PREINC)	/* "*++(reg)" */
			code0 (P_ILDB, r, gaddress (n->Nleft->Nleft));
#if 0	/* add when LDBI, LDBD, and DLDB are defined here, below, and in 
	 * gassign() for case N_PTR:
	 */
		    else if (n->Nleft->Nop == N_PREDEC)	/* "*--(reg) */
			code0 (P_DLDB, r, gaddress (n->Nleft->Nleft));
		    else if (n->Nleft->Nop == N_POSTINC)	/* "*(reg)++" */
			code0 (P_LDBI, r, gaddress (n->Nleft->Nleft));
		    else if (n->Nleft->Nop == N_POSTDEC)	/* "*(reg)--" */
			code0 (P_LDBD, r, gaddress (n->Nleft->Nleft));
		    else if (n->Nleft->Nop == NULL)
			code0 (P_LDB, r, gaddress (n->Nleft->Nleft));
#endif
		    else	/* approximate getmem() for registers */
#if 0
			r = rgetmem(genexpr(n->Nleft), n->Ntype,
				    tisbytepointer(n->Nleft->Ntype), 0);
#else
			r = rgetmem(genexpr(n->Nleft), n->Ntype, 0);
#endif
		    }
		else		/* approximate getmem() for registers */
#endif
#if 0
		    r = rgetmem(genexpr(n->Nleft), n->Ntype,
			    tisbytepointer(n->Nleft->Ntype), 0);
#else
		    r = rgetmem(genexpr(n->Nleft), n->Ntype, 0);
#endif
		}
	    else 
	/* if "*++(exp)" of a byte pointer */ if (optgen && tisbytepointer(n->Nleft->Ntype) &&
		    n->Nleft->Nop == N_PREINC)
		{
		r = vrget();
		r->Vrtype = n->Ntype; /* Set C type of object in reg */
		code4 (P_ILDB, r, gaddress(n->Nleft->Nleft));
		}
	    else
		r = getmem(genexpr(n->Nleft), n->Ntype,
				    tisbytepointer(n->Nleft->Ntype), 0);
	    if (volat)
		flushcode();
	    return r;

	case Q_MUUO:
	    return gmuuo(n);

	case N_NEG:
	    if (Register_Id(n->Nleft))
		{
#if 0
		if ( n->Ntype->Tspec == TS_DOUBLE
			|| n->Ntype->Tspec == TS_LNGDBL)
		    {
		    r = vrdget();
		    r->Vrtype = n->Nleft->Ntype;
		    code00(P_DMOVN, r->Vrloc, n->Nleft->Nid->Sreg);
		    }
		else
#endif
		    {
		    r = vrget();
		    r->Vrtype = n->Nleft->Ntype;
		    code00(P_MOVN, r->Vrloc, n->Nleft->Nid->Sreg);
		    }
		return r;
		}
	    r = genexpr(n->Nleft);
	    if ( n->Ntype->Tspec == TS_DOUBLE
		    || n->Ntype->Tspec == TS_LNGDBL)
		code0(P_DMOVN, r, r);
	    else
		code0(P_MOVN, r, r);
	    return r;

	case Q_COMPL:
	    if (Register_Id(n->Nleft))
		{
		r = vrget();
		r->Vrtype = n->Nleft->Ntype;
		code00(P_SETCM, r->Vrloc, n->Nleft->Nid->Sreg);
		return r;
		}

	    r = genexpr(n->Nleft);
	    code0(P_SETCM, r, r);
	    return r;

	default:
	    int_error("gunary: bad op %N", n);
	    return 0;
	}
}

/* GCAST - Generate code for type conversion (cast)
**
**	Note that the way we manage the task of keeping char values
** masked off is NOT by implementing a mask for casts to (char) type.
** Rather, we mask the register value only when widening.  This works
** because a value of type (char) is always either assigned to a (char) object
** (in which case a byte pointer is used and the mask is automatic) or
** it is used in an expression -- and always promoted to an int or u_int.
** The masking would be wasteful and unnecessary for the first case, and
** the second case will always have an explicit N_CAST to widen the integer.
** See the INTERN.DOC file for a better explanation.
*/

static VREG *
gcast(NODE *n)
{
    VREG *r;
    /* If this expression is a return value, see if we can pass on
    ** the flag which marks it thusly.  This basically benefits
    ** gcall() which uses the flag to do tail recursion; we want to ensure
    ** that a no-op cast won't prevent this optimization.
    */
    if ((n->Nflag & NF_RETEXPR)		/* This expr is a return val? */
	&& gcastr(n->Ncast, (VREG *)NULL,	/* and cast is a no-op? */
			n->Nleft->Ntype, n->Ntype, n->Nleft) == NULL)
	{
	n->Nleft->Nflag |= NF_RETEXPR;	/* Yes, pass flag on! */
	if ((r = genexpr(n->Nleft)) != NULL) /* No cast, just generate expr */
	    r->Vrtype = n->Ntype;	/* and reflect correct type */
	return r;
	}

    return gcastr(n->Ncast, genexpr(n->Nleft),
			n->Nleft->Ntype, n->Ntype, n->Nleft);
}

static VREG *
gcastr(cop, r, tfrom, tto, ln)
int cop;	/* Cast op (a CAST_ value) */
VREG *r;	/* Virtual reg holding value to cast.
		** NOTE NOTE NOTE!!!  If this is NULL, we are merely testing
		** to see whether a cast would be produced.  If there is
		** no cast, NULL will be returned, else (VREG *)-1.
		*/
TYPE *tfrom, *tto;
NODE *ln;	/* If non-null, is node that R was generated from. */
{
    switch (cop)
	{
	case CAST_NONE:		/* No actual action required */
	    break;

	case CAST_VOID:		/* Throwing away the value */
	    if (r)
		relflush(r);	/* Release the register */
	    return NULL;

	case CAST_IT_PT:
	    if (!r)					/* Just checking? */
		return gintwiden(r, tfrom, uinttype, ln);
	    else
		r = gintwiden(r, tfrom, uinttype, ln); /* Widen int to uint */
	    break;

	case CAST_IT_EN:
	case CAST_IT_IT:
	    if (!r)					/* Just checking? */
		return gintwiden(r, tfrom, tto, ln);
	    else
#if 0	/* Later, Reg linkage */	
	    if (Register_Nopreserve (r->Vrloc) && unsigned)
#endif
		r = gintwiden(r, tfrom, tto, ln); /*Widen integer if needed */
	    break;

	case CAST_EN_EN:
	case CAST_EN_IT:
	case CAST_PT_IT:			/* No representation change needed */
	    break;

	case CAST_PT_PT:			/* General ptr to ptr conversion */
	    if (tisbytepointer(tfrom))
		{
		if (tisbytepointer(tto))
		    {
		/* Byte pointer to byte pointer, check sizes */
		    int fsiz = elembsize(tfrom);
		    int tsiz = elembsize(tto);
		    if (!fsiz)
			{
		    /* (void *) to byte pointer. */
			if (tischarpointer(tto))	/* If any kind of char obj, */
			    break;			/* do no conversion. */
			fsiz = TGSIZ_CHAR;		/* Else cvt as if (char *) */
			}
		    if (!tsiz)
			{
		    /* Byte pointer to (void *) */
			if (tischarpointer(tfrom))	/* If any kind of char obj, */
			    break;			/* do no conversion. */
			tsiz = TGSIZ_CHAR;		/* Else cvt as if (char *) */
			}
		    if (fsiz == tsiz)
			break;	/* No conversion needed? */

		    if (!r)
			return (VREG *)-1;	/* Need, stop if just chking */

		/* If converting between char and short
		** (9 and 18 bit bytes), use special op.
		*/
		    if (   (fsiz == TGSIZ_CHAR && tsiz == TGSIZ_SHORT)
			|| (fsiz == TGSIZ_SHORT && tsiz == TGSIZ_CHAR))
			{
			code10(P_PTRCNV, r, (SYMBOL *)NULL, tsiz, fsiz);
			break;
			}

		/* Odd size, convert to word pointer, then to byte pointer. */
		    code10(P_TDZ+POF_ISSKIP+POS_SKPE,	/* Check for NULL */
			r, (SYMBOL *)NULL, -1, 0);	/* Mask off P+S */
		    code10(P_IOR, r, (SYMBOL *) NULL, tsiz, 0);	/* make BP */
		    }
		else
		    {
		/* Byte pointer (any kind!) to word pointer */
		    if (!r)
			return (VREG *)-1;	/* Stop if just checking. */
		    code10(P_TDZ, r, (SYMBOL *) NULL, -1, 0); /* Mask off P+S */
		    }
		}
	    else if (tisbytepointer(tto))
		{
		int tsiz;
		/* Word pointer to byte pointer */
		if (!r)
		    return (VREG *)-1;	/* Stop if just checking. */
		if ((tsiz = elembsize(tto)) == 0)   /* Check for (void *) */
		    tsiz = TGSIZ_CHAR;
		pitopc(r, tsiz, 0, 0);
		}
	    break;

	case CAST_FP_IT:
	    if (!r)
		return (VREG *)-1;	/* Stop if just checking. */
	    switch (tfrom->Tspec)
		{
		case TS_FLOAT:
		    code0(P_FIX, r, r);	/* just use that! */
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    code0(P_DFIX, r, r);	/* r must be a register pair */
		    vrnarrow(r);		/* Use 1st AC as result */
		    break;
		}
	/* Narrow the int here if needed */
	    break;

	case CAST_FP_FP:
	    switch (castidx(tfrom->Tspec,tto->Tspec))
		{
		case castidx(TS_DOUBLE,TS_FLOAT):
		case castidx(TS_LNGDBL,TS_FLOAT):
		    if (!r)
			return (VREG *)-1;	/* Stop if just checking. */
		    code0(P_DSNGL, r, r);	/* r must be a register pair! */
		    vrnarrow(r);		/* Forget about the second word */
		    break;
		case castidx(TS_FLOAT,TS_DOUBLE):
		case castidx(TS_FLOAT,TS_LNGDBL):
		    if (!r)
			return (VREG *)-1;	/* Stop if just checking. */
		    vrlowiden(r);
		    code5(P_SETZ, VR2(r));
		    break;
		case castidx(TS_LNGDBL,TS_DOUBLE):
		case castidx(TS_DOUBLE,TS_LNGDBL):
		    break;
		}
	    break;

	case CAST_IT_FP:
	    if (!r)
		return (VREG *)-1;	/* Stop if just checking. */
	    r = gintwiden(r, tfrom,		/* Ensure widened to int or unsigned */
		    tissigned(tfrom) ? inttype : uinttype,
		    ln);
	    switch (tto->Tspec)
		{
		case TS_FLOAT:
		/* Although FLTR and UFLTR are always supported by CCOUT,
		** on KA-10s they are inefficient enough that it is worth
		** checking for the opportunity to use a simple FSC, which
		** is limited to integers of 27 bits or less.
		*/
		    if (tissigned(tfrom) || tbitsize(tfrom) < TGSIZ_WORD)
			{
		    /* Signed or known positive */
			code0(P_FLTR, r, r); /* Use FLTR instr or macro */
			break;
			}
		/* Ugh, unsigned full word value, must use hairy UFLTR. */
		    code0(P_UFLTR, r, r); /* Use UFLTR simulated op */
		    break;

		case TS_DOUBLE:
		case TS_LNGDBL:
		    vrlowiden(r);	/* Make into register pair */
		    code5(P_SETZ, VR2(r)); /* zero the next reg */
		    if (tissigned(tfrom) || tbitsize(tfrom) < TGSIZ_WORD)
			{
			code8(P_ASHC, r, -8); /* shift out mantissa*/
			code8(P_TLC, r, 0243000L); /* put exponent in */
			}
		    else			/* Unsigned conversion */
			{
			code8(P_LSHC, r, -9);		/* Shift unsigned */
			code8(P_LSH, VR2(r), -1); /* Fix up lo wd */
			code8(P_TLC, r, 0244000L); /* exp (note 1 bigger!) */
			}
		    code9(P_DFAD, r, 0.0, 1);	/* Normalize the result */
		    break;
		}
	    break;

	default:
	    int_error("gcastr: bad cast %d", cop);
	    return NULL;
	}

    /* Cast done, now set new type of object in virtual register! */
    if (r)
	r->Vrtype = tto;
    return r;
}

/* GINTWIDEN and GUINTWIDEN - Auxiliaries for GCAST to widen integral values.
**	Always widens to full word even if new type is smaller, because
**	it's just as easy and makes no difference to handling of new type.
** NOTE: treats a VREG arg of NULL just as gcastr() does, i.e. only checks
**	to see whether a conversion would be necessary or not.
** GUINTWIDEN is a subroutine just so gboolean() can invoke it to force
**	an unsigned-type widen.
*/
static VREG *
gintwiden(VREG *r, TYPE *tfrom, TYPE *tto, NODE *n)		
/* Node that R was generated from (if any) */
{
    if (tbitsize(tto) > tbitsize(tfrom))
	{
	if (tisunsign(tfrom))	/* Handle unsigned.  Easy, just mask off */
	    {
	    r = guintwiden(r, tbitsize(tfrom), n);
	    }
	else		/* Handle signed.  Harder, must test bit. */
	    {
	    if (!r)
		return (VREG *)-1;		/* Stop if just checking. */
	    if (tbitsize(tfrom) == TGSIZ_HALFWD)	/* Special case */
		{
		code0(P_HRRE, r, r);		/* Extend sign of halfwd */
		return r;
		}
	    code8(P_TRN+POF_ISSKIP+POS_SKPE, r, (1<<(tbitsize(tfrom)-1)));
	    code8(P_TRO+POF_ISSKIP+POS_SKPA, r, -(1 << tbitsize(tfrom)));
	    code1(P_AND, r, (1 << tbitsize(tfrom))-1);	/* Positive, zap! */
	    }
	}
    return r;
}

static VREG *
guintwiden(VREG *r, int fbitsize, NODE *n)
/* # bits of value in R and Node that R was generated from (if any) */
{
    /* Must zap high-order bits.  Try to avoid doing this by
    ** seeing whether those bits are known to already be zero.
    ** Primary case is that of an LDB data fetch.
    */
    if (!(n &&
      (bptrref(n) > 0			/* Win if LDB fetch */
      || (n->Nop == Q_ASGN		/* Or if an assignment of a */
	&& bptrref(n->Nright) > 0	/* LDB also of safe size */
	&& tbitsize(n->Nright->Ntype) <= fbitsize))) )

⌨️ 快捷键说明

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