📄 ccgen2.c
字号:
{
VREG *r;
int volat;
switch (n->Nop)
{
case N_PREINC:
return gincdec(n, 1, 1);
case N_PREDEC:
return gincdec(n, -1, 1);
case N_POSTINC:
return gincdec(n, 1, 0);
case N_POSTDEC:
return gincdec(n, -1, 0);
case N_CAST:
return gcast(n);
case N_ADDR:
return gaddress(n->Nleft);
case N_PTR:
/* See comments at gprimary() about volatile objects. */
if ((volat = tisvolatile(n->Ntype)) != 0)
flushcode(); /* Obj is volatile, avoid optimiz */
if (debcsi == KCC_DBG_NULL)
{
_chnl = n->sfline;
switch (n->Nleft->Nop)
{
case Q_IDENT:
code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft));
break;
case N_PREINC:
case N_PREDEC:
case N_POSTINC:
case N_POSTDEC:
code4 (P_NULPTR, (VREG *) NULL, gaddress (n->Nleft->Nleft));
break;
default:
_chnl = -1;
break;
}
}
/* Special check for doing ILDB. Safer to do here instead of
** in peephole, at least until peepholer fixed to allow keeping
** an index reg around!
*/
if (Register_Id(n->Nleft))
{
#if 0 /* Reg linkage */
if (optgen && tisbytepointer(n->Nleft->Ntype)) /* if byte ptr */
{
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
if (n->Nleft->Nop == N_PREINC) /* "*++(reg)" */
code0 (P_ILDB, r, gaddress (n->Nleft->Nleft));
#if 0 /* add when LDBI, LDBD, and DLDB are defined here, below, and in
* gassign() for case N_PTR:
*/
else if (n->Nleft->Nop == N_PREDEC) /* "*--(reg) */
code0 (P_DLDB, r, gaddress (n->Nleft->Nleft));
else if (n->Nleft->Nop == N_POSTINC) /* "*(reg)++" */
code0 (P_LDBI, r, gaddress (n->Nleft->Nleft));
else if (n->Nleft->Nop == N_POSTDEC) /* "*(reg)--" */
code0 (P_LDBD, r, gaddress (n->Nleft->Nleft));
else if (n->Nleft->Nop == NULL)
code0 (P_LDB, r, gaddress (n->Nleft->Nleft));
#endif
else /* approximate getmem() for registers */
#if 0
r = rgetmem(genexpr(n->Nleft), n->Ntype,
tisbytepointer(n->Nleft->Ntype), 0);
#else
r = rgetmem(genexpr(n->Nleft), n->Ntype, 0);
#endif
}
else /* approximate getmem() for registers */
#endif
#if 0
r = rgetmem(genexpr(n->Nleft), n->Ntype,
tisbytepointer(n->Nleft->Ntype), 0);
#else
r = rgetmem(genexpr(n->Nleft), n->Ntype, 0);
#endif
}
else
/* if "*++(exp)" of a byte pointer */ if (optgen && tisbytepointer(n->Nleft->Ntype) &&
n->Nleft->Nop == N_PREINC)
{
r = vrget();
r->Vrtype = n->Ntype; /* Set C type of object in reg */
code4 (P_ILDB, r, gaddress(n->Nleft->Nleft));
}
else
r = getmem(genexpr(n->Nleft), n->Ntype,
tisbytepointer(n->Nleft->Ntype), 0);
if (volat)
flushcode();
return r;
case Q_MUUO:
return gmuuo(n);
case N_NEG:
if (Register_Id(n->Nleft))
{
#if 0
if ( n->Ntype->Tspec == TS_DOUBLE
|| n->Ntype->Tspec == TS_LNGDBL)
{
r = vrdget();
r->Vrtype = n->Nleft->Ntype;
code00(P_DMOVN, r->Vrloc, n->Nleft->Nid->Sreg);
}
else
#endif
{
r = vrget();
r->Vrtype = n->Nleft->Ntype;
code00(P_MOVN, r->Vrloc, n->Nleft->Nid->Sreg);
}
return r;
}
r = genexpr(n->Nleft);
if ( n->Ntype->Tspec == TS_DOUBLE
|| n->Ntype->Tspec == TS_LNGDBL)
code0(P_DMOVN, r, r);
else
code0(P_MOVN, r, r);
return r;
case Q_COMPL:
if (Register_Id(n->Nleft))
{
r = vrget();
r->Vrtype = n->Nleft->Ntype;
code00(P_SETCM, r->Vrloc, n->Nleft->Nid->Sreg);
return r;
}
r = genexpr(n->Nleft);
code0(P_SETCM, r, r);
return r;
default:
int_error("gunary: bad op %N", n);
return 0;
}
}
/* GCAST - Generate code for type conversion (cast)
**
** Note that the way we manage the task of keeping char values
** masked off is NOT by implementing a mask for casts to (char) type.
** Rather, we mask the register value only when widening. This works
** because a value of type (char) is always either assigned to a (char) object
** (in which case a byte pointer is used and the mask is automatic) or
** it is used in an expression -- and always promoted to an int or u_int.
** The masking would be wasteful and unnecessary for the first case, and
** the second case will always have an explicit N_CAST to widen the integer.
** See the INTERN.DOC file for a better explanation.
*/
static VREG *
gcast(NODE *n)
{
VREG *r;
/* If this expression is a return value, see if we can pass on
** the flag which marks it thusly. This basically benefits
** gcall() which uses the flag to do tail recursion; we want to ensure
** that a no-op cast won't prevent this optimization.
*/
if ((n->Nflag & NF_RETEXPR) /* This expr is a return val? */
&& gcastr(n->Ncast, (VREG *)NULL, /* and cast is a no-op? */
n->Nleft->Ntype, n->Ntype, n->Nleft) == NULL)
{
n->Nleft->Nflag |= NF_RETEXPR; /* Yes, pass flag on! */
if ((r = genexpr(n->Nleft)) != NULL) /* No cast, just generate expr */
r->Vrtype = n->Ntype; /* and reflect correct type */
return r;
}
return gcastr(n->Ncast, genexpr(n->Nleft),
n->Nleft->Ntype, n->Ntype, n->Nleft);
}
static VREG *
gcastr(cop, r, tfrom, tto, ln)
int cop; /* Cast op (a CAST_ value) */
VREG *r; /* Virtual reg holding value to cast.
** NOTE NOTE NOTE!!! If this is NULL, we are merely testing
** to see whether a cast would be produced. If there is
** no cast, NULL will be returned, else (VREG *)-1.
*/
TYPE *tfrom, *tto;
NODE *ln; /* If non-null, is node that R was generated from. */
{
switch (cop)
{
case CAST_NONE: /* No actual action required */
break;
case CAST_VOID: /* Throwing away the value */
if (r)
relflush(r); /* Release the register */
return NULL;
case CAST_IT_PT:
if (!r) /* Just checking? */
return gintwiden(r, tfrom, uinttype, ln);
else
r = gintwiden(r, tfrom, uinttype, ln); /* Widen int to uint */
break;
case CAST_IT_EN:
case CAST_IT_IT:
if (!r) /* Just checking? */
return gintwiden(r, tfrom, tto, ln);
else
#if 0 /* Later, Reg linkage */
if (Register_Nopreserve (r->Vrloc) && unsigned)
#endif
r = gintwiden(r, tfrom, tto, ln); /*Widen integer if needed */
break;
case CAST_EN_EN:
case CAST_EN_IT:
case CAST_PT_IT: /* No representation change needed */
break;
case CAST_PT_PT: /* General ptr to ptr conversion */
if (tisbytepointer(tfrom))
{
if (tisbytepointer(tto))
{
/* Byte pointer to byte pointer, check sizes */
int fsiz = elembsize(tfrom);
int tsiz = elembsize(tto);
if (!fsiz)
{
/* (void *) to byte pointer. */
if (tischarpointer(tto)) /* If any kind of char obj, */
break; /* do no conversion. */
fsiz = TGSIZ_CHAR; /* Else cvt as if (char *) */
}
if (!tsiz)
{
/* Byte pointer to (void *) */
if (tischarpointer(tfrom)) /* If any kind of char obj, */
break; /* do no conversion. */
tsiz = TGSIZ_CHAR; /* Else cvt as if (char *) */
}
if (fsiz == tsiz)
break; /* No conversion needed? */
if (!r)
return (VREG *)-1; /* Need, stop if just chking */
/* If converting between char and short
** (9 and 18 bit bytes), use special op.
*/
if ( (fsiz == TGSIZ_CHAR && tsiz == TGSIZ_SHORT)
|| (fsiz == TGSIZ_SHORT && tsiz == TGSIZ_CHAR))
{
code10(P_PTRCNV, r, (SYMBOL *)NULL, tsiz, fsiz);
break;
}
/* Odd size, convert to word pointer, then to byte pointer. */
code10(P_TDZ+POF_ISSKIP+POS_SKPE, /* Check for NULL */
r, (SYMBOL *)NULL, -1, 0); /* Mask off P+S */
code10(P_IOR, r, (SYMBOL *) NULL, tsiz, 0); /* make BP */
}
else
{
/* Byte pointer (any kind!) to word pointer */
if (!r)
return (VREG *)-1; /* Stop if just checking. */
code10(P_TDZ, r, (SYMBOL *) NULL, -1, 0); /* Mask off P+S */
}
}
else if (tisbytepointer(tto))
{
int tsiz;
/* Word pointer to byte pointer */
if (!r)
return (VREG *)-1; /* Stop if just checking. */
if ((tsiz = elembsize(tto)) == 0) /* Check for (void *) */
tsiz = TGSIZ_CHAR;
pitopc(r, tsiz, 0, 0);
}
break;
case CAST_FP_IT:
if (!r)
return (VREG *)-1; /* Stop if just checking. */
switch (tfrom->Tspec)
{
case TS_FLOAT:
code0(P_FIX, r, r); /* just use that! */
break;
case TS_DOUBLE:
case TS_LNGDBL:
code0(P_DFIX, r, r); /* r must be a register pair */
vrnarrow(r); /* Use 1st AC as result */
break;
}
/* Narrow the int here if needed */
break;
case CAST_FP_FP:
switch (castidx(tfrom->Tspec,tto->Tspec))
{
case castidx(TS_DOUBLE,TS_FLOAT):
case castidx(TS_LNGDBL,TS_FLOAT):
if (!r)
return (VREG *)-1; /* Stop if just checking. */
code0(P_DSNGL, r, r); /* r must be a register pair! */
vrnarrow(r); /* Forget about the second word */
break;
case castidx(TS_FLOAT,TS_DOUBLE):
case castidx(TS_FLOAT,TS_LNGDBL):
if (!r)
return (VREG *)-1; /* Stop if just checking. */
vrlowiden(r);
code5(P_SETZ, VR2(r));
break;
case castidx(TS_LNGDBL,TS_DOUBLE):
case castidx(TS_DOUBLE,TS_LNGDBL):
break;
}
break;
case CAST_IT_FP:
if (!r)
return (VREG *)-1; /* Stop if just checking. */
r = gintwiden(r, tfrom, /* Ensure widened to int or unsigned */
tissigned(tfrom) ? inttype : uinttype,
ln);
switch (tto->Tspec)
{
case TS_FLOAT:
/* Although FLTR and UFLTR are always supported by CCOUT,
** on KA-10s they are inefficient enough that it is worth
** checking for the opportunity to use a simple FSC, which
** is limited to integers of 27 bits or less.
*/
if (tissigned(tfrom) || tbitsize(tfrom) < TGSIZ_WORD)
{
/* Signed or known positive */
code0(P_FLTR, r, r); /* Use FLTR instr or macro */
break;
}
/* Ugh, unsigned full word value, must use hairy UFLTR. */
code0(P_UFLTR, r, r); /* Use UFLTR simulated op */
break;
case TS_DOUBLE:
case TS_LNGDBL:
vrlowiden(r); /* Make into register pair */
code5(P_SETZ, VR2(r)); /* zero the next reg */
if (tissigned(tfrom) || tbitsize(tfrom) < TGSIZ_WORD)
{
code8(P_ASHC, r, -8); /* shift out mantissa*/
code8(P_TLC, r, 0243000L); /* put exponent in */
}
else /* Unsigned conversion */
{
code8(P_LSHC, r, -9); /* Shift unsigned */
code8(P_LSH, VR2(r), -1); /* Fix up lo wd */
code8(P_TLC, r, 0244000L); /* exp (note 1 bigger!) */
}
code9(P_DFAD, r, 0.0, 1); /* Normalize the result */
break;
}
break;
default:
int_error("gcastr: bad cast %d", cop);
return NULL;
}
/* Cast done, now set new type of object in virtual register! */
if (r)
r->Vrtype = tto;
return r;
}
/* GINTWIDEN and GUINTWIDEN - Auxiliaries for GCAST to widen integral values.
** Always widens to full word even if new type is smaller, because
** it's just as easy and makes no difference to handling of new type.
** NOTE: treats a VREG arg of NULL just as gcastr() does, i.e. only checks
** to see whether a conversion would be necessary or not.
** GUINTWIDEN is a subroutine just so gboolean() can invoke it to force
** an unsigned-type widen.
*/
static VREG *
gintwiden(VREG *r, TYPE *tfrom, TYPE *tto, NODE *n)
/* Node that R was generated from (if any) */
{
if (tbitsize(tto) > tbitsize(tfrom))
{
if (tisunsign(tfrom)) /* Handle unsigned. Easy, just mask off */
{
r = guintwiden(r, tbitsize(tfrom), n);
}
else /* Handle signed. Harder, must test bit. */
{
if (!r)
return (VREG *)-1; /* Stop if just checking. */
if (tbitsize(tfrom) == TGSIZ_HALFWD) /* Special case */
{
code0(P_HRRE, r, r); /* Extend sign of halfwd */
return r;
}
code8(P_TRN+POF_ISSKIP+POS_SKPE, r, (1<<(tbitsize(tfrom)-1)));
code8(P_TRO+POF_ISSKIP+POS_SKPA, r, -(1 << tbitsize(tfrom)));
code1(P_AND, r, (1 << tbitsize(tfrom))-1); /* Positive, zap! */
}
}
return r;
}
static VREG *
guintwiden(VREG *r, int fbitsize, NODE *n)
/* # bits of value in R and Node that R was generated from (if any) */
{
/* Must zap high-order bits. Try to avoid doing this by
** seeing whether those bits are known to already be zero.
** Primary case is that of an LDB data fetch.
*/
if (!(n &&
(bptrref(n) > 0 /* Win if LDB fetch */
|| (n->Nop == Q_ASGN /* Or if an assignment of a */
&& bptrref(n->Nright) > 0 /* LDB also of safe size */
&& tbitsize(n->Nright->Ntype) <= fbitsize))) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -