mirror of
https://github.com/cc65/cc65.git
synced 2025-02-05 20:31:53 +00:00
New optimization step
git-svn-id: svn://svn.cc65.org/cc65/trunk@4278 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
0b4c486a49
commit
c2b03e0208
@ -447,7 +447,7 @@ static unsigned OptShift4 (CodeSeg* S)
|
||||
CS_DelEntry (S, I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
++Changes;
|
||||
}
|
||||
|
||||
NextEntry:
|
||||
@ -1110,6 +1110,7 @@ static OptFunc DOptIndLoads2 = { OptIndLoads2, "OptIndLoads2", 0, 0,
|
||||
static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptJumpTarget1 = { OptJumpTarget1, "OptJumpTarget1", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptJumpTarget2 = { OptJumpTarget2, "OptJumpTarget2", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptJumpTarget3 = { OptJumpTarget3, "OptJumpTarget3", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptRTS = { OptRTS, "OptRTS", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptRTSJumps1 = { OptRTSJumps1, "OptRTSJumps1", 100, 0, 0, 0, 0, 0 };
|
||||
@ -1198,6 +1199,7 @@ static OptFunc* OptFuncs[] = {
|
||||
&DOptJumpCascades,
|
||||
&DOptJumpTarget1,
|
||||
&DOptJumpTarget2,
|
||||
&DOptJumpTarget3,
|
||||
&DOptLoad1,
|
||||
&DOptNegA1,
|
||||
&DOptNegA2,
|
||||
@ -1568,6 +1570,7 @@ static unsigned RunOptGroup3 (CodeSeg* S)
|
||||
C += RunOptFunc (S, &DOptBoolTrans, 1);
|
||||
C += RunOptFunc (S, &DOptJumpTarget1, 1);
|
||||
C += RunOptFunc (S, &DOptJumpTarget2, 1);
|
||||
C += RunOptFunc (S, &DOptJumpTarget3, 1);
|
||||
C += RunOptFunc (S, &DOptCondBranches1, 1);
|
||||
C += RunOptFunc (S, &DOptCondBranches2, 1);
|
||||
C += RunOptFunc (S, &DOptRTSJumps1, 1);
|
||||
|
@ -183,8 +183,7 @@ static short ZPRegVal (unsigned short Use, const RegContents* RC)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0 /* Currently unused */
|
||||
|
||||
static short RegVal (unsigned short Use, const RegContents* RC)
|
||||
/* Return the contents of the given register */
|
||||
{
|
||||
@ -198,7 +197,6 @@ static short RegVal (unsigned short Use, const RegContents* RC)
|
||||
return ZPRegVal (Use, RC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -750,6 +748,82 @@ NextEntry:
|
||||
|
||||
|
||||
|
||||
unsigned OptJumpTarget3 (CodeSeg* S)
|
||||
/* Jumps to load instructions of a register, that do already have the matching
|
||||
* register contents may skip the load instruction, since it's job is already
|
||||
* done.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
/* Generate register info for this step */
|
||||
CS_GenRegInfo (S);
|
||||
|
||||
/* Walk over the entries */
|
||||
I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
unsigned J, K;
|
||||
CodeEntry* N;
|
||||
|
||||
/* New jump label */
|
||||
CodeLabel* LN = 0;
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this is a load insn with a label */
|
||||
if ((E->Info & OF_LOAD) != 0 &&
|
||||
CE_IsConstImm (E) &&
|
||||
CE_HasLabel (E) &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0) {
|
||||
|
||||
/* Walk over all insn that jump here */
|
||||
for (J = 0; J < CE_GetLabelCount (E); ++J) {
|
||||
|
||||
/* Get the label */
|
||||
CodeLabel* L = CE_GetLabel (E, J);
|
||||
for (K = 0; K < CL_GetRefCount (L); ++K) {
|
||||
|
||||
/* Get the entry that jumps here */
|
||||
CodeEntry* Jump = CL_GetRef (L, K);
|
||||
|
||||
/* Get the register info from this insn */
|
||||
short Val = RegVal (E->Chg, &Jump->RI->Out2);
|
||||
|
||||
/* Check if the outgoing value is the one thatr's loaded */
|
||||
if (Val == (unsigned char) E->Num) {
|
||||
|
||||
/* Ok, skip the insn. First, generate a label */
|
||||
if (LN == 0) {
|
||||
LN = CS_GenLabel (S, N);
|
||||
}
|
||||
|
||||
/* Change the jump target to point to this new label */
|
||||
CS_MoveLabelRef (S, Jump, LN);
|
||||
|
||||
/* Remember that we had changes */
|
||||
++Changes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Free register info */
|
||||
CS_FreeRegInfo (S);
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimize conditional branches */
|
||||
/*****************************************************************************/
|
||||
@ -1076,7 +1150,7 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
break;
|
||||
|
||||
case OP65_STA:
|
||||
/* If we store into a known zero page location, and this
|
||||
/* If we store into a known zero page location, and this
|
||||
* location does already contain the value to be stored,
|
||||
* remove the store.
|
||||
*/
|
||||
@ -1129,7 +1203,7 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
* that in the A register, replace the store by a STA. The
|
||||
* optimizer will then remove the load instruction for Y
|
||||
* later. If replacement by A is not possible try a
|
||||
* replacement by X, but check for invalid addressing modes
|
||||
* replacement by X, but check for invalid addressing modes
|
||||
* in this case.
|
||||
*/
|
||||
} else if (RegValIsKnown (In->RegY)) {
|
||||
@ -1182,39 +1256,39 @@ unsigned OptDupLoads (CodeSeg* S)
|
||||
!CE_UseLoadFlags (N)) {
|
||||
/* Value is identical and not followed by a branch */
|
||||
Delete = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP65_TYA:
|
||||
case OP65_TYA:
|
||||
if (RegValIsKnown (In->RegY) &&
|
||||
In->RegY == In->RegA &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||
!CE_UseLoadFlags (N)) {
|
||||
/* Value is identical and not followed by a branch */
|
||||
Delete = 1;
|
||||
}
|
||||
break;
|
||||
/* Value is identical and not followed by a branch */
|
||||
Delete = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the entry if requested */
|
||||
if (Delete) {
|
||||
/* Delete the entry if requested */
|
||||
if (Delete) {
|
||||
|
||||
/* Register value is not used, remove the load */
|
||||
CS_DelEntry (S, I);
|
||||
/* Register value is not used, remove the load */
|
||||
CS_DelEntry (S, I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,12 @@ unsigned OptJumpTarget2 (CodeSeg* S);
|
||||
* it's job is already done.
|
||||
*/
|
||||
|
||||
unsigned OptJumpTarget3 (CodeSeg* S);
|
||||
/* Jumps to load instructions of a register, that do already have the matching
|
||||
* register contents may skip the load instruction, since it's job is already
|
||||
* done.
|
||||
*/
|
||||
|
||||
unsigned OptCondBranches1 (CodeSeg* S);
|
||||
/* If an immidiate load of a register is followed by a conditional jump that
|
||||
* is never taken because the load of the register sets the flags in such a
|
||||
|
Loading…
x
Reference in New Issue
Block a user