📄 cccse.c
字号:
isindex[q->Pr2] = maxcse + 1; /* treat mem reg as index */
break;
case PTA_BYTEPOINT:
case PTV_IINDEXED:
case PTA_MINDEXED:
isindex[q->Pindex] = maxcse + 1; /* extract index register */
break; /* accept */
case PTV_IMMED:
case PTA_ONEREG:
case PTA_FCONST:
case PTA_DCONST:
case PTA_DCONST1:
case PTA_DCONST2:
break;
default:
return 0;
}
/*
** An opcode making it this far has also passed the opcode type test.
** Add it to the codes we are looking to match and either continue
** looking for such ops or break out now that we are done looking.
*/
target[maxcse++] = q; /* remember op we found */
if (i) break; /* break out of while loop */
if (maxcse >= MAXCSE) return 0; /* too much, give up */
q = before (q); /* or skip back and try for more */
} /* end while(1) */
/*
** We have discovered complete expression, now set up register
** match machines. If a register is still assigned, we ignore it
** to save later confusion in code generation.
*/
for (i = 0; i < NREGS; i++) {
if ((rfree(i) || safedouble) && isindex[i] < 0)
matchedto[i] = 0; /* OK to check this reg, set initial match */
else matchedto[i] = -1; /* Not OK, don't use it */
/*
if ((!rfree(i) && !safedouble) || isindex[i] >= 0)
matchedto[i] = -1;
else matchedto[i] = 0;
*/
regret[i] = i; /* reg starts returning self */
}
if (isindex[r] >= 0) /* If R used (as index) in its own */
return 0; /* calculation, give up... */
matchedto[r] = 0; /* OK to re-use main reg */
if (maxflush < 0) maxflush = maxcse; /* remember top flush margin */
else if (maxflush == 0) return 0; /* If nothing to flush, give up */
isindex[0] = isindex[R_SP] = -1; /* ignore zero as index */
stkoffset = 0; /* no stack hackery yet */
return 1; /* OK, say target is ready! */
}
/* FINDCSE() - Fold common subexpressions
*/
static int
findcse(r, p, safedouble)
PCODE *p;
{
PCODE *q;
int i, flushfound;
if (!cseinit(r, p, safedouble))
return 0;
/*
** Now all the preliminaries are done, we can go look for a match.
** We go back through all the ops, advancing the state machine of
** the register of the op until we find a complete match.
** This is the second loop and the big one.
*/
q = p; /* start again */
flushfound = 0; /* haven't found flushes yet */
while (1) { /* until we match or give up */
if (q == NULL) return 0; /* nothing there, give up */
if (flushfound < maxflush && target[flushfound] == q) {
flushfound++; /* going to go away, move marker on */
q = before (q); /* ignore this one */
continue; /* try something more substantial */
}
switch (q->Pop & (POF_OPCODE | POF_BOTH)) {
/*
** Byte instructions. P_LDB doesn't change memory, but the
** rest do (the pointer, the contents, or both).
** We also handle folding P_IBP + P_LDB => P_ILDB here.
*/
case P_LDB:
if ((r = safematch (q, P_LDB)) != 0)
break; /* matched, return */
q = before (q); /* not, back one */
continue; /* and try again */
case P_DPB:
if (q == target[0]) { /* are we looking for P_IDPB fold? */
q = before (q); /* yes, just skip over the P_DPB */
continue; /* and look for a real match */
}
case P_IDPB:
/* This used to drop through to the ILDB case. However, this
** caused lossage because it's unsafe to assume that the DPB
** operand is correctly masked off, thus the register contents
** don't necessarily correspond to what an LDB would get. Someday
** this could be improved to check for masking instructions.
*/
return 0;
case P_ILDB:
if (match (q, P_LDB)) {
r = q->Preg; /* matched, set reg */
break; /* and return success */
}
if (flushalias (q)) return 0;
q = before (q); /* back up */
continue; /* and try again */
case P_IBP:
/* Bug here, the sequence
** IBP x ? MOVEM x,addr ? LDB r,x
** becomes zapped into
** MOVEM x,addr ? ILDB r,x
** which is real wrong.
** Until this is figured out and protected against, we enforce a
** restriction that the IBP must immediately precede the DPB/LDB.
*/
if (match (q, P_IBP)) switch(target[0]->Pop) {
case P_LDB: /* turn P_IBP x + P_LDB R,x */
/* Temp fix */ if (q != before(target[0]))
/* Temp fix */ break;
target[0]->Pop = P_ILDB; /* into P_ILDB R,x */
q->Pop = P_NOP;
return 0;
case P_DPB: /* same with P_DPB */
/* Temp fix */ if (q != before(target[0]))
/* Temp fix */ break;
target[0]->Pop = P_IDPB;
q->Pop = P_NOP;
return 0;
default:
; /* do nothing */
}
if (flushalias (q)) return 0;
q = before (q); /* back up */
continue; /* try again */
/*
** Binary operations. If they are not of type POF_BOTH, then
** they must match the individual op, and if it matches
** keep looking for the instruction before that in the sequence.
**
** If they are POF_BOTH explicitly or implicitly, then they can
** only match a P_MOVE, and we have to be careful about mem changes.
*/
case P_IDIV: case P_UIDIV:
/* 3/92 SPR-9774 avoid faulty register-pair opt when one is '/' and the
* the other is '%', as in a[x%y][x/y]; Later, fix ismod[] in cccse.c
*/
#if SYS_CSI
return 0;
#endif
case P_DFMP: case P_DFDV: case P_DFSB: case P_DFAD:
case P_DMOVE: case P_DMOVN:
flushreg(q->Preg + 1);
case P_FADR: case P_FSBR: case P_FMPR: case P_FDVR:
case P_ADD: case P_IMUL: case P_SUB:
case P_AND: case P_IOR: case P_XOR:
case P_TRO: case P_TRZ: case P_TRC:
case P_TDO: case P_TDZ: case P_TDC:
case P_ADJBP: case P_LSH:
if ((r = safematch(q, q->Pop)) != 0)
matchedto[r]++;
q = before (q); /* whether or no success, back one */
continue; /* and try again */
case P_SETO+POF_BOTH: case P_SETZ+POF_BOTH:
if ((r = match (q, q->Pop &~ POF_BOTH)) != 0) break;
case P_MOVEM: case P_DMOVEM:
case P_AOS: case P_SOS:
case P_MOVN+POF_BOTH: case P_MOVM+POF_BOTH:
case P_ADD+POF_BOTH: case P_IMUL+POF_BOTH:
case P_FADR+POF_BOTH: case P_FSBR+POF_BOTH:
case P_FMPR+POF_BOTH: case P_FDVR+POF_BOTH:
case P_XOR+POF_BOTH: case P_IOR+POF_BOTH: case P_AND+POF_BOTH:
case P_SETCM+POF_BOTH:
case P_IDIV+POF_BOTH:
if ((r = match (q, P_MOVE)) != 0)
break; /* matched, set reg and return */
if (flushalias (q)) return 0;
if (q->Pop != P_MOVEM) flushreg (q->Preg);
if (q->Pop == P_DMOVEM) flushreg (q->Preg + 1);
q = before (q); /* back one */
continue; /* and try again */
/*
** Unary operations. These are treated the same as binary ops,
** except that a successful match means we have found the whole
** common subexpression.
*/
case P_SETCM: case P_MOVN: case P_SETO: case P_SETZ:
case P_HRRZ: case P_HLRZ: case P_HRRE: case P_HLRE:
case P_FIX: case P_FLTR:
if ((r = safematch (q, q->Pop)) != 0) break; /* matched, return */
q = before (q); /* move back */
continue; /* try again */
#if 1 /* erroneous code generated by this optimization! assumes
* left half of register is insignificant!
*/
case P_HRRM:
case P_HRLM:
if (match (q, (q->Pop == P_HRRM)? P_HRRZ : P_HLRZ)) {
r = q->Preg;
break;
}
if (flushalias (q)) return 0;
flushreg (q->Preg);
q = before (q);
continue;
#endif
/*
** Simple moves. The moves cause the subexpression finder to
** succeed as above with the unary operations.
**
** The !dropsout(q) check is in case this is a P_SKIPA to a P_JRST
** or P_POPJ, in which case it would still be safe to check for a match
** but we don't want deadjump() spoiling a perfectly good register
** when we find that there isn't the match we want.
*/
case P_SKIP:
if (q->Pop == P_SKIP+POF_ISSKIP+POS_SKPE
&& dropsout (after (q))
&& (r = match (q, P_SETZ)) != 0)
break; /* P_SKIPE+P_JRST leaves 0 in reg */
case P_MOVE:
if (!dropsout (q) && (r = safematch (q, P_MOVE)) != 0) break;
q = before (q); /* not, move back */
continue; /* try again */
/*
** Jumps. These cause the flow of control to split, so we can't
** pull P_IBPs across them. Also, we remember unconditional jumps
** in case they are preceded by a P_CAME or cascaded P_SKIP.
*/
case P_JRST: case P_POPJ: case P_JUMP:
if (q->Pop == P_JUMP+POS_SKPN && (r = match (q, P_SETZ)) != 0)
break;
jumped = 1; /* can't fold P_IBP before here */
q = before (q); /* move back */
continue;
case P_AOJ: case P_SOJ:
if ((q->Pop & POF_OPSKIP) == POS_SKPN
&& (r = match (q, P_SETZ)) != 0)
break;
jumped = 1; /* this is a jump */
flushreg (q->Preg); /* we can't deal with the reg change */
q = before (q); /* so just move back */
continue; /* and try again */
/*
** We handle here P_PUSH and P_ADJSP, which effectively change only the
** stack pointer.
*/
case P_PUSH:
if ((r = match (q, P_MOVE)) != 0)
break; /* register pushed matches 0(17) */
if (chgpush (q)) /* change refs to here into pushed x */
return findcse (target[0]->Preg, p, safedouble); /* retry */
stkoffset++; /* remember change to stack */
q = before (q); /* move back */
continue; /* try for another */
case P_ADJSP:
stkoffset += q->Pvalue; /* remember change to stack */
q = before (q); /* move back */
continue; /* try for another */
/*
** Comparisons
**
** We already did P_SKIP; these ones don't change their register.
** But if we are past a P_CAME / P_JRST, we know the P_CAME skipped
** and therefore the register contains the value compared to.
*/
case P_CAI: case P_CAM:
if (dropsout (after (q)) && (q->Pop & POF_OPSKIP) == POS_SKPE &&
match (q, P_MOVE)) { /* P_CAME+P_JRST is like P_MOVE */
r = q->Preg; /* (except that reg not munged) */
break;
}
case P_TRN: case P_TDN:
q = before (q); /* innocuous op, move back */
continue; /* and look for more */
default:
return 0; /* unknown op, give up */
}
break; /* propagate escape */
}
/*
** Here when we've found a complete match. The register containing
** the match is now in R instead of the initial register.
** Eliminate the old ops and return success.
*/
for (i = 0; i < maxflush; i++) target[i]->Pop = P_NOP; /* drop op */
fixprev(); /* update previous from drop */
return regret[r]; /* return the successful register */
}
/*
** Test two instructions to see if they refer to the same place
*/
int
sameaddr(p, q, stkoffset)
INT stkoffset;
PCODE *p, *q;
{
if ( (p->Ptype &~ (PTF_IMM + PTF_SKIPPED))
!= (q->Ptype &~ (PTF_IMM + PTF_SKIPPED)))
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -