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