📄 cccode.c
字号:
void
code6(op, reg, s)
SYMBOL *s;
VREG *reg;
{
PCODE *p;
int r = reg ? vrtoreal(reg) : 0; /* Handle JRST 0,lab */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE6", op, r);
if (s)
fputs(s->Sname, fpho);
fputc('\n', fpho);
}
#endif
/* Pre-optimization, sigh */
if (optobj
&& (op & POF_OPCODE) == P_JUMP
&& previous && !isskip(previous->Pop))
{
/* Emit: JUMPx R,lab as: CAIx R,0
** JRST lab
**
** So skip optimization can work best. If it doesn't get folded,
** then optjrst() will turn it back into JUMPx.
*/
r = ufcreg(r); /* optimization loses w/o this? */
p = newcode(PTA_RCONST,
op ^ (P_CAI ^ P_JUMP ^ POF_ISSKIP ^ POSF_INVSKIP),
r);
p->Pvalue = 0;
foldskip(p, 1);
op = P_JRST; /* make it a jump */
r = 0; /* JRST doesn't take a register */
}
/* All set up, drop values into the node */
p = newcode(PTA_MINDEXED, op, r);
p->Pptr = s;
p->Pindex = 0;
p->Poffset = 0;
reflabel(s, 1); /* Increment label reference count */
/* Now do post-optimization */
if (op == P_JRST && optobj)
{
foldjump(before(p), s);
optjrst(previous); /* p may have become nop */
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODEMDX - Generates general-purpose PTA_MINDEXED op.
** OP rreg,pptr+poffset(rindex)
**
** NOTE!!! Because this is only used to duplicate addressing of an
** already-generated op, the register args are REAL register numbers,
** not virtual reg pointers!
*/
void
codemdx(op, rreg, pptr, poffset, rindex)
int op;
SYMBOL *pptr;
int rreg;
INT poffset;
int rindex; /* Not vregs! */
{
PCODE *p;
int nreg;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODEMDX", op, rreg);
fprintf(fpho,"%s+%o(%o)\n", (pptr ? pptr->Sname : ""),poffset,rindex);
}
#endif
/* Maybe can do more complicated optimizing code generation */
if (pptr == NULL && poffset == 0)
{
code40(op, rreg, ufcreg(rindex), 0);
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
return;
}
nreg = ufcreg(rreg); /* undo failed changereg */
/* too general for optimization, just add the code */
p = newcode(PTA_MINDEXED, op, nreg);
p->Pptr = pptr;
p->Poffset = poffset;
p->Pindex = rindex;
if (nreg != rreg) /* Put result back in right register */
code00(P_MOVE, rreg, nreg);
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE8 - Generates instruction with integer constant operand
** OP r,const
**
** Like code1(), but op doesn't become immediate, making type PTA_RCONST.
** E.g. code8(P_ADJSP, VR_SP, n) where n is some stack offset.
**
** KLH: Note slipshod assumption that because CCGSWI calls code8 heavily
** for P_CAIx, foldskip() shouldn't try to change value of R, in case
** it is needed by later switch tests.
*/
void
code8(op, reg, val)
int op;
VREG *reg;
INT val;
{
codr8(op, vrtoreal(reg), val);
}
static void
codr8(op, r, val)
int op;
int r;
INT val;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE8", op, r);
fprintf(fpho,"%o\n", val);
}
#endif
/* Pre-optimization when about to add ADJSP */
if (optobj && op == P_ADJSP)
{
val = foldstack(val);
if (val == 0) /* If completely folded, can return */
{
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
return;
}
}
p = newcode(PTA_RCONST, op, r);
p->Pvalue = val;
/* Post-optimization for ADJSP, CAIx, CAMx */
if (optobj)
{
if (op == P_ADJSP)
{
if ((p = before(p)) != NULL
&& p->Ptype == PTV_IINDEXED) /* && !prevskips */
{
if (p->Pindex == R_SP)
p->Poffset -= val; /* Adjust stk addr for swap */
swappseudo(p, previous); /* Encourage tail recursion */
}
}
else /* See if can fold: CAM or CAI */
foldskip(p, 0); /* Could be from switch, be careful */
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE9 - Generates instruction with floating-point constant operand
** OP r,[float]
**
** Grave misunderstandings will result if the "twowds" flag
** does not match the op specified!
** Either that flag or the opcode are valid ways of determining
** whether we are dealing with a 1 or 2 word constant.
*/
void
code9(int op, VREG *vr, double value, int twowds)
/* twowds is TRUE if 2 wds (double), else 1-wd float */
{
PCODE *p;
int r = vrtoreal(vr);
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE9", op, r);
fprintf(fpho,"[%.20g]\n", value);
}
#endif
/* Optimize a P_MOVE or P_DMOVE of 0.0 since floating point zero is
* same as integer zero.
*/
if (value == 0.0 && optobj)
switch (op)
{
case P_DMOVE: /* Make DMOVE R,[0 ? 0] be SETZB R,R+1 */
/* Can't use code0 as that would release r+1 */
p = newcode(PTA_REGIS, P_SETZ+POF_BOTH, r);
p->Pr2 = r+1;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
return;
case P_MOVE:
code5(P_SETZ, vr);
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
return;
}
p = newcode((twowds ? PTA_DCONST : PTA_FCONST), op, r);
if (twowds)
p->Pdouble = value;
else
p->Pfloat = (float) value;
if (optobj)
foldmove(p); /* see if already have this one */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE10 - Generate op with pointer constant operand (ie a pointer literal)
** OP r,[pointer]
**
** The pointer is made from an:
** address (pointer to a symbol)
** offset (in bytes from address)
** bytesize (0,6,7,8,9,18)
** Using this information, CCOUT constructs a byte or word pointer using
** symbolic references which are resolved at load time into whatever
** the proper values are, whether local or OWGBP format (non-extended or
** extended).
** A bytesize of -1 is special and indicates that a MASK is desired
** for the P+S field of a byte-pointer. This should never be used with
** an address or offset.
** When used with the P_PTRCNV op (which converts a pointer in
** the register), the offset indicates the byte size of the current pointer,
** and the bsize indicates the desired byte size to convert it to.
** The address must be NULL.
*/
void
code10(op, vr, addr, bsize, offset)
int op;
VREG *vr;
SYMBOL *addr;
INT bsize, offset;
{
codr10(op, vrtoreal(vr), addr, bsize, offset);
}
void
codr10(op, r, addr, bsize, offset)
int op, r;
SYMBOL *addr;
INT bsize, offset;
{
PCODE *p;
int nreg;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE10", op, r);
fprintf(fpho,"[%s+%o (size %d)]\n",
(addr ? addr->Sname : ""), offset, bsize);
}
#endif
nreg = ufcreg(r); /* undo failed changereg */
/* this goes with the code0 call below */
p = newcode(PTA_PCONST, op, nreg);
p->Pptr = addr;
p->Poffset = offset;
p->Pbsize = bsize;
if (nreg != r)
code00(P_MOVE, r, nreg);
if (optobj && op == P_MOVE)
foldmove(previous); /* see if already have this one */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODRMDX - Auxiliary for following routines, just to share
** common code that creates a PTA_MINDEXED op and returns without
** doing any optimization.
** Note that the registers "reg" and "index" are real regs, not virtual.
*/
static void
codrmdx(type, op, reg, ptr, offset, index)
int type, op, reg;
SYMBOL *ptr;
INT offset;
int index;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODRMDX", op, reg);
if (type&PTF_IMM)
fputs("+I ", fpho);
if (type&PTF_IND)
fputc('@', fpho);
if (ptr)
fputs(ptr->Sname, fpho);
if (ptr && offset)
fputc('+', fpho);
if (offset)
fprintf(fpho, "%o", offset);
if (index)
fprintf(fpho, "(%o)", index);
fputc('\n', fpho);
}
#endif
p = newcode(type, op, reg);
p->Pptr = ptr;
p->Poffset = offset;
p->Pindex = index;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE12 - Generates register despill instruction.
** OP reg,offset(17)
**
** This is used only by CCREG to despill registers with MOVE or DMOVE.
*/
void
code12(op, vr, offset)
int op;
VREG *vr;
INT offset;
{
codrmdx(PTA_MINDEXED, op, vrtoreal(vr), (SYMBOL *)NULL, offset, R_SP);
}
/* CODE13 - Generates MOVEI of stack location.
** opI reg,offset(17)
**
** Used by several things, but op is always MOVE, so this always
** becomes an MOVEI of a stack location.
*/
void
code13(op, vr, offset)
int op;
VREG *vr;
INT offset;
{
codrmdx(PTA_MINDEXED+PTF_IMM, op, vrtoreal(vr),
(SYMBOL *)NULL, offset, R_SP);
}
/* CODE15 - Generates op with indirect indexed local label
** OP @lab+offset(idx)
**
** Only used by CCGSWI with op JRST for switch jump tables.
*/
void
code15(op, lab, off, idx)
SYMBOL *lab;
INT off;
VREG *idx;
{
codrmdx(PTA_MINDEXED+PTF_IND, op, 0, lab, off, vrtoreal(idx));
}
/* CODE16 - Generates op with indexed local label.
** OP reg,$lab(idx)
**
** Only used by CCGSWI with op CAM for checking switch hash tables.
*/
void
code16(op, vr, lab, vs)
SYMBOL *lab;
VREG *vr, *vs;
{
int r = vrstoreal(vr, vs); /* Ensure both R and S in real regs */
codrmdx(PTA_MINDEXED, op, r, lab, 0, vrreal(vs));
}
/* CODE17 - Generates a literal value.
**
** Only used by CCGSWI for generating switch hash tables.
*/
void
code17(value)
INT value;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
fprintf(fpho,"CODE17: literal %o\n", value);
}
#endif
p = newcode(PTA_RCONST, P_CVALUE, 0);
p->Pvalue = value;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODESTR - Generate "code" consisting of a direct user-specified
** assembly language string. This implements the asm() construction.
*/
void
codestr(s, len)
char *s;
int len;
{
flushcode(); /* Ensure pcode buffer flushed */
while (--len >= 0)
outc(*s++);
}
/* CODLABEL, CODGOLAB - Generate "code" consisting of the given label symbol.
** codlab does more optimization and may not actually emit the label.
** codgolab always emits its label; it is used for goto labels.
*/
/* CODLABEL - Emit a (forward) label.
**
** Optimizations are performed and if the label still has references
** to it, it is emitted. Then realfreelabel() is called on it, and
** if we emitted it and thus cleared the peephole buffer we also free
** the list of labels queued by freelabel().
*/
void
codlabel(lab)
SYMBOL *lab;
{
INT after = 0;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
fprintf(fpho, "CODLAB: %s\n", lab->Sname);
}
#endif
if (optobj)
{
after = hackstack(lab); /* pull ADJSP across POPJ */
optlab(lab); /* call peephole optimizer */
}
if (lab->Svalue > 0) /* See if still must emit */
{
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum(); /* Yes, report changes prior to */
#endif
flushcode(); /* clearing out previous code. */
outlab(lab); /* Now emit label. */
cleanlabs(); /* Now OK to clean up queued labels */
}
if (after)
code8(P_ADJSP, VR_SP, after); /* fix up stack */
freelabel(lab);
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODGOLAB - Emit a GOTO type label.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -