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

📄 ccgen2.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
	    return;

	case Q_LAND:
	    if (reverse)
		gor(n, false, reverse); /* more tail recursion */
	    else
		gand(n, false, reverse);
	    return;

	case Q_LOR:
	    if (reverse)
		gand(n, false, reverse); /* still more */
	    else
		gor(n, false, reverse);
	    return;

	case Q_NEQ:
	case Q_LEQ:
	case Q_GEQ:
	case Q_LESS:
	case Q_GREAT:
	case Q_EQUAL:
	    gboolop(n, reverse);		/* comparison, make skip */
	    break;				/* followed by GOTO */

	case N_ICONST:
	case N_PCONST:
	    op = n->Niconst;		/* unconditional condition */
	    if (reverse && op)
		break;	/* jump when true and true? */
	    if (!reverse && !op)
		break;	/* jump when false and false? */
	    return;

	default:
	    n->Nendlab = NULL;	/* cond endlab is not expr endlab */
	    if ((r = genexpr(n)) != NULL)	/* get expression into reg (may be discarded)*/
		{
		int bits = tbitsize(n->Ntype);	/* Find # bits of value */
		if (bits < TGSIZ_WORD)		/* If not full wd, then */
		    r = guintwiden(r, bits, n);	/* widen it unsignedly! */
		code6(reverse? P_JUMP+POS_SKPN : P_JUMP+POS_SKPE,
			    r, false);	/* test and jump */
		vrfree(r);			/* now done with register */
		}
	    return;				/* don't make spurious P_JRST */
	}
    code6(P_JRST, (VREG *)NULL, false);	/* broke out, want a GOTO */
}

/* GOR - Generate || expression
*/
static void
gor(NODE *n, SYMBOL *false, int reverse)
{
    SYMBOL *lab;

    if ((lab = n->Nendlab) == 0)
	lab = newlabel(); /* get label */
    gboolean(n->Nleft, lab, !reverse);	/* output first clause */
    n->Nright->Nendlab = lab;		/* no more labels in second clause */
    gboolean(n->Nright, false, reverse);
    if (n->Nendlab == 0)
	codlabel(lab); /* send out made label */
}

/* GAND - Generate && expression
*/
static void
gand(NODE *n, SYMBOL *false, int reverse)
{
    n->Nright->Nendlab = n->Nendlab;
    gboolean(n->Nleft, false, reverse);
    gboolean(n->Nright, false, reverse);
}

/* GBOOLOP - Generate code for == > < <= >= !=
**
*/
static void
gboolop(NODE *n, int reverse)
{
    int op;
    VREG *r1, *r2;

    /*
    ** Generate operands and skip instruction for the test
    **
    ** Note that floating point can use the same comparison
    ** instructions as integers, so we don't have to test for them.
    */

    switch (n->Nop)
	{
	case Q_EQUAL:
	    op = P_CAM+POF_ISSKIP+POS_SKPE;
	    break;
	case Q_NEQ:
	    op = P_CAM+POF_ISSKIP+POS_SKPN;
	    break;
	case Q_LEQ:
	    op = P_CAM+POF_ISSKIP+POS_SKPLE;
	    break;
	case Q_GEQ:
	    op = P_CAM+POF_ISSKIP+POS_SKPGE;
	    break;
	case Q_LESS:
	    op = P_CAM+POF_ISSKIP+POS_SKPL;
	    break;
	case Q_GREAT:
	    op = P_CAM+POF_ISSKIP+POS_SKPG;
	    break;
	}

    /* May need to munch on char pointers to get into comparable form */
    switch (n->Nop)
	{
	case Q_LEQ:
	case Q_GEQ:
	case Q_LESS:
	case Q_GREAT:
	    if (tisunsign(n->Nleft->Ntype))	/* If operands are unsigned */
		{
		r1 = genexpr(n->Nleft);		/* Get operand 1 */
		code8(P_TLC, r1, 0400000L);	/* and flip sign bit */
		r2 = genexpr(n->Nright);	/* Ditto for operand 2 */
		code8(P_TLC, r2, 0400000L);
		break;
		}
	    else if (tisbytepointer(n->Nleft->Ntype))
		{
		/* If operands are byte pointers */
		/* Note that:
		** OWGBPs can omit the SKIP+TLC, or use this:
		**	MOVE R,PTR1
		**	SUB R,PTR2
		**	ROT R,6
		**	CAIx R,0
		** Local-fmt BPs can use the sequence:
		**	MOVE R,PTR1
		**	MOVE R+1,PTR2	; Needs double reg
		**	ROTC R,6	; Yes this really works!
		**	CAMx R,R+1
		*/
		r1 = genexpr(n->Nleft);		/* Get operand 1 */
		code0(P_SKIP+POF_ISSKIP+POS_SKPL, r1, r1);
		code8(P_TLC, r1, 0770000L);	/* Zap P bits if local */
		code8(P_ROT, r1, 6);		/* Get P or PS into low bits */

		/* Repeat for 2nd operand */
		r2 = genexpr(n->Nright);	/* Get operand 2 */
		code0(P_SKIP+POF_ISSKIP+POS_SKPL, r2, r2);
		code8(P_TLC, r2, 0770000L);	/* Zap P bits if local */
		code8(P_ROT, r2, 6);		/* Get P or PS into low bits */

		/* Now can compare the registers with normal CAM! */
		break;
		}
	    /* Else just fall through for normal expression evaluation */

	case Q_EQUAL:
	case Q_NEQ:
	    r1 = genexpr (n->Nleft);	/* calculate values to compare */
	    r2 = genexpr (n->Nright);
	    break;
	}

    if (reverse)
	op = revop (op);	/* maybe invert test */

    /*
    ** Generate and optimize the test.
    **
    ** If we are comparing double precision floating point we need
    ** to look at both pairs of words, so we use a cascaded pair or
    ** trio of comparisons.
    */

    if (   n->Nleft->Ntype->Tspec == TS_DOUBLE
	|| n->Nleft->Ntype->Tspec == TS_LNGDBL )
	{
	switch (op)
	    {
	    case P_CAM+POF_ISSKIP+POS_SKPL:
		flushcode();		/* don't confuse peepholer */
		code0(P_CAM+POF_ISSKIP+POS_SKPL, r1, r2);
		code0(P_CAM+POF_ISSKIP+POS_SKPGE, VR2(r1), VR2(r2));
		op = P_CAM+POF_ISSKIP+POS_SKPLE;
		break;
	    case P_CAM+POF_ISSKIP+POS_SKPLE:
		flushcode();		/* don't confuse peepholer */
		code0(P_CAM+POF_ISSKIP+POS_SKPL, r1, r2);
		code0(P_CAM+POF_ISSKIP+POS_SKPG, VR2(r1), VR2(r2));
		break;
	    case P_CAM+POF_ISSKIP+POS_SKPG:
		flushcode();		/* don't confuse peepholer */
		code0(P_CAM+POF_ISSKIP+POS_SKPG, r1, r2);
		code0(P_CAM+POF_ISSKIP+POS_SKPLE, VR2(r1), VR2(r2));
		op = P_CAM+POF_ISSKIP+POS_SKPGE;
		break;
	    case P_CAM+POF_ISSKIP+POS_SKPGE:
		flushcode();		/* don't confuse peepholer */
		code0(P_CAM+POF_ISSKIP+POS_SKPG, r1, r2);
		code0(P_CAM+POF_ISSKIP+POS_SKPL, VR2(r1), VR2(r2));
		break;
	    case P_CAM+POF_ISSKIP+POS_SKPE:
		code0(P_CAM+POF_ISSKIP+POS_SKPN, VR2(r1), VR2(r2));
		break;
	    case P_CAM+POF_ISSKIP+POS_SKPN:
		code0(P_CAM+POF_ISSKIP+POS_SKPN, VR2(r1), VR2(r2));
		code0(P_CAM+POF_ISSKIP+POS_SKPE, r1, r2);
		code5(P_TRN+POF_ISSKIP+POS_SKPA, 0);
		vrfree(r1);
		return;
	    }
	}
    code0(op, r1, r2);			/* generate and optimize test */
    vrfree(r1);
}

/* GASSIGN - Generate assignment expression.
**	Various tricky stuff involved.
** Note the hair needed for handling compound assignment, because the f*ed-up
** peepholer zaps index registers with wild abandon.  We have to compensate
** for this by being careful how we generate the address of the destination.
**
** Also note hair for storing into volatile objects!  This is the counterpart
** to the fetch checking in gprimary() and gunary().  The other store code is
** in gincdec().
*/

static VREG *
gassign(NODE *n)
{
    VREG *r1, *r2, *ra;
    int ptr, savaddr;
    INT siz;
    NODE *nod;		/* Points to lvalue (without conversion) */
    int lconv;		/* Holds lvalue conversion op if any */
    int volat;		/* True if obj is volatile */
    TYPE *fromt, *tot;

    nod = n->Nleft;
    if (nod->Nop == N_CAST)	/* If lvalue needs conversion before the op */
	{
	lconv = nod->Ncast;	/* Remember conversion op for lvalue */
	tot = nod->Ntype;	/* cast to this type */
	nod = nod->Nleft;	/* Then get ptr to real lvalue */
	fromt = nod->Ntype;	/* cast from this type */
	}
    else
	lconv = CAST_NONE;

    siz = sizetype(n->Ntype);	/* Get size of result type, in words */

    /* See if object will be referenced via a byte pointer */
    if ((ptr = bptrref(nod)) < 0)
	{
	int_error("gassign: bad op %N", nod);
	ptr = 0;
	}
    if ((volat = tisanyvolat(nod->Ntype)) != 0)
	flushcode();		/* Barf, foil peepholer if volatile obj */

    if (n->Nop == Q_ASGN)	/* Simple assignment? */
	{
	r1 = genexpr(n->Nright);	/* Generate value first */
	/* Special check for doing IDPB.  Safer to do here instead of
	** in peephole, at least until peepholer fixed to allow keeping
	** an index reg around!
	*/
#if 0
/* Later, add many cases here when new MACRO instructions are defined.
 * Imitate case N_PTR: in gunary() below.
 */
#endif
	if (optgen && ptr			/* If a byte ptr */
		&& nod->Nop == N_PTR		/* and op is "*++(exp)" */
		&& nod->Nleft->Nop == N_PREINC)
	    {
#if 0		/* Later, fix Reg linkage for pointers */
	    if (Register_Id(nod->Nleft->Nleft))
		code40(P_IDPB, r1->Vrloc, nod->Nleft->Nleft->Nid->Sreg, 0);
	    else
#endif
		code4(P_IDPB, r1, gaddress(nod->Nleft->Nleft));
	    return r1;
	    }
	else if (Register_Id(nod))	/* approximate stomem for registers */
	    {
	    r_preserve = nod->Nid->Sreg;
	    if (siz == 1)
		{
		ra = vrget();
		ra->Vrtype = nod->Ntype;
		code00(P_MOVE, ra->Vrloc, r1->Vrloc);
		}
	    else
		int_error ("gassign: reg argument size > 1");
	    vrfree (r1);
	    return ra;
	    }
	else
	    r1 = stomem(r1,		/* Store the value */
		gaddress(nod),		/* into address of lvalue */
		/* Operand and operation types are same, so siz is correct */
		siz,
		ptr);			/* and flag saying if addr is ptr */
	if (volat)
	    flushcode();
	return r1;
	}

    /* Some compound assignment type.
    ** First, generate the right operand, including any conversions.
    */
    r2 = (n->Ntype->Tspec == TS_PTR) ?		/* Doing pointer arith? */
	gptraddend(n->Nleft->Ntype, n->Nright)	/* Operand for ptr arith */
	: genexpr(n->Nright);			/* General-type operand */

    /* Then generate the left operand.  For the time being, the peephole
    ** optimizer is so screwed up that we can't keep the address around
    ** and have to generate it twice.
    */
    savaddr = sideffp(nod);     /* Warn user if we'll fail */

    if (Register_Id(nod))	/* approximate getmem() for registers */
	{
	r_preserve = nod->Nid->Sreg;
	ra = vrget();
	ra->Vrtype = nod->Ntype;
#if 0
	r1 = rgetmem(ra, nod->Ntype, ptr, savaddr);
#else
	r1 = rgetmem(ra, nod->Ntype, savaddr);
#endif
	}
    else
	r1 = getmem(ra=gaddress(nod), /* Get left operand, WITHOUT releasing addr!*/
	    nod->Ntype,	/* using its real type */
	    ptr,			/* addr may be a byte pointer */
	    savaddr);			/* Keep the address reg! */

    /* Now have left operand in R1.  Convert it for operation, if needed. */
    if (lconv != CAST_NONE)	/* Convert left operand if necessary */
	r1 = gcastr(lconv, r1, fromt, tot, nod);

    /* Apply the arithmetic operation, checking to make sure pointer
    ** arithmetic is handled properly.  r2 is released.
    */
    if (n->Ntype->Tspec == TS_PTR)	/* If doing pointer arith */
	r1 = gptrop(n->Nop, r1, r2, n->Ntype, n->Nright->Ntype);
    else
	r1 = garithop(n->Nop, r1, r2, n->Nleft->Ntype->Tspec);

    /* Now see if there's any assignment conversion to perform on
    ** the result of the operation.
    */
    if (n->Nascast != CAST_NONE)
	{
	r1 = gcastr(n->Nascast, r1, n->Nleft->Ntype, n->Ntype, (NODE *)NULL);
	}

    if (Register_Id(nod))	/* approximate stomem for registers */
	{
	if (siz == 1)
	    {
	    code00(P_MOVE, nod->Nid->Sreg, r1->Vrloc);
	    if (Register_Nopreserve(ra->Vrloc)) /* garithop changed it!? */
		vrfree (ra);
	    return r1;
	    }
	else
	    int_error ("gassign: reg argument size > 1");
	return ra;
	}
    else
	{
	/* Finally, can store the value back. We either use the
	** saved address, if one, or generate it all over again.
	*/
	if (!savaddr)
	    ra = gaddress(nod);		/* Else re-use saved addr */
	r1 = stomem(r1, ra, siz, ptr);
	}
    if (volat)
	flushcode();			/* Barf bletch */
    return r1;
}

/* GBINARY - Generate code for binary operators.
**
*/
static VREG *
gbinary(NODE *n)
{
    VREG *r1, *r2;

    /*
    ** First, check for pointer arithmetic.  Legal operations are:
    **	Operation	Result
    **	(1) num + ptr	ptr
    **	(2) ptr + num	ptr
    **	(3) ptr - num	ptr
    **	(4) ptr - ptr	int or long
    **
    **	If the pointer is a byte pointer, we always make the number first.
    ** This is only because the current optimizer is too stupid to recognize
    ** certain patterns any other way.
    */
    if (n->Ntype->Tspec == TS_PTR		/* Catch cases 1, 2, 3 */
	|| n->Nleft->Ntype->Tspec == TS_PTR)	/* Catch case 4 */
	{
	if (n->Nop == Q_MINUS)	/* Cases 3 and 4 */
	    {
	    if (n->Nright->Ntype->Tspec == TS_PTR)	/* Case 4: ptr-ptr */
		{
		r1 = genexpr(n->Nleft);		/* Make the left operand 1st */
		return gptrop(n->Nop, r1, genexpr(n->Nright),
			n->Nleft->Ntype, n->Nright->Ntype);
		}
	    else					/* Case 3: ptr-num */
		{
		r1 = genexpr(n->Nleft);				/* Make ptr */
		r2 = gptraddend(n->Nleft->Ntype, n->Nright);	/* Make num */
		return gptrop(n->Nop, r1, r2,
			n->Nleft->Ntype, n->Nright->Ntype);
		}
	    }
	/* Cases 1 and 2 */
	if (n->Nleft->Ntype->Tspec != TS_PTR)	/* Do case 1: num+ptr */
	    {
	    r2 = gptraddend(n->Nright->Ntype,n->Nleft);	/* Make num 1st */
	    return gptrop(n->Nop, genexpr(n->Nright), r2,
			n->Nright->Ntype, n->Nleft->Ntype);	/* reversed */
	    }
	else				/* Do case 2: ptr+num */
	    {

⌨️ 快捷键说明

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