📄 cccode.c
字号:
** This is a CODxxx routine both for consistency and so that
** PHO debugging information can be output if desired.
** Returns 1 if all relevant instances of the "from" register in the
** peephole buffer were successfully changed to the "to" register.
** Otherwise returns 0 and nothing was changed.
*/
int
codcreg(to, from)
VREG *to, *from;
{
int ret;
(void) vrstoreal(from, to);
ret = changereg(vrreal(to), vrreal(from), previous);
#if DEBUG_KCC /* 5/91 KCC size */
if (ret && debpho)
{
fprintf(fpho, "CODCREG: to %o from %o\n", vrreal(to), vrreal(from));
shocum();
}
#endif
return ret;
}
/* CODE0 - Generates instruction with register-only operands.
** OP r1,r2
**
** CODE0 releases register r2 for future reassignment (although later
** peephole optimizations might notice that it hasn't been changed yet
** and re-use whatever value it contained).
**
** CODEK0 does NOT release register r2. The assignment operators need to
** keep around two registers sometimes.
*/
void
codek0(op, r1, r2) /* KEEP the second register!! */
int op;
VREG *r1, *r2;
{
VREG *r3 = vrget(); /* Get another temp reg */
int s = vrstoreal(r3, r2); /* Ensure it and both regs real */
int r = vrstoreal(r1, r2);
vrfree(r3);
code00(P_SETM, s, vrreal(r2)); /* Use this to avoid losing r2 */
code00(op, r, s);
}
void
code0(op, r1, r2)
int op;
VREG *r1, *r2;
{
int s = vrstoreal(r2, r1); /* Make regs real ones */
if (r1 != r2)
vrfree(r2); /* flush operand for later */
code00(op, vrreal(r1), s);
}
void
code00(int op, int r, int s)
{
PCODE *p, *prev;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE0", op, r);
fprintf(fpho, "%o\n", s);
}
#endif
if (Register_Preserve(s) && op == P_MOVE && r == s)
return; /* Don't create useless "MOVE R,R" */
if (Register_Nopreserve(s))
/* Simple pre-optimization. */
s = ufcreg(s); /* Flush failed changereg for 2nd AC */
if (Register_Nopreserve(r))
if ((op & POF_OPCODE) == P_CAM) /* and other if comparison */
r = ufcreg(r);
/* Now just add the instruction. */
prev = previous; /* Remember previous, if any */
p = newcode(PTA_REGIS, op, r);
p->Pr2 = s;
/* Everything else is optimization hacks */
/* Try to avoid storing a MOVE-type op by going back through
** the buffer and changing code so that the operand register (s)
** is already the destination (r).
** Neither pushneg nor pnegreg creates or kills any instructions,
** so pointers remain safe.
*/
if (Register_Nopreserve(p->Preg) && Register_Nopreserve(p->Pr2) &&
Register_Nopreserve(prev->Preg) && Register_Nopreserve(prev->Pr2))
if (optobj)
switch (op)
{
case P_SETM: /* Special code to avoid optimizer! */
break; /* Otherwise S will get re-used. */
case P_MOVM: /* If case hash, also do nothing */
break;
case P_MOVN: /* fold: out P_MOVN */
if (r == s && pnegreg(s, prev)) /* Try to use other instrs */
{
flsprev(); /* Win, don't need MOVN at all! */
break;
}
if (!pushneg(s, prev)) /* Try to negate value */
{
codrrx(prev, p); /* Didn't work, try other opts */
break;
}
p->Pop = P_MOVE; /* Value negated! Change op to MOVE */
/* and drop thru to handle MOVE */
case P_MOVE:
if (changereg(r, s, prev))
flsprev(); /* Won, can flush instr we added */
else
codrrx(prev, p); /* Nope, just apply other opts. */
break;
case P_DMOVE:
if (r == s) /* Changereg doesn't like doubles, */
flsprev(); /* so this is the best we can do. */
else
codrrx(prev, p); /* Nope, try other optimizations. */
break;
default: /* None of above, just try */
codrrx(prev, p); /* normal post-optimizations */
break;
}
#if DEBUG_KCC /* 5/91 KCC size */
/* Done, show updated buffer on debugging output if required */
if (debpho)
shocum();
#endif
}
/* CODE1 - Generates instruction with an immediate integer constant operand
** OP+I r,val
** This becomes type PTA_RCONST+PTF_IMM.
*/
void
code1(op, vr, s)
int op;
VREG *vr;
INT s;
{
codr1(op, vrtoreal(vr), s);
}
void
codr1(op, r, s)
int op, r;
INT s;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE1", op, r);
fprintf(fpho,"<imm> %o\n", s);
}
#endif
p = newcode(PTA_RCONST+PTF_IMM, op, r);
p->Poffset = s;
if (optobj)
{
foldplus(p); /* now do post-optimizations */
foldmove(previous); /* "previous" instead of "p", maybe changed */
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODEBP - Generate instr with PTA_BYTEPOINT local byte pointer operand.
** OP r,[bbbbii,,sym+o]
**
** Used in optimization of string ops, and in generating struct bit fields.
** NOTE!!! The reg and index arguments are REAL register #s, not pointers
** to virtual regs.
*/
void
codebp(op, r, b, i, sym, o)
int op, r; /* Note real, not vreg */
INT b;
int i;
SYMBOL *sym;
INT o;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODEBP", op, r);
fprintf(fpho,"[%o,,%s+%o(%o)]\n",
b, (sym ? sym->Sname : ""), o, i);
}
#endif
p = newcode(PTA_BYTEPOINT, op, r); /* Add the instruction */
p->Pindex = i;
p->Pptr = sym;
p->Poffset = o;
p->Pbsize = b; /* Store P+S field here */
/* Apply local-format byte-pointer optimizations */
if (optobj)
{
foldbp(p); /* Try to optimize operand (doesn't change opcode) */
foldbyte(p); /* Attempt byte op optimizations */
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE3 - Generates address for symbol.
** OPI R,sym
**
** Only used with P_MOVE, so this becomes MOVEI R,SYM.
*/
void
code3(op, vr, s)
SYMBOL *s;
VREG *vr;
{
codrmdx(PTA_MINDEXED+PTF_IMM, op, vrtoreal(vr), s, 0, 0);
}
/* CODE4 - Generates instruction using indexed register operand.
** OP r,(idx)
**
** This is used after a gaddress() to get the contents of a variable,
** and also for assignment ops (like Q_ASGN = P_MOVEM). The index is released.
**
** CODEK4 is the same but doesn't release the index register.
**
** CODE4S takes an extra argument which it stuffs into the Pbsize field
** of the stored op. This is used as a special hack for P_SMOVE only,
** and the size is associated with the op rather than the operand.
*/
void
code4(op, reg, idx)
VREG *reg, *idx;
{
int r, s;
r = reg ? vrstoreal(reg, idx) : 0; /* Allow IBP/JRST 0, */
s = ufcreg(vrtoreal(idx));
if (reg != idx)
vrfree(idx); /* will no longer need register */
code40(op, r, s, 0);
}
static char *tmp_mnem; /* KAR-2/91, static storage for imuuo mnemonic */
extern int _chnl; /* KAR-2/91, temporary storage for channel numbers */
void
code4m(op, reg, idx, mnem)
int op;
VREG *reg, *idx;
char *mnem;
{
int r, s;
tmp_mnem = (char *) calloc(1, strlen(mnem) + 1);
if (tmp_mnem == NULL)
jerr("Out of memory for imuuo mnemonic\n");
strcpy(tmp_mnem, mnem);
r = reg ? vrstoreal(reg, idx) : 0; /* Allow IBP/JRST 0, */
s = ufcreg(vrtoreal(idx));
if (reg != idx)
vrfree(idx); /* will no longer need register */
code40(op, r, s, 0);
}
void
codek4(op, reg, idx)
VREG *reg, *idx;
{
VREG *r3;
int r, s;
r = ufcreg(vrtoreal(idx));
s = vrstoreal(r3 = vrget(), idx);
code00(P_SETM, s, r); /* Use this to avoid losing r2 */
r = vrstoreal(reg, r3);
s = vrreal(r3);
vrfree(r3);
code40(op, r, s, 0);
}
void
code4s(op, reg, idx, keep, bsiz)
int op;
VREG *reg, *idx;
INT bsiz;
{
VREG *r3;
int r, s;
if (keep)
{
r = ufcreg(vrtoreal(idx));
s = vrstoreal(r3 = vrget(), idx);
code00(P_SETM, s, r); /* Use this to avoid losing r2 */
r = vrstoreal(reg, r3);
vrfree(r3);
}
else
{
r = vrstoreal(reg, idx);
s = ufcreg(vrreal(idx));
if (reg != idx)
vrfree(idx); /* will no longer need register */
}
code40(op, r, s, bsiz);
}
void
code40(op, r, s, bsiz)
int op;
int r, s;
INT bsiz;
{
PCODE *p;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE4", op, r);
fprintf(fpho,"(%o) siz %lo\n", s, (INT) bsiz);
}
#endif
/* First just add the instruction */
p = newcode(PTA_MINDEXED, op, r);
p->Pptr = NULL;
p->Poffset = 0;
p->Pindex = s;
p->Pbsize = bsiz;
/*
* KAR-1/92, use channel field for null ptr det. to store line number also
* need to skip mnemonic copy, so changed "if" to a "switch" below.
*/
switch (op)
{
case P_MUUO:
p->p_im.mnemonic = (char *) calloc(1, strlen(tmp_mnem) + 1);
if (p->p_im.mnemonic == NULL)
jerr("Out of memory for null ptr detection mnemonic\n");
strcpy(p->p_im.mnemonic, tmp_mnem);
free(tmp_mnem);
tmp_mnem = NULL;
case P_NULPTR:
p->p_im.p_chnl = _chnl;
_chnl = -1; /* KAR-6/91, Changed empty signal to -1 from 0 */
break;
default:
if (optobj) /* Apply post-optimization */
foldxref(p);
break;
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE5 - Generate op using only a single register operand.
** OP reg,
**
** Currently only used for SETZ, POPJ, TRNA.
*/
void
code5(op, reg)
VREG *reg;
{
PCODE *p, *q;
int r;
r = reg ? vrtoreal(reg) : 0; /* Allow for TRNA 0, in gboolop() */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE5", op, r);
fputc('\n', fpho);
}
#endif
p = newcode(PTA_ONEREG, op, r); /* Add the instruction */
if (optobj && (op == P_SETZ || op == P_SETO))
{
if ((q = before(p)) != NULL /* Check previous instr */
&& q->Pop == op
&& q->Ptype == PTA_ONEREG /* && !prevskips */)
{
/*
** fold: SETZ S, / SETZ R, (or SETO)
** into: SETZB S,R (or SETOB)
*/
p->Ptype = PTA_REGIS;
p->Pop |= POF_BOTH;
p->Pr2 = r;
dropinstr(p); /* Flush instr we just added */
}
else if (op == P_SETZ)
foldmove(p);
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
extern void free();
void
code5m(op, reg, mnem)
VREG *reg;
char *mnem;
{
PCODE *p, *q;
int r;
r = reg ? vrtoreal(reg) : 0; /* Allow for TRNA 0, in gboolop() */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
shohdr("CODE5", op, r);
fputc('\n', fpho);
}
#endif
p = newcode(PTA_ONEREG, op, r); /* Add the instruction */
/* KAR-2/91, Copies mnemonic into PCODE node for imuuo */
if (op == P_MUUO)
{
p->p_im.mnemonic = (char *) calloc(1, strlen(mnem) + 1);
if (p->p_im.mnemonic == NULL)
jerr("Out of memory for null ptr mnemonic\n");
strcpy(p->p_im.mnemonic, mnem);
p->p_im.p_chnl = _chnl;
_chnl = -1; /* KAR-6/91, Changed sentinal value to -1 from 0 */
}
if (optobj && (op == P_SETZ || op == P_SETO))
{
if ((q = before(p)) != NULL /* Check previous instr */
&& q->Pop == op
&& q->Ptype == PTA_ONEREG /* && !prevskips */)
{
/*
** fold: SETZ S, / SETZ R, (or SETO)
** into: SETZB S,R (or SETOB)
*/
p->Ptype = PTA_REGIS;
p->Pop |= POF_BOTH;
p->Pr2 = r;
dropinstr(p); /* Flush instr we just added */
}
else if (op == P_SETZ)
foldmove(p);
}
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* CODE6 - Generate op with a symbolic address operand.
** OP reg,sym
** This is mostly used for jumps and switch jump tables.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -