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

📄 ccgen2.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
	    r1 = genexpr(n->Nleft);			/* Make ptr 1st */
	    r2 = gptraddend(n->Nleft->Ntype,n->Nright);	/* num 2nd */
	    return gptrop(n->Nop, r1, r2,
			n->Nleft->Ntype, n->Nright->Ntype);
	    }
	}

    /* No pointer arithmetic involved, can just generate arithmetic stuff.
    ** Normally we generate the left operand first, but if the right operand
    ** is a function call then we reverse the order so as to avoid
    ** saving/restoring registers across the call.
    ** Also, if using normal ordering, we check to see whether the left
    ** operand will need to be widened (since integer division requires
    ** a doubleword register), and if so widen it ahead of time so that
    ** the generation of the right operand won't suboptimally seize the
    ** 2nd register and then have to be shuffled around later.
    */
    if (n->Nright->Nop == N_FNCALL && optgen)
	{
	r2 = genexpr(n->Nright);	/* Do function call first */
	r1 = genexpr(n->Nleft);		/* then left operand */
	}
    else
	{
	r1 = genexpr(n->Nleft);		/* Normal order, left first */
	if ((n->Nop == Q_DIV || n->Nop == Q_MOD) && tisinteg(n->Ntype)
		&& optgen)
	    vrlowiden(r1);		/* Widen in preparation for div */
	r2 = genexpr(n->Nright);	/* Now generate right operand */
	}
    return garithop(n->Nop, r1, r2, n->Ntype->Tspec);
}

/* GARITHOP - Generate code for binary arithmetic operators
**	given values in registers.
** The only types permitted are:
**		TS_FLOAT, TS_DOUBLE, TS_LNGDBL
**		TS_INT, TS_UINT
**		TS_LONG, TS_ULONG
**	Note that types "char" and "short" should already have been converted
** (via usual unary/binary conversions) to "int" before the operation
** is performed.
*/

static VREG *
garithop(op, r1, r2, ts)
int op;			/* Operation to generate code for */
int ts;			/* Type of the operands (TS_ value) */
VREG *r1, *r2;		/* Registers operands are in (r2 is released) */
{
    switch(op)
	{
	case Q_ASPLUS:
	case Q_PLUS:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad +");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
		    code0(P_ADD,  r1, r2);
		    break;
		case TS_FLOAT:
		    code0(P_FADR, r1, r2);
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    code0(P_DFAD, r1, r2);
		    break;
		}
	    break;

	case Q_ASMINUS:
	case Q_MINUS:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad -");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
		    code0(P_SUB,  r1, r2);
		    break;
		case TS_FLOAT:
		    code0(P_FSBR, r1, r2);
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    code0(P_DFSB, r1, r2);
		    break;
		}
	    break;

	/*	* Unsigned Multiplication
	**	MUL R,E
	**	TRNE R,1	or	LSH R+1,1	or	LSH R+1,1
	**	 TLOA R+1,400000	LSHC R,-1		LSHC R,-35.
	**	  TLZ R+1,400000
	**	result in R+1		result in R+1		result in R
	*/
	case Q_ASMPLY:
	case Q_MPLY:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad *");
		case TS_UINT:
		case TS_ULONG:
		    if (!vrispair(r1))	/* Unless already widened, */
			vrlowiden(r1);	/* grab two words for the multiply */
		    code0(P_MUL, r1, r2);
		    code8(P_TRN+POF_ISSKIP+POS_SKPE, r1, 1);
		    code8(P_TLO+POF_ISSKIP+POS_SKPA, VR2(r1), 0400000L);
		    code8(P_TLZ, VR2(r1), 0400000L);
		    vrnarrow(r1 = VR2(r1));	/* Narrow back, keep 2nd wd */
		    break;
		case TS_INT:
		case TS_LONG:
		    code0(P_IMUL, r1, r2);
		    break;
		case TS_FLOAT:
		    code0(P_FMPR, r1, r2);
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    code0(P_DFMP, r1, r2);
		    break;
		}
	    break;

    /* Integer division is done differently from other integer operations
    ** because the IDIV instruction produces a doubleword result.
    ** Note that we can't do the apparent optimization of using ASH or AND
    ** when the divisor is a constant power of two, because they perform
    ** inconsistently with IDIV on negative numbers.
    */
	case Q_ASDIV:
	case Q_DIV:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad /");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG: /* Hair for integer division */
			{
			int save_reg = r1->Vrloc;
			if (!vrispair(r1))	/*Unless already widened by gbinary,*/
			    vrlowiden(r1);	/* grab two words for the division. */
			code0((tspisunsigned(ts) ? P_UIDIV : P_IDIV), r1, r2);
			vrnarrow(r1);		/* Narrow back, keep 1st word */
			if (Register_Preserve(save_reg) && save_reg != r1->Vrloc)
			    {
			    code00(P_MOVE, save_reg, r1->Vrloc);
			    r1->Vrloc = save_reg;
			    }
			folddiv(r1);		/* Do cse on result */
			break;
			}
		case TS_FLOAT:
		    code0(P_FDVR, r1, r2);
		    break;
		case TS_DOUBLE:
		case TS_LNGDBL:
		    code0(P_DFDV, r1, r2);
		    break;
		}
	    break;

	case Q_ASMOD:
	case Q_MOD:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad %%");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
					/* Hair for integer remainder */
		    if (!vrispair(r1))	/* Unless already widened by gbinary,*/
			vrlowiden(r1);	/* grab two words for the division. */
		    code0((tspisunsigned(ts) ? P_UIDIV : P_IDIV), r1, r2);
		    vrnarrow(r1 = VR2(r1)); /* Narrow back, keep 2nd word */
		    folddiv(r1);		/* Do cse on result */
		    break;
		}
	    break;

	case Q_ASRSH:
	case Q_RSHFT:
	    code0(P_MOVN, r2, r2);		/* negate arg to make right shift */
					/* Then drop through to do shift */
	case Q_ASLSH:
	case Q_LSHFT:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad shift");

		case TS_INT:	/* Signed values use arith shift for >> */
		case TS_LONG:
		    if (op == Q_ASRSH || op == Q_RSHFT)
			{
			code4(P_ASH, r1, r2);
			break;
			}
		/* Drop thru if <<, for logical shift. */
		/* According to CARM, << is always logical even if signed */

		case TS_UINT:		/* Unsigned values use logical shift */
		case TS_ULONG:
		    code4(P_LSH, r1, r2);	/* this takes arg as if PTA_RCONST */
		    break;
		}
	    break;

	case Q_ASOR:
	case Q_OR:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad |");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
		    code0 (P_IOR, r1, r2);
		    break;
		}
	    break;

	case Q_ASAND:
	case Q_ANDT:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad &");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
		    code0 (P_AND, r1, r2);
		    break;
		}
	    break;

	case Q_ASXOR:
	case Q_XORT:
	    switch (ts)
		{
		default:
		    int_error("garithop: bad ^");
		case TS_INT:
		case TS_UINT:
		case TS_LONG:
		case TS_ULONG:
		    code0 (P_XOR, r1, r2);
		    break;
		}
	    break;

	default:
	    int_error("garithop: bad op %d", op);
	    vrfree(r2);
	}
    return r1;
}

/* GPTROP - Generate code for pointer arithmetic operations.
**	Legal pointer arithmetic operations are:
**		Operation	Result
**		* (1) num + ptr	ptr
**		(2) ptr + num	ptr
**		(3) ptr - num	ptr	
**		(4) ptr - ptr	int or long
**
** NOTE: It is the caller's responsibility to swap the operands of case 1 to
** transform it into case 2.  It is up to the caller to decide which one
** to generate first; however, for case 4 it is probably best to do the
** left operand first.
**	If the 2nd operand is a number it must have been generated by
** gptraddend (rather than genexpr).  In this case, r2 may be NULL if
** gptraddend has determined that the number is zero and nothing needs
** to be added or subtracted.
*/
static VREG *
gptrop(op, r1, r2, lt, rt)
int op;			/* Q_PLUS, Q_MINUS, Q_ASPLUS, Q_ASMINUS */
VREG *r1, *r2;		/* Registers holding left and right operands */
TYPE *lt, *rt;		/* Types of left and right operands */
{
    INT size;

    switch (op)
	{
	case Q_ASMINUS:
	case Q_MINUS:
	    if (rt->Tspec == TS_PTR)	/* Handle case 4 */
	    /* Handle case 4: ptr-ptr (make left operand first) */
		{
		if (tisbytepointer(lt))
		    {
		    vrlowiden(r1);			/* Must widen */
		    code0(P_SUBBP, r1, r2);		/* Do the sub */
		    vrnarrow(r1 = VR2(r1));		/* Result in 2nd word */
		    }
		else
		    code0(P_SUB, r1, r2);
		if ((size = sizeptobj(lt)) > 1)
		    {
		    vrlowiden(r1);		/* Ugh, must adjust result */
		    code1(P_IDIV, r1, size);
		    vrnarrow(r1);		/* Narrow to get result in 1st wd */
		    folddiv(r1);
		    }
		break;
		}

	/* Handle case 3: ptr-num.  Num must be generated by gptraddend. */
	    if (r2 == NULL)
		return r1;	/* Ensure have something to subtract */
	    if (tisbytepointer(lt))
		{
		code0(P_MOVN, r2, r2);
		code0(P_ADJBP, r2, r1);	/* Adjust char pointer */
		return r2;
		}
	    code0(P_SUB, r1, r2);		/* Adjust word pointer */
	    break;

	case Q_ASPLUS:
	case Q_PLUS:
	/* Handle case 2: ptr+num.  Num must be generated by gptraddend. */
	/* Note that case 1 should be transformed into case 2 by caller. */
	    if (r2 == NULL)
		return r1;	/* Ensure something to add */
	    if (tisbytepointer(lt))		/* If ptr is a char ptr */
		{
		code0(P_ADJBP, r2, r1);	/* Adjust char pointer */
		return r2;
		}
	    code0(P_ADD, r2, r1);		/* Adjust word pointer */
	    return r2;

	default:
	    int_error("gptrop: bad op %d", op);
	}
    return r1;
}

/* GPTRADDEND - Auxiliary to GPTROP.  This routine generates the
**	proper value for adding or subtracting from a pointer.
**	Note that it may return NULL if it determines that the value
**	is zero; that is, no value (and no operation) is necessary.
*/
static VREG *
gptraddend(TYPE *t, NODE *n)
/* Type of the pointer this value is being added to and Addend(or subtrahend)
 * expression */
{
    VREG *r;
    INT size;

    if (n->Nop == N_ICONST && optgen)		/* Do optimization */
	{
	size = sizeptobj(t) * n->Niconst;	/* If num is a constant */
	if (size == 0)
	    return NULL;		/* Zero value, gen nothing! */
	r = vrget();
	code1(P_MOVE, r, size);
	r->Vrtype = n->Ntype;		/* Set C type of object in reg */
	return r;
	}
    r = genexpr(n);			/* First generate value as given */
    if ((size = sizeptobj(t)) > 1)	/* Then check to see if mult needed */
	code1(P_IMUL, r, size);	/* Yeah, multiply it by size of obj */
    return r;
}

/* GLOGICAL - Generate code for boolean binary & unary operators
*/

static VREG *
glogical(NODE *n)
{
    VREG *reg;
    SYMBOL *false, *true, *temp;
    int reverse;

    reverse = (optgen && n->Nop == Q_LOR);
    n->Nendlab = true = newlabel();	/* get label for true case */
    false = newlabel();			/* get label for false case */

    /*
    ** See gternary() for an explanation of why this call is needed.
    */
    vrallspill();

    gboolean (n, false, reverse);	/* make the boolean code */
    if (optgen && unjump (false))	/* can put false case first? */
	{
	temp = false;			/* yes, swap meaning of false */
	false = true;			/* and true, so labels go out */
	true = temp;			/* in correct order. */
	reverse = !reverse;		/* also invert reversal switch */
	}

    if (n->Nflag & NF_RETEXPR)
	reg = vrretget(); /* get value in return reg */
    else
	reg = vrget();		/* not for return, use normal reg */
    reg->Vrtype = n->Ntype;		/* Set C type of object in reg */
    codlabel(true);			/* true label goes here */
    if (reverse)
	code0(P_TDZ+POF_ISSKIP+POS_SKPA, reg, reg); /* make zero, skip */
    else
	code1(P_SKIP+POF_ISSKIP+POS_SKPA, reg, 1); /* make one, skip */

    codlabel(false);			/* now make false label */
    if (reverse)
	code1(P_MOVE, reg, 1);	/* reversed false makes one */
    else
	code5(P_SETZ, reg);		/* normal false makes zero */
    return reg;				/* return the register */
}

extern int _chnl;

/* GUNARY - Generate code for unary operators
*/

static VREG *
gunary(NODE *n)

⌨️ 快捷键说明

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