📄 ccopt.c
字号:
{
case P_SETZ:
case P_SETO:
case P_MOVN:
if (!unsetz (q))
break; /* turn P_SETZ into P_MOVE */
case P_MOVE:
/*
** fold: P_MOVE R,x
** P_PUSH 17,R
**
** into: P_PUSH 17,x
** P_MOVE R,0(17)
**
** in hope that genrelease() will flush the P_MOVE.
*/
if (q->Ptype == PTV_IINDEXED)
break; /* no XP_PUSHI */
p->Pop = P_MOVE; /* get different P_MOVE instr */
p->Ptype = PTA_MINDEXED; /* from memory, no indirection */
p->Preg = q->Preg; /* into destination register */
p->Pindex = R_SP; /* from stack */
p->Pptr = 0; /* not global variable space */
p->Poffset = 0; /* top of stack */
q->Pop = P_PUSH; /* now make old P_MOVE into P_PUSH */
q->Preg = R_SP; /* onto stack */
}
return; /* no more to do here */
default:
switch (p->Ptype & PTF_ADRMODE)
{
case PTA_MINDEXED:
case PTA_BYTEPOINT:
if (p->Pindex == R_SP)
{
if (p->Poffset < previous->Poffset)
continue; /* arg, safe */
p = NULL; /* Not safe */
}
break;
case PTA_REGIS:
if (p->Pr2 == R_SP)
p = NULL; /* OP R,17 loses big */
break;
}
}
/*--------------------------------------*/
if ((b = before(previous)) != NULL
#if SYS_CSI /* Reg linkage, avoid faulty optimizations */
&& Register_Nopreserve (b->Pr2)
#endif
&& b->Ptype == PTA_REGIS /* !prevskips */
&& b->Pop == P_MOVE && b->Preg == previous->Preg
#if SYS_CSI
&& (previous->Pr2 != b->Preg) /* FEW, 2A(37) 17-Jul-92 (SPR 9877) */
/* Cannot perform this fold if 2d */
/* operand of 2d instr ('x' below) */
/* refers to common register ('R'). */
#endif
&& rfree(b->Pr2) /* Ensure OK to clobber S */
&& snglop(previous->Pop)) /* Single-word op */
/*
&& p->Pop != P_IDIV && p->Pop != P_UIDIV) {
*/
/* BUG! This call is known to swap an IDIVI and zap its reg!
*/
/*
** fold: MOVE R,S
** OP R,x
**
** into: OP S,x
** MOVE R,S
*/
{
previous->Preg = (char) (b->Pr2); /* flatten the register change */ // FW KCC-NT
swappseudo(b, previous); /* switch the two ops */
p = b; /* forget about the P_MOVE */
}
else
b = p = previous; /* no move, start at the top */
if (p->Ptype != PTA_MINDEXED)
return;
switch (p->Pop)
{
case P_AOS:
case P_SOS:
#if 0 /* BAD STUFF! KLH: This code loses (and has caused actual lossage in
** compiled code of the form "++I * ++I") because it generates a
** MOVE S,R which causes the peepholer to think that it is safe
** to throw R away completely -- which is NOT what the original code
** wanted to do or imply!
*/
if ((b = before (p)) != NULL && b->Pop == P_MOVEM &&
b->Ptype == PTA_MINDEXED /* !prevskips */ && b->Pptr == p->Pptr &&
b->Pindex == p->Pindex && b->Poffset == p->Poffset)
{
/*
** fold: P_MOVEM R,x
** P_AOS S,x
**
** into: P_ADDI R,1
** P_MOVEM R,x
** P_MOVE S,R
*/
b->Pop = P_ADD; /* make P_ADD */
b->Ptype = PTV_IMMED; /* immediate quantity */
b->Pvalue = (p->Pop == P_AOS)? 1 : -1; /* by one */
s = p->Preg; /* remember the reg we want */
p->Pop = P_MOVEM; /* now make P_MOVEM */
r = p->Preg = b->Preg; /* using old register */
foldplus(b); /* fix up addition */
code00(P_MOVE, s, r); /* and fix up registers */
}
else
#endif /* End of bad stuff */
foldinc(p);
default:
return;
case P_MOVEM:
break;
}
/*
** At this point we know that p = previous points to a MOVEM R,X.
** Search back to find the last instruction that uses R, to see if we
** can fold it with the MOVEM.
*/
badidx = 0;
ramask_p = rbinaddr(p); /* Remember regs used in X */
rrmask_p = rbits[p->Preg]; /* And in R (for completeness) */
while (1)
{
int rrmask_b;
b = before(b); /* skip over unlikely candidate */
if (b == NULL)
return; /* ran out of them */
if (rbinaddr(b) & rrmask_p) /* Can't hack if its addr uses R */
return;
rrmask_b = rbinreg(b); /* Find mask of regs that Preg uses */
if (rrmask_b & ramask_p) /* If reg used in X, then */
badidx = 1; /* can't fold unless SETZ */
if (rrmask_b & rrmask_p) /* If both use same Preg, */
break; /* done with loop! */
}
if (prevskips(b))
return; /* skipped over, lose */
switch (b->Pop)
{
case P_FMPR:
case P_IMUL:
if ((q = findmove(b, p)) != NULL && q->Pop == P_MOVN && !badidx)
{
/*
** fold: P_MOVN R,x
** P_IMUL R,y
** P_MOVEM R,x
**
** into: P_MOVN R,y
** P_IMULB R,x
*/
p->Pop = b->Pop | POF_BOTH; /* move mply op over */
b->Pop = P_MOVN; /* make old add into negated move */
q->Pop = P_NOP; /* flush the first move */
foldplus(p); /* maybe we can turn it into an AOS */
break;
}
case P_FADR:
case P_FSBR:
case P_ADD:
case P_SUB:
case P_AND:
case P_IOR:
case P_XOR:
if ((q = findmove(b, p)) != NULL && q->Pop == P_MOVE && !badidx)
{
/* fold: MOVE R,x
** ADD R,y
** MOVEM R,x
** into:
** MOVE R,y
** ADDB R,x
*/
if (b->Pop == P_SUB)
{
p->Pop = P_ADD+POF_BOTH; /* make ADDB */
b->Pop = P_MOVN; /* and MOVN */
}
else if (b->Pop == P_FSBR)
{
p->Pop = P_FADR+POF_BOTH; /* make floating add */
b->Pop = P_MOVN; /* and floating MOVN (same as int) */
}
else
{
p->Pop = b->Pop | POF_BOTH; /* move add op over */
b->Pop = P_MOVE; /* make old add into move */
}
q->Pop = P_NOP; /* flush the first move */
if (b->Ptype == PTA_REGIS
&& (b->Pop == P_MOVE || pushneg(b->Pr2, before (b))))
{
b->Pop = P_NOP;
p->Preg = (char) (b->Pr2); // FW KCC-NT
code00(P_MOVE, b->Preg, b->Pr2);
}
foldplus(p); /* maybe we can turn it into an AOS */
break;
}
/* If didn't have preceding MOVE, check following optimization */
case P_MOVE:
case P_MOVN:
case P_MOVM:
case P_SETCM:
case P_FDVR:
case P_IDIV: /* yes, P_IDIVB works */
if (b->Ptype == p->Ptype
&& b->Poffset == p->Poffset
&& b->Pindex == p->Pindex
&& b->Pptr == p->Pptr
&& !badidx)
{
/*
** fold: OP R,addr
** MOVEM R,addr
**
** into: OPB R,addr
*/
p->Pop = b->Pop; /* move opcode across */
if (b->Pop != P_MOVE)
p->Pop |= POF_BOTH;
b->Pop = P_NOP; /* flush old instruction */
foldplus(p); /* maybe we can turn it into an AOS */
}
break;
case P_SETZ:
case P_SETO:
if (b->Ptype == PTA_ONEREG)
{
/*
** fold: SETZ R,
** MOVEM R,x
**
** into: SETZB R,x
*/
p->Pop = b->Pop+POF_BOTH; /* move opcode across, make both */
b->Pop = P_NOP; /* flush old instruction */
}
}
}
#if 0 /* Old stuff from last part of foldboth() */
switch (rchange (b->Pop))
{
case PRC_RSAME: /* nice single word op? */
case PRC_RSET:
case PRC_RCHG:
case PRC_RCHG_DSAME:
if (b->Preg == p->Preg)
break; /* the one we want */
continue; /* else look back some more */
case PRC_DSAME: /* nasty double word op? */
case PRC_DSET:
case PRC_DSET_RSAME:
case PRC_DCHG:
case PRC_DCHG_RSAME:
if (!prevskips(b)
&& (b->Pop == P_DFMP || b->Pop == P_DFDV)
&& b->Preg == p->Preg
&& (q = before(b))
&& !prevskips(q)
&& q->Pop == P_SETZ
&& q->Preg == p->Preg + 1)
{
/*
** fold: SETZ R+1,
** DFMP R,y (or DFDV R,y)
** MOVEM R,x
**
** into: FMPR R,y (or FDVR R,y)
** MOVEM R,x
**
** so that later optimization can turn it into a FMPRB.
** The low order word of the double can't affect the result,
** but only for multiply -- this is not safe for DFAD and DFSB!
*/
if (q->Ptype == PTA_ONEREG)
q->Pop = P_NOP; /* drop P_SETZ */
b->Pop = ((b->Pop == P_DFMP)? P_FMPR : P_FDVR); /* make singleword */
/* Fix up operand if a constant */
if ((b->Ptype&PTF_ADRMODE) == PTA_DCONST)
{
b->Ptype = (b->Ptype& ~PTF_ADRMODE) | PTA_FCONST;
b->Pfloat = (float)b->Pdouble;
}
break; /* escape loop */
}
if ((b->Preg + 1) == p->Pindex)
badidx = 1;
if (b->Preg != p->Preg && (b->Preg + 1) != p->Preg)
continue;
default: /* P_PUSHJ? */
return; /* give up */
}
break;
}
#endif
static PCODE *
findmove(b, p)
PCODE *b, *p;
{
PCODE *q = b;
/* Scan back from potentially foldable op (B) to set Q for some
** cases that might need it. (KLH: seems dumb)
*/
while ((q = before(q)) != NULL
&& q->Preg != b->Preg
&& q->Preg != p->Preg
&& q->Preg != p->Pindex)
{
switch (q->Pop)
{
case P_FADR:
case P_FSBR:
case P_FDVR:
case P_FMPR:
case P_ADD:
case P_IMUL:
case P_SUB:
case P_MOVE:
case P_MOVN:
case P_SETZ:
case P_SETO:
case P_FLTR:
case P_FIX:
case P_AND:
case P_IOR:
case P_SETCM:
continue;
}
return NULL; /* unknown op, stop */
}
if (q
&& q->Preg == p->Preg
&& q->Ptype == p->Ptype /* !prevskips */
&& q->Pptr == p->Pptr
&& q->Poffset == p->Poffset
&& q->Pindex == p->Pindex)
return q;
return NULL;
}
static int
snglop(op)
int op;
{
switch (rchange(op))
{
case PRC_RSAME:
case PRC_RSET:
case PRC_RCHG:
case PRC_RCHG_DSAME:
return 1; /* OK single-word operation */
default:
return 0; /* Anything else is assumed not OK */
}
}
/* FOLDSTACK(n) - Optimize previous instructions into P_ADJSP.
**
** Attempts to pull previous P_ADJSPs, P_PUSHs, etc into a new P_ADJSP
** which would, if no such optimization occurred, have constant n.
** The return value is what the constant should be, taking into
** account any optimization which has been done.
** This is only called by code8 in CCCODE when about to generate
** an ADJSP. This is also invoked via code8 when code0 generates
** a PUSH P,R.
** It is ALWAYS safe to flush an ADJSP P,-n because that just
** leaves some extra junk on the stack and doesn't invalidate any
** following references.
** The thing to beware of is flushing positive adjustments
** (ADJSP P,+n) because this could leave following code referencing
** places beyond the end of the stack (i.e. indexing through P with
** a positive offset), unless we are careful and
** have made sure that no such references exist.
** The "maxfold" variable is to ensure that we don't accidentally
** do this. It is set to the largest positive N that it is safe to
** flush (if an ADJSP P,+N is encountered); this means that no code
** has been seen which references a location higher than -maxfold(P).
** That is, -maxfold(P) is assumed to have a reference.
** Note that 0(P) is a valid reference. maxfold should never be
** negative!
** Finally, if we know from "stackrefs" that the current function
** generates an address pointing to something on the stack, then it is
** never safe to flush a positive ADJSP, since we can't tell just from
** the instruction memory references whether a portion of the stack is
** really being used or not. This is why maxfold is set to 0 in that
** case, which means that as far as is known, all of the current stack is
** referenced.
*/
INT
foldstack(n)
INT n;
{
PCODE *p = previous; /* Start from end of buffer */
INT maxfold = (stackrefs ? 0 : 1000000L); /* limit on pos ADJSP fold */
while (p != NULL)
switch (p->Pop & POF_OPCODE)
{
case P_ADJSP:
/* See if safe to merge this ADJSP in with current one (at end),
** and if so adjust stack to account for its flushage, and
** then flush it.
*/
if (p->Preg != R_SP /* Must be ADJSP 17, */
|| prevskips(p) /* and not skipped over */
|| p->Pvalue > maxfold) /* and not about to invalidate refs */
return n; /* Failed one of above, quit. */
n += adjstack(p->Pvalue, p); /* Won, adjust all following refs */
n += p->Pvalue;
maxfold -= p->Pvalue;
dropinstr(p); /* Flush that ADJSP */
p = previous; /* Start loop over */
break;
case P_PUSH:
/* If this PUSH is the last instruction, and "n" is negative
** (meaning stack being reduced) then we can simply flush the PUSH
** since the value pushed is never used.
** Otherwise, OK to look past a PUSH P,[0]/[-1] because
** adjstack() knows how to convert those to a SETZB/SETOB -n(P)
** which is more efficient.
** Likewise, PUSH P,R is ok because adjstack() can change it to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -