📄 ccgen2.c
字号:
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 + -