📄 ccgen2.c
字号:
{
if (!r)
return (VREG *)-1; /* Stop if just checking. */
code1(P_AND, r, ((INT) 1 << fbitsize)-1); /* Zap! */
}
return r;
}
/* GINCDEC - Generate code for prefix/postfix increment/decrement.
** This is special-cased (instead of being handled by general
** arith code) both for efficiency and because the address is
** only supposed to be evaluated once. The code also checks
** for NF_DISCARD to see whether the result value is needed or not;
** if not, it forces the operation to be prefix instead of postfix,
** so that all fixup work can be avoided!
*/
static VREG *
gincdec(NODE *n, int inc, int pre)
/* The inc/dec expression node, +1 for increment, -1 for decrement, and
* True if prefix, else postfix.
*/
{
VREG *r, *ra, *r2;
INT size = 1; /* Default size for most common case */
int savaddr;
int volat;
if (n->Nflag & NF_DISCARD) /* Will result be discarded? */
pre = 1; /* If so, prefix form is always better! */
n = n->Nleft; /* Mainly interested in operand */
if ((volat = tisvolatile(n->Ntype)) != 0)
flushcode(); /* Barfo, avoid optimiz of volatile obj */
if (Register_Id(n))
{
void codr1(int, int, INT);
if (pre) /* r->Vrloc = n->Nid->Sreg, if preserve reg */
r_preserve = n->Nid->Sreg;
switch(n->Ntype->Tspec)
{
case TS_FLOAT:
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code00(P_MOVE, r->Vrloc, n->Nid->Sreg);
codr1(P_FADR, n->Nid->Sreg,(INT) ((inc > 0)? 1.0 : -1.0)); // FW KCC-NT
break;
#if 0 /* for next version of KCC regs */
case TS_DOUBLE:
case TS_LNGDBL:
r = vrdget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
if (!pre)
{
code00(P_DMOVE, r->Vrloc, n->Nid->Sreg);
r_preserve = n->Nid->Sreg;
ra = vrdget();
ra->Vrtype = n->Ntype;/* Set C type of object in reg */
code9(P_DFAD, ra, ((inc > 0)? 1.0 : -1.0), 1);
vrfree(ra);
}
else
code9(P_DFAD, r, ((inc > 0)? 1.0 : -1.0), 1);
break;
case TS_PTR: /* Hacking pointer? */
case TS_ENUM:
case TS_BITF:
case TS_UBITF:
#endif
case TS_INT:
case TS_UINT:
case TS_LONG:
case TS_ULONG:
case TS_CHAR:
case TS_UCHAR:
case TS_SHORT:
case TS_USHORT:
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code00(P_MOVE, r->Vrloc, n->Nid->Sreg);
codr1(P_ADD, n->Nid->Sreg,((inc > 0)? 1 : -1));
break;
default:
int_error("gincdec: bad reg type %N", n);
return NULL;
}
}
else
switch (n->Ntype->Tspec)
{
case TS_FLOAT:
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code9(P_MOVE, r, (inc > 0 ? 1.0 : -1.0), 0);
code4(P_FADR+POF_BOTH, r, gaddress(n));
if (!pre)
code9(P_FSBR, r, (inc > 0 ? 1.0 : -1.0), 0);
break;
case TS_DOUBLE:
case TS_LNGDBL:
r = vrdget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
if ((savaddr = sideffp(n)) != 0) /* See if lvalue has side effects */
{
ra = gaddress(n); /* Yes, make address first */
code9(P_DMOVE, r, (inc > 0 ? 1.0 : -1.0), 1);
codek4(P_DFAD, r, ra); /* Do op, keep address reg around */
code4(P_DMOVEM, r, ra);
}
else
{
code9(P_DMOVE, r, (inc > 0 ? 1.0 : -1.0), 1);
code4(P_DFAD, r, gaddress(n));
code4(P_DMOVEM, r, gaddress(n));
}
if (!pre)
code9(P_DFSB, r, (inc > 0 ? 1.0 : -1.0), 1);
break;
case TS_PTR: /* Hacking pointer? */
size = sizeptobj(n->Ntype); /* Find size of obj */
if (!size)
int_error("gincdec: 0-size obj %N", n);
if (tisbytepointer(n->Ntype)) /* Special if a (char *) */
{
if (inc < 0)
size = -size;
if ((savaddr = sideffp(n)) != 0) /* See addr has side effs */
ra = gaddress(n); /* Ugh, find & save it */
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of obj in reg */
/* If doing post-increment, save orig pointer value */
if (!pre)
{
r2 = vrget();
r->Vrtype = n->Ntype; /* Set C type of obj in reg */
if (savaddr)
codek4(P_MOVE, r2, ra); /* Save ptr */
else
code4(P_MOVE, r2, gaddress(n));
}
/* Now perform the increment. If the address of the pointer
** was saved in ra, it is released in this process. r has
** a copy of the new pointer value.
*/
if (size == 1) /* Special case */
{
if (savaddr)
codek4(P_IBP, 0, ra);
else
code4(P_IBP, (VREG *)NULL, gaddress(n));
if (pre) /* If will need val, get it. */
code4(P_MOVE, r, (savaddr ? ra : gaddress(n)));
}
else /* General case */
{
code1(P_MOVE, r, size); /* get how much */
if (savaddr)
codek4(P_ADJBP, r, ra);
else
code4(P_ADJBP, r, gaddress(n));
code4(P_MOVEM, r, /* store back in memory */
(savaddr ? ra : gaddress(n)));
}
/* Now, if doing postincrement, flush r and use r2 instead */
if (!pre)
{
vrfree(r);
r = r2;
}
break; /* Break out to return R */
}
/* Drop through to handle non-char pointer as integer */
case TS_ENUM:
case TS_INT:
case TS_UINT:
case TS_LONG:
case TS_ULONG:
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of obj in reg */
if (size == 1)
code4((inc > 0 ? P_AOS : P_SOS), r, gaddress(n));
else /* inc/dec by non-1 integer */
{
code1(P_MOVE, r, (inc > 0 ? size : -size));
code4(P_ADD+POF_BOTH, r, gaddress(n));
}
if (!pre) /* For postincrement, undo reg */
code1((inc > 0 ? P_SUB : P_ADD), r, size); /* undo change */
break;
case TS_BITF:
case TS_UBITF:
case TS_CHAR:
case TS_UCHAR:
case TS_SHORT:
case TS_USHORT:
if (inc < 0)
size = -size;
savaddr = sideffp(n); /* See if addr has side effs */
ra = gaddress(n); /* Ugh, find & save it */
/* Fetch byte, save addr if savaddr != 0 */
r = getmem(ra, n->Ntype, 1, savaddr);
code1(P_ADD, r, size); /* Add inc/dec value */
/* Now store byte back */
if (!savaddr)
ra = gaddress(n); /* else, re-use ra */
stomem(r, ra, 1, 1);
if (!pre) /* For postfix, undo reg */
code1(P_SUB, r, size); /* undo change */
break;
default:
int_error("gincdec: bad type %N", n);
return NULL;
}
if (volat)
flushcode(); /* Finish up after volatile obj */
return r;
}
/* GPRIMARY - Generate primary expression.
**
** This handles all primary expressions, which are composed of node ops
** N_FNCALL,
** Q_DOT, (may be lvalue)
** Q_MEMBER, (always lvalue)
** Q_IDENT, (always lvalue)
** N_ICONST, N_FCONST, N_PCONST, N_SCONST, N_VCONST, Q_ASM.
** The first three of those are not terminal nodes and may have further
** sub-expressions.
** Note that array subscripting is done as pointer arithmetic rather than
** using a specific operator. Similarly, parenthesized expressions have
** no specific op since the parse tree structure reflects any parenthesizing.
** This is where array and function names are caught and turned into
** pointers instead. Arrays and functions are the only Q_IDENTs for which
** the node type (Ntype) is different from the symbol type (Stype)! The
** symbol type will have the actual type of the name, whereas the node type
** will be that of "pointer to <Stype>".
** Note special checking for fetching a value from "volatile"-qualified
** lvalues. There are only four nodes that can be lvalues -- the three above,
** plus N_PTR which is handled in gunary(). Storing into those lvalues is
** handled by gassign() and gincdec(). Because the peephole optimizer is
** such a mess, we can't easily tell it to avoid volatile objects; instead
** we simply flush out all peephole code before and after generating the
** fetch from (or store into) a volatile object! Crude, but should work.
*/
static VREG *
gprimary(NODE *n)
{
VREG *q, *r;
INT siz;
int volat, t;
switch (n->Nop)
{
case Q_IDENT: /* Variable name */
if ((t = n->Nid->Stype->Tspec) == TS_FUNCT || t == TS_ARRAY )
{
/* Check for funct/array. Make sure Ntype is ptr */
if (n->Ntype->Tspec != TS_PTR)
/* Later make this error again */
int_warn("gprimary: array/funct %N", n);
return gaddress(n); /* Yup, just return ptr to object */
}
/* Normal variable or structure/union */
if ((volat = tisanyvolat(n->Ntype)) != 0)
flushcode(); /* If volatile, avoid optimization */
if (Register_Id(n)) /* approximate getmem() for registers */
#if 0
r = rgetmem(gaddress(n), n->Ntype, tisbyte(n->Ntype), 0);
#else
r = rgetmem(gaddress(n), n->Ntype, 0);
#endif
else
r = getmem(gaddress(n), n->Ntype, tisbyte(n->Ntype), 0);
if (volat)
flushcode();
return r;
case N_SCONST: /* Literal string - get char pointer to it */
n->Nsclab = newlabel();
n->Nscnext = litstrings; /* link on string stack */
litstrings = n; /* include this one */
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
/* Get byte ptr to str, using given bytesize of type! */
code10(P_MOVE, r, n->Nsclab, elembsize(n->Ntype), 0);
return r;
case N_VCONST: /* Void "constant" */
return NULL; /* No register used! */
case N_ICONST: /* Integer constant */
case N_PCONST: /* Pointer constant uses same cell etc */
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code1(P_MOVE, r, n->Niconst);
return r;
case N_FCONST: /* Floating-point constant */
switch (n->Ntype->Tspec)
{
case TS_FLOAT:
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code9(P_MOVE, r, n->Nfconst, 0);
break;
case TS_DOUBLE:
case TS_LNGDBL:
r = vrdget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code9(P_DMOVE, r, n->Nfconst, 1);
break;
}
return r;
case Q_ASM:
gasm(n);
return NULL; /* Currently never returns anything */
case N_FNCALL: /* Function call */
return gcall(n);
case Q_DOT: /* (). direct component selection */
if (!(n->Nleft->Nflag & NF_LVALUE))
break; /* Ugh, do hairy stuff if not lvalue! */
if ((debcsi == KCC_DBG_NULL) && (n->Nleft->Nop == Q_MEMBER))
{
_chnl = n->Nleft->sfline;
if (n->Nleft->Nleft->Nop == N_CAST)
code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft->Nleft));
else
code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft));
}
/* OK, fall thru to handle like Q_MEMBER */
case Q_MEMBER: /* ()-> indirect component selection */
if ((volat = tisanyvolat(n->Ntype)) != 0)
flushcode(); /* Ugh, avoid optimiz of volatile */
#if 0 /* KAR-1/92, leaving this as #if 0 in case I need it later */
if ((debcsi == KCC_DBG_NULL) && (n->Nop == Q_MEMBER))
{
_chnl = n->sfline;
code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft));
}
#endif
if (Register_Id(n)) /* approximate getmem() for registers */
#if 0
r = rgetmem(gaddress(n), n->Ntype,
(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
#else
r = rgetmem(gaddress(n), n->Ntype, 0);
#endif
else
r = getmem(gaddress(n), n->Ntype,
(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
if (volat)
flushcode();
return r;
case Q_MUUO:
return gmuuo(n);
default:
int_error("gprimary: bad op %N", n);
return NULL;
}
/* Hairy stuff for Q_DOT of something that isn't an lvalue.
** This can only happen for a struct returned from a function call.
** The structure resulting from the expression will either be
** completely contained in the registers (if size <= 2) or the register
** will contain the structure address.
*/
if ((siz = sizetype(n->Nleft->Ntype)) > 2) /* Find # wds in it */
/* Fake out gaddress into using genexpr instead of another gaddress
** when evaluating the structure expression, since result will
** be a pointer.
*/
{
n->Nop = Q_MEMBER;
if (Register_Id(n)) /* approximate getmem() for registers */
#if 0
return rgetmem(gaddress(n), n->Ntype,
(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
#else
return rgetmem(gaddress(n), n->Ntype, 0);
#endif
else
return getmem(gaddress(n), n->Ntype,
(n->Nxoff < 0) || tisbyte(n->Ntype), 0);
}
/* Pull component out of structure in 1- or 2-word register */
r = genexpr(n->Nleft); /* Get the structure */
switch (n->Nxoff) /* See which part of it we want */
{
case 0: /* Want first word? */
if (siz == 2 && sizetype(n->Ntype) == 1)
vrnarrow(r); /* Keep 1st word of a 2-word value */
return r;
case 1: /* Want second word? */
vrnarrow(r = VR2(r)); /* Keep second word of a 2-word value */
return r;
default: /* Bitfield of some kind */
/* NOTE: This generates a very uncommon use of PTA_BYTEPOINT
** wherein the E field of the byte pointer is actually a register
** address. This is why vrreal() is called, to get the
** actual register number. As long as this is one of the return-value
** registers as it should be, this usage is probably safe from
** the peephole optimizer.
*/
q = vrget(); /* Get another register */
q->Vrtype = n->Ntype; /* Set C type of object in reg */
(void) vrstoreal(q, r); /* Make sure both regs are active! */
codebp(P_LDB, vrreal(q), (unsigned)((- (n->Nxoff)) &
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -