📄 cccode.c
字号:
** These are not as well behaved as loop and if labels so we can't do as much.
*/
void
codgolab(lab)
SYMBOL *lab;
{
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
fprintf(fpho, "CODGOLAB: %s\n", lab->Sname);
}
#endif
if (optobj)
optlab(lab); /* Optimize */
flushcode(); /* Clear out previous code */
outlab(lab); /* and unconditionally emit label */
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
shocum();
#endif
}
/* This code should be flushed eventually,
** and TXO, TXZ, TXC forms substituted for this silly nonsense.
*/
/* ------------------------------------------------------ */
/* return immediate version of boolean operator */
/* ------------------------------------------------------ */
immedop(int op)
{
switch (op & POF_OPCODE)
{
case P_CAM:
return op ^ (P_CAM ^ P_CAI);
case P_TDN:
return op ^ (P_TDN ^ P_TRN);
case P_TDO:
return op ^ (P_TDO ^ P_TRO);
case P_TDC:
return op ^ (P_TDC ^ P_TRC);
case P_TDZ:
return op ^ (P_TDZ ^ P_TRZ);
default:
return 0;
}
}
/* PEEPHOLER PSEUDO-OP OPTIMIZATION ROUTINES */
/* CODRRX - Optimization auxiliary for CODE0.
** Basically intended to help make sense of the gigantic switch
** statement that previously existed.
**
** prev - instruction farther back in peephole buffer, which we are
** looking at.
** np - instruction we are trying to optimize (normally what was
** just added; an OP R,S instr).
*/
static void
codrrx(prev, np)
PCODE *prev, *np;
{
PCODE *q;
/* Avoids faulty optimizations in the functions: codrrx, rrpre1, rrpre2,
* rrpre3, rrpopt, rrpop2, localbyte, chkref, chkmref, rincode, rinaddr,
* rrchg, foldbyte, foldplus, foldadjbp, foldskip, sameaddr, alias,
* inskip, and findconst.
*/
if (Register_Preserve(np->Pr2))
return;
/* If have an unskipped previous instruction to look at,
** try to fold: our newly added instr into it.
*/
if (prev && !prevskips(prev))
{
if (prev->Preg != np->Pr2
&& rrpre1(np)) /* Prev instr R != new S */
return; /* If won, just return. */
if ((q = findrset(prev, np->Pr2)) != NULL
&& rrpre2(q, np)) /* Prev instr R == new S */
return; /* If won, just return */
}
rrpop2(np); /* Try standard optimizations */
}
/* RRPRE1 - Auxiliary for CODE0.
** Does some commutative register-register optimization.
** The constraints for coming here are that:
** A previous instr exists, which is not skipped,
** such that its R (register field) is NOT the same as the S
** of the new instruction we are adding.
** P points to the newly added instruction, which is always a
** register-register op.
**
** Returns TRUE if an optimization change was made.
*/
static int
rrpre1(p)
PCODE *p;
{
PCODE *q;
int r, s;
/* See if opcode of new instruction is one we can do something with.
** If the operation is commutative or can otherwise have the
** ordering of its operands reversed, then see if this can result
** in an improvement.
*/
switch (p->Pop & POF_OPCODE)
{
case P_ADD:
case P_IMUL: /* Commutative integer ops */
case P_FADR:
case P_FMPR: /* Commutative floating ops */
case P_IOR:
case P_AND:
case P_XOR: /* Bitwise ops */
case P_CAM: /* Invertible test */
break; /* Win, can check further! */
default:
return 0; /* Something else, so fail */
}
/* A recognized op, check further. */
if (p->Pr2 == R_SP /* Never mess with stack reg! */
|| (q = findrset(before(p), p->Preg)) == NULL) /* Find instr setting R */
return 0;
switch (q->Pop) /* Does that instr */
{
case P_SETZ:
case P_SETO: /* set R in a simple way? */
case P_MOVE:
case P_MOVN:
break;
default: /* No, just give up. */
return 0;
}
if (q->Ptype == PTV_IINDEXED) /* Also ignore if imm addr op */
return 0;
/* OK, try swapping the operands and see if that helps. */
r = p->Preg;
s = p->Pr2;
p->Preg = s; /* Reverse order of AC,E in op */
p->Pr2 = r;
if ((p->Pop&POF_OPCODE) == P_CAM)
{
p->Pop = swapop(p->Pop); /* Invert the skip test */
if (rrpre2(q, p)) /* See if this helped optimize */
return 1;
p->Pop = swapop(p->Pop); /* Nope, restore original test */
}
else if (rrpre2(q, p)) /* Re-check optimization now */
{
code00(P_MOVE, r, s); /* Won! Put back in right reg */
return 1;
}
p->Preg = r; /* Failed, restore original ordering. */
p->Pr2 = s;
return 0; /* Return failure so rrpre2 called */
}
/* RRPRE2 - (another) Auxiliary for CODE0.
** Checks previous instruction for optimization with the one we're
** currently adding. The constraints for coming here are that:
** P points to a previous instr, which is not skipped,
** such that its R (register field) is the SAME as the S
** of the new instruction we are adding.
** NP points to the newly added instruction, which is an OP R,S.
** (register-register op)
** Note that S is NOT referenced by anything between P and NP,
** which makes various things safe.
*/
static int
rrpre2(p, np)
PCODE *p, *np; /* An existing instruction being examined */
{
int op = np->Pop; /* OP R,S of new instruction we just added */
int r = np->Preg;
int s = np->Pr2;
PCODE *q;
/* Check opcode of PREVIOUS instr.
** Breaking out of the switch statement simply leaves new instr alone
** and returns failure.
*/
switch (p->Pop & (POF_OPCODE | POF_BOTH))
{
case P_IMUL:
{
PCODE *b, *bb;
if (p != before(np))
break; /* For now */
if (op != P_SUB || (q = before (p)) == NULL || q->Pop != P_IDIV ||
q->Preg != p->Preg || !sameaddr (p, q, 0) ||
(b = before (q)) == NULL || b->Pop != P_MOVE ||
b->Preg != p->Preg)
break;
if (b->Ptype == PTA_REGIS && b->Pr2 == r)
bb = NULL;
else if ((bb = before (b)) == NULL || bb->Preg != r ||
bb->Pop != P_MOVE || prevskips (bb) ||
!sameaddr (b, bb, 0))
break;
/*
** fold: MOVE R,x
** MOVE S,x
** IDIV S,y
** IMUL S,y
** SUB R,S
**
** into: MOVE S,x
** IDIV S,y ;error if S is preserve reg.
** MOVE R,S+1
**
** for ignorant Pascal programmers.
*/
if (bb != NULL)
bb->Pop = P_NOP; /* drop first move */
p->Pop = P_NOP; /* drop P_IMUL */
dropinstr(np); /* Drop new instr, fix up previous */
code00(P_MOVE, r, s+1); /* put result in right reg */
return 1;
}
case P_DMOVN: /* similar to P_MOVN below */
switch (op)
{
case P_DMOVE: /* move over for optimization */
p->Pop = P_DMOVE;
op = P_DMOVN;
break;
case P_DMOVN: /* cancel double DMOVN */
p->Pop = P_DMOVE;
op = P_DMOVE;
break;
case P_DFAD: /* R + -X is same as R - X */
p->Pop = P_DMOVE;
op = P_DFSB;
break;
case P_DFSB: /* R - -X is same as R + X */
p->Pop = P_DMOVE;
op = P_DFAD;
break;
default:
return 0; /* Give up, failed to add instr */
}
np->Pop = op;
/* Then drop through to following case */
case P_DMOVE:
switch (op)
{
case P_DFAD:
case P_DFSB:
case P_DFDV:
case P_DFMP:
case P_DMOVE:
case P_DMOVN:
/* Optimize DMOVE S,x /.../ Dop R,S
** into Dop R,x
*/
rrpre3(p, np, op);
return 1;
/* Try to fold: DMOVE R,M / PUSH x,R / PUSH x,R+1
** into PUSH x,M / PUSH x,M+1
** We come here when the current instr is DMOVE and we are adding
** a PUSH.
*/
case P_PUSH:
if (p != before(np))
break; /* For now */
/* Check out addressing mode, and forget it unless
** it's a plain vanilla REGIS, MINDEXED, or DCONST.
** Indirection, immediateness, or skippedness all cause failure.
*/
switch (p->Ptype)
{
case PTA_REGIS:
case PTA_MINDEXED:
case PTA_DCONST:
break;
default:
return 0; /* Give up, no optimization done */
}
/* First turn DMOVE R,M / PUSH P,R
** into MOVE R+1,M+1 / PUSH P,M
*/
p->Pop = P_MOVE; /* fold: the DMOVE R,M */
p->Preg++; /* into MOVE R+1,M */
switch (p->Ptype) /* Now fix up memory operand */
{
case PTA_REGIS:
p->Pr2++; /* MOVE R+1,R2+1 */
/* PUSH P,R2 */
break;
case PTA_MINDEXED:
dropinstr(np); /* Flush new instr */
codemdx(P_PUSH, r, p->Pptr, /* MOVE R+1,M+1 */
p->Poffset++, p->Pindex); /* PUSH P,M */
np = previous;
break;
case PTA_DCONST:
p->Ptype = PTA_DCONST2; /* MOVE R+1,1+[const] */
np->Ptype = PTA_DCONST1; /* PUSH R,[const] */
np->Pdouble = p->Pdouble;
break;
}
/* Now try to rearrange the MOVE / PUSH into PUSH / MOVE
** if we still know where things are (not always true).
** np should point to the PUSH.
*/
if (np->Pop != P_PUSH)
return 1; /* If not, forget it */
if ((p = before(np)) != NULL /* See if prev instr is */
&& (p->Pop == P_MOVE)) /* still MOVE */
/* Yep, swap 'em */
{
if ((p->Ptype&PTF_ADRMODE)==PTA_MINDEXED
&& p->Pindex == R_SP)
p->Poffset--;
swappseudo(p, np); /* into PUSH / MOVE */
}
return 1;
}
break;
case P_IOR: /* Prev instr was IOR of possible BP */
case P_ADJBP: /* or ADJBP of known BP */
if (op == P_LDB || op == P_DPB) /* If one-time use of BP, */
{
if (localbyte(p, np)) /* try to make it local-fmt */
return 1; /* Won, folded. */
}
break;
case P_SETZ:
switch (op)
{
case P_MOVE: /* fold: SETZ S, ; error if S preserve reg */
case P_FMPR: /* ... */
case P_IMUL: /* MOVE/etc R,S */
case P_MOVN: /* into: SETZ R, */
case P_FLTR:
np->Pop = P_SETZ; /* Replace this op with a SETZ R, */
np->Ptype = PTA_ONEREG;
dropinstr(p); /* Flush the old SETZ */
return 1;
case P_ADD: /* fold: SETZ S, error if S preserve reg */
case P_FADR: /* ... */
case P_SUB: /* ADD R,S */
case P_FSBR: /* into: null */
dropinstr(np); /* Flush the new op */
dropinstr(p); /* and flush the SETZ */
return 1;
}
case P_SETO: /* fall in from P_SETZ above */
/* fold: SETZ/SETO S, to MOVNI S,0/1 */
p->Pvalue = (p->Pop == P_SETO ? 1 : 0);
p->Pop = P_MOVN;
p->Ptype = PTV_IMMED; /* then drop through */
case P_MOVN:
/* invert MOVN(*) to MOVE(*) for following optimization */
switch(op & POF_OPCODE)
{
case P_MOVE:
p->Pop = P_MOVE; /* move P_MOVN over for optimization */
np->Pop = P_MOVN;
break;
case P_MOVN:
p->Pop = P_MOVE; /* cancel double P_MOVN */
np->Pop = P_MOVE;
if (changereg (r, s, p))
{
dropinstr(np); /* Flush pointless MOVE */
return 1;
}
break;
case P_ADD: /* R + -X is same as R - X */
p->Pop = P_MOVE;
np->Pop = P_SUB;
break;
case P_SUB: /* R - -X is same as R + X */
p->Pop = P_MOVE;
np->Pop = P_ADD;
break;
case P_FADR: /* R + -X is same as R - X */
p->Pop = P_MOVE;
np->Pop = P_FSBR;
break;
case P_FSBR: /* R - -X is same as R + X */
p->Pop = P_MOVE;
np->Pop = P_FADR;
break;
case P_CAM:
case P_IMUL:
case P_FMPR:
case P_FDVR:
if (p->Ptype != PTV_IMMED
&& (q = before(p)) != NULL
&& q->Preg == r
&& !prevskips (q))
switch (q->Pop)
{
case P_MOVE: /* a <= -b is same as -a >= b */
q->Pop = P_MOVN;
p->Pop = P_MOVE;
np->Pop = swapop(np->Pop);
codrrx(p, np); /* Continue looking back */
return 1;
case P_MOVN: /* -a <= -b is same as a >= b */
q->Pop = P_MOVE;
p->Pop = P_MOVE;
np->Pop = swapop(np->Pop);
codrrx(p, np); /* Continue looking back */
return 1;
}
default:
if (p->Ptype == PTV_IMMED)
{
p->Pop = P_MOVE; /* unknown const case, make P_MOVE */
p->Pvalue = - p->Pvalue; /* with negated value */
}
else
{
return 0; /* Give up, no optimization done */
}
} /* Drop through to following case */
case P_MOVE:
rrpre3(p, np, np->Pop); /* Always takes care of everything */
return 1;
case P_HRRZ:
case P_HLRZ:
/* Turn HLRZ/HRRZ S,X
** ...
** HRRE R,S
** into:
** HLRE/HRRE R,X
*/
if (op == P_HRRE)
{
rrpre3(p, np, (p->Pop == P_HRRZ ? P_HRRE : P_HLRE));
return 1;
}
break;
case P_ADD:
case P_SUB:
/*
** fold: ADD/SUB S,x
** ...
** ADD/SUB R,S
**
** into: ADD/SUB R,x
** ...
** ADD/SUB R,S
**
** and keep looking back for further optimization.
*/
/* Ensure that new instr is ADD or SUB before wasting more time */
if (op != P_ADD && op != P_SUB)
break;
/* Make sure the old ADD/SUB doesn't use its own reg as index */
if (rinaddr(p, p->Preg))
break;
/* See whether new instr's reg is otherwise referenced.
** It is OK to skip over references of the form ADD/SUB R,M as
** the result doesn't depend on the order of the instrs, and this
** allows us to convert things like (a - (b+c+d)) into (a-b-c-d).
*/
for (q = before(np); (q = chkref(p, q, r)) != NULL; q = before(q))
{
/* Found a reference, see if it's OK to pass by. */
if ((q->Pop == P_ADD || q->Pop == P_SUB) /* ADD or SUB? */
&& r == q->Preg && !rinaddr(q, r)) /* R ref reg-only? */
continue; /* Win, skip over */
return 0; /* Failed, no optimization. */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -